c - IP_PKTINFO 套接字选项不起作用

标签 c linux sockets vlan

几个星期以来,我一直在为这个问题苦苦思索,终于接受了我无法弄清楚的事实。我也一直在与我的团队中的网络工程师合作,但无济于事。我的问题如下:

我正在开发一个应用程序,该应用程序在多个 vlan 上执行非常直接的 UDP 组加入(每个 vlan 都作为其自己的虚拟接口(interface)公开,在这种情况下,如果相关,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 获取接口(interface)索引或通过 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 种不同的控制消息类型,但只填充了时间戳。此行为与我是加入单个接口(interface)上的单个 UDP 组还是多个接口(interface)上的多个组无关。

一种解决方案是重写应用程序,将每个接口(interface)放在自己的套接字上,然后将所有内容汇集到一个队列中,但根据我的经验,上下文切换会降低应用程序的性能。根据 ip(7) 手册页,IP_PKTINFO 自 Linux 内核 2.2 起可用。我正在运行使用内核 3.13.0-24-generic 的 Ubuntu 14.04.4。

如有任何帮助、见解或指导,我们将不胜感激!

最佳答案

暗中猜测

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

关于c - IP_PKTINFO 套接字选项不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37597410/

相关文章:

c - 外部并行循环中的内部顺序循环 - OMP

java - 使用 apache、java、tomcat、mysql 设置 AMI linux 微实例

python - 用户无法与代理通信

java - 在java中结束Inputstream

c - 使用递归乘以幂

c# - 基于OOP概念的C和C#有什么区别?

c - 时间延迟 (Linux)/(Windows)

linux - 防止提交同名文件

linux - virtualbox debian 中的共享文件夹中的 create-react-app 无法正常工作 - 符号链接(symbolic link)错误

ios - 使用套接字发送 HTTP POST 请求