lib/route: SRIOV Parse and Read support

* This patch adds support for parsing SRIOV VF specific
  information on a link.
  * Adds LINK_ATTR_VF_LIST to add to link->ce_mask.
  * Extends the rtnl_link object to include 'l_vf_list', a member
    to carry information for SRIOV VFs.
  * Adds rtnl_link_sriov, a private structure to fill link->l_vf_list.

* This patch adds support for reading parsed SRIOV VF specific
  informatino on a link.

* This patch adds support for freeing stored SRIOV VF specific
  information on a link.

Signed-off-by: Jef Oliver <jef.oliver@intel.com>
Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Jef Oliver 2016-11-07 13:33:54 -08:00 committed by Thomas Haller
parent d9840f648c
commit 5d6e43ebef
11 changed files with 1001 additions and 1 deletions

View File

@ -64,6 +64,7 @@ nobase_libnlinclude_HEADERS = \
netlink/route/link/sit.h \
netlink/route/link/ipvlan.h \
netlink/route/link/vrf.h \
netlink/route/link/sriov.h \
netlink/route/qdisc/cbq.h \
netlink/route/qdisc/dsmark.h \
netlink/route/qdisc/fifo.h \
@ -171,4 +172,5 @@ noinst_HEADERS = \
netlink-private/cache-api.h \
netlink-private/object-api.h \
netlink-private/route/link/api.h \
netlink-private/route/link/sriov.h \
netlink-private/route/tc-api.h

View File

@ -78,6 +78,7 @@
*/
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
#define ETH_P_TIPC 0x88CA /* TIPC */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */

View File

@ -625,6 +625,7 @@ enum {
IFLA_VF_TRUST, /* Trust VF */
IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
__IFLA_VF_MAX,
};
@ -641,6 +642,22 @@ struct ifla_vf_vlan {
__u32 qos;
};
enum {
IFLA_VF_VLAN_INFO_UNSPEC,
IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */
__IFLA_VF_VLAN_INFO_MAX,
};
#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1)
#define MAX_VLAN_LIST_LEN 1
struct ifla_vf_vlan_info {
__u32 vf;
__u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
__u32 qos;
__be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */
};
struct ifla_vf_tx_rate {
__u32 vf;
__u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */

View File

@ -0,0 +1,30 @@
/*
* include/netlink-private/route/link/sriov.h 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>
*/
#ifndef NETLINK_PRIV_LINK_SRIOV_H_
#define NETLINK_PRIV_LINK_SRIOV_H_
#include <netlink/netlink.h>
#include <netlink/route/link/sriov.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void rtnl_link_sriov_free_data(struct rtnl_link *);
extern int rtnl_link_sriov_parse_vflist(struct rtnl_link *, struct nlattr **);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -22,6 +22,7 @@
#include <netlink/netfilter/ct.h>
#include <netlink-private/object-api.h>
#include <netlink-private/route/tc-api.h>
#include <netlink-private/route/link/sriov.h>
#include <linux/tc_act/tc_mirred.h>
#include <linux/tc_act/tc_skbedit.h>
@ -36,6 +37,7 @@ struct nl_cache_ops;
struct nl_sock;
struct nl_object;
struct nl_hash_table;
struct nl_vf_vlans;
struct nl_cb
{
@ -154,6 +156,26 @@ struct rtnl_link_map
uint8_t lm_port;
};
struct rtnl_link_vf
{
struct nl_list_head vf_list;
int ce_refcnt;
uint32_t ce_mask;
uint32_t vf_index;
uint64_t vf_guid_node;
uint64_t vf_guid_port;
uint32_t vf_linkstate;
struct nl_addr * vf_lladdr;
uint32_t vf_max_tx_rate;
uint32_t vf_min_tx_rate;
uint32_t vf_rate;
uint32_t vf_rss_query_en;
uint32_t vf_spoofchk;
uint64_t vf_stats[RTNL_LINK_VF_STATS_MAX+1];
uint32_t vf_trust;
struct nl_vf_vlans * vf_vlans;
};
#define IFQDISCSIZ 32
struct rtnl_link
@ -197,6 +219,7 @@ struct rtnl_link
struct nl_data * l_phys_port_id;
int l_ns_fd;
pid_t l_ns_pid;
struct rtnl_link_vf * l_vf_list;
};
struct rtnl_ncacheinfo

View File

@ -244,6 +244,10 @@ extern int rtnl_link_release(struct nl_sock *, struct rtnl_link *);
extern int rtnl_link_fill_info(struct nl_msg *, struct rtnl_link *);
extern int rtnl_link_info_parse(struct rtnl_link *, struct nlattr **);
extern int rtnl_link_has_vf_list(struct rtnl_link *);
extern void rtnl_link_set_vf_list(struct rtnl_link *);
extern void rtnl_link_unset_vf_list(struct rtnl_link *);
/* deprecated */
extern int rtnl_link_set_info_type(struct rtnl_link *, const char *) __attribute__((deprecated));

