From 2511e27e7673db2fa070395476aec93d54d7f148 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 14 Apr 2017 23:03:33 +0200 Subject: [PATCH 1/4] platform: detect SR-IOV support and allow changing the number of VFs (cherry picked from commit 0a7694cf81d27cd3e73295372065f46a4765f3a1) --- src/platform/nm-fake-platform.c | 24 +++++++++ src/platform/nm-linux-platform.c | 91 ++++++++++++++++++++++++++++++++ src/platform/nm-platform.c | 24 +++++++++ src/platform/nm-platform.h | 4 ++ 4 files changed, 143 insertions(+) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 42979ed209..38706f3796 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -573,6 +573,12 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) return !!device; } +static gboolean +link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) +{ + return TRUE; +} + static const char * link_get_udi (NMPlatform *platform, int ifindex) { @@ -632,6 +638,22 @@ link_supports_vlans (NMPlatform *platform, int ifindex) } } +static gboolean +link_supports_sriov (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + switch (device->link.type) { + case NM_LINK_TYPE_LOOPBACK: + return FALSE; + default: + return TRUE; + } +} + static gboolean link_enslave (NMPlatform *platform, int master, int slave) { @@ -1470,11 +1492,13 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_set_mtu = link_set_mtu; + platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs; platform_class->link_get_driver_info = link_get_driver_info; platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; + platform_class->link_supports_sriov = link_supports_sriov; platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 251bc17f92..93264809be 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4604,6 +4604,30 @@ link_supports_vlans (NMPlatform *platform, int ifindex) return nmp_utils_ethtool_supports_vlans (ifindex); } +static gboolean +link_supports_sriov (NMPlatform *platform, int ifindex) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + nm_auto_close int dirfd = -1; + char ifname[IFNAMSIZ]; + int total = -1; + + if (!nm_platform_netns_push (platform, &netns)) + return FALSE; + + dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname); + if (dirfd < 0) + return FALSE; + + total = nm_platform_sysctl_get_int32 (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_totalvfs"), + -1); + + return total > 0; +} + static NMPlatformError link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length) { @@ -4695,6 +4719,71 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static gboolean +link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + nm_auto_close int dirfd = -1; + int total, current; + char ifname[IFNAMSIZ]; + char buf[64]; + + _LOGD ("link: change %d: num VFs: %u", ifindex, num_vfs); + + if (!nm_platform_netns_push (platform, &netns)) + return FALSE; + + dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname); + if (!dirfd) + return FALSE; + + total = nm_platform_sysctl_get_int32 (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_totalvfs"), + -1); + if (total < 1) + return FALSE; + if (num_vfs > total) { + _LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs); + num_vfs = total; + } + + current = nm_platform_sysctl_get_int32 (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + -1); + if (current == num_vfs) + return TRUE; + + if (current != 0) { + /* We need to destroy all other VFs before changing the value */ + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + "0")) { + _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", 0, strerror (errno)); + return FALSE; + } + if (num_vfs == 0) + return TRUE; + } + + /* Finally, set the desired value */ + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + nm_sprintf_buf (buf, "%d", num_vfs))) { + _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno)); + return FALSE; + } + + return TRUE; +} + static char * link_get_physical_port_id (NMPlatform *platform, int ifindex) { @@ -6845,6 +6934,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_set_mtu = link_set_mtu; + platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; @@ -6853,6 +6943,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; + platform_class->link_supports_sriov = link_supports_sriov; platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 334b94d411..7ef22ad5ab 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1179,6 +1179,30 @@ nm_platform_link_supports_vlans (NMPlatform *self, int ifindex) return klass->link_supports_vlans (self, ifindex); } +gboolean +nm_platform_link_supports_sriov (NMPlatform *self, int ifindex) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex >= 0, FALSE); + + return klass->link_supports_sriov (self, ifindex); +} + +gboolean +nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + _LOGD ("link: setting %u VFs for %s (%d)", + num_vfs, + nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), + ifindex); + return klass->link_set_sriov_num_vfs (self, ifindex, num_vfs); +} + /** * nm_platform_link_set_up: * @self: platform instance diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 202cbe5c59..f1679fd113 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -575,6 +575,7 @@ typedef struct { size_t *length); NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); + gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs); char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); guint (*link_get_dev_id) (NMPlatform *, int ifindex); @@ -587,6 +588,7 @@ typedef struct { gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); + gboolean (*link_supports_sriov) (NMPlatform *, int ifindex); gboolean (*link_enslave) (NMPlatform *, int master, int slave); gboolean (*link_release) (NMPlatform *, int master, int slave); @@ -825,6 +827,7 @@ gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtils gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length); NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length); gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); +gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs); char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex); guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex); @@ -837,6 +840,7 @@ gboolean nm_platform_link_get_driver_info (NMPlatform *self, gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex); gboolean nm_platform_link_supports_vlans (NMPlatform *self, int ifindex); +gboolean nm_platform_link_supports_sriov (NMPlatform *self, int ifindex); gboolean nm_platform_link_enslave (NMPlatform *self, int master, int slave); gboolean nm_platform_link_release (NMPlatform *self, int master, int slave); From 2409de0bb1736b7a54c1ff100eb288ea1a4f8602 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 14 Apr 2017 23:16:11 +0200 Subject: [PATCH 2/4] all: detect SR-IOV device support (cherry picked from commit f13fd4524c8c5ed250530471a27be83f6f0914ae) --- clients/cli/devices.c | 6 ++++-- libnm-core/nm-dbus-interface.h | 3 ++- src/devices/nm-device.c | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/clients/cli/devices.c b/clients/cli/devices.c index e4c49c113f..387edef8ef 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -101,10 +101,11 @@ NmcOutputField nmc_fields_dev_show_cap[] = { {"CARRIER-DETECT", N_("CARRIER-DETECT")}, /* 1 */ {"SPEED", N_("SPEED")}, /* 2 */ {"IS-SOFTWARE", N_("IS-SOFTWARE")}, /* 3 */ + {"SRIOV", N_("SRIOV")}, /* 4 */ {NULL, NULL} }; -#define NMC_FIELDS_DEV_SHOW_CAP_ALL "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE" -#define NMC_FIELDS_DEV_SHOW_CAP_COMMON "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE" +#define NMC_FIELDS_DEV_SHOW_CAP_ALL "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE,SRIOV" +#define NMC_FIELDS_DEV_SHOW_CAP_COMMON "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE,SRIOV" /* Available fields for 'device show' - wired properties part */ NmcOutputField nmc_fields_dev_show_wired_prop[] = { @@ -1196,6 +1197,7 @@ show_device_info (NMDevice *device, NmCli *nmc) set_val_strc (arr, 1, (caps & NM_DEVICE_CAP_CARRIER_DETECT) ? _("yes") : _("no")); set_val_str (arr, 2, speed_str); set_val_strc (arr, 3, (caps & NM_DEVICE_CAP_IS_SOFTWARE) ? _("yes") : _("no")); + set_val_strc (arr, 4, (caps & NM_DEVICE_CAP_SRIOV) ? _("yes") : _("no")); g_ptr_array_add (nmc->output_data, arr); print_data (nmc); /* Print all data */ diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 16318b78bc..8abc91bbf8 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -239,6 +239,7 @@ typedef enum { * @NM_DEVICE_CAP_NM_SUPPORTED: NetworkManager supports this device * @NM_DEVICE_CAP_CARRIER_DETECT: this device can indicate carrier status * @NM_DEVICE_CAP_IS_SOFTWARE: this device is a software device + * @NM_DEVICE_CAP_SRIOV: this device supports single-root I/O virtualization * * General device capability flags. **/ @@ -247,9 +248,9 @@ typedef enum { /*< flags >*/ NM_DEVICE_CAP_NM_SUPPORTED = 0x00000001, NM_DEVICE_CAP_CARRIER_DETECT = 0x00000002, NM_DEVICE_CAP_IS_SOFTWARE = 0x00000004, + NM_DEVICE_CAP_SRIOV = 0x00000008, } NMDeviceCapabilities; - /** * NMDeviceWifiCapabilities: * @NM_WIFI_DEVICE_CAP_NONE: device has no encryption/authentication capabilities diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 9aeef9a87a..24c61b607d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2934,6 +2934,9 @@ realize_start_setup (NMDevice *self, if (nm_platform_check_support_user_ipv6ll (nm_device_get_platform (self))) priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ifindex); + + if (nm_platform_link_supports_sriov (nm_device_get_platform (self), priv->ifindex)) + capabilities |= NM_DEVICE_CAP_SRIOV; } if (klass->get_generic_capabilities) From 0c2576e4bf75a0e777ff65149884ba2566a15d07 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 14 Apr 2017 23:33:14 +0200 Subject: [PATCH 3/4] core: allow setting SR-IOV num_vfs (cherry picked from commit 32975b6aa5b48118ec65a3790e763a530a4ad913) --- man/NetworkManager.conf.xml | 10 ++++++++++ src/devices/nm-device.c | 23 +++++++++++++++++++++++ src/nm-config-data.h | 2 ++ src/nm-config.h | 1 + 4 files changed, 36 insertions(+) diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 1230347d83..658fd7c2d6 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -855,6 +855,16 @@ unmanaged=1 + + sriov-num-vfs + + + Specify the number of virtual functions (VF) to enable + for a PCI physical device that supports single-root I/O + virtualization (SR-IOV). + + + diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 24c61b607d..577de2eafb 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2814,6 +2814,27 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) } } +static void +device_init_sriov_num_vfs (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gs_free char *value = NULL; + int num_vfs; + + if ( priv->ifindex > 0 + && nm_device_has_capability (self, NM_DEVICE_CAP_SRIOV)) { + value = nm_config_data_get_device_config (NM_CONFIG_GET_DATA, + "sriov-num-vfs", + self, + NULL); + num_vfs = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, -1); + if (num_vfs >= 0) { + nm_platform_link_set_sriov_num_vfs (nm_device_get_platform (self), + priv->ifindex, num_vfs); + } + } +} + static void config_changed_update_ignore_carrier (NMConfig *config, NMConfigData *config_data, @@ -2978,6 +2999,8 @@ realize_start_setup (NMDevice *self, priv->carrier = TRUE; } + device_init_sriov_num_vfs (self); + nm_assert (!priv->stats.timeout_id); real_rate = _stats_refresh_rate_real (priv->stats.refresh_rate_ms); if (real_rate) diff --git a/src/nm-config-data.h b/src/nm-config-data.h index d7d14a61e9..98c667516c 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -171,6 +171,8 @@ const char *nm_config_data_get_rc_manager (const NMConfigData *self); gboolean nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device); gboolean nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *device); +int nm_config_data_get_sriov_num_vfs (const NMConfigData *self, NMDevice *device); + NMGlobalDnsConfig *nm_config_data_get_global_dns_config (const NMConfigData *self); char *nm_config_data_get_connection_default (const NMConfigData *self, diff --git a/src/nm-config.h b/src/nm-config.h index f66d44baba..bfb4383a63 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -75,6 +75,7 @@ #define NM_CONFIG_KEYFILE_KEY_AUDIT "audit" #define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier" +#define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs" #define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was." #define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set." From 5413d3bcc7c6feb515b94267b3712c8ff1b6045a Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 14 Apr 2017 17:46:20 +0200 Subject: [PATCH 4/4] device: re-apply sriov_numvfs after SIGHUP (cherry picked from commit 264624f91dce43859205faa20303ec2d9cddaa64) --- src/devices/nm-device.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 577de2eafb..d656d8d7fc 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -296,7 +296,7 @@ typedef struct _NMDevicePrivate { guint link_disconnected_id; guint carrier_defer_id; guint carrier_wait_id; - gulong ignore_carrier_id; + gulong config_changed_id; guint32 mtu; guint32 ip6_mtu; guint32 mtu_initial; @@ -2836,17 +2836,20 @@ device_init_sriov_num_vfs (NMDevice *self) } static void -config_changed_update_ignore_carrier (NMConfig *config, - NMConfigData *config_data, - NMConfigChangeFlags changes, - NMConfigData *old_data, - NMDevice *self) +config_changed (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); if ( priv->state <= NM_DEVICE_STATE_DISCONNECTED || priv->state > NM_DEVICE_STATE_ACTIVATED) priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self); + + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) + device_init_sriov_num_vfs (self); } static void @@ -2981,10 +2984,10 @@ realize_start_setup (NMDevice *self, /* Note: initial hardware address must be read before calling get_ignore_carrier() */ config = nm_config_get (); priv->ignore_carrier = nm_config_data_get_ignore_carrier (nm_config_get_data (config), self); - if (!priv->ignore_carrier_id) { - priv->ignore_carrier_id = g_signal_connect (config, + if (!priv->config_changed_id) { + priv->config_changed_id = g_signal_connect (config, NM_CONFIG_SIGNAL_CONFIG_CHANGED, - G_CALLBACK (config_changed_update_ignore_carrier), + G_CALLBACK (config_changed), self); } @@ -3202,7 +3205,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); _notify (self, PROP_CAPABILITIES); - nm_clear_g_signal_handler (nm_config_get (), &priv->ignore_carrier_id); + nm_clear_g_signal_handler (nm_config_get (), &priv->config_changed_id); priv->real = FALSE; _notify (self, PROP_REAL); @@ -13727,7 +13730,7 @@ dispose (GObject *object) arp_cleanup (self); - nm_clear_g_signal_handler (nm_config_get (), &priv->ignore_carrier_id); + nm_clear_g_signal_handler (nm_config_get (), &priv->config_changed_id); dispatcher_cleanup (self);