简体   繁体   English

IP_PKTINFO套接字选项无效

[英]IP_PKTINFO socket option not working

I have been banging my head on this one for a few weeks now and am finally submitting to the fact that I just can't figure it out. 我已经在这个问题上敲了几个星期,现在我终于屈服于这样一个事实:我无法弄清楚这一点。 I have also been working with networking engineers on my team to no avail. 我也一直在我的团队中与网络工程师一起工作无济于事。 My problem is as follows: 我的问题如下:

I am working on an application that does pretty straight forward UDP group joins on multiple vlans (each vlan is exposed as its own virtual interface, the NIC in this case is a SolarFlare if that is relevant). 我正在开发一个应用程序,它可以在多个vlan上进行非常简单的UDP组连接(每个vlan都作为自己的虚拟接口公开,在这种情况下,如果相关,则NIC是SolarFlare)。 All of these joins happen on a single socket (where the messages are de-duplicated based on payload sequence numbers). 所有这些连接都发生在单个套接字上(根据有效负载序列号对消息进行重复数据删除)。 Prior to doing the IP_ADD_MEMBERSHIP I am setting socket options like this: 在执行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))

I need to get at either the interface index via IP_PKTINFO or the vlan id via PACKET_AUXDATA in order to gather statistics downstream. 我需要通过IP_PKTINFO获取接口索引或通过PACKET_AUXDATA获取vlan id,以便收集下游的统计信息。 Now, everything initializes without error and I am able to process UDP payloads without issue. 现在,一切都初始化没有错误,我能够毫无问题地处理UDP有效负载。 Where I run into trouble is when I attempt to access the ancillary / control messages requested above as demonstrated with the simple debug logging: 我遇到麻烦的地方是当我尝试访问上面请求的辅助/控制消息时,如简单的调试日志所示:

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

For every packet received, this only outputs: 对于收到的每个数据包,这只输出:

Control Message: cmsg_level: 1, cmsg_type 29

For reference, SOL_SOCKET=1 and SO_TIMESTAMP=29. 作为参考,SOL_SOCKET = 1且SO_TIMESTAMP = 29。 So, although I am requesting 3 different control message types, only the timestamping is being populated. 因此,虽然我正在请求3种不同的控制消息类型,但只填充了时间戳。 This behavior is independent of whether I am joining a single UDP group on a single interface or multiple groups on multiple interfaces. 此行为与我是在单个接口上加入单个UDP组还是在多个接口上加入多个组无关。

One solution would be to rewrite the application to put each interface on its own socket, and then funnel everything into a queue, but in my experience the context switching kills the performance of the app. 一种解决方案是重写应用程序以将每个接口放在其自己的套接字上,然后将所有内容汇集到队列中,但根据我的经验,上下文切换会破坏应用程序的性能。 According to the manual page ip(7) IP_PKTINFO has been available since Linux kernel 2.2. 根据手册页ip(7),自Linux内核2.2以来,IP_PKTINFO已经可用。 I am running Ubuntu 14.04.4 which uses kernel 3.13.0-24-generic. 我正在运行Ubuntu 14.04.4,它使用内核3.13.0-24-generic。

Any help, insight or direction would be greatly appreciated! 任何帮助,见解或方向将不胜感激!

Shot in the dark guesses 在黑暗的猜测中拍摄

1) You need to reset yes back to 1 after each successful call to setsockopt . 1)每次成功调用setsockopt后,需要将yes重置为1。 The docs imply this isn't needed, but it's what I would do. 文档暗示这不是必需的,但这就是我要做的。

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) Are you checking the return value of setsockopt to see if those calls are correctly succeeding. 2)您是否检查setsockopt的返回值以查看这些调用是否正确成功。 It's not clear if you've validated they are returning "0" for success or "-1" for error. 目前尚不清楚你是否已经验证他们返回“0”表示成功,或者“-1”表示错误。 You should print out the return code for each call. 您应该打印每个呼叫的返回码。

3) You aren't showing your recvmsg code which is what you presumably using to get the extra info. 3)您没有显示您的recvmsg代码,这是您可能用于获取额外信息的代码。 But it's possible the struct msghdr is not initialized correctly. 但是struct msghdr可能没有正确初始化。 Specifically is your buffer big enough to get all the control data? 具体来说,你的缓冲区是否足以获得所有控制数据? Here's how I do it in my code: 以下是我在代码中的操作方法:

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