显示桥接口的成员,可能通过netlink?

问题描述 投票:0回答:1

你能告诉我如何用C++语言显示桥的成员界面吗?

通过netlink我可以显示系统接口(目标ID,父ID和相同的类型),但是一旦获得这些信息,我不知道如何识别网桥的成员接口。

有这些接口:

1 洛

2 ens2

3 诺2

4 诺1

5 vethgw@if2

6 vethbras@if2

7 br0

8 vlan4094@br0

9 vlan4093@br0

10 virbr0

11 点击0

12 点击1

void function(void)
{
    char buf[16192] = {0};
    int err = 0;
    __u16 failcounter = 0;
    __u32 target_idx = 0;
    __u32 parent_idx = 0;
    int devtype_id = 0;
    int fd = EOF;
    size_t seq_num = 0;
    struct sockaddr_nl sa = {0};
    struct iovec iov = {0};
    struct msghdr msg = {0};
    struct nlmsghdr *nh;
    nl_req_t req = {0};
    std::string kinddevname;

    fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

    if(fd < 0)
        THROW("Failed to open netlink socket: %s", fcerr());

    req.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
    req.header.nlmsg_type = RTM_GETLINK;
    req.header.nlmsg_seq = ++seq_num;
    req.msg.ifi_family = AF_UNSPEC;
    req.msg.ifi_change = 0xFFFFFFFF;
    req.msg.ifi_index = 9;

    sa.nl_family = AF_NETLINK;
    iov.iov_base = &req;
    iov.iov_len = req.header.nlmsg_len;
    msg.msg_name = &sa;
    msg.msg_namelen = sizeof sa;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    if (sendmsg(fd, &msg, 0) < 0)
        THROW("Failed to sendmsg to netlink socket: %s", fcerr());

    iov.iov_base = buf;
    iov.iov_len = sizeof buf;

    while (true)
    {
        if (_signal == SIGINT)
            THROW("Interrupted...");

        if (failcounter > 64)
            THROW("Failed to rcvmsg to netlink socket: %s", fcerr());

        ssize_t len = recvmsg(fd, &msg, MSG_DONTWAIT);

        if (len < 0) 
        {
            if (errno == EINTR || errno == EAGAIN)
            {
                usleep(250000);
                continue;
            }

            LOG("Failed to read netlink: %s", fcerr());
            failcounter++;
            continue;
        }

        failcounter = 0;

        for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, (__u32)len); nh = NLMSG_NEXT(nh, len))
        {
            if (_signal == SIGINT)
                THROW("Interrupted...");

            size_t len, info_len, devtype_len;
            struct ifinfomsg *msg;
            struct rtattr *rta, *info, *devtype;

            if(nh->nlmsg_type == NLMSG_DONE)
                goto nldone;

            if(nh->nlmsg_type != RTM_BASE)
                continue;

            msg = (struct ifinfomsg *)NLMSG_DATA(nh); // message payload

            if (msg->ifi_type != ARPHRD_ETHER)
                continue;

            // Display section
            if (target_idx > 0)
                std::cout << target_idx << ' ' << parent_idx << ' ' << kinddevname << std::endl;

            target_idx = 0;
            parent_idx = 0;
            devtype_id = 0;

            target_idx = msg->ifi_index;

            rta = IFLA_RTA(msg); // message attributes
            len = nh->nlmsg_len - NLMSG_LENGTH(sizeof *msg);

            for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len))
            {
                if (_signal == SIGINT)
                    THROW("Interrupted...");

                if(rta->rta_type == IFLA_LINK) // there is a "parent" device
                    parent_idx = *(__u16 *)((char *) rta + NLA_HDRLEN);

                if(rta->rta_type == IFLA_LINKINFO)
                {
                    info = (rtattr *)RTA_DATA(rta);
                    info_len = RTA_PAYLOAD(rta);

                    while (RTA_OK(info, info_len))
                    {
                        if (_signal == SIGINT)
                            THROW("Interrupted...");

                        if (info->rta_type == IFLA_INFO_KIND)
                        {
                            kinddevname.clear();

                            if (strcmp((char *)RTA_DATA(info), "vlan") == 0)
                            {
                                kinddevname.assign("vlan");

                                info = RTA_NEXT(info, info_len);

                                if (RTA_OK(info, info_len))
                                {
                                    if (info->rta_type == IFLA_INFO_DATA)
                                    {
                                        devtype = (rtattr *)RTA_DATA(info);
                                        devtype_len = RTA_PAYLOAD(info);

                                        while (RTA_OK(devtype, devtype_len))
                                        {
                                            if (devtype->rta_type == IFLA_VLAN_ID)
                                                devtype_id = *(int *)RTA_DATA(devtype);

                                            devtype = RTA_NEXT(devtype, devtype_len);
                                        }
                                    }
                                }
                                else
                                    break;
                            }
                            else if (strcmp((char *)RTA_DATA(info), "bridge") == 0)
                                kinddevname.assign("bridge");
                            else if (strcmp((char *)RTA_DATA(info), "tun") == 0)
                                kinddevname.assign("tun");
                            else if (strcmp((char *)RTA_DATA(info), "veth") == 0)
                                kinddevname.assign("veth");
                        }

                        info = RTA_NEXT(info, info_len);
                    }
                }
            }
        }
    }

    nldone:

    close(fd);
    fd = EOF;

    // Display section
    if (target_idx > 0)
        std::cout << target_idx << ' ' << parent_idx << ' ' << kinddevname << std::endl;
}

该功能显示这些行

2 0

3 0

4 0

5 2 veth

6 2 veth

7 0 桥

8 7 个VLAN

9 7 个 VLAN

