Blame rtnl.c

Packit 9c3e7e
/**
Packit 9c3e7e
 * @file rtnl.c
Packit 9c3e7e
 * @note Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
Packit 9c3e7e
 *
Packit 9c3e7e
 * This program is free software; you can redistribute it and/or modify
Packit 9c3e7e
 * it under the terms of the GNU General Public License as published by
Packit 9c3e7e
 * the Free Software Foundation; either version 2 of the License, or
Packit 9c3e7e
 * (at your option) any later version.
Packit 9c3e7e
 *
Packit 9c3e7e
 * This program is distributed in the hope that it will be useful,
Packit 9c3e7e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 9c3e7e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 9c3e7e
 * GNU General Public License for more details.
Packit 9c3e7e
 *
Packit 9c3e7e
 * You should have received a copy of the GNU General Public License along
Packit 9c3e7e
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit 9c3e7e
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 9c3e7e
 */
Packit 9c3e7e
#include <asm/types.h>
Packit 9c3e7e
#include <sys/socket.h> /* Must come before linux/netlink.h on some systems. */
Packit 9c3e7e
#include <linux/netlink.h>
Packit 9c3e7e
#include <linux/rtnetlink.h>
Packit Service 9bb151
#include <linux/genetlink.h>
Packit Service 9bb151
#include <linux/if_team.h>
Packit 9c3e7e
#include <net/if.h>
Packit 9c3e7e
#include <stdio.h>
Packit 9c3e7e
#include <stdlib.h>
Packit 9c3e7e
#include <string.h>
Packit 9c3e7e
#include <unistd.h>
Packit 9c3e7e
Packit 9c3e7e
#include "missing.h"
Packit 9c3e7e
#include "print.h"
Packit 9c3e7e
#include "rtnl.h"
Packit 9c3e7e
Packit Service 9bb151
#define BUF_SIZE 4096
Packit Service 9bb151
#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
Packit Service 9bb151
Packit 9c3e7e
static int rtnl_len;
Packit 9c3e7e
static char *rtnl_buf;
Packit Service 9bb151
static int get_team_active_iface(int master_index);
Packit Service 9bb151
Packit Service 9bb151
static int nl_close(int fd)
Packit Service 9bb151
{
Packit Service 9bb151
	return close(fd);
Packit Service 9bb151
}
Packit Service 9bb151
Packit Service 9bb151
static int nl_open(int family)
Packit Service 9bb151
{
Packit Service 9bb151
	int fd;
Packit Service 9bb151
	struct sockaddr_nl sa;
Packit Service 9bb151
Packit Service 9bb151
	memset(&sa, 0, sizeof(sa));
Packit Service 9bb151
	sa.nl_family = AF_NETLINK;
Packit Service 9bb151
	sa.nl_groups = RTNLGRP_LINK;
Packit Service 9bb151
Packit Service 9bb151
	fd = socket(AF_NETLINK, SOCK_RAW, family);
Packit Service 9bb151
	if (fd < 0) {
Packit Service 9bb151
		pr_err("failed to open netlink socket: %m");
Packit Service 9bb151
		return -1;
Packit Service 9bb151
	}
Packit Service 9bb151
	if (bind(fd, (struct sockaddr *) &sa, sizeof(sa))) {
Packit Service 9bb151
		pr_err("failed to bind netlink socket: %m");
Packit Service 9bb151
		close(fd);
Packit Service 9bb151
		return -1;
Packit Service 9bb151
	}
Packit Service 9bb151
	return fd;
Packit Service 9bb151
}
Packit 9c3e7e
Packit 9c3e7e
int rtnl_close(int fd)
Packit 9c3e7e
{
Packit 9c3e7e
	if (rtnl_buf) {
Packit 9c3e7e
		free(rtnl_buf);
Packit 9c3e7e
		rtnl_buf = NULL;
Packit 9c3e7e
		rtnl_len = 0;
Packit 9c3e7e
	}
Packit Service 9bb151
	return nl_close(fd);
Packit Service 9bb151
}
Packit Service 9bb151
Packit Service 9bb151
int rtnl_open(void)
Packit Service 9bb151
{
Packit Service 9bb151
	return nl_open(NETLINK_ROUTE);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void rtnl_get_ts_device_callback(void *ctx, int linkup, int ts_index)
Packit 9c3e7e
{
Packit 9c3e7e
	int *dst = ctx;
Packit 9c3e7e
	*dst = ts_index;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int rtnl_get_ts_device(char *device, char *ts_device)
Packit 9c3e7e
{
Packit 9c3e7e
	int err, fd;
Packit 9c3e7e
	int ts_index = -1;
Packit 9c3e7e
Packit 9c3e7e
	fd = rtnl_open();
Packit 9c3e7e
	if (fd < 0)
Packit 9c3e7e
		return fd;
Packit 9c3e7e
Packit 9c3e7e
	err = rtnl_link_query(fd, device);
Packit 9c3e7e
	if (err) {
Packit 9c3e7e
		goto no_info;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	rtnl_link_status(fd, device, rtnl_get_ts_device_callback, &ts_index);
Packit 9c3e7e
	if (ts_index > 0 && if_indextoname(ts_index, ts_device))
Packit 9c3e7e
		err = 0;
Packit 9c3e7e
	else
Packit 9c3e7e
		err = -1;
Packit 9c3e7e
Packit 9c3e7e
no_info:
Packit 9c3e7e
	rtnl_close(fd);
Packit 9c3e7e
	return err;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int rtnl_link_query(int fd, char *device)
Packit 9c3e7e
{
Packit 9c3e7e
	struct sockaddr_nl sa;
Packit 9c3e7e
	struct msghdr msg;
Packit 9c3e7e
	struct iovec iov;
Packit 9c3e7e
	int cnt;
Packit 9c3e7e
Packit 9c3e7e
	struct {
Packit 9c3e7e
		struct nlmsghdr hdr;
Packit 9c3e7e
		struct ifinfomsg ifm;
Packit 9c3e7e
	} __attribute__((packed)) request;
Packit 9c3e7e
Packit 9c3e7e
	memset(&sa, 0, sizeof(sa));
Packit 9c3e7e
	sa.nl_family = AF_NETLINK;
Packit 9c3e7e
Packit 9c3e7e
	memset(&request, 0, sizeof(request));
Packit 9c3e7e
	request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.ifm));
Packit 9c3e7e
	request.hdr.nlmsg_type = RTM_GETLINK;
Packit 9c3e7e
	request.hdr.nlmsg_flags = NLM_F_REQUEST;
Packit 9c3e7e
	request.hdr.nlmsg_seq = 1;
Packit 9c3e7e
	request.hdr.nlmsg_pid = 0;
Packit 9c3e7e
	request.ifm.ifi_family = AF_UNSPEC;
Packit 9c3e7e
	request.ifm.ifi_index = if_nametoindex(device ? device : "");
Packit 9c3e7e
	request.ifm.ifi_change = 0xffffffff;
Packit 9c3e7e
Packit 9c3e7e
	iov.iov_base = &request;
Packit 9c3e7e
	iov.iov_len = sizeof(request);
Packit 9c3e7e
Packit 9c3e7e
	memset(&msg, 0, sizeof(msg));
Packit 9c3e7e
	msg.msg_name = &sa;
Packit 9c3e7e
	msg.msg_namelen = sizeof(sa);
Packit 9c3e7e
	msg.msg_iov = &iov;
Packit 9c3e7e
	msg.msg_iovlen = 1;
Packit 9c3e7e
Packit 9c3e7e
	cnt = sendmsg(fd, &msg, 0);
Packit 9c3e7e
	if (cnt < 0) {
Packit 9c3e7e
		pr_err("rtnl: sendmsg: %m");
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit Service 9bb151
static inline __u8 rta_getattr_u8(struct rtattr *rta)
Packit Service 9bb151
{
Packit Service 9bb151
	return *(__u8 *)RTA_DATA(rta);
Packit Service 9bb151
}
Packit Service 9bb151
Packit Service 9bb151
static inline __u16 rta_getattr_u16(struct rtattr *rta)
Packit Service 9bb151
{
Packit Service 9bb151
	return *(__u16 *)RTA_DATA(rta);
Packit Service 9bb151
}
Packit Service 9bb151
Packit Service 9bb151
static inline __u32 rta_getattr_u32(struct rtattr *rta)
Packit 9c3e7e
{
Packit 9c3e7e
	return *(__u32 *)RTA_DATA(rta);
Packit 9c3e7e
}
Packit 9c3e7e
Packit Service 9bb151
static inline char *rta_getattr_str(struct rtattr *rta)
Packit 9c3e7e
{
Packit Service 9bb151
	return (char *)RTA_DATA(rta);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len)
Packit 9c3e7e
{
Packit 9c3e7e
	unsigned short type;
Packit 9c3e7e
Packit 9c3e7e
	memset(tb, 0, sizeof(struct rtattr *) * max);
Packit 9c3e7e
	while (RTA_OK(rta, len)) {
Packit 9c3e7e
		type = rta->rta_type;
Packit 9c3e7e
		if ((type < max) && (!tb[type]))
Packit 9c3e7e
			tb[type] = rta;
Packit 9c3e7e
		rta = RTA_NEXT(rta, len);
Packit 9c3e7e
	}
Packit 9c3e7e
	if (len) {
Packit 9c3e7e
		pr_err("Length mismatch: len %d, rta_len=%d\n", len, rta->rta_len);
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static inline int rtnl_nested_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta)
Packit 9c3e7e
{
Packit 9c3e7e
	return rtnl_rtattr_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
Packit 9c3e7e
}
Packit 9c3e7e
Packit Service 9bb151
static int rtnl_linkinfo_parse(int master_index, struct rtattr *rta)
Packit 9c3e7e
{
Packit 9c3e7e
	struct rtattr *linkinfo[IFLA_INFO_MAX];
Packit 9c3e7e
	struct rtattr *bond[IFLA_BOND_MAX];
Packit Service 9bb151
	int index = -1;
Packit Service 9bb151
	char *kind;
Packit 9c3e7e
Packit 9c3e7e
	if (rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta) < 0)
Packit 9c3e7e
		return -1;
Packit 9c3e7e
Packit 9c3e7e
	if (linkinfo[IFLA_INFO_KIND]) {
Packit 9c3e7e
		kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]);
Packit 9c3e7e
Packit 9c3e7e
		if (kind && !strncmp(kind, "bond", 4) &&
Packit 9c3e7e
		    linkinfo[IFLA_INFO_DATA]) {
Packit 9c3e7e
			if (rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX,
Packit 9c3e7e
						 linkinfo[IFLA_INFO_DATA]) < 0)
Packit 9c3e7e
				return -1;
Packit 9c3e7e
Packit 9c3e7e
			if (bond[IFLA_BOND_ACTIVE_SLAVE]) {
Packit 9c3e7e
				index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]);
Packit 9c3e7e
			}
Packit Service 9bb151
		} else if (kind && !strncmp(kind, "team", 4)) {
Packit Service 9bb151
			index = get_team_active_iface(master_index);
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
	return index;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx)
Packit 9c3e7e
{
Packit Service 9bb151
	struct rtattr *tb[IFLA_MAX+1];
Packit Service 9bb151
	struct ifinfomsg *info = NULL;
Packit 9c3e7e
	int index, len, link_up;
Packit Service bbd96a
	struct sockaddr_nl sa;
Packit Service 9bb151
	int slave_index = -1;
Packit Service bbd96a
	struct nlmsghdr *nh;
Packit Service 9bb151
	struct msghdr msg;
Packit Service 9bb151
	struct iovec iov;
Packit 9c3e7e
Packit 9c3e7e
	index = if_nametoindex(device);
Packit 9c3e7e
	if (!rtnl_buf) {
Packit Service 9bb151
		rtnl_len = BUF_SIZE;
Packit 9c3e7e
		rtnl_buf = malloc(rtnl_len);
Packit 9c3e7e
		if (!rtnl_buf) {
Packit 9c3e7e
			pr_err("rtnl: low memory");
Packit 9c3e7e
			return -1;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	iov.iov_base = rtnl_buf;
Packit 9c3e7e
	iov.iov_len = rtnl_len;
Packit 9c3e7e
	memset(&msg, 0, sizeof(msg));
Packit 9c3e7e
	msg.msg_name = &sa;
Packit 9c3e7e
	msg.msg_namelen = sizeof(sa);
Packit 9c3e7e
	msg.msg_iov = &iov;
Packit 9c3e7e
	msg.msg_iovlen = 1;
Packit 9c3e7e
Packit 9c3e7e
	len = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC);
Packit 9c3e7e
	if (len < 1) {
Packit 9c3e7e
		pr_err("rtnl: recvmsg: %m");
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (len > rtnl_len) {
Packit 9c3e7e
		free(rtnl_buf);
Packit 9c3e7e
		rtnl_len = len;
Packit 9c3e7e
		rtnl_buf = malloc(len);
Packit 9c3e7e
		if (!rtnl_buf) {
Packit 9c3e7e
			pr_err("rtnl: failed to resize to %d bytes", len);
Packit 9c3e7e
			return -1;
Packit 9c3e7e
		}
Packit 9c3e7e
		iov.iov_base = rtnl_buf;
Packit 9c3e7e
		iov.iov_len = rtnl_len;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	len = recvmsg(fd, &msg, 0);
Packit 9c3e7e
	if (len < 1) {
Packit 9c3e7e
		pr_err("rtnl: recvmsg: %m");
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	nh = (struct nlmsghdr *) rtnl_buf;
Packit 9c3e7e
Packit 9c3e7e
	for ( ; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
Packit 9c3e7e
		if (nh->nlmsg_type != RTM_NEWLINK)
Packit 9c3e7e
			continue;
Packit 9c3e7e
Packit 9c3e7e
		info = NLMSG_DATA(nh);
Packit 9c3e7e
		if (index != info->ifi_index)
Packit 9c3e7e
			continue;
Packit 9c3e7e
Packit 9c3e7e
		link_up = info->ifi_flags & IFF_RUNNING ? 1 : 0;
Packit 9c3e7e
		pr_debug("interface index %d is %s", index,
Packit 9c3e7e
			 link_up ? "up" : "down");
Packit 9c3e7e
Packit 9c3e7e
		rtnl_rtattr_parse(tb, IFLA_MAX, IFLA_RTA(info),
Packit 9c3e7e
				  IFLA_PAYLOAD(nh));
Packit 9c3e7e
Packit 9c3e7e
		if (tb[IFLA_LINKINFO])
Packit Service 9bb151
			slave_index = rtnl_linkinfo_parse(index, tb[IFLA_LINKINFO]);
Packit 9c3e7e
Packit 9c3e7e
		if (cb)
Packit 9c3e7e
			cb(ctx, link_up, slave_index);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit Service 9bb151
static int genl_send_msg(int fd, int family_id, int genl_cmd, int genl_version,
Packit Service 9bb151
		  int rta_type, void *rta_data, int rta_len)
Packit 9c3e7e
{
Packit Service 9bb151
	struct sockaddr_nl daddr;
Packit Service 9bb151
	struct genlmsghdr *gnlh;
Packit Service 9bb151
	struct nlmsghdr *nlh;
Packit Service 9bb151
	struct rtattr *attr;
Packit Service 9bb151
	char msg[BUF_SIZE];
Packit a3d358
Packit Service 9bb151
	memset(&daddr, 0, sizeof(daddr));
Packit Service 9bb151
	daddr.nl_family = AF_NETLINK;
Packit a3d358
Packit Service 9bb151
	memset(&msg, 0, sizeof(msg));
Packit Service 9bb151
	nlh = (struct nlmsghdr *) msg;
Packit Service 9bb151
	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
Packit Service 9bb151
	nlh->nlmsg_type = family_id;
Packit Service 9bb151
	nlh->nlmsg_flags = NLM_F_REQUEST;
Packit Service 9bb151
Packit Service 9bb151
	gnlh = (struct genlmsghdr *) NLMSG_DATA(nlh);
Packit Service 9bb151
	gnlh->cmd = genl_cmd;
Packit Service 9bb151
	gnlh->version = genl_version;
Packit Service 9bb151
Packit Service 9bb151
	if (rta_data && rta_len > 0) {
Packit Service 9bb151
		attr = (struct rtattr *) GENLMSG_DATA(msg);
Packit Service 9bb151
		attr->rta_type = rta_type;
Packit Service 9bb151
		attr->rta_len = RTA_LENGTH(rta_len);
Packit Service 9bb151
		nlh->nlmsg_len += NLMSG_ALIGN(attr->rta_len);
Packit Service 9bb151
		if (nlh->nlmsg_len < sizeof(msg))
Packit Service 9bb151
			memcpy(RTA_DATA(attr), rta_data, rta_len);
Packit Service 9bb151
		else
Packit Service 9bb151
			return -1;
Packit Service 9bb151
	}
Packit Service 9bb151
Packit Service 9bb151
	return sendto(fd, &msg, nlh->nlmsg_len, 0,
Packit Service 9bb151
		      (struct sockaddr *)&daddr, sizeof(daddr));
Packit Service 9bb151
}
Packit Service 9bb151
Packit Service 9bb151
static int genl_get_family_id(int fd, void *family_name)
Packit Service 9bb151
{
Packit Service 9bb151
	struct rtattr *tb[CTRL_ATTR_MAX+1];
Packit Service 9bb151
	struct nlmsghdr *nlh;
Packit Service 9bb151
	struct rtattr *attr;
Packit Service 9bb151
	char msg[BUF_SIZE];
Packit Service 9bb151
	int len, gf_id;
Packit Service 9bb151
Packit Service 9bb151
	len = genl_send_msg(fd, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1,
Packit Service 9bb151
			    CTRL_ATTR_FAMILY_NAME, family_name,
Packit Service 9bb151
			    strlen(family_name) + 1);
Packit Service 9bb151
	if (len < 0)
Packit Service 9bb151
		return len;
Packit Service 9bb151
Packit Service 9bb151
	len = recv(fd, &msg, sizeof(msg), 0);
Packit Service 9bb151
	if (len < 0)
Packit Service 9bb151
		return len;
Packit Service 9bb151
Packit Service 9bb151
	nlh = (struct nlmsghdr *) msg;
Packit Service 9bb151
	if (nlh->nlmsg_type == NLMSG_ERROR || !NLMSG_OK(nlh, len))
Packit 9c3e7e
		return -1;
Packit Service 9bb151
Packit Service 9bb151
	attr = (struct rtattr *) GENLMSG_DATA(msg);
Packit Service 9bb151
	rtnl_rtattr_parse(tb, CTRL_ATTR_MAX, attr, NLMSG_PAYLOAD(nlh, GENL_HDRLEN));
Packit Service 9bb151
Packit Service 9bb151
	if (tb[CTRL_ATTR_FAMILY_ID])
Packit Service 9bb151
		gf_id = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
Packit Service 9bb151
	else
Packit Service 9bb151
		gf_id = -1;
Packit Service 9bb151
Packit Service 9bb151
	return gf_id;
Packit Service 9bb151
}
Packit Service 9bb151
Packit Service 9bb151
static int parase_team_list_option(struct rtattr *attr)
Packit Service 9bb151
{
Packit Service 9bb151
	struct rtattr *tb[TEAM_ATTR_OPTION_MAX+1];
Packit Service 9bb151
	int len = RTA_PAYLOAD(attr);
Packit Service 9bb151
	const char *optname = "";
Packit Service 9bb151
	const char *mode = "";
Packit Service 9bb151
	int active_index = -1;
Packit Service 9bb151
Packit Service 9bb151
	for (attr = RTA_DATA(attr); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
Packit Service 9bb151
		rtnl_nested_rtattr_parse(tb, TEAM_ATTR_OPTION_MAX, attr);
Packit Service 9bb151
Packit Service 9bb151
		if (tb[TEAM_ATTR_OPTION_NAME])
Packit Service 9bb151
			optname = rta_getattr_str(tb[TEAM_ATTR_OPTION_NAME]);
Packit Service 9bb151
Packit Service 9bb151
		if (!strcmp(optname, "mode") && tb[TEAM_ATTR_OPTION_TYPE] &&
Packit Service 9bb151
		    rta_getattr_u8(tb[TEAM_ATTR_OPTION_TYPE]) == NLA_STRING)
Packit Service 9bb151
			mode = rta_getattr_str(tb[TEAM_ATTR_OPTION_DATA]);
Packit Service 9bb151
Packit Service 9bb151
		if (!strcmp(optname, "activeport") && tb[TEAM_ATTR_OPTION_TYPE] &&
Packit Service 9bb151
		    rta_getattr_u8(tb[TEAM_ATTR_OPTION_TYPE]) == NLA_U32)
Packit Service 9bb151
			active_index = rta_getattr_u32(tb[TEAM_ATTR_OPTION_DATA]);
Packit 9c3e7e
	}
Packit Service 9bb151
Packit Service 9bb151
	if (strcmp(mode, "activebackup")) {
Packit Service 9bb151
		pr_err("team supported only in activebackup mode");
Packit 9c3e7e
		return -1;
Packit Service 9bb151
	} else {
Packit Service 9bb151
		return active_index;
Packit a3d358
	}
Packit Service 9bb151
}
Packit Service 9bb151
Packit Service 9bb151
static int get_team_active_iface(int master_index)
Packit Service 9bb151
{
Packit Service 9bb151
	struct rtattr *tb[TEAM_ATTR_MAX+1];
Packit Service 9bb151
	struct genlmsghdr *gnlh;
Packit Service 9bb151
	struct nlmsghdr *nlh;
Packit Service 9bb151
	char msg[BUF_SIZE];
Packit Service 9bb151
	int fd, gf_id, len;
Packit Service 9bb151
	int index = -1;
Packit Service 9bb151
Packit Service 9bb151
	fd = nl_open(NETLINK_GENERIC);
Packit Service 9bb151
	if (fd < 0)
Packit Service 9bb151
		return fd;
Packit Service 9bb151
Packit Service 9bb151
	gf_id = genl_get_family_id(fd, TEAM_GENL_NAME);
Packit Service 9bb151
	if (gf_id < 0) {
Packit Service 9bb151
		pr_err("get genl family failed");
Packit Service 9bb151
		goto no_info;
Packit Service 9bb151
	}
Packit Service 9bb151
Packit Service 9bb151
	len = genl_send_msg(fd, gf_id, TEAM_CMD_OPTIONS_GET,
Packit Service 9bb151
			    TEAM_GENL_VERSION, TEAM_ATTR_TEAM_IFINDEX,
Packit Service 9bb151
			    &master_index, sizeof(master_index));
Packit Service 9bb151
	if (len < 0) {
Packit Service 9bb151
		pr_err("send team info request failed: %m");
Packit Service 9bb151
		goto no_info;
Packit Service 9bb151
	}
Packit Service 9bb151
Packit Service 9bb151
	len = recv(fd, msg, sizeof(msg), 0);
Packit Service 9bb151
	if (len < 0) {
Packit Service 9bb151
		pr_err("recv team info failed: %m");
Packit Service 9bb151
		goto no_info;
Packit Service 9bb151
	}
Packit Service 9bb151
Packit Service 9bb151
	nlh = (struct nlmsghdr *) msg;
Packit Service 9bb151
	for ( ; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) {
Packit Service 9bb151
		if (nlh->nlmsg_type != gf_id)
Packit Service 9bb151
			continue;
Packit Service 9bb151
Packit Service 9bb151
		gnlh = (struct genlmsghdr *) NLMSG_DATA(nlh);
Packit Service 9bb151
		if (gnlh->cmd != TEAM_CMD_OPTIONS_GET)
Packit Service 9bb151
			continue;
Packit Service 9bb151
Packit Service 9bb151
		rtnl_rtattr_parse(tb, TEAM_ATTR_MAX, (struct rtattr *)GENLMSG_DATA(msg),
Packit Service 9bb151
				  NLMSG_PAYLOAD(nlh, GENL_HDRLEN));
Packit Service 9bb151
Packit Service 9bb151
		if (tb[TEAM_ATTR_TEAM_IFINDEX] &&
Packit Service 9bb151
		    master_index != rta_getattr_u32(tb[TEAM_ATTR_TEAM_IFINDEX]))
Packit Service 9bb151
			continue;
Packit Service 9bb151
Packit Service 9bb151
		if (tb[TEAM_ATTR_LIST_OPTION]) {
Packit Service 9bb151
			index = parase_team_list_option(tb[TEAM_ATTR_LIST_OPTION]);
Packit Service 9bb151
			break;
Packit Service 9bb151
		}
Packit Service 9bb151
	}
Packit Service 9bb151
Packit Service 9bb151
no_info:
Packit Service 9bb151
	nl_close(fd);
Packit Service 9bb151
	return index;
Packit 9c3e7e
}