Can you tell me how I can display the member interfaces of a bridge in C++ language?
Via netlink I can display the system interfaces (target id, parent id and type of the same) but once get these informations I don't know how to identify the member interfaces of the bridges.
Having these interfaces:
1 lo
2 ens2
3 eno2
4 eno1
5 vethgw@if2
6 vethbras@if2
7 br0
8 vlan4094@br0
9 vlan4093@br0
10 virbr0
11 tap0
12 tap1
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;
}
the function display these lines
2 0
3 0
4 0
5 2 veth
6 2 veth
7 0 bridge
8 7 vlan
9 7 vlan
10 0 bridge
11 0 tun
12 0 tun
But as you can see tun interfaces are only indicated by name and target idx.
Is it possible to also know the bridge they are a member of?
The code above now return:
2 0
3 0
4 0
5 2 veth
6 2 veth
7 0 bridge
8 7 vlan
9 7 vlan
10 0 bridge
11 0 tun (bridged to 10)
12 0 tun (bridged to 7)