10 0 桥

11 0 吨

12 0 吨

但是正如你所看到的,tun 接口仅由名称和目标 idx 指示。

是否还可以知道他们所属的桥接器?

c++ bridge netlink
1个回答
0
投票
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <cstring>
#include <linux/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if_arp.h>

using namespace std;

typedef struct {
    struct nlmsghdr header;
    struct ifinfomsg msg;
} nl_req_t;

void function (void)
{
    char buf[16192] = {0};
    int err = 0;
    __u32 target_idx = 0;
    __u32 parent_idx = 0;
    __u32 master_idx = 0;
    int devtype_id = 0;
    int fd = EOF;
    size_t seq_num = 0;
    struct sockaddr_nl sa = {0};
    struct iovec iov = {0};
    struct msghdr msg = {0};
    struct nlmsghdr *nh;
    nl_req_t req = {0};
    std::string kinddevname;

    fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

    if(fd < 0)
        perror("Failed to open netlink socket");

    req.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
    req.header.nlmsg_type = RTM_GETLINK;
    req.header.nlmsg_seq = ++seq_num;
    req.msg.ifi_family = AF_UNSPEC;
    req.msg.ifi_change = 0xFFFFFFFF;


    sa.nl_family = AF_NETLINK;
    iov.iov_base = &req;
    iov.iov_len = req.header.nlmsg_len;
    msg.msg_name = &sa;
    msg.msg_namelen = sizeof sa;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    if (sendmsg(fd, &msg, 0) < 0)
        perror("Failed to sendmsg to netlink socket");

    iov.iov_base = buf;
    iov.iov_len = sizeof buf;

    while (true)
    {
        ssize_t len = recvmsg(fd, &msg, MSG_DONTWAIT);

        if (len < 0) 
        {
            if (errno == EINTR || errno == EAGAIN)
            {
                usleep(250000);
                continue;
            }

            continue;
        }

        for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, (__u32)len); nh = NLMSG_NEXT(nh, len))
        {
            size_t len, info_len, devtype_len;
            struct ifinfomsg *msg;
            struct rtattr *rta, *info, *devtype;

            if(nh->nlmsg_type == NLMSG_DONE)
                goto nldone;

            if(nh->nlmsg_type != RTM_BASE)
                continue;

            msg = (struct ifinfomsg *)NLMSG_DATA(nh); // message payload

            if (msg->ifi_type != ARPHRD_ETHER)
                continue;

            // Display section
            if (target_idx > 0)
                std::cout << target_idx << ' ' << parent_idx << ' ' << kinddevname << std::endl;

            target_idx = 0;
            parent_idx = 0;
            master_idx = 0;
            devtype_id = 0;

            target_idx = msg->ifi_index;

            rta = IFLA_RTA(msg); // message attributes
            len = nh->nlmsg_len - NLMSG_LENGTH(sizeof *msg);

            for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len))
            {
                switch (rta->rta_type)
                {
                    case IFLA_LINK:
                        parent_idx = *(__u16 *)((char *) rta + NLA_HDRLEN);
                    break;
                    case IFLA_MASTER:
                        master_idx = *(__u16 *)((char *) rta + NLA_HDRLEN);
                    break;
                    default:
                    break;
                }

                if(rta->rta_type == IFLA_LINKINFO)
                {
                    info = (rtattr *)RTA_DATA(rta);
                    info_len = RTA_PAYLOAD(rta);

                    while (RTA_OK(info, info_len))
                    {
                        if (info->rta_type == IFLA_INFO_KIND)
                        {
                            kinddevname.clear();

                            if (strcmp((char *)RTA_DATA(info), "vlan") == 0)
                            {
                                kinddevname.assign("vlan");
                                info = RTA_NEXT(info, info_len);

                                if (RTA_OK(info, info_len))
                                {
                                    if (info->rta_type == IFLA_INFO_DATA)
                                    {
                                        devtype = (rtattr *)RTA_DATA(info);
                                        devtype_len = RTA_PAYLOAD(info);

                                        while (RTA_OK(devtype, devtype_len))
                                        {
                                            if (devtype->rta_type == IFLA_VLAN_ID)
                                                devtype_id = *(int *)RTA_DATA(devtype);

                                            devtype = RTA_NEXT(devtype, devtype_len);
                                        }
                                    }
                                }
                                else
                                    break;
                            }
                            else if (strcmp((char *)RTA_DATA(info), "bridge") == 0)
                                kinddevname.assign("bridge");
                            else if (strcmp((char *)RTA_DATA(info), "tun") == 0)
                                kinddevname.assign("tun");
                            else if (strcmp((char *)RTA_DATA(info), "veth") == 0)
                                kinddevname.assign("veth");
                        }
                        else if (info->rta_type == IFLA_INFO_SLAVE_KIND)
                        {
                            if (strcmp((char *)RTA_DATA(info), "bridge") == 0)
                            {
                                kinddevname.append(" (bridged to ");
                                kinddevname.append(std::to_string(master_idx));
                                kinddevname.append(")");
                            }
                        }

                        info = RTA_NEXT(info, info_len);
                    }
                }
            }
        }
    }

nldone:

    close(fd);
    fd = EOF;

    if (target_idx > 0)
        std::cout << target_idx << ' ' << parent_idx << ' ' << kinddevname << std::endl;
}

int main (void) {
    function();
    return 0;
}

上面的代码现在返回:

2 0

3 0

4 0

5 2 veth

6 2 veth

7 0 桥

8 7 个VLAN

9 7 个 VLAN

10 0 桥

11 0 tun(桥接到10)

12 0 tun(桥接到7)

© www.soinside.com 2019 - 2024. All rights reserved.