One solution is to put a script in /etc/network/if-up.d/ that executes before any other if-up.d script and waits for a specific condition to be met or a timeout occurs. For example, here's a script to wait for an non-link-local IPv6 address on an IPv6 interface configured with the "auto" method:
#!/bin/sh
LOG_FILE="/tmp/autoipv6.log"
if [ "$ADDRFAM" = "inet6" -a "$METHOD" = "auto" ]; then
echo "Auto method detected, waiting for IP address" >> $LOG_FILE
#wait until we have an IP address, or a timeout occurs
TIMEOUT=50 #5 second timeout--each iteration sleeps for 1/10th of a second
#get the number of addresses, excluding link-local addresses
ADDRESS_COUNT=`ip addr show dev eth0 | grep inet6 | grep -v fe80 | wc -l`
until [ $TIMEOUT -eq 0 ]; do
NEW_ADDRESS_COUNT=`ip addr show dev eth0 | grep inet6 | grep -v fe80 | wc -l`
# break out of the loop if more IPv6 addresses have been assigned
# this is implementation is naive: no guarantee is given that the new addresses
# are the result of the autoconfiguration request
if [ "$NEW_ADDRESS_COUNT" -gt "$ADDRESS_COUNT" ]; then
echo "Detected new IP address, exiting" >> $LOG_FILE
ifconfig >> $LOG_FILE
exit 0;
fi
TIMEOUT=$((TIMEOUT-1))
sleep .1
done
echo "Timeout waiting for IP address" >> $LOG_FILE
exit 1;
fi
It's important this "wait-for-condition" script run before the if-up.d Upstart script runs (the Upstart if-up.d script is where the net-device-up signals are generated). The if-up.d scripts are executed by run-parts in lexical sort order (the same order as the default output of the ls command), so a simple technique for guaranteeing order is to name the script "000wait-for-condition".