如何在linux上使用libnl3(netlink版本3)获取接口的ipv4地址?

如何在linux上使用libnl3(netlink版本3)获取接口的ipv4地址?,linux,netlink,Linux,Netlink,我正在学习netlink库版本3,我想知道如何获取指定网络接口的ipv4地址。我可以从链路数据结构中获取mac地址,甚至可以重新查询接口名称,但我不知道如何使用libnl和libnl路由libs获取ip地址。我确实找到了一些使用libnl cli lib获取ip地址的代码,但这是为了将结果转储到文件描述符(想想stdout)。我已向该库的邮件列表发送邮件,但尚未收到回复 这是我的密码: 以下是我的结果: ./stats Returned link name is enp6s0 Returne

我正在学习netlink库版本3,我想知道如何获取指定网络接口的ipv4地址。我可以从链路数据结构中获取mac地址,甚至可以重新查询接口名称,但我不知道如何使用libnl和libnl路由libs获取ip地址。我确实找到了一些使用libnl cli lib获取ip地址的代码,但这是为了将结果转储到文件描述符(想想stdout)。我已向该库的邮件列表发送邮件,但尚未收到回复

这是我的密码:

以下是我的结果:

./stats 
Returned link name is enp6s0
Returned link addr is a0:36:9f:66:93:13

我见过使用ioctls检索ip地址的机制,但由于netlink lib可以使用cli子库返回ip地址,我想这是可以做到的,但我找不到方法。

接口可以有多个地址(ipv4和ipv6地址-代码示例给了我一个ipv4和一个ipv6),所以并没有这样的函数为接口返回一个地址。如果您有特定的本地地址,就可以调用rtnl_addr_get。相反,您可以迭代地址

#include <libnl3/netlink/cache.h>

void addr_cb(struct nl_object *o, void *data)
{
    int ifindex = (int)(intptr_t)data;
    struct rtnl_addr *addr = (rtnl_addr *)o;
    if (NULL == addr) {
        /* error */
        printf("addr is NULL %d\n", errno);
        return;
    }

    int cur_ifindex = rtnl_addr_get_ifindex(addr);
    if(cur_ifindex != ifindex)
        return;

    const struct nl_addr *local = rtnl_addr_get_local(addr);
    if (NULL == local) {
        /* error */
        printf("rtnl_addr_get failed\n");
        return;
    }

    char addr_str[ADDR_STR_BUF_SIZE];
    const char *addr_s = nl_addr2str(local, addr_str, sizeof(addr_str));
    if (NULL == addr_s) {
        /* error */
        printf("nl_addr2str failed\n");
        return;
    }
    fprintf(stdout, "\naddr is: %s\n", addr_s);
}

要检查ip版本,请使用rtnl_addr_get_family。

以用户2518959的答案为基础

rtnl_addr_alloc_缓存和rtnl_link_alloc_缓存都返回nl_缓存对象/结构。即使这两个结果是同一类型的,它们也有不同的例程,可以在每个结果上使用

从rtnl_addr_alloc_缓存返回的nl_缓存可用于获取rtnl_addr对象/结构。它们反过来可用于调用rtnl_addr_get_local以获取ipv4或ipv6地址

相反,从rtnl_链接_分配_缓存返回的nl_缓存可用于获取接口名称(eth0、enp6s0等)和mac地址。这些例程分别是rtnl_link_get_by_name和rtnl_link_get_addr

在任何一种情况下,两者之间的公共链接都是例程rtnl_addr_get_index和rtnl_link_get_index,它们返回一个接口索引,可用于关联每个缓存中的任一项。即,来自nl_缓存的addr版本的接口1和来自链接nl_缓存的接口1是相同的接口。一个给出ip地址,另一个给出mac地址和名称

最后,隧道将有一个ip地址,但没有mac,因此它将没有链接名称或mac地址

下面是一些显示user25185959方法的代码,以及一个明确显示关系的替代方法。User2518959将接口号传递到回调以筛选出接口

