You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过libnl或原生Netlink API获取VLAN接口的父接口ID?

我需要获取指定VLAN接口的real_dev(例如ID)。我使用libnl编写了如下测试代码:

int main(void) {
    struct nl_sock *sock;
    struct nl_cache *cache;
    char iface[] = "eno1.10"; //char iface[] = "eno1";

    if (!(sock = nl_socket_alloc())) {
        perror("nl_socket_alloc");
        return -1;
    }

    if (nl_connect(sock, NETLINK_ROUTE) < 0) {
        perror("nl_connect");
        nl_socket_free( sock );
        return -1;
    }

    if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache) < 0) {
        perror("rtnl_link_alloc_cache");
        nl_socket_free( sock );
        nl_close( sock );
        return -1;
    }

    {
        int ifindex;
        struct rtnl_link *link = NULL;

        if (!(ifindex = rtnl_link_name2i(cache, iface))) {
            perror("rtnl_link_name2i");
            return -1;
        }

        printf("ind: %d\n", ifindex);

        if (!(link = rtnl_link_get(cache, ifindex))) {
            perror("rtnl_link_get");
            return -1;
        }

        if (rtnl_link_is_vlan(link)) {
            puts("It's VLAN link");
            /* alas it's not about the 'real' device */
            printf("master: %d\n", rtnl_link_get_master(link));
        } else
            puts("It's 'real' link");
    }

    return 0;
}

目前我能获取接口ID并判断是否为VLAN接口,但不知道如何获取该VLAN所依附的父接口。似乎libnl的API不提供此功能,请问是否可通过libnl或原生Netlink API获取VLAN的父接口ID?


解决方案

其实你完全可以通过libnl或者原生Netlink API获取VLAN的父接口ID,只是用错了API而已——rtnl_link_get_master是针对bond、网桥这类主从接口模型的,VLAN的父接口需要用专门的VLAN属性接口来获取。

方法一:使用libnl的VLAN专用API

libnl提供了rtnl_link_vlan_get_parent()函数,专门用来获取VLAN接口的父接口ifindex。你只需要在判断接口是VLAN之后调用这个函数即可,甚至还可以通过父接口的ifindex反向获取接口名称。

修改你的代码如下:

int main(void) {
    struct nl_sock *sock;
    struct nl_cache *cache;
    char iface[] = "eno1.10"; //char iface[] = "eno1";

    if (!(sock = nl_socket_alloc())) {
        perror("nl_socket_alloc");
        return -1;
    }

    if (nl_connect(sock, NETLINK_ROUTE) < 0) {
        perror("nl_connect");
        nl_socket_free( sock );
        return -1;
    }

    if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache) < 0) {
        perror("rtnl_link_alloc_cache");
        nl_socket_free( sock );
        nl_close( sock );
        return -1;
    }

    {
        int ifindex;
        struct rtnl_link *link = NULL;

        if (!(ifindex = rtnl_link_name2i(cache, iface))) {
            perror("rtnl_link_name2i");
            return -1;
        }

        printf("ind: %d\n", ifindex);

        if (!(link = rtnl_link_get(cache, ifindex))) {
            perror("rtnl_link_get");
            return -1;
        }

        if (rtnl_link_is_vlan(link)) {
            puts("It's VLAN link");
            
            // 获取VLAN父接口的ifindex
            int parent_ifindex = rtnl_link_vlan_get_parent(link);
            printf("Parent interface index: %d\n", parent_ifindex);
            
            // 可选:通过ifindex获取父接口名称
            char parent_name[IFNAMSIZ];
            if (rtnl_link_i2name(cache, parent_ifindex, parent_name, sizeof(parent_name))) {
                printf("Parent interface name: %s\n", parent_name);
            }
        } else {
            puts("It's 'real' link");
        }
        
        // 别忘了释放link对象
        rtnl_link_put(link);
    }
    
    // 释放缓存和socket
    nl_cache_free(cache);
    nl_socket_free(sock);

    return 0;
}

注意事项:

  • 编译时需要链接libnl-route库,比如用gcc your_code.c -o vlan_parent -lnl-3 -lnl-route-3
  • 用完rtnl_link_get获取的link对象后,记得调用rtnl_link_put释放,避免内存泄漏
  • 你的原代码没有释放缓存和socket,建议加上,养成良好的内存管理习惯

如果不想依赖libnl,直接用原生Netlink的话,你需要在接收RTM_NEWLINK消息时,解析嵌套的IFLA_VLAN属性,其中的IFLA_VLAN_PARENT字段就是父接口的ifindex。

核心逻辑大概是:

  1. 发送RTM_GETLINK请求,指定目标VLAN接口的ifindex
  2. 接收Netlink响应,遍历消息中的属性
  3. 找到IFLA_VLAN类型的属性(这是一个嵌套属性)
  4. IFLA_VLAN的子属性中找到IFLA_VLAN_PARENT,其值就是父接口的ifindex

示例伪代码片段:

// 假设已经获取到了Netlink消息的nlmsghdr指针nlh
struct ifinfomsg *ifm = NLMSG_DATA(nlh);
struct nlattr *tb[IFLA_MAX+1];

// 解析顶层属性
nla_parse(tb, IFLA_MAX, IFLA_RTA(ifm), NLMSG_PAYLOAD(nlh, sizeof(*ifm)), NULL);

if (tb[IFLA_VLAN]) {
    struct nlattr *vlan_tb[IFLA_VLAN_MAX+1];
    // 解析VLAN嵌套属性
    nla_parse(vlan_tb, IFLA_VLAN_MAX, nla_data(tb[IFLA_VLAN]), nla_len(tb[IFLA_VLAN]), NULL);
    
    if (vlan_tb[IFLA_VLAN_PARENT]) {
        int parent_ifindex = nla_get_u32(vlan_tb[IFLA_VLAN_PARENT]);
        printf("Parent ifindex: %d\n", parent_ifindex);
    }
}

这种方法更底层,但不需要依赖libnl库,适合对依赖有严格要求的场景。


内容的提问来源于stack exchange,提问作者red0ct

火山引擎 最新活动