我在从内核模块向userspace-daemon发送netlink消息时遇到了很多麻烦。他们随机失败。在内核方面,genlmsg_unicast
以EAGAIN
失败,而在用户端,nl_recvmsgs_default
(来自libnl
的函数)失败,NLE_NOMEM
由recvmsg
导致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}}
我完全不知道为什么会这样,我的项目因此而无法正常工作!我真的希望有人可以帮助我。
答案 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。我发现我的问题是在用户空间耗尽之前内核套接字缓冲区填充。
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()。