#include <libnl3/netlink/netlink.h>
#include <libnl3/netlink/route/link.h>
#include <libnl3/netlink/route/addr.h>
#include <libnl3/netlink/cache.h>
#include <libnl3/netlink/route/addr.h>

#include <errno.h>



/*
gcc ipchange.c -o ipchange $(pkg-config --cflags --libs libnl-3.0 libnl-route-3.0 libnl-cli-3.0)
*/

#include <stdbool.h>

#define ADDR_STR_BUF_SIZE 80

void addr_cb(struct nl_object *p_nl_object, void *data) {

    int ifindex = (int) (intptr_t) data;  // this is the link index passed as a parm
    struct rtnl_addr *p_rtnl_addr;
    p_rtnl_addr = (struct rtnl_addr *) p_nl_object;
    int result;

    if (NULL == p_rtnl_addr) {
        /* error */
        printf("addr is NULL %d\n", errno);
        return;
    }

    // This routine is not mentioned in the doxygen help.  
    // It is listed under Attributes, but no descriptive text.
    // this routine just returns p_rtnl_addr->a_ifindex
    int cur_ifindex = rtnl_addr_get_ifindex(p_rtnl_addr);
    if(cur_ifindex != ifindex) {
        // skip interaces where the index differs.
        return;
    }

    // Adding this to see if I can filter on ipv4 addr
    // this routine just returns p_rtnl_addr->a_family
    // this is not the one to use
    // ./linux/netfilter.h:    NFPROTO_IPV6   = 10,
    // ./linux/netfilter.h:    NFPROTO_IPV4   =  2,
    // this is the one to use
    // x86_64-linux-gnu/bits/socket.h
    // defines AF_INET6 = PF_INET6 = 10
    // defines AF_INET  = PF_INET  = 2
    result = rtnl_addr_get_family(p_rtnl_addr);
    // printf( "family is %d\n",result);
    if (AF_INET6 == result) {
    // early exit, I don't care about IPV6
    return;
    }

    // This routine just returns p_rtnl_addr->a_local
    const struct nl_addr *p_nl_addr_local = rtnl_addr_get_local(p_rtnl_addr);
    if (NULL == p_nl_addr_local) {
        /* error */
        printf("rtnl_addr_get failed\n");
        return;
    }

    char addr_str[ADDR_STR_BUF_SIZE];
    const char *addr_s = nl_addr2str(p_nl_addr_local, addr_str, sizeof(addr_str));
    if (NULL == addr_s) {
        /* error */
        printf("nl_addr2str failed\n");
        return;
    }
    fprintf(stdout, "\naddr is: %s\n", addr_s);

}

