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

时间:2011-12-12 17:24:24

标签: linux-kernel kernel netlink

我在从内核模块向userspace-daemon发送netlink消息时遇到了很多麻烦。他们随机失败。在内核方面,genlmsg_unicastEAGAIN失败,而在用户端,nl_recvmsgs_default(来自libnl的函数)失败,NLE_NOMEMrecvmsg导致ENOBUFS系统调用失败,int send_to_daemon(void* msg, int len, int command, int seq, u32 pid) { struct sk_buff* skb; void* msg_head; int res, payload; payload = GENL_HDRLEN+nla_total_size(len)+36; skb = genlmsg_new(payload, GFP_KERNEL); msg_head = genlmsg_put(skb, pid, seq, &psvfs_gnl_family, 0, command); nla_put(skb, PSVFS_A_MSG, len, msg); genlmsg_end(skb, msg_head); genlmsg_unicast(&init_net, skb, pid); return 0; }

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

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

{{1}}

我完全不知道为什么会这样,我的项目因此而无法正常工作!我真的希望有人可以帮助我。

2 个答案:

答案 0 :(得分:2)

我想知道你是否在64位机器上运行。如果是这种情况,我怀疑使用int作为payload的类型可能是某些问题的根源,因为genlmsg_new()期望size_t是64位在x86_64上。

其次,我认为您不需要将GENL_HDRLEN添加到payload,因为genlmsg_new()genlmsg_total_size()处理(使用genlmsg_msg_size(),其返回{{}最终进行添加的1}}。为什么这个+ 36呢?看起来不那么便携也不明确。

如果不仔细查看剩下的代码,很难说清楚。

答案 1 :(得分:2)

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

来自netlink(7) man page

   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.

我通过增加套接字接收缓冲区的大小来解决这个问题(setsockopt(fd,SOL_SOCKET,SO_RCVBUF,...) ,如果您使用的是libnl,则为nl_socket_set_buffer_size()