繁体   English   中英

IP_PKTINFO套接字选项无效

[英]IP_PKTINFO socket option not working

我已经在这个问题上敲了几个星期,现在我终于屈服于这样一个事实:我无法弄清楚这一点。 我也一直在我的团队中与网络工程师一起工作无济于事。 我的问题如下:

我正在开发一个应用程序,它可以在多个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),自Linux内核2.2以来,IP_PKTINFO已经可用。 我正在运行Ubuntu 14.04.4,它使用内核3.13.0-24-generic。

任何帮助,见解或方向将不胜感激!

在黑暗的猜测中拍摄

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM