linux - netlink 分散发送导致内核错误响应 (NLMSG_ERROR)

标签 linux sockets netlink

我正在编写一个使用 Netlink 协议(protocol)来收集任务统计信息的程序。我没有走得太远,因为内核对我认为有效的数据包做出了错误响应。我使用 strace 将我的程序的行为与正常工作的 iotop 的行为进行了比较。

来自 iotop 的 strace 的相关位:

socket(PF_NETLINK, SOCK_RAW, 16)        = 3
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [65536], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [65536], 4) = 0
bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0
getsockname(3, {sa_family=AF_NETLINK, pid=-4286, groups=00000000}, [12]) = 0
sendto(3, "\x24\x00\x00\x00\x10\x00\x01\x00\x01\x00\x00\x00\x42\xef\xff\xff\x03\x00\x00\x00\x0e\x00\x02\x00\x54\x41\x53\x4b\x53\x54\x41\x54\x53\x00\x00\x00", 36, 0, NULL, 0) = 36
recvfrom(3, "\x70\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00\x42\xef\xff\xff\x01\x02\x00\x00\x0e\x00\x02\x00\x54\x41\x53\x4b\x53\x54\x41\x54\x53\x00\x00\x00\x06\x00\x01\x00\x17\x00\x00\x00\x08\x00\x03\x00\x01\x00\x00\x00\x08\x00\x04\x00\x00\x00\x00\x00\x08\x00\x05\x00\x04\x00\x00\x00\x2c\x00\x06\x00\x14\x00\x01\x00\x08\x00\x01\x00\x01\x00\x00\x00\x08\x00\x02\x00\x0b\x00\x00\x00\x14\x00\x02\x00\x08\x00\x01\x00\x04\x00\x00\x00\x08\x00\x02\x00\x0a\x00\x00\x00", 16384, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, [12]) = 112

我的程序中 strace 输出的相应部分:

bind(8, {sa_family=AF_NETLINK, pid=19156, groups=00000000}, 12) = 0
setsockopt(8, SOL_SOCKET, SO_SNDBUF, [65536], 4) = 0
setsockopt(8, SOL_SOCKET, SO_RCVBUF, [65536], 4) = 0
sendmsg(8, {msg_name(0)=NULL, msg_iov(5)=[{"\x24\x00\x00\x00\x10\x00\x01\x00\x00\x00\x00\x00\xd4\x4a\x00\x00", 16}, {"\x03\x00\x00\x00", 4}, {"\x0e\x00\x02\x00", 4}, {"\x54\x41\x53\x4b\x53\x54\x41\x54\x53\x00", 10}, {"\x00\x00", 2}], msg_controllen=0, msg_flags=0}, MSG_NOSIGNAL) = 36
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\x38\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xd4\x4a\x00\x00", 16}], msg_controllen=0, msg_flags=MSG_TRUNC}, 0) = 16

如果我重新格式化它们,它们看起来有点像这样(作为十六进制转储): (请注意,这些来自不同的运行,因此 pid 值会不同,但重新格式化的 strace 输出的其余部分是相同的。)

sent from iotop
24000000 10000100 01000000 42efffff
03000000 0e000200 5441534b 53544154 
53000000

received by iotop
70000000 10000000 01000000 42efffff
01020000 0e000200 5441534b 53544154 
53000000 06000100 17000000 08000300 
01000000 08000400 00000000 08000500 
04000000 2c000600 14000100 08000100 
01000000 08000200 0b000000 14000200 
08000100 04000000 08000200 0a000000

sent from program
24000000 10000100 00000000 d44a0000
03000000 0e000200 5441534b 53544154 
53000000

received by program
38000000 02000000 00000000 d44a0000

在我看来,有两个区别。

  1. iotop 似乎对 pid 使用负值。 我尝试进行更改,以便我的程序也为 pid 发送负数。这没有什么区别。

  2. 我使用分散/聚集方法:这样可以减少内存浪费(这可能会受到我想要的目标 PC 的限制)。但是,我怀疑有一些(如果不是全部)Netlink 组件仅支持按请求发送和接收单个缓冲区。

有人知道 Netlink 是否允许分散/聚集,或者是否要求所有通信一次在一个大缓冲区中完成?

最佳答案

需要记住的一件事是,您需要特定的功能(CAP_NET_ADMIN、CAP_NET_RAW 之一)才能使用 netlink。一般来说,只有 root 才具备必要的能力。有一种方法可以将其提供给普通用户,但这是一个主要问题,涉及额外的 PAM 模块、修改/etc 中的文件以及向可执行文件添加扩展属性。

这对我来说似乎是一个很大的麻烦。

我最终通过放弃所有 asio 代码并粘贴来自 linux 发行版的示例代码来完成这项工作。我怀疑 netlink 与 sendmsg 不能很好地配合。

关于linux - netlink 分散发送导致内核错误响应 (NLMSG_ERROR),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23350602/

相关文章:

c - 如何防止子进程中的 SIGINT 传播到父进程并杀死父进程?

c - 通过套接字传输文件,最终大小字节数较少

c - 如何使用 C 语言的套接字将客户端连接到 IRC 服务器

sockets - 内核模块可以主动通过netlink向用户空间发送消息吗?

linux - generic netlink 中的策略和属性是什么概念?

c - 列 "symbol"显示地址而不是函数名

c - 如何从终端“按键缓冲区”读取?

linux - 逐行比较两个文件并使用 shell 脚本找到最大和最小的数字

python - 如何让我的 objective-c 客户端与我的 python 服务器通信?

linux - 使用 rtnetlink 套接字在 linux 路由表中安装新路由