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

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

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

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

c++ network-programming netlink
1个回答
0
投票

有这些接口:

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 指示。

还可以知道他们所属的桥吗?

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