[PATCH v2 1/5] lib/route: SRIOV Parse and Read support
Jef Oliver
jef.oliver at intel.com
Mon Nov 7 13:33:54 PST 2016
* 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 at intel.com>
---
include/Makefile.am | 2 +
include/linux-private/linux/if_ether.h | 1 +
include/linux-private/linux/if_link.h | 17 +
include/netlink-private/route/link/sriov.h | 30 ++
include/netlink-private/types.h | 23 +
include/netlink/route/link.h | 4 +
include/netlink/route/link/sriov.h | 112 +++++
lib/Makefile.am | 2 +-
lib/route/link.c | 37 ++
lib/route/link/sriov.c | 753 +++++++++++++++++++++++++++++
libnl-route-3.sym | 21 +
11 files changed, 1001 insertions(+), 1 deletion(-)
create mode 100644 include/netlink-private/route/link/sriov.h
create mode 100644 include/netlink/route/link/sriov.h
create mode 100644 lib/route/link/sriov.c
diff --git a/include/Makefile.am b/include/Makefile.am
index fafb90a..9b0bc39 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -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
diff --git a/include/linux-private/linux/if_ether.h b/include/linux-private/linux/if_ether.h
index a6af32d..7d82bd7 100644
--- a/include/linux-private/linux/if_ether.h
+++ b/include/linux-private/linux/if_ether.h
@@ -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 */
diff --git a/include/linux-private/linux/if_link.h b/include/linux-private/linux/if_link.h
index 15bbeb8..b3560e3 100644
--- a/include/linux-private/linux/if_link.h
+++ b/include/linux-private/linux/if_link.h
@@ -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 */
diff --git a/include/netlink-private/route/link/sriov.h b/include/netlink-private/route/link/sriov.h
new file mode 100644
index 0000000..49e601b
--- /dev/null
+++ b/include/netlink-private/route/link/sriov.h
@@ -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 at 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
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
index 23b9aba..d8c0e3f 100644
--- a/include/netlink-private/types.h
+++ b/include/netlink-private/types.h
@@ -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
diff --git a/include/netlink/route/link.h b/include/netlink/route/link.h
index 23b0183..42eb17f 100644
--- a/include/netlink/route/link.h
+++ b/include/netlink/route/link.h
@@ -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));
diff --git a/include/netlink/route/link/sriov.h b/include/netlink/route/link/sriov.h
new file mode 100644
index 0000000..71d0dbe
--- /dev/null
+++ b/include/netlink/route/link/sriov.h
@@ -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 at 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
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 21d28ca..b14a991 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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 \
diff --git a/lib/route/link.c b/lib/route/link.c
index 90d7a55..ba871af 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -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;
+}
+
/** @} */
/**
diff --git a/lib/route/link/sriov.c b/lib/route/link/sriov.c
new file mode 100644
index 0000000..528de83
--- /dev/null
+++ b/lib/route/link/sriov.c
@@ -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 at 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;
+}
+
+
+/** @} */
+
+/** @} */
diff --git a/libnl-route-3.sym b/libnl-route-3.sym
index bfab145..ef44d09 100644
--- a/libnl-route-3.sym
+++ b/libnl-route-3.sym
@@ -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;
--
2.10.1
More information about the libnl
mailing list