android13/external/libnl/lib/route/link/sriov.c

1467 lines
37 KiB
C

/*
* lib/route/link/sriov.c SRIOV VF Info
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2016 Intel Corp. All rights reserved.
* Copyright (c) 2016 Jef Oliver <jef.oliver@intel.com>
*/
/**
* @ingroup link
* @defgroup sriov SRIOV
* SR-IOV VF link module
*
* @details
* SR-IOV (Single Root Input/Output Virtualization) is a network interface
* that allows for the isolation of the PCI Express resources. In a virtual
* environment, SR-IOV allows multiple virtual machines can share a single
* PCI Express hardware interface. This is done via VFs (Virtual Functions),
* virtual hardware devices with their own PCI address.
*
* @{
*/
#include <netlink-private/netlink.h>
#include <netlink-private/route/link/api.h>
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <netlink-private/route/link/sriov.h>
#include <netlink/route/link/sriov.h>
/** @cond SKIP */
#define SRIOVON "on"
#define SRIOVOFF "off"
#define SET_VF_STAT(link, vf_num, stb, stat, attr) \
vf_data->vf_stats[stat] = nla_get_u64(stb[attr])
/* SRIOV-VF Attributes */
#define SRIOV_ATTR_INDEX (1 << 0)
#define SRIOV_ATTR_ADDR (1 << 1)
#define SRIOV_ATTR_VLAN (1 << 2)
#define SRIOV_ATTR_TX_RATE (1 << 3)
#define SRIOV_ATTR_SPOOFCHK (1 << 4)
#define SRIOV_ATTR_RATE_MAX (1 << 5)
#define SRIOV_ATTR_RATE_MIN (1 << 6)
#define SRIOV_ATTR_LINK_STATE (1 << 7)
#define SRIOV_ATTR_RSS_QUERY_EN (1 << 8)
#define SRIOV_ATTR_STATS (1 << 9)
#define SRIOV_ATTR_TRUST (1 << 10)
#define SRIOV_ATTR_IB_NODE_GUID (1 << 11)
#define SRIOV_ATTR_IB_PORT_GUID (1 << 12)
static struct nla_policy sriov_info_policy[IFLA_VF_MAX+1] = {
[IFLA_VF_MAC] = { .minlen = sizeof(struct ifla_vf_mac) },
[IFLA_VF_VLAN] = { .minlen = sizeof(struct ifla_vf_vlan) },
[IFLA_VF_VLAN_LIST] = { .type = NLA_NESTED },
[IFLA_VF_TX_RATE] = { .minlen = sizeof(struct ifla_vf_tx_rate) },
[IFLA_VF_SPOOFCHK] = { .minlen = sizeof(struct ifla_vf_spoofchk) },
[IFLA_VF_RATE] = { .minlen = sizeof(struct ifla_vf_rate) },
[IFLA_VF_LINK_STATE] = { .minlen = sizeof(struct ifla_vf_link_state) },
[IFLA_VF_RSS_QUERY_EN] = { .minlen = sizeof(struct ifla_vf_rss_query_en) },
[IFLA_VF_STATS] = { .type = NLA_NESTED },
[IFLA_VF_TRUST] = { .minlen = sizeof(struct ifla_vf_trust) },
[IFLA_VF_IB_NODE_GUID] = { .minlen = sizeof(struct ifla_vf_guid) },
[IFLA_VF_IB_PORT_GUID] = { .minlen = sizeof(struct ifla_vf_guid) },
};
static struct nla_policy sriov_stats_policy[IFLA_VF_STATS_MAX+1] = {
[IFLA_VF_STATS_RX_PACKETS] = { .type = NLA_U64 },
[IFLA_VF_STATS_TX_PACKETS] = { .type = NLA_U64 },
[IFLA_VF_STATS_RX_BYTES] = { .type = NLA_U64 },
[IFLA_VF_STATS_TX_BYTES] = { .type = NLA_U64 },
[IFLA_VF_STATS_BROADCAST] = { .type = NLA_U64 },
[IFLA_VF_STATS_MULTICAST] = { .type = NLA_U64 },
};
/** @endcond */
/* Clone SRIOV VF list in link object */
int rtnl_link_sriov_clone(struct rtnl_link *dst, struct rtnl_link *src) {
int err = 0;
struct nl_addr *vf_addr;
struct rtnl_link_vf *s_list, *d_vf, *s_vf, *next, *dest_h = NULL;
nl_vf_vlans_t *src_vlans = NULL, *dst_vlans = NULL;
nl_vf_vlan_info_t *src_vlan_info = NULL, *dst_vlan_info = NULL;
if (!(err = rtnl_link_has_vf_list(src)))
return 0;
dst->l_vf_list = rtnl_link_vf_alloc();
if (!dst->l_vf_list)
return -NLE_NOMEM;
dest_h = dst->l_vf_list;
s_list = src->l_vf_list;
nl_list_for_each_entry_safe(s_vf, next, &s_list->vf_list, vf_list) {
if (!(d_vf = rtnl_link_vf_alloc()))
return -NLE_NOMEM;
memcpy(d_vf, s_vf, sizeof(*s_vf));
if (s_vf->ce_mask & SRIOV_ATTR_ADDR) {
vf_addr = nl_addr_clone(s_vf->vf_lladdr);
if (!vf_addr) {
rtnl_link_vf_put(d_vf);
return -NLE_NOMEM;
}
d_vf->vf_lladdr = vf_addr;
}
if (s_vf->ce_mask & SRIOV_ATTR_VLAN) {
src_vlans = s_vf->vf_vlans;
src_vlan_info = src_vlans->vlans;
err = rtnl_link_vf_vlan_alloc(&dst_vlans,
src_vlans->size);
if (err < 0) {
rtnl_link_vf_put(d_vf);
return err;
}
dst_vlan_info = dst_vlans->vlans;
memcpy(dst_vlans, src_vlans, sizeof(nl_vf_vlans_t));
memcpy(dst_vlan_info, src_vlan_info,
dst_vlans->size * sizeof(dst_vlan_info));
d_vf->vf_vlans = dst_vlans;
}
nl_list_add_head(&d_vf->vf_list, &dest_h->vf_list);
dest_h = d_vf;
}
return 0;
}
/* Dump VLAN details for each SRIOV VF */
static void dump_sriov_vlans(nl_vf_vlans_t *vlans,
struct nl_dump_params *p) {
char buf[64];
int cur = 0;
nl_vf_vlan_info_t *vlan_data;
uint16_t prot;
vlan_data = vlans->vlans;
nl_dump(p, "\t VLANS:\n");
while (cur < vlans->size) {
nl_dump(p, "\t vlan %u", vlan_data[cur].vf_vlan);
if (vlan_data[cur].vf_vlan_qos)
nl_dump(p, " qos %u", vlan_data[cur].vf_vlan_qos);
if (vlan_data[cur].vf_vlan_proto) {
prot = vlan_data[cur].vf_vlan_proto;
nl_dump(p, " proto %s",
rtnl_link_vf_vlanproto2str(prot, buf,
sizeof(buf)));
}
nl_dump(p, "\n");
cur++;
}
return;
}
/* Dump details for each SRIOV VF */
static void dump_vf_details(struct rtnl_link_vf *vf_data,
struct nl_dump_params *p) {
char buf[64];
int err = 0;
struct nl_vf_rate vf_rate;
uint32_t v = 0;
nl_dump(p, "\tvf %u: ", vf_data->vf_index);
if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE) {
v = vf_data->vf_linkstate;
nl_dump(p, "state %s ",
rtnl_link_vf_linkstate2str(v, buf, sizeof(buf)));
}
if (vf_data->ce_mask & SRIOV_ATTR_ADDR) {
nl_dump(p, "addr %s ",
nl_addr2str(vf_data->vf_lladdr, buf, sizeof(buf)));
}
nl_dump(p, "\n");
v = vf_data->vf_spoofchk;
nl_dump(p, "\t spoofchk %s ", v ? SRIOVON : SRIOVOFF);
v = vf_data->vf_trust;
nl_dump(p, "trust %s ", v ? SRIOVON : SRIOVOFF);
v = vf_data->vf_rss_query_en;
nl_dump(p, "rss_query %s\n", v ? SRIOVON : SRIOVOFF);
err = rtnl_link_vf_get_rate(vf_data, &vf_rate);
if (!err) {
if (vf_rate.api == RTNL_LINK_VF_RATE_API_OLD)
nl_dump(p, "\t rate_api old rate %u\n",
vf_rate.rate);
else if (vf_rate.api == RTNL_LINK_VF_RATE_API_NEW)
nl_dump(p, "\t rate_api new min_rate %u "
"max_rate %u\n", vf_rate.min_tx_rate,
vf_rate.max_tx_rate);
}
if (vf_data->ce_mask & SRIOV_ATTR_VLAN)
dump_sriov_vlans(vf_data->vf_vlans, p);
return;
}
/* Loop through SRIOV VF list dump details */
void rtnl_link_sriov_dump_details(struct rtnl_link *link,
struct nl_dump_params *p) {
int err;
struct rtnl_link_vf *vf_data, *list, *next;
if (!(err = rtnl_link_has_vf_list(link)))
BUG();
nl_dump(p, " SRIOV VF List\n");
list = link->l_vf_list;
nl_list_for_each_entry_safe(vf_data, next, &list->vf_list, vf_list) {
if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
dump_vf_details(vf_data, p);
}
return;
}
/* Dump stats for each SRIOV VF */
static void dump_vf_stats(struct rtnl_link_vf *vf_data,
struct nl_dump_params *p) {
char *unit;
float res;
nl_dump(p, " VF %" PRIu64 " Stats:\n", vf_data->vf_index);
nl_dump_line(p, "\tRX: %-14s %-10s %-10s %-10s\n",
"bytes", "packets", "multicast", "broadcast");
res = nl_cancel_down_bytes(vf_data->vf_stats[RTNL_LINK_VF_STATS_RX_BYTES],
&unit);
nl_dump_line(p,
"\t%10.2f %3s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
res, unit,
vf_data->vf_stats[RTNL_LINK_VF_STATS_RX_PACKETS],
vf_data->vf_stats[RTNL_LINK_VF_STATS_MULTICAST],
vf_data->vf_stats[RTNL_LINK_VF_STATS_BROADCAST]);
nl_dump_line(p, "\tTX: %-14s %-10s\n", "bytes", "packets");
res = nl_cancel_down_bytes(vf_data->vf_stats[RTNL_LINK_VF_STATS_TX_BYTES],
&unit);
nl_dump_line(p, "\t%10.2f %3s %10" PRIu64 "\n", res, unit,
vf_data->vf_stats[RTNL_LINK_VF_STATS_TX_PACKETS]);
return;
}
/* Loop through SRIOV VF list dump stats */
void rtnl_link_sriov_dump_stats(struct rtnl_link *link,
struct nl_dump_params *p) {
struct rtnl_link_vf *vf_data, *list, *next;
list = link->l_vf_list;
nl_list_for_each_entry_safe(vf_data, next, &list->vf_list, vf_list) {
if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
dump_vf_stats(vf_data, p);
}
nl_dump(p, "\n");
return;
}
/* Free stored SRIOV VF data */
void rtnl_link_sriov_free_data(struct rtnl_link *link) {
int err = 0;
struct rtnl_link_vf *list, *vf, *next;
if (!(err = rtnl_link_has_vf_list(link)))
return;
list = link->l_vf_list;
nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
nl_list_del(&vf->vf_list);
rtnl_link_vf_put(vf);
}
rtnl_link_vf_put(link->l_vf_list);
return;
}
/* Fill VLAN info array */
static int rtnl_link_vf_vlan_info(int len, struct ifla_vf_vlan_info **vi,
nl_vf_vlans_t **nvi) {
int cur = 0, err;
nl_vf_vlans_t *vlans;
if (len <= 0)
return 0;
if ((err = rtnl_link_vf_vlan_alloc(&vlans, len)) < 0)
return err;
cur = 0;
while (cur < len) {
vlans->vlans[cur].vf_vlan = vi[cur]->vlan ? vi[cur]->vlan : 0;
vlans->vlans[cur].vf_vlan_qos = vi[cur]->qos ? vi[cur]->qos : 0;
if (vi[cur]->vlan_proto) {
vlans->vlans[cur].vf_vlan_proto = ntohs(vi[cur]->vlan_proto);
} else {
vlans->vlans[cur].vf_vlan_proto = ETH_P_8021Q;
}
cur++;
}
*nvi = vlans;
return 0;
}
/* Fill the IFLA_VF_VLAN attribute */
static void sriov_fill_vf_vlan(struct nl_msg *msg, nl_vf_vlan_info_t *vinfo,
uint32_t index) {
struct ifla_vf_vlan vlan;
vlan.vf = index;
vlan.vlan = vinfo[0].vf_vlan;
vlan.qos = vinfo[0].vf_vlan_qos;
NLA_PUT(msg, IFLA_VF_VLAN, sizeof(vlan), &vlan);
nla_put_failure:
return;
}
/* Fill the IFLA_VF_VLAN_LIST attribute */
static int sriov_fill_vf_vlan_list(struct nl_msg *msg, nl_vf_vlans_t *vlans,
uint32_t index) {
int cur = 0;
nl_vf_vlan_info_t *vlan_info = vlans->vlans;
struct ifla_vf_vlan_info vlan;
struct nlattr *list;
if (!(list = nla_nest_start(msg, IFLA_VF_VLAN_LIST)))
return -NLE_MSGSIZE;
vlan.vf = index;
while (cur < vlans->size) {
vlan.vlan = vlan_info[cur].vf_vlan;
vlan.qos = vlan_info[cur].vf_vlan_qos;
vlan.vlan_proto = vlan_info[cur].vf_vlan_proto;
NLA_PUT(msg, IFLA_VF_VLAN_INFO, sizeof(vlan), &vlan);
cur++;
}
nla_put_failure:
nla_nest_end(msg, list);
return 0;
}
/* Fill individual IFLA_VF_INFO attributes */
static int sriov_fill_vfinfo(struct nl_msg *msg,
struct rtnl_link_vf *vf_data) {
int err = 0, new_rate = 0;
nl_vf_vlans_t *vlan_list;
nl_vf_vlan_info_t *vlan_info;
struct ifla_vf_guid vf_node_guid;
struct ifla_vf_guid vf_port_guid;
struct ifla_vf_link_state vf_link_state;
struct ifla_vf_mac vf_mac;
struct ifla_vf_rate new_vf_rate;
struct ifla_vf_rss_query_en vf_rss_query_en;
struct ifla_vf_spoofchk vf_spoofchk;
struct ifla_vf_trust vf_trust;
struct ifla_vf_tx_rate vf_rate;
struct nlattr *list;
uint16_t proto;
if (!(vf_data->ce_mask & SRIOV_ATTR_INDEX))
return -NLE_MISSING_ATTR;
if (!(list = nla_nest_start(msg, IFLA_VF_INFO)))
return -NLE_MSGSIZE;
/* IFLA_VF_MAC */
if (vf_data->ce_mask & SRIOV_ATTR_ADDR) {
vf_mac.vf = vf_data->vf_index;
memset(vf_mac.mac, 0, sizeof(vf_mac.mac));
memcpy(vf_mac.mac, nl_addr_get_binary_addr(vf_data->vf_lladdr),
nl_addr_get_len(vf_data->vf_lladdr));
NLA_PUT(msg, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac);
}
/* IFLA_VF_VLAN IFLA_VF_VLAN_LIST */
if (vf_data->ce_mask & SRIOV_ATTR_VLAN) {
vlan_list = vf_data->vf_vlans;
vlan_info = vlan_list->vlans;
proto = vlan_info[0].vf_vlan_proto;
if (!proto)
proto = ETH_P_8021Q;
if ((vlan_list->size == 1) && (proto == ETH_P_8021Q))
sriov_fill_vf_vlan(msg, vlan_info, vf_data->vf_index);
else
err = sriov_fill_vf_vlan_list(msg, vlan_list,
vf_data->vf_index);
}
/* IFLA_VF_TX_RATE */
if (vf_data->ce_mask & SRIOV_ATTR_TX_RATE) {
vf_rate.vf = vf_data->vf_index;
vf_rate.rate = vf_data->vf_rate;
NLA_PUT(msg, IFLA_VF_TX_RATE, sizeof(vf_rate), &vf_rate);
}
/* IFLA_VF_RATE */
new_vf_rate.min_tx_rate = 0;
new_vf_rate.max_tx_rate = 0;
new_vf_rate.vf = vf_data->vf_index;
if (vf_data->ce_mask & SRIOV_ATTR_RATE_MIN) {
new_vf_rate.min_tx_rate = vf_data->vf_min_tx_rate;
new_rate = 1;
}
if (vf_data->ce_mask & SRIOV_ATTR_RATE_MAX) {
new_vf_rate.max_tx_rate = vf_data->vf_max_tx_rate;
new_rate = 1;
}
if (new_rate)
NLA_PUT(msg, IFLA_VF_RATE, sizeof(new_vf_rate), &new_vf_rate);
/* IFLA_VF_SPOOFCHK */
if (vf_data->ce_mask & SRIOV_ATTR_SPOOFCHK) {
vf_spoofchk.vf = vf_data->vf_index;
vf_spoofchk.setting = vf_data->vf_spoofchk;
NLA_PUT(msg, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
&vf_spoofchk);
}
/* IFLA_VF_LINK_STATE */
if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE) {
vf_link_state.vf = vf_data->vf_index;
vf_link_state.link_state = vf_data->vf_linkstate;
NLA_PUT(msg, IFLA_VF_LINK_STATE, sizeof(vf_link_state),
&vf_link_state);
}
/* IFLA_VF_RSS_QUERY_EN */
if (vf_data->ce_mask & SRIOV_ATTR_RSS_QUERY_EN) {
vf_rss_query_en.vf = vf_data->vf_index;
vf_rss_query_en.setting = vf_data->vf_rss_query_en;
NLA_PUT(msg, IFLA_VF_RSS_QUERY_EN, sizeof(vf_rss_query_en),
&vf_rss_query_en);
}
/* IFLA_VF_TRUST */
if (vf_data->ce_mask & SRIOV_ATTR_TRUST) {
vf_trust.vf = vf_data->vf_index;
vf_trust.setting = vf_data->vf_trust;
NLA_PUT(msg, IFLA_VF_TRUST, sizeof(vf_trust), &vf_trust);
}
/* IFLA_VF_IB_NODE_GUID */
if (vf_data->ce_mask & SRIOV_ATTR_IB_NODE_GUID) {
vf_node_guid.vf = vf_data->vf_index;
vf_node_guid.guid = vf_data->vf_guid_node;
NLA_PUT(msg, IFLA_VF_IB_NODE_GUID, sizeof(vf_node_guid),
&vf_node_guid);
}
/* IFLA_VF_IB_PORT_GUID */
if (vf_data->ce_mask & SRIOV_ATTR_IB_PORT_GUID) {
vf_port_guid.vf = vf_data->vf_index;
vf_port_guid.guid = vf_data->vf_guid_port;
NLA_PUT(msg, IFLA_VF_IB_PORT_GUID, sizeof(vf_port_guid),
&vf_port_guid);
}
nla_put_failure:
nla_nest_end(msg, list);
return err;
}
/* Fill the IFLA_VFINFO_LIST attribute */
int rtnl_link_sriov_fill_vflist(struct nl_msg *msg, struct rtnl_link *link) {
int err = 0;
struct nlattr *data;
struct rtnl_link_vf *list, *vf, *next;
if (!(err = rtnl_link_has_vf_list(link)))
return 0;
if (!(data = nla_nest_start(msg, IFLA_VFINFO_LIST)))
return -NLE_MSGSIZE;
list = link->l_vf_list;
nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
if (vf->ce_mask & SRIOV_ATTR_INDEX) {
if ((err = sriov_fill_vfinfo(msg, vf)) < 0)
goto nla_nest_list_failure;
}
}
nla_nest_list_failure:
nla_nest_end(msg, data);
return err;
}
/* Parse IFLA_VFINFO_LIST and IFLA_VF_INFO attributes */
int rtnl_link_sriov_parse_vflist(struct rtnl_link *link, struct nlattr **tb) {
int err, len, list_len, list_rem;
struct ifla_vf_mac *vf_lladdr;
struct ifla_vf_vlan *vf_vlan;
struct ifla_vf_vlan_info *vf_vlan_info[MAX_VLAN_LIST_LEN];
struct ifla_vf_tx_rate *vf_tx_rate;
struct ifla_vf_spoofchk *vf_spoofchk;
struct ifla_vf_link_state *vf_linkstate;
struct ifla_vf_rate *vf_rate;
struct ifla_vf_rss_query_en *vf_rss_query;
struct ifla_vf_trust *vf_trust;
struct nlattr *nla, *nla_list, *t[IFLA_VF_MAX+1],
*stb[RTNL_LINK_VF_STATS_MAX+1];
nl_vf_vlans_t *vf_vlans = NULL;
struct rtnl_link_vf *vf_data, *vf_head = NULL;
len = nla_len(tb[IFLA_VFINFO_LIST]);
link->l_vf_list = rtnl_link_vf_alloc();
if (!link->l_vf_list)
return -NLE_NOMEM;
vf_head = link->l_vf_list;
for (nla = nla_data(tb[IFLA_VFINFO_LIST]); nla_ok(nla, len);
nla = nla_next(nla, &len)) {
err = nla_parse(t, IFLA_VF_MAX, nla_data(nla), nla_len(nla),
sriov_info_policy);
if (err < 0)
return err;
vf_data = rtnl_link_vf_alloc();
if (!vf_data)
return -NLE_NOMEM;
if (t[IFLA_VF_MAC]) {
vf_lladdr = nla_data(t[IFLA_VF_MAC]);
vf_data->vf_index = vf_lladdr->vf;
vf_data->ce_mask |= SRIOV_ATTR_INDEX;
vf_data->vf_lladdr = nl_addr_build(AF_LLC,
vf_lladdr->mac, 6);
if (vf_data->vf_lladdr == NULL) {
rtnl_link_vf_put(vf_data);
return -NLE_NOMEM;
}
nl_addr_set_family(vf_data->vf_lladdr, AF_LLC);
vf_data->ce_mask |= SRIOV_ATTR_ADDR;
}
if (t[IFLA_VF_VLAN_LIST]) {
list_len = 0;
nla_for_each_nested(nla_list, t[IFLA_VF_VLAN_LIST],
list_rem) {
if (list_len >= MAX_VLAN_LIST_LEN)
break;
vf_vlan_info[list_len] = nla_data(nla_list);
list_len++;
}
err = rtnl_link_vf_vlan_info(list_len, vf_vlan_info,
&vf_vlans);
if (err < 0) {
rtnl_link_vf_put(vf_data);
return err;
}
vf_data->vf_vlans = vf_vlans;
vf_data->ce_mask |= SRIOV_ATTR_VLAN;
} else if (t[IFLA_VF_VLAN]) {
vf_vlan = nla_data(t[IFLA_VF_VLAN]);
if (vf_vlan->vlan) {
err = rtnl_link_vf_vlan_alloc(&vf_vlans, 1);
if (err < 0) {
rtnl_link_vf_put(vf_data);
return err;
}
vf_vlans->vlans[0].vf_vlan = vf_vlan->vlan;
vf_vlans->vlans[0].vf_vlan_qos = vf_vlan->qos;
vf_vlans->vlans[0].vf_vlan_proto = ETH_P_8021Q;
vf_data->vf_vlans = vf_vlans;
vf_data->ce_mask |= SRIOV_ATTR_VLAN;
}
}
if (t[IFLA_VF_TX_RATE]) {
vf_tx_rate = nla_data(t[IFLA_VF_TX_RATE]);
if (vf_tx_rate->rate) {
vf_data->vf_rate = vf_tx_rate->rate;
vf_data->ce_mask |= SRIOV_ATTR_TX_RATE;
}
}
if (t[IFLA_VF_SPOOFCHK]) {
vf_spoofchk = nla_data(t[IFLA_VF_SPOOFCHK]);
if (vf_spoofchk->setting != -1) {
vf_data->vf_spoofchk = vf_spoofchk->setting ? 1 : 0;
vf_data->ce_mask |= SRIOV_ATTR_SPOOFCHK;
}
}
if (t[IFLA_VF_LINK_STATE]) {
vf_linkstate = nla_data(t[IFLA_VF_LINK_STATE]);
vf_data->vf_linkstate = vf_linkstate->link_state;
vf_data->ce_mask |= SRIOV_ATTR_LINK_STATE;
}
if (t[IFLA_VF_RATE]) {
vf_rate = nla_data(t[IFLA_VF_RATE]);
if (vf_rate->max_tx_rate) {
vf_data->vf_max_tx_rate = vf_rate->max_tx_rate;
vf_data->ce_mask |= SRIOV_ATTR_RATE_MAX;
}
if (vf_rate->min_tx_rate) {
vf_data->vf_min_tx_rate = vf_rate->min_tx_rate;
vf_data->ce_mask |= SRIOV_ATTR_RATE_MIN;
}
}
if (t[IFLA_VF_RSS_QUERY_EN]) {
vf_rss_query = nla_data(t[IFLA_VF_RSS_QUERY_EN]);
if (vf_rss_query->setting != -1) {
vf_data->vf_rss_query_en = vf_rss_query->setting ? 1 : 0;
vf_data->ce_mask |= SRIOV_ATTR_RSS_QUERY_EN;
}
}
if (t[IFLA_VF_STATS]) {
err = nla_parse_nested(stb, IFLA_VF_STATS_MAX,
t[IFLA_VF_STATS],
sriov_stats_policy);
if (err < 0) {
rtnl_link_vf_put(vf_data);
return err;
}
SET_VF_STAT(link, cur, stb,
RTNL_LINK_VF_STATS_RX_PACKETS,
IFLA_VF_STATS_RX_PACKETS);
SET_VF_STAT(link, cur, stb,
RTNL_LINK_VF_STATS_TX_PACKETS,
IFLA_VF_STATS_TX_PACKETS);
SET_VF_STAT(link, cur, stb,
RTNL_LINK_VF_STATS_RX_BYTES,
IFLA_VF_STATS_RX_BYTES);
SET_VF_STAT(link, cur, stb,
RTNL_LINK_VF_STATS_TX_BYTES,
IFLA_VF_STATS_TX_BYTES);
SET_VF_STAT(link, cur, stb,
RTNL_LINK_VF_STATS_BROADCAST,
IFLA_VF_STATS_BROADCAST);
SET_VF_STAT(link, cur, stb,
RTNL_LINK_VF_STATS_MULTICAST,
IFLA_VF_STATS_MULTICAST);
vf_data->ce_mask |= IFLA_VF_STATS;
}
if (t[IFLA_VF_TRUST]) {
vf_trust = nla_data(t[IFLA_VF_TRUST]);
if (vf_trust->setting != -1) {
vf_data->vf_trust = vf_trust->setting ? 1 : 0;
vf_data->ce_mask |= SRIOV_ATTR_TRUST;
}
}
nl_list_add_head(&vf_data->vf_list, &vf_head->vf_list);
vf_head = vf_data;
}
return 0;
}
/**
* @name SR-IOV Sub-Object
* @{
*/
/**
* Add a SRIOV VF object to a link object
* @param link Link object to add to
* @param vf_data SRIOV VF object to add
*
* @return 0 if SRIOV VF object added successfully
* @return -NLE_OBJ_NOTFOUND if \p link or \p vf_data not provided
* @return -NLE_NOMEM if out of memory
*/
int rtnl_link_vf_add(struct rtnl_link *link, struct rtnl_link_vf *vf_data) {
struct rtnl_link_vf *vf_head = NULL;
if (!link||!vf_data)
return -NLE_OBJ_NOTFOUND;
if (!link->l_vf_list) {
link->l_vf_list = rtnl_link_vf_alloc();
if (!link->l_vf_list)
return -NLE_NOMEM;
}
vf_head = vf_data;
vf_head->ce_refcnt++;
vf_head = link->l_vf_list;
nl_list_add_head(&vf_data->vf_list, &vf_head->vf_list);
link->l_vf_list = vf_head;
rtnl_link_set_vf_list(link);
return 0;
}
/**
* Allocate a new SRIOV VF object
*
* @return NULL if out of memory
* @return New VF Object
*
* @see rtnl_link_vf_put()
*
* The SRIOV VF object must be returned to the link object with
* rtnl_link_vf_put() when operations are done to prevent memory leaks.
*/
struct rtnl_link_vf *rtnl_link_vf_alloc(void) {
struct rtnl_link_vf *vf;
if (!(vf = calloc(1, sizeof(*vf))))
return NULL;
NL_INIT_LIST_HEAD(&vf->vf_list);
vf->ce_refcnt = 1;
NL_DBG(4, "Allocated new SRIOV VF object %p\n", vf);
return vf;
}
/**
* Free SRIOV VF object.
* @arg vf_data SRIOV VF data object
*/
void rtnl_link_vf_free(struct rtnl_link_vf *vf_data) {
if (!vf_data)
return;
if (vf_data->ce_refcnt > 0)
NL_DBG(1, "Warning: Freeing SRIOV VF object in use...\n");
if (vf_data->ce_mask & SRIOV_ATTR_ADDR)
nl_addr_put(vf_data->vf_lladdr);
if (vf_data->ce_mask & SRIOV_ATTR_VLAN)
rtnl_link_vf_vlan_put(vf_data->vf_vlans);
NL_DBG(4, "Freed SRIOV VF object %p\n", vf_data);
free(vf_data);
return;
}
/**
* Lookup SRIOV VF in link object by VF index.
*
* @return NULL if VF not found
* @return VF Object
*
* @see rtnl_link_vf_put()
*
* The SRIOV VF object must be returned to the link object with
* rtnl_link_vf_put() when operations are done to prevent memory leaks.
*/
struct rtnl_link_vf *rtnl_link_vf_get(struct rtnl_link *link, uint32_t vf_num) {
struct rtnl_link_vf *list, *vf, *next, *ret = NULL;
list = link->l_vf_list;
nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
if (vf->vf_index == vf_num) {
ret = vf;
break;
}
}
if (ret) {
ret->ce_refcnt++;
NL_DBG(4, "New reference to SRIOV VF object %p, total %i\n",
ret, ret->ce_refcnt);
}
return ret;
}
/**
* Return SRIOV VF object to the owning link object.
* @arg vf_data SRIOV VF data object
*
* @see rtnl_link_vf_alloc()
* @see rtnl_link_vf_get()
*/
void rtnl_link_vf_put(struct rtnl_link_vf *vf_data) {
if (!vf_data)
return;
vf_data->ce_refcnt--;
NL_DBG(4, "Returned SRIOV VF object reference %p, %i remaining\n",
vf_data, vf_data->ce_refcnt);
if (vf_data->ce_refcnt < 0)
BUG();
if (vf_data->ce_refcnt <= 0)
rtnl_link_vf_free(vf_data);
return;
}
/**
* Get link layer address of SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg addr Pointer to store Link Layer address
*
* @see rtnl_link_get_num_vf()
* @see rtnl_link_vf_set_addr()
*
* @copydoc pointer_lifetime_warning
* @return 0 if addr is present and addr is set to pointer containing address
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the link layer address is not set
*/
int rtnl_link_vf_get_addr(struct rtnl_link_vf *vf_data, struct nl_addr **addr)
{
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_ADDR)
*addr = vf_data->vf_lladdr;
else
return -NLE_NOATTR;
return 0;
}
/**
* Set link layer address of SRIOV Virtual Function object
* @param vf_data SRIOV VF object
* @param addr New link layer address
*
* This function increments the reference counter of the address object
* and overwrites any existing link layer address previously assigned.
*
* @see rtnl_link_vf_get_addr()
*/
void rtnl_link_vf_set_addr(struct rtnl_link_vf *vf_data, struct nl_addr *addr) {
if (vf_data->vf_lladdr)
nl_addr_put(vf_data->vf_lladdr);
nl_addr_get(addr);
vf_data->vf_lladdr = addr;
vf_data->ce_mask |= SRIOV_ATTR_ADDR;
return;
}
/**
* Set the Infiniband node GUID for the SRIOV Virtual Function object
* @param vf_data SRIOV VF object
* @param guid node GUID
*/
void rtnl_link_vf_set_ib_node_guid(struct rtnl_link_vf *vf_data,
uint64_t guid) {
vf_data->vf_guid_node = guid;
vf_data->ce_mask |= SRIOV_ATTR_IB_NODE_GUID;
return;
}
/**
* Set the Infiniband port GUID for the SRIOV Virtual Function object
* @param vf_data SRIOV VF object
* @param guid port GUID
*/
void rtnl_link_vf_set_ib_port_guid(struct rtnl_link_vf *vf_data,
uint64_t guid) {
vf_data->vf_guid_port = guid;
vf_data->ce_mask |= SRIOV_ATTR_IB_PORT_GUID;
return;
}
/**
* Get index of SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg vf_index Pointer to store VF index
*
* @see rtnl_link_get_num_vf()
*
* @return 0 if index is present and vf_index is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF index is not set
*/
int rtnl_link_vf_get_index(struct rtnl_link_vf *vf_data, uint32_t *vf_index)
{
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
*vf_index = vf_data->vf_index;
else
return -NLE_NOATTR;
return 0;
}
/**
* Set index of SRIOV Virtual Function object
* @param vf_data SRIOV VF object
* @param vf_index Index value
*
* @see rtnl_link_vf_get_index()
*/
void rtnl_link_vf_set_index(struct rtnl_link_vf *vf_data, uint32_t vf_index)
{
vf_data->vf_index = vf_index;
vf_data->ce_mask |= SRIOV_ATTR_INDEX;
return;
}
/**
* Get link state of SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg vf_linkstate Pointer to store VF link state
*
* @see rtnl_link_get_num_vf()
* @see rtnl_link_set_linkstate()
*
* @return 0 if link state is present and vf_linkstate is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF link state is not set
*/
int rtnl_link_vf_get_linkstate(struct rtnl_link_vf *vf_data,
uint32_t *vf_linkstate)
{
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE)
*vf_linkstate = vf_data->vf_linkstate;
else
return -NLE_NOATTR;
return 0;
}
/**
* Set link state of SRIOV Virtual Function object
* @param vf_data SRIOV VF object
* @param vf_linkstate Link state value
*
* @see rtnl_link_get_linkstate()
*
* Not all hardware supports setting link state. If the feature is unsupported,
* the link change request will fail with -NLE_OPNOTSUPP
*/
void rtnl_link_vf_set_linkstate(struct rtnl_link_vf *vf_data,
uint32_t vf_linkstate) {
vf_data->vf_linkstate = vf_linkstate;
vf_data->ce_mask |= SRIOV_ATTR_LINK_STATE;
return;
}
/**
* Get TX Rate Limit of SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg vf_rate Pointer to store VF rate limiting data
*
* @see rtnl_link_get_num_vf()
* @see rtnl_link_set_rate()
*
* When the older rate API has been implemented, the rate member of the struct
* will be set, and the api member will be set to RTNL_LINK_VF_API_OLD.
* When the newer rate API has been implemented, the max_tx_rate
* and/or the minx_tx_rate will be set, and the api member will be set to
* RTNL_LINK_VF_API_NEW.
*
* Old rate API supports only a maximum TX rate.
* ip link set dev vf 0 rate
* New rate API supports minumum and maximum TX rates.
* ip link set dev vf 0 min_tx_rate
* ip link set dev vf 0 max_tx_rate
*
* @return 0 if rate is present and vf_rate is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF rate is not set
*/
int rtnl_link_vf_get_rate(struct rtnl_link_vf *vf_data,
struct nl_vf_rate *vf_rate)
{
int set = 0;
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
vf_rate->api = RTNL_LINK_VF_RATE_API_UNSPEC;
vf_rate->rate = 0;
vf_rate->max_tx_rate = 0;
vf_rate->min_tx_rate = 0;
if (vf_data->ce_mask & SRIOV_ATTR_RATE_MAX) {
if (vf_data->vf_max_tx_rate) {
vf_rate->api = RTNL_LINK_VF_RATE_API_NEW;
vf_rate->max_tx_rate = vf_data->vf_max_tx_rate;
set = 1;
}
}
if (vf_data->ce_mask & SRIOV_ATTR_RATE_MIN) {
if (vf_data->vf_min_tx_rate) {
vf_rate->api = RTNL_LINK_VF_RATE_API_NEW;
vf_rate->min_tx_rate = vf_data->vf_min_tx_rate;
set = 1;
}
}
if ((!set) && (vf_data->ce_mask & SRIOV_ATTR_TX_RATE)) {
if (vf_data->vf_rate) {
vf_rate->api = RTNL_LINK_VF_RATE_API_OLD;
vf_rate->rate = vf_data->vf_rate;
set = 1;
}
}
if (!set)
return -NLE_NOATTR;
return 0;
}
/**
* Set TX Rate Limit of SRIOV Virtual Function object
* @param vf_data SRIOV VF object
* @param vf_rate Rate limiting structure
*
* @see rtnl_link_vf_get_rate()
*
* When setting the rate, the API level must be specificed.
* Valid API levels:
* RTNL_LINK_VF_RATE_API_NEW
* RTNL_LINK_VF_RATE_API_OLD
*
* When using the new API, if either the min_tx_rate or
* max_tx_rate has been set, and the other is being changed,
* you must specify the currently set values to preserve
* them. If this is not done, that setting will be disabled.
*
* Old rate API supports only a maximum TX rate.
* ip link set dev vf 0 rate
* New rate API supports minumum and maximum TX rates.
* ip link set dev vf 0 min_tx_rate
* ip link set dev vf 0 max_tx_rate
*
* Not all hardware supports min_tx_rate.
*/
void rtnl_link_vf_set_rate(struct rtnl_link_vf *vf_data,
struct nl_vf_rate *vf_rate) {
if (vf_rate->api == RTNL_LINK_VF_RATE_API_OLD) {
vf_data->vf_rate = vf_rate->rate;
vf_data->ce_mask |= SRIOV_ATTR_TX_RATE;
} else if (vf_rate->api == RTNL_LINK_VF_RATE_API_NEW) {
vf_data->vf_max_tx_rate = vf_rate->max_tx_rate;
vf_data->ce_mask |= SRIOV_ATTR_RATE_MAX;
vf_data->vf_min_tx_rate = vf_rate->min_tx_rate;
vf_data->ce_mask |= SRIOV_ATTR_RATE_MIN;
}
return;
}
/**
* Get RSS Query EN value of SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg vf_rss_query_en Pointer to store VF RSS Query value
*
* @see rtnl_link_get_num_vf()
* @see rtnl_link_vf_set_rss_query_en()
*
* @return 0 if rss_query_en is present and vf_rss_query_en is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF RSS Query EN value is not set
*/
int rtnl_link_vf_get_rss_query_en(struct rtnl_link_vf *vf_data,
uint32_t *vf_rss_query_en)
{
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_RSS_QUERY_EN)
*vf_rss_query_en = vf_data->vf_rss_query_en;
else
return -NLE_NOATTR;
return 0;
}
/**
* Set RSS configuration querying of SRIOV Virtual Function Object
* @arg vf_data SRIOV VF object
* @arg vf_rss_query_en RSS Query value
*
* @see rtnl_link_vf_get_rss_query_en()
*/
void rtnl_link_vf_set_rss_query_en(struct rtnl_link_vf *vf_data,
uint32_t vf_rss_query_en) {
vf_data->vf_rss_query_en = vf_rss_query_en;
vf_data->ce_mask |= SRIOV_ATTR_RSS_QUERY_EN;
return;
}
/**
* Get spoof checking value of SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg vf_spoofchk Pointer to store VF spoofchk value
*
* @see rtnl_link_get_num_vf()
* @see rtnl_link_set_spoofchk()
*
* @return 0 if spoofchk is present and vf_spoofchk is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF spoofcheck is not set
*/
int rtnl_link_vf_get_spoofchk(struct rtnl_link_vf *vf_data,
uint32_t *vf_spoofchk)
{
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_SPOOFCHK)
*vf_spoofchk = vf_data->vf_spoofchk;
else
return -NLE_NOATTR;
return 0;
}
/**
* Set spoof checking value of SRIOV Virtual Function Object
* @param vf_data
* @param vf_spoofchk
*
* @see rtnl_link_vf_get_spoofchk()
*/
void rtnl_link_vf_set_spoofchk(struct rtnl_link_vf *vf_data,
uint32_t vf_spoofchk) {
vf_data->vf_spoofchk = vf_spoofchk;
vf_data->ce_mask |= SRIOV_ATTR_SPOOFCHK;
return;
}
/**
* Get value of stat counter for SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg stat Identifier of statistical counter
* @arg vf_stat Pointer to store VF stat value in
*
* @see rtnl_link_get_num_vf()
*
* @return 0 if stat is present and vf_stat is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF stat is not set
*/
int rtnl_link_vf_get_stat(struct rtnl_link_vf *vf_data,
rtnl_link_vf_stats_t stat, uint64_t *vf_stat)
{
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_STATS)
*vf_stat = vf_data->vf_stats[stat];
else
return -NLE_NOATTR;
return 0;
}
/**
* Get trust setting of SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg vf_trust Pointer to store VF trust value
*
* @see rtnl_link_get_num_vf()
* @see rtnl_link_set_trust()
*
* @return 0 if trust is present and vf_trust is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF trust setting is not set
*/
int rtnl_link_vf_get_trust(struct rtnl_link_vf *vf_data, uint32_t *vf_trust)
{
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_TRUST)
*vf_trust = vf_data->vf_trust;
else
return -NLE_NOATTR;
return 0;
}
/**
* Set user trust setting on SRIOV Virtual Function Object
* @param vf_data
* @param vf_trust
*
* @see rtnl_link_vf_get_trust()
*/
void rtnl_link_vf_set_trust(struct rtnl_link_vf *vf_data, uint32_t vf_trust) {
vf_data->vf_trust = vf_trust;
vf_data->ce_mask |= SRIOV_ATTR_TRUST;
return;
}
/**
* Get an array of VLANS on SRIOV Virtual Function
* @arg vf_data SRIOV VF object
* @arg vf_vlans Pointer to nl_vf_vlans_t struct to store vlan info.
*
* @see rtnl_link_get_num_vf()
*
* The SRIOV VF VLANs object must be returned to the SRIOV VF object with
* rtnl_link_vf_vlans_put() when operations are done to prevent memory leaks.
*
* @copydoc pointer_lifetime_warning
* @return 0 if VLAN info is present and vf_vlans is set
* @return -NLE_OBJ_NOTFOUND if information for VF info is not found
* @return -NLE_NOATTR if the VF vlans is not set
*/
int rtnl_link_vf_get_vlans(struct rtnl_link_vf *vf_data,
nl_vf_vlans_t **vf_vlans) {
nl_vf_vlans_t *vf;
if (!vf_data)
return -NLE_OBJ_NOTFOUND;
if (vf_data->ce_mask & SRIOV_ATTR_VLAN) {
vf = vf_data->vf_vlans;
vf->ce_refcnt++;
*vf_vlans = vf;
} else
return -NLE_NOATTR;
return 0;
}
/**
* Add a SRIOV VF VLANs object to the SRIOV Virtual Function Object
* @param vf_data SRIOV VF object
* @param vf_vlans SRIOV VF VLANs object
*
* @see rtnl_link_vf_get_vlans()
* @see rtnl_link_vf_vlan_alloc()
*
* This function assigns ownership of the SRIOV VF object \p vf_vlans
* to the SRIOV Virtual Function object \p vf_data. Do not use
* rtnl_link_vf_vlan_put() on \p vf_vlans after this.
*/
void rtnl_link_vf_set_vlans(struct rtnl_link_vf *vf_data,
nl_vf_vlans_t *vf_vlans) {
if (!vf_data||!vf_vlans)
return;
vf_data->vf_vlans = vf_vlans;
vf_data->vf_vlans->ce_refcnt++;
vf_data->ce_mask |= SRIOV_ATTR_VLAN;
return;
}
/**
* Allocate a SRIOV VF VLAN object
* @param vf_vlans Pointer to store VLAN object at
* @param vlan_count Number of VLANs that will be stored in VLAN object
*
* The SRIOV VF VLANs object must be returned to the sRIOV VF object with
* rtnl_link_vf_vlan_put() when operations are done to prevent memory leaks.
*
* @return 0 if VLAN object is created and vf_vlans is set.
* @return -NLE_NOMEM if object could not be allocated.
* @return -NLE_INVAL if vlan_count is more than supported by SRIOV VF
*/
int rtnl_link_vf_vlan_alloc(nl_vf_vlans_t **vf_vlans, int vlan_count) {
nl_vf_vlans_t *vlans;
nl_vf_vlan_info_t *vlan_info;
if (vlan_count > MAX_VLAN_LIST_LEN)
return -NLE_INVAL;
vlans = calloc(1, sizeof(*vlans));
if (!vlans)
return -NLE_NOMEM;
vlan_info = calloc(vlan_count+1, sizeof(*vlan_info));
if (!vlan_info) {
free(vlans);
return -NLE_NOMEM;
}
NL_DBG(4, "Allocated new SRIOV VF VLANs object %p\n", vlans);
vlans->ce_refcnt = 1;
vlans->size = vlan_count;
vlans->vlans = vlan_info;
*vf_vlans = vlans;
return 0;
}
/**
* Free an allocated SRIOV VF VLANs object
* @param vf_vlans SRIOV VF VLANs object
*/
void rtnl_link_vf_vlan_free(nl_vf_vlans_t *vf_vlans) {
if (!vf_vlans)
return;
if (vf_vlans->ce_refcnt > 0)
NL_DBG(1, "Warning: Freeing SRIOV VF VLANs object in use...\n");
NL_DBG(4, "Freed SRIOV VF object %p\n", vf_vlans);
free(vf_vlans->vlans);
free(vf_vlans);
return;
}
/**
* Return SRIOV VF VLANs object to the owning SRIOV VF object.
* @param vf_vlans SRIOV VF VLANs object
*/
void rtnl_link_vf_vlan_put(nl_vf_vlans_t *vf_vlans) {
if (!vf_vlans)
return;
vf_vlans->ce_refcnt--;
NL_DBG(4, "Returned SRIOV VF VLANs object reference %p, %i remaining\n",
vf_vlans, vf_vlans->ce_refcnt);
if (vf_vlans->ce_refcnt < 0)
BUG();
if (vf_vlans->ce_refcnt <= 0)
rtnl_link_vf_vlan_free(vf_vlans);
return;
}
/** @} */
/**
* @name Utilities
* @{
*/
static const struct trans_tbl vf_link_states[] = {
__ADD(IFLA_VF_LINK_STATE_AUTO, autodetect),
__ADD(IFLA_VF_LINK_STATE_ENABLE, up),
__ADD(IFLA_VF_LINK_STATE_DISABLE, down),
};
char *rtnl_link_vf_linkstate2str(uint32_t ls, char *buf, size_t len)
{
return __type2str(ls, buf, len, vf_link_states,
ARRAY_SIZE(vf_link_states));
}
int rtnl_link_vf_str2linkstate(const char *name)
{
return __str2type(name, vf_link_states, ARRAY_SIZE(vf_link_states));
}
static const struct trans_tbl vf_vlan_proto[] = {
__ADD(ETH_P_8021Q, 8021Q),
__ADD(ETH_P_8021AD, 8021AD),
};
char *rtnl_link_vf_vlanproto2str(uint16_t proto, char *buf, size_t len)
{
return __type2str(proto, buf, len, vf_vlan_proto,
ARRAY_SIZE(vf_vlan_proto));
}
int rtnl_link_vf_str2vlanproto(const char *name)
{
return __str2type(name, vf_vlan_proto, ARRAY_SIZE(vf_vlan_proto));
}
/* Return a guid from a format checked string.
* Format string must be xx:xx:xx:xx:xx:xx:xx:xx where XX can be an
* arbitrary hex digit
*
* Function modified from original at iproute2/lib/utils.c:get_guid()
* Original by Eli Cohen <eli@mellanox.com>.
* iproute2 git commit d91fb3f4c7e4dba806541bdc90b1fb60a3581541
*/
int rtnl_link_vf_str2guid(uint64_t *guid, const char *guid_s) {
unsigned long int tmp;
char *endptr;
int i;
if (strlen(guid_s) != RTNL_VF_GUID_STR_LEN)
return -1;
for (i = 0; i < 7; i++) {
if (guid_s[2 + i * 3] != ':')
return -1;
}
*guid = 0;
for (i = 0; i < 8; i++) {
tmp = strtoul(guid_s + i * 3, &endptr, 16);
if (endptr != guid_s + i * 3 + 2)
return -1;
if (tmp > 255)
return -1;
*guid |= tmp << (56 - 8 * i);
}
return 0;
}
/** @} */
/** @} */