Linux kernel Netlink:从内核发送到用户-EAGAIN和ENOBUFS

Linux kernel Netlink:从内核发送到用户-EAGAIN和ENOBUFS,linux-kernel,kernel,netlink,Linux Kernel,Kernel,Netlink,我在将netlink消息从内核模块发送到用户空间守护进程时遇到了很多问题。他们随机失败。在内核端,genlmsg_单播因EAGAIN而失败,而在用户端,nl_recvmsgs_default(函数来自libnl)因recvmsg系统调用因ENOBUFS而失败 Netlink消息很小,最大有效负载大小约为300B 下面是从内核发送消息的代码: int-send_-to_-daemon(void*msg,int-len,int-command,int-seq,u32-pid){ 结构sk_buff*

我在将netlink消息从内核模块发送到用户空间守护进程时遇到了很多问题。他们随机失败。在内核端,
genlmsg_单播
EAGAIN
而失败,而在用户端,
nl_recvmsgs_default
(函数来自
libnl
)因
recvmsg
系统调用因
ENOBUFS
而失败

Netlink消息很小,最大有效负载大小约为300B

下面是从内核发送消息的代码:

int-send_-to_-daemon(void*msg,int-len,int-command,int-seq,u32-pid){
结构sk_buff*skb;
空*味精头;
有效载荷;
有效载荷=GENL\U HDRLEN+nla\U总尺寸(len)+36;
skb=genlmsg_new(有效载荷,GFP_内核);
msg_head=genlmsg_put(skb、pid、seq和psvfs_gnl_系列,0,命令);
nla_put(skb、PSVFS_A_MSG、len、MSG);
genlmsg_端(skb、msg_端);
genlmsg_单播(初始化网络、skb、pid);
返回0;
}

我完全不知道为什么会发生这种情况,我的项目就是因为这个而无法工作!我真的希望有人能帮我。

我想知道你是不是在64位的机器上运行。如果是这样的话,我怀疑使用
int
作为
有效负载的类型可能是一些问题的根源,因为
genlmsg\u new()
要求在x86\u 64上使用64位的
size\u t

其次,我认为您不需要将
GENL\u HDRLEN
添加到
payload
中,因为这是由
genlmsg\u new()
处理的(通过使用
genlmsg\u total\u size()
,它返回
genlmsg\u msg\u size()
,最终执行添加)。顺便问一下,为什么是这个
+36
?看起来不是很方便,也不清楚它的用途


如果不看代码的其余部分,很难说出更多信息。

我在从netlink套接字通过recvmsg接收ENOBUFS时遇到了类似的问题。我发现我的问题是内核套接字缓冲区在用户空间耗尽之前就被填满了

从:

我通过增加套接字接收缓冲区(setsockopt(fd,SOL_socket,SO_RCVBUF,…)的大小来解决这个问题
,或者如果您正在使用libnl)

为什么不检查任何genlmsg_*函数给出的返回值。这应该是您识别导致问题的函数的第一步。我会检查这些值
genlmsg_unicast
返回
-EAGAIN
,如上所述,而所有其他函数都成功。我刚刚删除了上面代码中的检查,以使其更短并显示逻辑本身。感谢您的兴趣:)我正在32位机器上运行它。不管怎样,我认为情况并非如此,因为我的消息非常小(最多1KB)。我的代码中的有效负载计算是由于我无法确定应该传递给
genlmsg\u new
的确切内容。如果我不添加这36个字节,
nla\u put
将失败。我知道这很难看。我将在我的帖子中展示更多的代码。如果您感兴趣的话,整个代码都在这里:(有点难看,但它不会被维护或扩展,所以这并不重要)。
   However, reliable transmissions from kernel to user are impossible in
   any case.  The kernel can't send a  netlink  message  if  the  socket
   buffer  is  full:  the message will be dropped and the kernel and the
   user-space process will no longer have the same view of kernel state.
   It  is  up  to  the  application to detect when this happens (via the
   ENOBUFS error returned by recvmsg(2)) and resynchronize.