几个星期以来,我一直在努力解决这个问题,最后终于接受了这样一个事实:我就是想不通。我也一直在与团队中的网络工程师合作,但无济于事。我的问题如下:
我正在开发一个应用程序,该应用程序在多个 vlan 上执行非常直接的 UDP 组连接(每个 vlan 都作为其自己的虚拟接口公开,在这种情况下,如果相关,NIC 是 SolarFlare)。所有这些连接都发生在单个套接字上(其中消息根据有效负载序列号进行重复数据删除)。在执行 IP_ADD_MEMBERSHIP 之前,我正在设置这样的套接字选项:
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &yes, sizeof yes)
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes))
setsockopt(sock, IPPROTO_IP, PACKET_AUXDATA, &yes, sizeof(yes))
我需要通过 IP_PKTINFO 获取接口索引或通过 PACKET_AUXDATA 获取 vlan id,以便收集下游统计信息。现在,一切初始化都没有错误,我能够毫无问题地处理 UDP 有效负载。我遇到麻烦的地方是当我尝试访问上面请求的辅助/控制消息时,如简单的调试日志所示:
for (cmsgptr = CMSG_FIRSTHDR(&msg);
cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
printf("Control Message: cmsg_level: %d, cmsg_type %d\n", cmsgptr->cmsg_level, cmsgptr->cmsg_type);
}
对于收到的每个数据包,这仅输出:
Control Message: cmsg_level: 1, cmsg_type 29
作为参考,SOL_SOCKET=1 和 SO_TIMESTAMP=29。因此,尽管我请求了 3 种不同的控制消息类型,但仅填充了时间戳。此行为与我是在单个接口上加入单个 UDP 组还是在多个接口上加入多个组无关。
一种解决方案是重写应用程序以将每个接口放在自己的套接字上,然后将所有内容汇集到一个队列中,但根据我的经验,上下文切换会破坏应用程序的性能。根据手册页 ip(7),IP_PKTINFO 自 Linux 内核 2.2 起就可用。我正在运行使用内核 3.13.0-24-generic 的 Ubuntu 14.04.4。
任何帮助、见解或方向将不胜感激!