On 15:43 Sun 09 Jun     , martin f krafft wrote:
> also sprach martin f krafft <madd...@debian.org> [2013.04.23.1433 +0200]:
> >   ip monitor address | while read n iface proto address rest; do
> >     [ $iface = $IFACE ] && [ ${address%/*} = $IF_ADDRESS ] && break;
> >   done
> 
> This is brittle. I've had it wait endlessly for output from
> ip-monitor, e.g. if the NETLINK message is emitted before the hook
> runs and then no other messages take place.
> 
> Maybe another way would simply be to pull the ip-address output
> until the 'tentative' flag is gone?
> 

Hi,

Any news on this? It impacts virtually every service during boot when 
binding a non-wildcard IPv6 address (see for example #726323). Also the 
Linux kernel does not provide the equivalent of 
sys.net.ipv4.ip_nonlocal_bind for IPv6, which could be used as a 
workaround, thus making things even worse.

To recap:
 - DAD is enabled by default, and dad_transmits is set to 1. With the 
   default settings, this causes a delay of approx. 2 seconds where the 
   address is in a tentative state, and thus unavailable to userspace.

 - Optimistic DAD does not work when the interface does not yet have a 
   next-hop router address (see RFC 4429, section 3.3) so it doesn't 
   help things. Also, section 3.1 states that Optimistic DAD should not 
   be used with manually entered addresses.

 - After DAD, there are two possible outcomes:
   a) If DAD is succesful, the kernel removes the tentative flag and 
      emits a Netlink message about the newly-added address.
   b) If DAD is unsuccessful, the kernel replaces the tentative flag 
      with the dadfailed flag. Not sure if it emits a Netlink message.

Ideally ifupdown should wait (either by monitoring or by polling 
netlink/iproute2 with a reasonable timeout) and check for the outcome of 
DAD and also propagate any dadfailed error to its exit code. The 
attached if-up.d hook is a proof-of-concept of how something like this 
could be done (I have tested it only slightly). Any ideas/suggestions?

Regards,
Apollon
#!/bin/sh

# 6 seconds maximum wait time
attempts=60
delay=0.1

[ "$ADDRFAM" = inet6 ] || exit 0

echo -n "Waiting for DAD... "
for attempt in $(seq 1 $attempts); do
        tentative=$(ip -o -6 address list dev "$IFACE" to 
"${IF_ADDRESS}/${IF_NETMASK}" tentative | wc -l)
        if [ $tentative -eq 0 ]; then
                attempt=0 # This might have been our last attempt, but succesful
                break
        fi
        sleep $delay
done

if [ $attempt -eq $attempts ]; then
        echo "Timed out"
        exit 1
fi

dadfailed=$(ip -o -6 address list dev "$IFACE" to "${IF_ADDRESS}/${IF_NETMASK}" 
dadfailed | wc -l)

if [ $dadfailed -ge 1 ]; then
        echo "Failed"
        exit 1
fi

echo Done

Reply via email to