Get all link and address information when listenning to a PF_NETLINK socket

StackOverflow https://stackoverflow.com/questions/22545607

  •  18-06-2023
  •  | 
  •  

문제

I've written a peace of code that notifies me whenever relevant (to me) networking information changes (mainly listenning to RTM_NEWADDR, RTM_DELADDR, RTM_NEWLINK and RTM_DELLINK. this works pretty fine, each time I unplug, change ip or whatsoever I get notified. only problem, is the first time I launch my code, I would like it to give me the whole current status (RTM_GETLINK and RTM_GETADDR).

I am able to request either RTM_GETLINK or 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... */

but if I request both at the same time:

req.nlmsghdr.nlmsg_type  = RTM_GETLINK | RTM_GETADDR;

I only get ip informtion.

am I supposed to use two different sockets, on for the requests and the other one for listening, or is it possible to do all that in the same socket ?

I've tried performing a send for each request, and using seq (increasing it for the second request), I am able to see that the second reply is only 40 bytes long :(

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... */

Analyzing it a bit more, it seems I get an NLMSG_ERROR message type. with error code -16 meaning "device or ressource busy".

if I read the socket after each send, I don't get the problem. but I'd rather be able do all my requests, and only then gather all the replies...

도움이 되었습니까?

해결책 2

here is an answer I found in http://www.carisma.slowglass.com/~tgr/libnl/doc/core.html

Optionally, the kernel may send out notifications for configuration changes allowing userspace to listen for changes instead of polling frequently. Notifications typically reuse an existing message type and rely on the application using a separate socket to differ between requests and notifications but you may also specify a separate message type.

but not sure what this means:

but you may also specify a separate message type.

다른 팁

User space needs to wait for NLMSG_DONE netlink control message before sending next request to netlink socket. In other words, if you want to send several netlink requests in a row, then the sequence should look like this:

  1. Send req1
  2. Wait for NLMSG_DONE
  3. Send req2
  4. Wait for NLMSG_DONE
  5. ...
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top