Как асинхронно проверить, меняет ли сетевой интерфейс ipv6 состояние с предварительного на «действительный» в Linux? - PullRequest
0 голосов
/ 10 апреля 2019

До и после назначения адреса IPv6 он проходит через различные состояния, такие как предварительный адрес, дублированный адрес и предпочтительный адрес. Эти состояния адресов применимы как к настроенным вручную, так и к автоматически настроенным адресам. У меня возникла ситуация, когда при использовании сетевого интерфейса в предварительном состоянии запрос к времени суток блокирует сервер на неопределенный срок. (При вызове утилиты rdate из скрипта Python). Путем экспериментов мне удалось сделать вывод, что вызов rdate при пробном состоянии интерфейса является проблемой.

Я вижу, что

ip-monitor
Команду

можно использовать и найти интересные идеи здесь с сокетом AF_NETLINK В Linux: как программно определить, включен ли интерфейс NIC и включен ли он?

Я пытаюсь настроить какой-то асинхронный вызов (предпочтительно в python3), который будет возвращаться, как только интерфейс будет готов и rdate может возобновиться. И сокет netlink кажется просто инструментом для решения проблемы. Прочитав this и netlink (7), я вижу, что мне нужно что-то вроде

s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);

Но я не могу найти правильную информацию о том, какие поля структуры / флаги устройства проверять после получения вывода из сокета. В netdevice (7) я нашел

IFF_UP            Interface is running.

Но я не уверен, что это не будет так же в предварительном состоянии.

Конечно, самый простой способ - это просто переспать со сном и проверить с помощью

ip a show dev devName

до тех пор, пока состояние не станет действительным, но я оставлю его в качестве крайней меры в случае сбоя при асинхронном вызове.

1 Ответ

1 голос
/ 11 апреля 2019

Если вы хотите отслеживать изменения и статус IPv6-адресов, вы можете использовать мой пример , который вы упомянули.

Если вас интересует только уведомление об IPv6-адресах, вы должны заменить эту строку:

local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;

с этим:

local.nl_groups = RTMGRP_IPV6_IFADDR;

Вот что вы должны сделать в случае 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;
}

Это быстрый и грязный примерно вы должны увидеть, как это работает.В этом примере мы обрабатываем данные ifaddrmsg в сообщении netlink, получая назначенный адрес ipv6.

Возможно, самая интересная часть - это IFA_CACHEINFO.На этом этапе мы можем проверить кэш адресов и получить некоторую полезную информацию о допустимых и предпочтительных состояниях адреса.Как вы можете видеть, здесь может быть установлен тайм-аут или бесконечность.Вы можете поиграть с сетевым интерфейсом, чтобы обнаружить различные состояния адреса IPv6 и состояния IFA_CACHEINFO.

...