int main(int argc, char **argv, char **envp) {

    int err;

    struct nl_sock *p_nl_sock;
    struct nl_cache *link_cache;
    struct nl_cache *addr_cache;

    struct rtnl_addr *p_rtnl_addr;
    struct nl_addr *p_nl_addr;
    struct nl_link *p_nl_link;

    struct rtnl_link *p_rtnl_link;


    char addr_str[ADDR_STR_BUF_SIZE];

    char *pchLinkName;
    char *pchLinkAddr;
    char *pchIPAddr;
    char *interface;
    interface = "enp6s0";
    pchLinkAddr = malloc(40);
    pchIPAddr = malloc(40);
    strcpy(pchLinkAddr,"11:22:33:44:55:66");
    strcpy(pchIPAddr,"123.456.789.abc");





    p_nl_sock = nl_socket_alloc();
    if (!p_nl_sock) {
        fprintf(stderr, "Could not allocate netlink socket.\n");
        exit(ENOMEM);
    }



    // Connect to socket
    if(err = nl_connect(p_nl_sock, NETLINK_ROUTE)) {
        fprintf(stderr, "netlink error: %s\n", nl_geterror(err));
        p_nl_sock = NULL;
        exit(err);
    }


    // Either choice, the result below is a mac address
    err = rtnl_link_alloc_cache(p_nl_sock, AF_UNSPEC, &link_cache);
    //err = rtnl_link_alloc_cache(p_nl_sock, AF_INET, &link_cache);
    //err = rtnl_link_alloc_cache(p_nl_sock, IFA_LOCAL, &link_cache);
    if (0 != err) {
        /* error */
    printf("rtnl_link_alloc_cache failed: %s\n", nl_geterror(err));
    return(EXIT_FAILURE);
    }

    err = rtnl_addr_alloc_cache(p_nl_sock, &addr_cache);
    if (0 != err) {
        /* error */
    printf("rtnl_addr_alloc_cache failed: %s\n", nl_geterror(err));
    return(EXIT_FAILURE);
    }



    p_rtnl_link = rtnl_link_get_by_name(link_cache, "enp6s0");
    if (NULL == p_rtnl_link) {
        /* error */
    printf("rtnl_link_get_by_name failed\n");
    return(EXIT_FAILURE);
    }


    pchLinkName = rtnl_link_get_name(p_rtnl_link);
    if (NULL == pchLinkName) {
        /* error */
    printf("rtnl_link_get_name failed\n");
    return(EXIT_FAILURE);
    }
    printf("Returned link name is %s\n",pchLinkName);


    ////////////////////////////////// mac address  
    p_nl_addr = rtnl_link_get_addr(p_rtnl_link);
    if (NULL == p_nl_addr) {
        /* error */
    printf("rtnl_link_get_addr failed\n");
    return(EXIT_FAILURE);
    }


    pchLinkAddr = nl_addr2str(p_nl_addr, pchLinkAddr, 40);
    if (NULL == pchLinkAddr) {
        /* error */
    printf("rtnl_link_get_name failed\n");
    return(EXIT_FAILURE);
    }
    printf("Returned link addr is %s\n",pchLinkAddr);



    ////////////////////////////////// ip address  
    // How to get ip address for a specified interface?








    //
    // The way she showed me.
    //


    // Return interface index of link object
    int ifindex = rtnl_link_get_ifindex(p_rtnl_link);
    printf("ifindex: %d\n", ifindex);

    // She gave me this but its not necessary
    // Returns true if the cache is empty. True if the cache is empty.
    // bool empty = nl_cache_is_empty(addr_cache);
    // printf("empty: %d\n", empty);

    // Call a callback on each element of the cache.  The
    // arg is passed on the callback function.
    // addr_cache is the cache to iterate on
    // addr_cb is the callback function
    // ifindex is the argument passed to the callback function
    // 
    nl_cache_foreach(addr_cache, addr_cb, (void*)(intptr_t)ifindex);



    // This shows that the link index returned from rtnl_addr_get_index
    // and rtnl_link_get_index are equivalent when using the rtnl_addr
    // and rtnl_link from the two respective caches.


   // Another way...
   // This will iterate through the cache of ip's
   printf("Getting the list of interfaces by ip addr cache\n");
   int count = nl_cache_nitems(addr_cache);
   printf("addr_cache has %d items\n",count);
   struct nl_object *p_nl_object;
   p_nl_object = nl_cache_get_first(addr_cache); 
   p_rtnl_addr = (struct rtnl_addr *) p_nl_object;
   for (int i=0; i<count; i++) {
    // This routine just returns p_rtnl_addr->a_local
    const struct nl_addr *p_nl_addr_local = rtnl_addr_get_local(p_rtnl_addr);
    if (NULL == p_nl_addr_local) {
        /* error */
        printf("rtnl_addr_get failed\n");
        return(EXIT_FAILURE);
    }



    int cur_ifindex = rtnl_addr_get_ifindex(p_rtnl_addr);
    printf("This is index %d\n",cur_ifindex);

    const char *addr_s = nl_addr2str(p_nl_addr_local, addr_str, sizeof(addr_str));
    if (NULL == addr_s) {
        /* error */
        printf("nl_addr2str failed\n");
        return(EXIT_FAILURE);
    }
    fprintf(stdout, "\naddr is: %s\n", addr_s);

    //       
    printf("%d\n",i);
    p_nl_object = nl_cache_get_next(p_nl_object); 
        p_rtnl_addr = (struct rtnl_addr *) p_nl_object;

    // Just for grins


    }



   // Another way...
   // This will iterate through the cache of LLC
   printf("Getting the list of interfaces by mac cache\n");
   count = nl_cache_nitems(link_cache);
   printf("addr_cache has %d items\n",count);
   p_nl_object = nl_cache_get_first(link_cache); 
   p_rtnl_link = (struct rtnl_link *) p_nl_object;
   for (int i=0; i<count; i++) {
    // This routine just returns p_rtnl_addr->a_local
    const struct nl_addr *p_nl_addr_mac = rtnl_link_get_addr(p_rtnl_link);
    if (NULL == p_nl_addr_mac) {
        /* error */
        printf("rtnl_addr_get failed\n");
        return(EXIT_FAILURE);
    }

    int cur_ifindex = rtnl_link_get_ifindex(p_rtnl_link);
    printf("This is index %d\n",cur_ifindex);

    const char *addr_s = nl_addr2str(p_nl_addr_mac, addr_str, sizeof(addr_str));
    if (NULL == addr_s) {
        /* error */
        printf("nl_addr2str failed\n");
        return(EXIT_FAILURE);
    }
    fprintf(stdout, "\naddr is: %s\n", addr_s);

    //       
    printf("%d\n",i);
    p_nl_object = nl_cache_get_next(p_nl_object); 
        p_rtnl_link = (struct rtnl_link *) p_nl_object;

    }


    return(EXIT_SUCCESS);
}
#包括
#包括
#包括
#包括
#包括
#包括
/*
gcc ipchange.c-o ipchange$(pkg config--cflags--libs libnl-3.0 libnl-route-3.0 libnl-cli-3.0)
*/
#包括
#定义ADDR_STR_BUF_大小80
void addr\u cb(结构nl\u对象*p\u nl\u对象,void*数据){
int-ifindex=(int)(intptr\u t)data;//这是作为parm传递的链接索引
结构rtnl_addr*p_rtnl_addr;
p_rtnl_addr=(struct rtnl_addr*)p_nl_对象;
int结果;
if(NULL==p_rtnl_addr){
/*错误*/
printf(“地址为空%d\n”,错误号);
返回;
}
//doxygen帮助中未提及此例程。
//它列在属性下,但没有描述性文本。
//此例程只返回p_rtnl_addr->a_iIndex
int cur\U ifindex=rtnl\U addr\U get\U ifindex(p\U rtnl\U addr);
如果(当前ifindex!=ifindex){
//跳过索引不同的区间。
返回;
}
//添加此项以查看是否可以在ipv4地址上进行筛选
//此例程只返回p_rtnl_addr->a_族
//这不是要使用的
//./linux/netfilter.h:NFPROTO_IPV6=10,
//./linux/netfilter.h:NFPROTO_IPV4=2,
//这是一个使用
//x86_64-linux-gnu/bits/socket.h
//定义AF_INET6=PF_INET6=10
//定义AF_INET=PF_INET=2
结果=rtnl_addr_get_family(p_rtnl_addr);
//printf(“族为%d\n”,结果);
if(AF_INET6==结果){
//提前退出,我不关心IPV6
返回;
}
//这个例程只返回p_rtnl_addr->a_local
const struct nl_addr*p_nl_addr_local=rtnl_addr_get_local(p_rtnl_addr);
if(NULL==p_nl_addr_local){
/*错误*/
printf(“rtnl_addr_get failed\n”);
返回;
}
char addr_str[addr_str_BUF_SIZE];
const char*addr_s=nl_addr2str(p_nl_addr_local,addr_str,sizeof(addr_str));
如果(NULL==地址){
/*错误*/
printf(“nl_addr2str失败\n”);
返回;
}
fprintf(标准输出,“\naddr是:%s\n”,地址);
}
内部主(内部argc、字符**argv、字符**envp){
INTERR;
结构nl_sock*p_nl_sock;
结构nl_缓存*链接_缓存;
结构nl_缓存*addr_缓存;
结构rtnl_addr*p_rtnl_addr;
结构nl_addr*p_nl_addr;
结构nl_链接*p_nl_链接;
结构rtnl_链接*p_rtnl_链接;
char addr_str[addr_str_BUF_SIZE];
char*pchLinkName;
char*pchlinkadr;
char*pchIPAddr;
字符*接口;
接口=“enp6s0”;
pchlinkadr=malloc(40);
pchIPAddr=malloc(40);
strcpy(pchlinkadr,“11:22:33:44:55:66”);
strcpy(pchIPAddr,“123.456.789.abc”);
p_nl_sock=nl_socket_alloc();
如果(!p_nl_sock){
fprintf(stderr,“无法分配netlink套接字。\n”);
出口(ENOMEM);
}
//连接到插座
if(err=nl_连接(p_nl_sock,NETLINK_路由)){
fprintf(标准,“网络链接错误:%s\n”,nl_geterror(err));
p_nl_sock=NULL;
退出(err);
}
//无论是哪种选择,下面的结果都是mac地址
err=rtnl_link_alloc_缓存(p_nl_sock、AF_unsec和link_缓存);
//err=rtnl\u link\u alloc\u缓存(p\u nl\u sock、AF\u INET和link\u缓存);
//err=rtnl\u link\u alloc\u缓存(p\u nl\u sock、IFA\u LOCAL和link\u缓存);
如果(0!=错误){
/*错误*/
printf(“rtnl_链接_分配_缓存失败:%s\n”,nl_geterror(err));
返回(退出失败);
}
err=rtnl\u addr\u alloc\u缓存(p\u nl\u sock,&a
#include <libnl3/netlink/netlink.h>
#include <libnl3/netlink/route/link.h>
#include <libnl3/netlink/route/addr.h>
#include <libnl3/netlink/cache.h>
#include <libnl3/netlink/route/addr.h>

#include <errno.h>



/*
gcc ipchange.c -o ipchange $(pkg-config --cflags --libs libnl-3.0 libnl-route-3.0 libnl-cli-3.0)
*/

#include <stdbool.h>

#define ADDR_STR_BUF_SIZE 80

void addr_cb(struct nl_object *p_nl_object, void *data) {

    int ifindex = (int) (intptr_t) data;  // this is the link index passed as a parm
    struct rtnl_addr *p_rtnl_addr;
    p_rtnl_addr = (struct rtnl_addr *) p_nl_object;
    int result;

    if (NULL == p_rtnl_addr) {
        /* error */
        printf("addr is NULL %d\n", errno);
        return;
    }

    // This routine is not mentioned in the doxygen help.  
    // It is listed under Attributes, but no descriptive text.
    // this routine just returns p_rtnl_addr->a_ifindex
    int cur_ifindex = rtnl_addr_get_ifindex(p_rtnl_addr);
    if(cur_ifindex != ifindex) {
        // skip interaces where the index differs.
        return;
    }

    // Adding this to see if I can filter on ipv4 addr
    // this routine just returns p_rtnl_addr->a_family
    // this is not the one to use
    // ./linux/netfilter.h:    NFPROTO_IPV6   = 10,
    // ./linux/netfilter.h:    NFPROTO_IPV4   =  2,
    // this is the one to use
    // x86_64-linux-gnu/bits/socket.h
    // defines AF_INET6 = PF_INET6 = 10
    // defines AF_INET  = PF_INET  = 2
    result = rtnl_addr_get_family(p_rtnl_addr);
    // printf( "family is %d\n",result);
    if (AF_INET6 == result) {
    // early exit, I don't care about IPV6
    return;
    }

    // This routine just returns p_rtnl_addr->a_local
    const struct nl_addr *p_nl_addr_local = rtnl_addr_get_local(p_rtnl_addr);
    if (NULL == p_nl_addr_local) {
        /* error */
        printf("rtnl_addr_get failed\n");
        return;
    }

    char addr_str[ADDR_STR_BUF_SIZE];
    const char *addr_s = nl_addr2str(p_nl_addr_local, addr_str, sizeof(addr_str));
    if (NULL == addr_s) {
        /* error */
        printf("nl_addr2str failed\n");
        return;
    }
    fprintf(stdout, "\naddr is: %s\n", addr_s);

}

int main(int argc, char **argv, char **envp) {

    int err;

    struct nl_sock *p_nl_sock;
    struct nl_cache *link_cache;
    struct nl_cache *addr_cache;

    struct rtnl_addr *p_rtnl_addr;
    struct nl_addr *p_nl_addr;
    struct nl_link *p_nl_link;

    struct rtnl_link *p_rtnl_link;


    char addr_str[ADDR_STR_BUF_SIZE];

    char *pchLinkName;
    char *pchLinkAddr;
    char *pchIPAddr;
    char *interface;
    interface = "enp6s0";
    pchLinkAddr = malloc(40);
    pchIPAddr = malloc(40);
    strcpy(pchLinkAddr,"11:22:33:44:55:66");
    strcpy(pchIPAddr,"123.456.789.abc");





    p_nl_sock = nl_socket_alloc();
    if (!p_nl_sock) {
        fprintf(stderr, "Could not allocate netlink socket.\n");
        exit(ENOMEM);
    }



    // Connect to socket
    if(err = nl_connect(p_nl_sock, NETLINK_ROUTE)) {
        fprintf(stderr, "netlink error: %s\n", nl_geterror(err));
        p_nl_sock = NULL;
        exit(err);
    }


    // Either choice, the result below is a mac address
    err = rtnl_link_alloc_cache(p_nl_sock, AF_UNSPEC, &link_cache);
    //err = rtnl_link_alloc_cache(p_nl_sock, AF_INET, &link_cache);
    //err = rtnl_link_alloc_cache(p_nl_sock, IFA_LOCAL, &link_cache);
    if (0 != err) {
        /* error */
    printf("rtnl_link_alloc_cache failed: %s\n", nl_geterror(err));
    return(EXIT_FAILURE);
    }

    err = rtnl_addr_alloc_cache(p_nl_sock, &addr_cache);
    if (0 != err) {
        /* error */
    printf("rtnl_addr_alloc_cache failed: %s\n", nl_geterror(err));
    return(EXIT_FAILURE);
    }



    p_rtnl_link = rtnl_link_get_by_name(link_cache, "enp6s0");
    if (NULL == p_rtnl_link) {
        /* error */
    printf("rtnl_link_get_by_name failed\n");
    return(EXIT_FAILURE);
    }


    pchLinkName = rtnl_link_get_name(p_rtnl_link);
    if (NULL == pchLinkName) {
        /* error */
    printf("rtnl_link_get_name failed\n");
    return(EXIT_FAILURE);
    }
    printf("Returned link name is %s\n",pchLinkName);


    ////////////////////////////////// mac address  
    p_nl_addr = rtnl_link_get_addr(p_rtnl_link);
    if (NULL == p_nl_addr) {
        /* error */
    printf("rtnl_link_get_addr failed\n");
    return(EXIT_FAILURE);
    }


    pchLinkAddr = nl_addr2str(p_nl_addr, pchLinkAddr, 40);
    if (NULL == pchLinkAddr) {
        /* error */
    printf("rtnl_link_get_name failed\n");
    return(EXIT_FAILURE);
    }
    printf("Returned link addr is %s\n",pchLinkAddr);



    ////////////////////////////////// ip address  
    // How to get ip address for a specified interface?








    //
    // The way she showed me.
    //


    // Return interface index of link object
    int ifindex = rtnl_link_get_ifindex(p_rtnl_link);
    printf("ifindex: %d\n", ifindex);

    // She gave me this but its not necessary
    // Returns true if the cache is empty. True if the cache is empty.
    // bool empty = nl_cache_is_empty(addr_cache);
    // printf("empty: %d\n", empty);

    // Call a callback on each element of the cache.  The
    // arg is passed on the callback function.
    // addr_cache is the cache to iterate on
    // addr_cb is the callback function
    // ifindex is the argument passed to the callback function
    // 
    nl_cache_foreach(addr_cache, addr_cb, (void*)(intptr_t)ifindex);



    // This shows that the link index returned from rtnl_addr_get_index
    // and rtnl_link_get_index are equivalent when using the rtnl_addr
    // and rtnl_link from the two respective caches.


   // Another way...
   // This will iterate through the cache of ip's
   printf("Getting the list of interfaces by ip addr cache\n");
   int count = nl_cache_nitems(addr_cache);
   printf("addr_cache has %d items\n",count);
   struct nl_object *p_nl_object;
   p_nl_object = nl_cache_get_first(addr_cache); 
   p_rtnl_addr = (struct rtnl_addr *) p_nl_object;
   for (int i=0; i<count; i++) {
    // This routine just returns p_rtnl_addr->a_local
    const struct nl_addr *p_nl_addr_local = rtnl_addr_get_local(p_rtnl_addr);
    if (NULL == p_nl_addr_local) {
        /* error */
        printf("rtnl_addr_get failed\n");
        return(EXIT_FAILURE);
    }



    int cur_ifindex = rtnl_addr_get_ifindex(p_rtnl_addr);
    printf("This is index %d\n",cur_ifindex);

    const char *addr_s = nl_addr2str(p_nl_addr_local, addr_str, sizeof(addr_str));
    if (NULL == addr_s) {
        /* error */
        printf("nl_addr2str failed\n");
        return(EXIT_FAILURE);
    }
    fprintf(stdout, "\naddr is: %s\n", addr_s);

    //       
    printf("%d\n",i);
    p_nl_object = nl_cache_get_next(p_nl_object); 
        p_rtnl_addr = (struct rtnl_addr *) p_nl_object;

    // Just for grins


    }



   // Another way...
   // This will iterate through the cache of LLC
   printf("Getting the list of interfaces by mac cache\n");
   count = nl_cache_nitems(link_cache);
   printf("addr_cache has %d items\n",count);
   p_nl_object = nl_cache_get_first(link_cache); 
   p_rtnl_link = (struct rtnl_link *) p_nl_object;
   for (int i=0; i<count; i++) {
    // This routine just returns p_rtnl_addr->a_local
    const struct nl_addr *p_nl_addr_mac = rtnl_link_get_addr(p_rtnl_link);
    if (NULL == p_nl_addr_mac) {
        /* error */
        printf("rtnl_addr_get failed\n");
        return(EXIT_FAILURE);
    }

    int cur_ifindex = rtnl_link_get_ifindex(p_rtnl_link);
    printf("This is index %d\n",cur_ifindex);

    const char *addr_s = nl_addr2str(p_nl_addr_mac, addr_str, sizeof(addr_str));
    if (NULL == addr_s) {
        /* error */
        printf("nl_addr2str failed\n");
        return(EXIT_FAILURE);
    }
    fprintf(stdout, "\naddr is: %s\n", addr_s);

    //       
    printf("%d\n",i);
    p_nl_object = nl_cache_get_next(p_nl_object); 
        p_rtnl_link = (struct rtnl_link *) p_nl_object;

    }


    return(EXIT_SUCCESS);
}