How to bundle requests?

Tilman Baumann tilman.baumann at grandeye.com
Tue Oct 25 05:50:52 EDT 2011


Hi,

I need IP address information and link mac addresses in my programme.

I thought I can combine requests with nlmsg_flags = NLM_F_MULTI but it 
seems like this does not really work at all.
Or I'm doing it wrong.

I'm not constantly listening on the socket. I just send a request and do 
one recv(). I could imagine that this is bad practice. If you tell me 
how it is better done I would appreciate this very much.

Sorry about the line breaks. I did not take care of max line length.
I will attach the file as well, to make it more readable.


Below code works if I just send one RTM_GETADDR or RTM_GETLINK packet. 
But the combined request like below does only return GETADDR data.


Am I doing the NLM_F_MULTI request right? Should it work and how should 
I use it do make it work.

Any help appreciated. Thanks
  Tilman Baumann


#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <inttypes.h>
#include <net/ethernet.h>
#include <netinet/ether.h>


#define IF_NAME "br0"
#define LL_NET_ADDRESS "169.254.0.0"
#define LL_NET_MASK "255.255.0.0"
#define HWADDR_LEN 17


int parse_netlink_response(char * buf, int buf_size, uint32_t * 
linklocal_address_p, uint32_t * ipaddr_p, struct ether_addr * hwaddr);

int get_ipdata(uint32_t * linklocal_address_p, uint32_t * ipaddr_p, 
struct ether_addr * hwaddr)
{
         int status, ifaddr_nlmsg_len, ifinfo_nlmsg_len, packet_length;
         char buf[16384];        /* arbitrary size */

         int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);

         struct nlmsghdr  *ifaddr_hdr = NULL;
         struct nlmsghdr  *ifinfo_hdr = NULL;
         struct ifaddrmsg *ifaddr_msg = NULL;
         struct ifinfomsg *ifinfo_msg = NULL;

         ifaddr_nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
         ifinfo_nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
         packet_length = ifaddr_nlmsg_len + ifinfo_nlmsg_len;



         ifaddr_hdr = (struct nlmsghdr *) malloc(packet_length);
         memset(ifaddr_hdr, 0, packet_length);

         // Set NL message header
         ifaddr_hdr->nlmsg_len   = ifaddr_nlmsg_len;
         ifaddr_hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MULTI;
         ifaddr_hdr->nlmsg_type  = RTM_GETADDR;

         // set payload sruct
         ifaddr_msg = (struct ifaddrmsg *) NLMSG_DATA(ifaddr_hdr);
         ifaddr_msg->ifa_family = AF_INET;

         // Set NL message header
         ifinfo_hdr = (struct nlmsghdr *) NLMSG_NEXT(ifaddr_hdr, 
packet_length);
         ifinfo_hdr->nlmsg_len   = ifaddr_nlmsg_len;
         ifinfo_hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLMSG_DONE;
         ifinfo_hdr->nlmsg_type  = RTM_GETLINK;

         // set payload sruct
         ifinfo_msg = (struct ifinfomsg *) NLMSG_DATA(ifinfo_hdr);
         ifinfo_msg->ifi_family = AF_UNSPEC;

         status = send(fd, ifaddr_hdr, packet_length, 0);

         if (status < 0) {
                 perror("send");
                 return 1;
         }

         status = recv(fd, buf, sizeof(buf), 0);

         if (status < 0) {
                 perror("recv");
                 return 1;
         }

         if(status == 0){
                 printf("EOF\n");
                 return 1;
         }

         return parse_netlink_response(buf, status, linklocal_address_p, 
ipaddr_p, hwaddr);
}

