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