View File

@ -0,0 +1,112 @@
/*
* include/netlink/route/link/sriov.h 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>
*/
#ifndef NETLINK_LINK_SRIOV_H_
#define NETLINK_LINK_SRIOV_H_
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup sriov
*/
typedef enum {
RTNL_LINK_VF_RATE_API_UNSPEC, /*!< Unspecified API type */
RTNL_LINK_VF_RATE_API_OLD, /*!< Old Rate setting API */
RTNL_LINK_VF_RATE_API_NEW, /*!< New Rate setting API */
__RTNL_LINK_VF_RATE_API_MAX,
} rtnl_link_rate_api_t;
#define RTNL_LINK_VF_RATE_API_MAX (__RTNL_LINK_VF_RATE_API_MAX - 1)
/**
* @ingroup sriov
*/
typedef enum {
RTNL_LINK_VF_STATS_RX_PACKETS, /*!< Packets Received */
RTNL_LINK_VF_STATS_TX_PACKETS, /*!< Packets Sent */
RTNL_LINK_VF_STATS_RX_BYTES, /*!< Bytes Recieved */
RTNL_LINK_VF_STATS_TX_BYTES, /*!< Bytes Sent */
RTNL_LINK_VF_STATS_BROADCAST, /*!< Broadcast packets received */
RTNL_LINK_VF_STATS_MULTICAST, /*!< Multicast packets received */
__RTNL_LINK_VF_STATS_MAX,
} rtnl_link_vf_stats_t;
#define RTNL_LINK_VF_STATS_MAX (__RTNL_LINK_VF_STATS_MAX - 1)
/**
* @struct rtnl_link_vf sriov.h "netlink/route/link/sriov.h"
* @brief SRIOV VF object
* @ingroup sriov
*
* @copydoc private_struct
*/
struct rtnl_link_vf;
/**
* @brief SRIOV VF VFLAN settings
* @ingroup sriov
*/
typedef struct nl_vf_vlan_info {
uint32_t vf_vlan; /*!< VLAN number */
uint32_t vf_vlan_qos; /*!< VLAN QOS value */
uint16_t vf_vlan_proto; /*!< VLAN protocol */
} nl_vf_vlan_info_t;
/**
* @brief SRIOV VF VLANs information
* @ingroup sriov
*/
typedef struct nl_vf_vlans {
int ce_refcnt; /*!< Reference counter. Don't change this value */
int size; /*!< Number of VLANs on the SRIOV VF */
nl_vf_vlan_info_t * vlans; /*!< nl_vf_vlan_info_t array of SRIOV VF VLANs */
} nl_vf_vlans_t;
/**
* @brief VF Rate information structure
* @ingroup sriov
*/
struct nl_vf_rate {
int api; /*!< rtnl_link_rate_api_t API Version to use */
uint32_t rate; /*!< Old API Max Rate in Mbps */
uint32_t max_tx_rate; /*!< New API Max Rate in Mbps */
uint32_t min_tx_rate; /*!< New API Mix Rate in Mbps */
};
extern struct rtnl_link_vf *rtnl_link_vf_alloc(void);
extern void rtnl_link_vf_free(struct rtnl_link_vf *);
extern struct rtnl_link_vf *rtnl_link_vf_get(struct rtnl_link *, uint32_t);
extern void rtnl_link_vf_put(struct rtnl_link_vf *);
extern int rtnl_link_vf_get_addr(struct rtnl_link_vf *, struct nl_addr **);
extern int rtnl_link_vf_get_index(struct rtnl_link_vf *, uint32_t *);
extern int rtnl_link_vf_get_linkstate(struct rtnl_link_vf *, uint32_t *);
extern int rtnl_link_vf_get_rate(struct rtnl_link_vf *, struct nl_vf_rate *);
extern int rtnl_link_vf_get_rss_query_en(struct rtnl_link_vf *, uint32_t *);
extern int rtnl_link_vf_get_spoofchk(struct rtnl_link_vf *, uint32_t *);
extern int rtnl_link_vf_get_stat(struct rtnl_link_vf *, rtnl_link_vf_stats_t,
uint64_t *);
extern int rtnl_link_vf_get_trust(struct rtnl_link_vf *, uint32_t *);
extern int rtnl_link_vf_get_vlans(struct rtnl_link_vf *, nl_vf_vlans_t **);
extern int rtnl_link_vf_vlan_alloc(nl_vf_vlans_t **, int);
extern void rtnl_link_vf_vlan_put(nl_vf_vlans_t *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -92,7 +92,7 @@ libnl_route_3_la_SOURCES = \
route/addr.c route/class.c route/cls.c route/act.c route/link.c \
route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \
route/route.c route/route_obj.c route/route_utils.c route/rtnl.c \
route/rule.c route/tc.c route/classid.c \
route/rule.c route/tc.c route/classid.c route/link/sriov.c \
\
route/cls/fw.c route/cls/police.c route/cls/u32.c route/cls/basic.c \
route/cls/cgroup.c \

View File

@ -28,6 +28,7 @@
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <netlink-private/route/link/api.h>
#include <netlink-private/route/link/sriov.h>
/** @cond SKIP */
#define LINK_ATTR_MTU (1 << 0)
@ -63,6 +64,7 @@
#define LINK_ATTR_NS_PID (1 << 30)
/* 31 used by 32-bit api */
#define LINK_ATTR_LINK_NETNSID ((uint64_t) 1 << 32)
#define LINK_ATTR_VF_LIST ((uint64_t) 1 << 33)
static struct nl_cache_ops rtnl_link_ops;
static struct nl_object_ops link_obj_ops;
@ -272,6 +274,9 @@ static void link_free_data(struct nl_object *c)
do_foreach_af(link, af_free, NULL);
nl_data_free(link->l_phys_port_id);
if (link->ce_mask & LINK_ATTR_VF_LIST)
rtnl_link_sriov_free_data(link);
}
}
@ -331,6 +336,7 @@ struct nla_policy rtln_link_policy[IFLA_MAX+1] = {
[IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
[IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ },
[IFLA_NUM_VF] = { .type = NLA_U32 },
[IFLA_VFINFO_LIST] = { .type = NLA_NESTED },
[IFLA_AF_SPEC] = { .type = NLA_NESTED },
[IFLA_PROMISCUITY] = { .type = NLA_U32 },
[IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
@ -584,6 +590,12 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (tb[IFLA_NUM_VF]) {
link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
link->ce_mask |= LINK_ATTR_NUM_VF;
if (link->l_num_vf && tb[IFLA_VFINFO_LIST]) {
if ((err = rtnl_link_sriov_parse_vflist(link, tb)) < 0) {
goto errout;
}
link->ce_mask |= LINK_ATTR_VF_LIST;
}
}
if (tb[IFLA_LINKINFO]) {
@ -2882,6 +2894,31 @@ int rtnl_link_str2carrier(const char *name)
return __str2type(name, carrier_states, ARRAY_SIZE(carrier_states));
}
int rtnl_link_has_vf_list(struct rtnl_link *link) {
if (link->ce_mask & LINK_ATTR_VF_LIST)
return 1;
else
return 0;
}
void rtnl_link_set_vf_list(struct rtnl_link *link) {
int err;
if (!(err = rtnl_link_has_vf_list(link)))
link->ce_mask |= LINK_ATTR_VF_LIST;
return;
}
void rtnl_link_unset_vf_list(struct rtnl_link *link) {
int err;
if ((err = rtnl_link_has_vf_list(link)))
link->ce_mask &= ~LINK_ATTR_VF_LIST;
return;
}
/** @} */
/**

753
lib/route/link/sriov.c Normal file
View File

@ -0,0 +1,753 @@
/*
* 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 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)
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 */
/* 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;
}
/* 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)
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) {
vf_vlan_info[len] = nla_data(nla_list);
list_len++;
}
err = rtnl_link_vf_vlan_info(list_len, vf_vlan_info,
&vf_vlans);
if (err < 0)
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)
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)
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
* @{
*/
/**
* 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()
*
* @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;
}
/**
* 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;
}
/**
* 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()
*
* @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;
}
/**
* 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()
*
* 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.
*
* @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;
}
/**
* 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()
*
* @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;
}
/**
* 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()
*
* @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;
}
/**
* 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()
*
* @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;
}
/**
* 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;
}
/**
* 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 (!vf_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;
}
/** @} */
/** @} */

View File

@ -984,5 +984,26 @@ global:
rtnl_link_vxlan_set_udp_csum;
rtnl_link_vxlan_set_udp_zero_csum6_rx;
rtnl_link_vxlan_set_udp_zero_csum6_tx;
rtnl_link_has_vf_list;
rtnl_link_set_vf_list;
rtnl_link_unset_vf_list;
rtnl_link_sriov_free_data;
rtnl_link_sriov_parse_vflist;
rtnl_link_vf_alloc;
rtnl_link_vf_free;
rtnl_link_vf_get;
rtnl_link_vf_put;
rtnl_link_vf_get_addr;
rtnl_link_vf_get_index;
rtnl_link_vf_get_linkstate;
rtnl_link_vf_get_rate;
rtnl_link_vf_get_rss_query_en;
rtnl_link_vf_get_spoofchk;
rtnl_link_vf_get_stat;
rtnl_link_vf_get_trust;
rtnl_link_vf_get_vlans;
rtnl_link_vf_vlan_alloc;
rtnl_link_vf_vlan_free;
rtnl_link_vf_vlan_put;
} libnl_3_2_28;