7

I claim an IPv6 address using ifconfig in a script. This address is then immediately used to listen on a TCP port.

When I write the script like this, it fails because the service is unable to listen:

ifconfig igb0 inet6 2001:db8::10/64 add
service my_service start #fails

However, it succeeds when I do it like this:

ifconfig igb0 inet6 2001:db8::10/64 add
sleep 1
service my_service start

I tried writing the output of ifconfig directly after running the add-operation. It appears that ifconfig reports the IP-address as being tentative, which apparently prevents a service from listening on it.

Naturally, waiting exactly one second and hoping that the address has become available is not a very good way to handle this. How can I wait for a tentative address to become available, or make ifconfig return later so that the address is all set up?

jornane
  • 301
  • 3
  • 14
  • You can replace the sleep with a loop, maybe `until ifconfig igb0 inet6|grep something;do true; done` but I don't have a suitable machine to test it on (why it's a comment rather than an answer). If you _do_ get it to work, you can put the working code in an answer yourself. – MAP Jul 30 '16 at 22:24
  • @MAP This will probably work, but it'll hog the CPU and spawn many short-lived processes. In my case, I think using `sleep` is safer, but there may be other cases where the loop is preferred. – jornane Aug 02 '16 at 19:38
  • Well, it shouldn't be very long, but you're right it should probably be throttled (at least by replacing `true` in the loop with a `sleep`, for some suitable interval). – MAP Aug 03 '16 at 04:16
  • An address can be in several states, tentative is one of them. Having `ifconfig` wait for an address to leave the state tentative is simply not in harmony with how addresses are being handled. ~ N.B. The `ip` utility of the iproute2 package is far superior to `ifconfig`. – countermode Feb 10 '17 at 15:21
  • You may configure to use _optimistic DAD_ as defined in RFC 4429. The purpose is to make an address available to applications even if the DAD is not yet completed. You may need to reconfigure the kernel to utilize this feature. – countermode Feb 10 '17 at 15:24
  • @countermode I think that RFC 4429 is a better solution, and a good candidate for accepted answer. Would you be willing to publish this as an answer? – jornane Feb 12 '17 at 16:42
  • `ip -6 monitor addr dev igb0` works in event mode by using the kernel's rtnetlink API. But I guess nowadays, this would be integrated in networking tools directly. – A.B Aug 26 '23 at 13:49

2 Answers2

3

An address can be in several states, tentative is one of them. Having ifconfig wait for an address to leave the state tentative is simply not in accord with the design.

You may configure to use optimistic DAD as defined in RFC 4429. The purpose is to make an address available to applications even if the DAD is not yet completed. You may need to reconfigure the kernel to utilize this feature.

Once the kernel is built to provide optimistic DAD, then you may certain sysctl-settings to enable it. From ip-sysctl.txt:

/proc/sys/net/ipv6/* Variables:
...

conf/interface/*:
        Change special settings per interface.

        The functional behaviour for certain settings is different
        depending on whether local forwarding is enabled or not.

...

optimistic_dad - BOOLEAN
        Whether to perform Optimistic Duplicate Address Detection (RFC 4429).
                0: disabled (default)
                1: enabled

use_optimistic - BOOLEAN
        If enabled, do not classify optimistic addresses as deprecated during
        source address selection.  Preferred addresses will still be chosen
        before optimistic addresses, subject to other ranking in the source
        address selection algorithm.
                0: disabled (default)
                1: enabled

That is, do something like

sysctl -w net.ipv6.conf.enp2s6.optimistic_dad=1
sysctl -w net.ipv6.conf.enp2s6.use_optimistic=1

at boot time.

countermode
  • 7,373
  • 5
  • 31
  • 58
2

After asking a NetBSD-developer, and verifying that the same applies to FreeBSD, I found out the solution (which applies on both these OSes):

The Duplicate Address Detection (DAD) will use some time detecting if the address is already in use. The amount of time it will use for this is defined in seconds in the sysctl(3) value net.inet6.ip6.dad_count. In NetBSD's /etc/rc.d/network, function network_start_ipv6_autoconf, the script waits for this amount plus one second.

When DAD finds out that the address is already in use on the network, ifconfig(8) will show the address as duplicated. In this state it is not possible to bind to the address, similar to when the address is tentative.

A more complete and correcter solution would thus be:

ifconfig igb0 inet6 2001:db8::10/64 add
dadcount=$(/sbin/sysctl -n net.inet6.ip6.dad_count 2>/dev/null)
sleep $dadcount
sleep 1
ifconfig igb0 | grep 2001:db8::10/64 | egrep '(duplicated|tentative)$' >&2 && exit 1
service my_service start

I have observed that FreeBSD and NetBSD behave differently when adding an address that is currently in duplicated state:

  • FreeBSD 11 will immediatly remove the duplicated state, allowing the address to be used, abeit possibly causing conflicts.
  • NetBSD 7 will mark the address as tentative, and it won't change the state from there, at least not for a couple minutes. The address must be removed and added again in order to be useable.
jornane
  • 301
  • 3
  • 14