IP_PKTINFO套接字选项无法工作

5
我已经苦思冥想了几周,但最终还是不得不承认我无法解决这个问题。我还与团队中的网络工程师一起努力,但没有结果。我的问题如下:
我正在开发一个应用程序,在多个虚拟局域网上进行相当直接的UDP组加入(每个虚拟局域网都公开为自己的虚拟接口,在这种情况下,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),自Linux内核2.2以来就可用IP_PKTINFO。我正在运行Ubuntu 14.04.4,使用内核3.13.0-24-generic。
非常感谢任何帮助、见解或指导!
1个回答

1

猜测:

1)每次成功调用 setsockopt 后,您需要将 yes 重置为 1。文档暗示不需要这样做,但这是我会做的。

int yes = 1;
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &yes, sizeof(yes));

yes = 1;
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes));

yes = 1;
setsockopt(sock, IPPROTO_IP, PACKET_AUXDATA, &yes, sizeof(yes));

2) 你是否检查了setsockopt的返回值以确保这些调用正确成功。不清楚你是否验证它们返回成功的“0”或错误的“-1”。你应该打印出每个调用的返回代码。

3) 你没有展示你的recvmsg代码,这是你可能使用来获取额外信息的。但是可能struct msghdr未正确初始化。具体而言,你的缓冲区是否足够大以获取所有控制数据?以下是我在我的代码中所做的方式:

struct iovec vec;
ssize_t ret;

const size_t CONTROL_DATA_SIZE = 1000;  // THIS NEEDS TO BE BIG ENOUGH.
char controldata[CONTROL_DATA_SIZE]; 
struct msghdr hdr = {};
sockaddr_storage addrRemote = {};

vec.iov_base = buf;
vec.iov_len = len;

hdr.msg_name = &addrRemote;
hdr.msg_namelen = sizeof(addrRemote);
hdr.msg_iov = &vec;
hdr.msg_iovlen = 1;
hdr.msg_control = controldata;
hdr.msg_controllen = CONTROL_DATA_SIZE;

ret = ::recvmsg(sockfd, &hdr, flags);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接