summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2018-05-23 14:33:24 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2018-07-11 16:16:22 +0200
commit8720dd3df1d9970684fca07bc62f3341988a77bd (patch)
treea746bfd0bb2681cf43e3b67756a5d67819fe01bb
parent7df33338797fc335c245fed65ac1186284afc357 (diff)
downloadNetworkManager-8720dd3df1d9970684fca07bc62f3341988a77bd.tar.gz
platform: add support for changing VF attributes
-rw-r--r--src/platform/nm-linux-platform.c136
-rw-r--r--src/platform/nm-platform.c71
-rw-r--r--src/platform/nm-platform.h23
3 files changed, 230 insertions, 0 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 19821a87c3..641f7d68c0 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -215,6 +215,46 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
/*****************************************************************************/
+/* Redefine VF enums and structures that are not available on older kernels. */
+
+#define IFLA_VF_UNSPEC 0
+#define IFLA_VF_MAC 1
+#define IFLA_VF_VLAN 2
+#define IFLA_VF_TX_RATE 3
+#define IFLA_VF_SPOOFCHK 4
+#define IFLA_VF_LINK_STATE 5
+#define IFLA_VF_RATE 6
+#define IFLA_VF_RSS_QUERY_EN 7
+#define IFLA_VF_STATS 8
+#define IFLA_VF_TRUST 9
+#define IFLA_VF_IB_NODE_GUID 10
+#define IFLA_VF_IB_PORT_GUID 11
+#define IFLA_VF_VLAN_LIST 12
+
+#define IFLA_VF_VLAN_INFO_UNSPEC 0
+#define IFLA_VF_VLAN_INFO 1
+
+/* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */
+struct _ifla_vf_setting {
+ guint32 vf;
+ guint32 setting;
+};
+
+struct _ifla_vf_rate {
+ guint32 vf;
+ guint32 min_tx_rate;
+ guint32 max_tx_rate;
+};
+
+struct _ifla_vf_vlan_info {
+ guint32 vf;
+ guint32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+ guint32 qos;
+ guint16 vlan_proto; /* VLAN protocol, either 802.1Q or 802.1ad */
+};
+
+/*****************************************************************************/
+
#define _NMLOG_PREFIX_NAME "platform-linux"
#define _NMLOG_DOMAIN LOGD_PLATFORM
#define _NMLOG2_DOMAIN LOGD_PLATFORM
@@ -5617,6 +5657,101 @@ link_set_sriov_params (NMPlatform *platform,
return TRUE;
}
+static gboolean
+link_set_sriov_vfs (NMPlatform *platform, int ifindex, const NMPlatformVF *const *vfs)
+{
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct nlattr *list, *info, *vlan_list;
+ guint i;
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ 0,
+ ifindex,
+ NULL,
+ 0,
+ 0);
+ if (!nlmsg)
+ g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED);
+
+ if (!(list = nla_nest_start (nlmsg, IFLA_VFINFO_LIST)))
+ goto nla_put_failure;
+
+ for (i = 0; vfs[i]; i++) {
+ const NMPlatformVF *vf = vfs[i];
+
+ if (!(info = nla_nest_start (nlmsg, IFLA_VF_INFO)))
+ goto nla_put_failure;
+
+ if (vf->spoofchk >= 0) {
+ struct _ifla_vf_setting ivs = { 0 };
+
+ ivs.vf = vf->index;
+ ivs.setting = vf->spoofchk;
+ NLA_PUT (nlmsg, IFLA_VF_SPOOFCHK, sizeof (ivs), &ivs);
+ }
+
+ if (vf->trust >= 0) {
+ struct _ifla_vf_setting ivs = { 0 };
+
+ ivs.vf = vf->index;
+ ivs.setting = vf->trust;
+ NLA_PUT (nlmsg, IFLA_VF_TRUST, sizeof (ivs), &ivs);
+ }
+
+ if (vf->mac.len) {
+ struct ifla_vf_mac ivm = { 0 };
+
+ ivm.vf = vf->index;
+ memcpy (ivm.mac, vf->mac.data, vf->mac.len);
+ NLA_PUT (nlmsg, IFLA_VF_MAC, sizeof (ivm), &ivm);
+ }
+
+ if (vf->min_tx_rate || vf->max_tx_rate) {
+ struct _ifla_vf_rate ivr = { 0 };
+
+ ivr.vf = vf->index;
+ ivr.min_tx_rate = vf->min_tx_rate;
+ ivr.max_tx_rate = vf->max_tx_rate;
+ NLA_PUT (nlmsg, IFLA_VF_RATE, sizeof (ivr), &ivr);
+ }
+
+ /* Kernel only supports one VLAN per VF now. If this
+ * changes in the future, we need to figure out how to
+ * clear existing VLANs and set new ones in one message
+ * with the new API.*/
+ if (vf->num_vlans > 1) {
+ _LOGW ("multiple VLANs per VF are not supported at the moment");
+ return FALSE;
+ } else {
+ struct _ifla_vf_vlan_info ivvi = { 0 };
+
+ if (!(vlan_list = nla_nest_start (nlmsg, IFLA_VF_VLAN_LIST)))
+ goto nla_put_failure;
+
+ ivvi.vf = vf->index;
+ if (vf->num_vlans == 1) {
+ ivvi.vlan = vf->vlans[0].id;
+ ivvi.qos = vf->vlans[0].qos;
+ ivvi.vlan_proto = htons (vf->vlans[0].proto_ad ? ETH_P_8021AD : ETH_P_8021Q);
+ } else {
+ /* Clear existing VLAN */
+ ivvi.vlan = 0;
+ ivvi.qos = 0;
+ ivvi.vlan_proto = htons (ETH_P_8021Q);
+ }
+
+ NLA_PUT (nlmsg, IFLA_VF_VLAN_INFO, sizeof (ivvi), &ivvi);
+ nla_nest_end (nlmsg, vlan_list);
+ }
+ nla_nest_end (nlmsg, info);
+ }
+ nla_nest_end (nlmsg, list);
+
+ return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
+}
+
static char *
link_get_physical_port_id (NMPlatform *platform, int ifindex)
{
@@ -7761,6 +7896,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_set_mtu = link_set_mtu;
platform_class->link_set_name = link_set_name;
platform_class->link_set_sriov_params = link_set_sriov_params;
+ platform_class->link_set_sriov_vfs = link_set_sriov_vfs;
platform_class->link_get_physical_port_id = link_get_physical_port_id;
platform_class->link_get_dev_id = link_get_dev_id;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 1146a07309..174d863637 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1490,6 +1490,27 @@ nm_platform_link_set_sriov_params (NMPlatform *self,
return klass->link_set_sriov_params (self, ifindex, num_vfs, autoprobe);
}
+gboolean
+nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs)
+{
+ guint i;
+ _CHECK_SELF (self, klass, FALSE);
+
+ g_return_val_if_fail (ifindex > 0, FALSE);
+
+ _LOGD ("link: setting VFs for \"%s\" (%d):",
+ nm_platform_link_get_name (self, ifindex),
+ ifindex);
+
+ for (i = 0; vfs[i]; i++) {
+ const NMPlatformVF *vf = vfs[i];
+
+ _LOGD ("link: VF %s", nm_platform_vf_to_string (vf, NULL, 0));
+ }
+
+ return klass->link_set_sriov_vfs (self, ifindex, vfs);
+}
+
/**
* nm_platform_link_set_up:
* @self: platform instance
@@ -6055,6 +6076,56 @@ nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b)
return 0;
}
+const char *
+nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len)
+{
+ char str_mac[128], mac[128];
+ char str_spoof_check[64];
+ char str_trust[64];
+ char str_min_tx_rate[64];
+ char str_max_tx_rate[64];
+ nm_auto_free_gstring GString *gstr_vlans = NULL;
+ guint i;
+
+ if (!nm_utils_to_string_buffer_init_null (vf, &buf, &len))
+ return buf;
+
+ if (vf->mac.len) {
+ nm_utils_hwaddr_ntoa_buf (vf->mac.data, vf->mac.len, TRUE, mac, sizeof (mac));
+ nm_sprintf_buf (str_mac, " mac %s", mac);
+ } else
+ str_mac[0] = '\0';
+
+ if (vf->num_vlans) {
+ gstr_vlans = g_string_new ("");
+ for (i = 0; i < vf->num_vlans; i++) {
+ g_string_append_printf (gstr_vlans, " vlan %u", (unsigned) vf->vlans[i].id);
+ if (vf->vlans[i].qos)
+ g_string_append_printf (gstr_vlans, " qos %u", (unsigned) vf->vlans[i].qos);
+ if (vf->vlans[i].proto_ad)
+ g_string_append (gstr_vlans, " proto 802.1ad");
+ }
+ }
+
+ g_snprintf (buf, len,
+ "%u" /* index */
+ "%s" /* MAC */
+ "%s" /* spoof check */
+ "%s" /* trust */
+ "%s" /* min tx rate */
+ "%s" /* max tx rate */
+ "%s", /* VLANs */
+ vf->index,
+ str_mac,
+ vf->spoofchk >= 0 ? nm_sprintf_buf (str_spoof_check, " spoofchk %d", vf->spoofchk) : "",
+ vf->trust >= 0 ? nm_sprintf_buf (str_trust, " trust %d", vf->trust) : "",
+ vf->min_tx_rate ? nm_sprintf_buf (str_min_tx_rate, " min_tx_rate %u", (unsigned) vf->min_tx_rate) : "",
+ vf->max_tx_rate ? nm_sprintf_buf (str_max_tx_rate, " max_tx_rate %u", (unsigned) vf->max_tx_rate) : "",
+ gstr_vlans ? gstr_vlans->str : "");
+
+ return buf;
+}
+
void
nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h)
{
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 01e13f2178..7e49e064a9 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -608,6 +608,26 @@ extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
typedef struct {
+ guint16 id;
+ guint32 qos;
+ bool proto_ad:1;
+} NMPlatformVFVlan;
+
+typedef struct {
+ guint32 index;
+ guint32 min_tx_rate;
+ guint32 max_tx_rate;
+ guint num_vlans;
+ NMPlatformVFVlan *vlans;
+ struct {
+ guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */
+ guint8 len;
+ } mac;
+ gint8 spoofchk;
+ gint8 trust;
+} NMPlatformVF;
+
+typedef struct {
in_addr_t local;
in_addr_t remote;
int parent_ifindex;
@@ -803,6 +823,7 @@ typedef struct {
NMPlatformError (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name);
gboolean (*link_set_sriov_params) (NMPlatform *, int ifindex, guint num_vfs, int autoprobe);
+ gboolean (*link_set_sriov_vfs) (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
char * (*link_get_physical_port_id) (NMPlatform *, int ifindex);
guint (*link_get_dev_id) (NMPlatform *, int ifindex);
@@ -1194,6 +1215,7 @@ NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, con
NMPlatformError nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name);
gboolean nm_platform_link_set_sriov_params (NMPlatform *self, int ifindex, guint num_vfs, int autoprobe);
+gboolean nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex);
guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex);
@@ -1434,6 +1456,7 @@ const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, ch
const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len);
const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len);
const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len);
+const char *nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len);
const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
const NMVlanQosMapping *map,