收听AF_NETLINK套接字时获取所有链接和地址信息

时间:2014-03-20 21:34:13

标签: c netlink

我编写了一段代码,在网络信息发生变化(主要是收听RTM_NEWADDR,RTM_DELADDR,RTM_NEWLINK和RTM_DELLINK)时,会通知我。 这工作得非常好,每次我拔掉电源,更改IP或任何我收到通知。 唯一的问题,是我第一次启动我的代码,我希望它能给我整个当前状态(RTM_GETLINK和RTM_GETADDR)。

我可以请求RTM_GETLINK或RTM_GETADDR:

memset(&req, 0, sizeof(req));
req.nlmsghdr.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; /* request to dump all kernel subsystem */
req.nlmsghdr.nlmsg_type  = RTM_GETLINK;  /* link information              */
req.nlmsghdr.nlmsg_seq   = 1;
req.nlmsghdr.nlmsg_pid   = pid;
req.rtgenmsg.rtgen_family = AF_UNSPEC;

iovec.iov_base = &req;
iovec.iov_len  = req.nlmsghdr.nlmsg_len;

memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_iov     = &iovec;
msghdr.msg_iovlen  = 1;
msghdr.msg_name    = &addr;
msghdr.msg_namelen = sizeof(addr);

/*
** TODO: check for number of sent characters
**       on error display errno
*/
sendmsg(nls, &msghdr, 0);

/* do listening stuff... */

但如果我同时要求两者:

req.nlmsghdr.nlmsg_type  = RTM_GETLINK | RTM_GETADDR;

我只收到ip informtion。

我应该使用两个不同的套接字,on用于请求,另一个用于监听,或者是否可以在同一个套接字中执行所有操作?

我已尝试为每个请求执行发送,并使用seq(将其增加为第二个请求),我能够看到第二个回复只有40个字节:(

memset(&kms.addr, 0, sizeof(kms.addr));
kms.addr.nl_family = AF_NETLINK;

/* prepare request */
memset(&req, 0, sizeof(req));
req.nlmsghdr.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP /*| NLM_F_ACK*/; /* request to dump all kernel subsystem */
req.nlmsghdr.nlmsg_type  = RTM_GETLINK;                /* link information                     */
req.nlmsghdr.nlmsg_seq   = 1;
req.nlmsghdr.nlmsg_pid   = pid;
req.rtgenmsg.rtgen_family = AF_UNSPEC;

iovec.iov_base = &req;
iovec.iov_len  = req.nlmsghdr.nlmsg_len;

memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_iov     = &iovec;
msghdr.msg_iovlen  = 1;
msghdr.msg_name    = &kms.addr;
msghdr.msg_namelen = sizeof(kms.addr);

/*
** TODO: check for number of sent characters
**       on error display errno
*/
sendmsg(kms.nls, &msghdr, 0);

memset(&req, 0, sizeof(req));
req.nlmsghdr.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP /*| NLM_F_ACK*/; /* request to dump all kernel subsystem */
req.nlmsghdr.nlmsg_type  = RTM_GETADDR;                /* link information                     */
req.nlmsghdr.nlmsg_seq   = 2;
req.nlmsghdr.nlmsg_pid   = pid;
req.rtgenmsg.rtgen_family = AF_UNSPEC;

iovec.iov_base = &req;
iovec.iov_len  = req.nlmsghdr.nlmsg_len;

memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_iov     = &iovec;
msghdr.msg_iovlen  = 1;
msghdr.msg_name    = &kms.addr;
msghdr.msg_namelen = sizeof(kms.addr);

/* do listening stuff... */

再分析一下,我似乎得到了一个N​​LMSG_ERROR消息类型。 错误代码为-16 意思是"设备或资源忙碌"。

如果我在每次发送后读取套接字,我都不会遇到问题。但我宁愿能够做我的所有要求,然后收集所有回复...

2 个答案:

答案 0 :(得分:2)

在向netlink套接字发送下一个请求之前,用户空间需要等待NLMSG_DONE netlink控制消息。换句话说,如果要连续发送多个netlink请求,则序列应如下所示:

  1. 发送req1
  2. 等待NLMSG_DONE
  3. 发送req2
  4. 等待NLMSG_DONE
  5. ...

答案 1 :(得分:0)

这是我在http://www.carisma.slowglass.com/~tgr/libnl/doc/core.html

中找到的答案
  

可选地,内核可以发送配置通知   允许用户空间监听更改而不是轮询的更改   经常。通知通常重用现有的消息类型和   依赖应用程序使用单独的套接字来区分   请求和通知,但您也可以指定单独的消息   类型。

但不确定这意味着什么:

  

但您也可以指定单独的消息类型。