int parse_netlink_response(char * buf, int buf_size, uint32_t * 
linklocal_address_p, uint32_t * ipaddr_p, struct ether_addr * hwaddr){
         struct nlmsghdr *nlh;
         uint32_t  linklocal_netmask, linklocal_network_address;
         struct in_addr *inp;

         /* Prepare netlink netmask and network address for later 
validation of address with mask */
         inet_pton(AF_INET, LL_NET_ADDRESS, &linklocal_network_address);
         inet_pton(AF_INET, LL_NET_MASK, &linklocal_netmask);

         /* Get first netlink message header */
         nlh = (struct nlmsghdr *) buf;
         /* While valid imessage herader is available */
         while ((NLMSG_OK(nlh, buf_size)) && (nlh->nlmsg_type != 
NLMSG_DONE)) {

                 if (nlh->nlmsg_type == RTM_NEWADDR) { /* if this is a 
IP Addr response */
                         struct ifaddrmsg *ifa = (struct ifaddrmsg *) 
NLMSG_DATA(nlh);   /* Read ifaddrmsg */
                         struct rtattr *rth = IFA_RTA(ifa);
                         int rtl = IFA_PAYLOAD(nlh);
                         char name[IFNAMSIZ];

                         /* Only stuff about interface IF_NAME is 
relevant */
                         if_indextoname(ifa->ifa_index, name);
                         if(ifa->ifa_family == AF_INET && strncmp ( 
name, IF_NAME, IFNAMSIZ) == 0 ){
                                 /* Read first rtattr attribute header */
                                 while (rtl && RTA_OK(rth, rtl)) {
                                         if(rth->rta_type == IFA_ADDRESS){
                                                 inp = (struct in_addr 
*)RTA_DATA(rth);  /* Read IP in in_addr */

                                                 if(ifa->ifa_prefixlen 
== 16 && linklocal_network_address == (inp->s_addr & linklocal_netmask)){
 
*linklocal_address_p = inp->s_addr; /* This is a addfress in link local 
scope */
                                                 }else{
                                                         *ipaddr_p = 
inp->s_addr;        /* This is a regular address */
                                                 }
                                         }
                                         rth = RTA_NEXT(rth, rtl); 
  /* Advance to next rtattr attribute header */
                                 }
                         }

                 }else if(nlh->nlmsg_type == RTM_NEWLINK || 
nlh->nlmsg_type == RTM_DELLINK || nlh->nlmsg_type == RTM_GETLINK){ 
/*Only link respnses */
                         struct ifinfomsg *ifinfo = (struct ifinfomsg *) 
NLMSG_DATA(nlh);        /* Read ifinfomsg */
                         int rtl = IFA_PAYLOAD(nlh);
                         struct rtattr *rth = IFLA_RTA(ifinfo);
                         char name[IFNAMSIZ];

                         /* Only stuff about interface IF_NAME is 
relevant */
                         if_indextoname(ifinfo->ifi_index, name);
                         if(strncmp ( name, IF_NAME, IFNAMSIZ) == 0 ){
                                 /* Read first rtattr attribute header */
                                 while (rtl && RTA_OK(rth, rtl)) {
                                         if(rth->rta_type == IFLA_ADDRESS){
                                                 /* Copy ether_addr 
struct to prepared destination */
                                                 memcpy (hwaddr, (struct 
ether_addr *)RTA_DATA(rth), sizeof (hwaddr));
                                         }
                                         rth = RTA_NEXT(rth, rtl); 
  /* Advance to next rtattr attribute header */
                                 }
                         }
                 }
                 nlh = NLMSG_NEXT(nlh, buf_size);        /* Advance to 
next netlink message header */
         }
         return 0;
}

int main()
{

         uint32_t  linklocal_address, ipaddr;
         char linklocal_address_s[INET_ADDRSTRLEN];
         char ipaddr_s[INET_ADDRSTRLEN];
         struct ether_addr *hwaddr;


         linklocal_address = 0;
         ipaddr = 0;
         hwaddr = (struct ether_addr *) malloc(sizeof(struct ether_addr));

         get_ipdata(&linklocal_address, &ipaddr, hwaddr);

         inet_ntop(AF_INET, &ipaddr, ipaddr_s, INET_ADDRSTRLEN);
         inet_ntop(AF_INET, &linklocal_address, linklocal_address_s, 
INET_ADDRSTRLEN);

         printf("Address: %s\n", ipaddr_s);
         printf("Linklocal Address: %s\n", linklocal_address_s);
         printf("HW Address: %s\n", ether_ntoa(hwaddr));
         return 0;

}




-- 
Tilman Baumann
Grandeye Limited
6 Huxley Road, Surrey Research Park
Guildford, GU2 7RE, United Kingdom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: netlinktest.c
Type: text/x-csrc
Size: 6607 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20111025/b578c6c4/attachment.bin>


More information about the libnl mailing list