On 15:43 Sun 09 Jun , martin f krafft wrote:
> also sprach martin f krafft <[email protected]> [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