linux - 如何异步检查 ipv6 网络接口(interface)是否在 linux 中将状态从 tentative 更改为 "valid"?

标签 linux sockets linux-kernel netlink

IPv6地址分配前后,会经历暂定地址、重复地址、首选地址等多种状态。这些地址状态适用于手动和自动配置的地址。 我有一种情况,在暂定状态下使用网络接口(interface)时,对一天中的时间服务器的请求会无限期地阻塞。 (当从 python 脚本中调用 rdate 实用程序时)。通过实验,我设法得出结论,当界面的暂定状态是问题所在时调用 rdate。

我看到了

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?

我正在尝试设置一些异步调用(最好是在 python3 中),一旦接口(interface)准备好并且 rdate 可以恢复,它将返回。而 netlink 套接字似乎只是解决问题的工具。 看完this和 netlink(7) 我看到我需要类似的东西

s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);

但是我无法找到关于从套接字获得输出后要检查哪些结构字段/设备标志的正确信息。 在 netdevice(7) 中我找到了

IFF_UP            Interface is running.

但我不确定这在暂定状态下是否也不是真的。

当然,简单的方法就是循环 sleep 并检查

ip a show dev devName

直到状态有效,但我将其保留为万一异步调用失败的最后手段。

最佳答案

如果你想监控IPv6地址变化和状态可以采用我的example你提到的。

就您只对 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;
}

这是一个快速而肮脏的例子,但你应该看看它是如何工作的。 在这个例子中,我们处理 netlink 消息中的 ifaddrmsg 数据,以获得分配的 ipv6 地址。

也许最有趣的部分是 IFA_CACHEINFO。 此时我们可以检查地址缓存并获得有关地址有效和首选状态的一些有用信息。 如您所见,可以设置一些超时值或无穷大值。 您可以使用网络接口(interface)来发现 IPv6 地址和 IFA_CACHEINFO 状态的不同状态。

关于linux - 如何异步检查 ipv6 网络接口(interface)是否在 linux 中将状态从 tentative 更改为 "valid"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55614270/

相关文章:

python - Zeromq:不允许使用 unicode,请使用 send_unicode

perl - 是否可以为 Perl 的套接字监听增加 QUEUESIZE?

将数据从内核空间复制到用户空间

linux - Bare Git repo 无法添加文件或提交文件

linux - 登录时 Bash 提示 "have not a command"

java - 如何增加最大 JVM 线程数(Linux 64 位)

c - Socket 服务器关闭命令的连接

c - 有什么办法可以用我自己的 softirq 调用 linux 内核

c++ - 需要非常小的开源内核

c++ - 如何从 cvPoint 中分别获取 x 和 y 坐标到 int?