1

Before and after an IPv6 address is assigned, it goes through various states, such as tentative address, duplicate address, and preferred address. These address states are applicable to both manually and automatically configured addresses. I have a situation when using network interface in tentative state a request to time of day server blocks indefinitely. (When calling rdate utility from within python script). By experiments I managed to to conclude that calling rdate when tentative state of the interface is the problem.

I see that

ip-monitor

command can be used and found some interesting ideas here with AF_NETLINK socket On Linux: how can I programmatically determine if a NIC interface is enabled and plugged in?

I'm trying to setup some asynchronous call (preferably in python3) which will return once the interface is ready and rdate can resume. And the netlink socket seems just the tool for the problem. Having read this and netlink(7) I see that I need something like

s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);

But I cannot find proper information on which struct fields/device flags to check once got output from socket. In netdevice(7) I found

IFF_UP            Interface is running.

But I'm not sure whether this will not be true in tentative state too.

Of course the easy way is just looping with a sleep and checking with

ip a show dev devName

until the state is valid, but I keep it as last resort in case I fail with asynchronous call.

dmytro.poliarush
  • 383
  • 4
  • 11

1 Answers1

5

If you want to monitor IPv6 address changes and status you can adopt my example that you mentioned.

As far as you only interested in IPv6 addresses notification you should replace this string:

local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;

with this:

local.nl_groups = RTMGRP_IPV6_IFADDR;

Here is what you should do in case of RTM_NEWADDR/RTM_DELADDR:

struct ifaddrmsg *ifa = NLMSG_DATA(h);
struct rtattr *tb[IFLA_MAX + 1];

parseRtattr(tb, IFA_MAX, IFA_RTA(ifa), h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));

if (!tb[IFA_LOCAL]) {
    tb[IFA_LOCAL] = tb[IFA_ADDRESS];
}

if (!tb[IFA_ADDRESS]) {
    tb[IFA_ADDRESS] = tb[IFA_LOCAL];
}

char ifAddress[INET6_ADDRSTRLEN];

switch (h->nlmsg_type) {
    case RTM_NEWADDR:
        if (tb[IFA_LOCAL]) {
            inet_ntop(AF_INET6, RTA_DATA(tb[IFA_LOCAL]), ifAddress, sizeof(ifAddress));
            printf("New local IPv6 address: %s\n", ifAddress);
        } else if (tb[IFA_BROADCAST]) {
            inet_ntop(AF_INET6, RTA_DATA(tb[IFA_BROADCAST]), ifAddress, sizeof(ifAddress));
            printf("New local IPv6 address: %s\n", ifAddress);
        } else if (tb[IFA_ANYCAST]) {
            inet_ntop(AF_INET6, RTA_DATA(tb[IFA_ANYCAST]), ifAddress, sizeof(ifAddress));
            printf("New anycast IPv6 address: %s\n", ifAddress);
        }

        if (tb[IFA_CACHEINFO]) {
            struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]);

            if (ci->ifa_valid == 0xFFFFFFFFU) {
                printf("ifa_valid infinity\n");
            } else {
                printf("ifa_valid = %u sec\n", ci->ifa_valid);
            }

            if (ci->ifa_prefered == 0xFFFFFFFFU) {
                printf("ifa_prefered = %u sec\n", ci->ifa_prefered);
            }
        }

        break;

    case RTM_DELADDR:
        printf("IPv6 address was deleted\n");
        break;
}

This is a quick and dirty example but you should see how it works. In this example we processing ifaddrmsg data in netlink message getting assigned ipv6 address.

Maybe most interesting part is a IFA_CACHEINFO. At this point we can check address cache and get some useful information about valid and preferred states of the address. As you can see there are can be some set timeout or infinity value. You can play with you network interface to discover different states of the IPv6 address and IFA_CACHEINFO state.

elenbert
  • 95
  • 5