diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml index 1a024a0c30..9887aa8701 100644 --- a/man/systemd.net-naming-scheme.xml +++ b/man/systemd.net-naming-scheme.xml @@ -170,6 +170,7 @@ ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]uport…[cconfig][iinterface] ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]vslot ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]rslot + ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]Ssfnum This property describes the slot position. Different schemes are used depending on the bus type, as described in the table below. In case of USB, BCMA, and SR-VIO devices, the full @@ -222,6 +223,11 @@ … rslot SR-IOV slot number + + + … Ssfnum + Auxiliary sub-function (SF) number + @@ -247,6 +253,20 @@ is linked to the particular representor, with any leading zeros removed. The physical port name and the bus number are ignored. + Auxiliary sub-function (SF) network devices, where the network device's parent is an + auxiliary device exposing a sfnum sysfs attribute (currently mlx5_core SFs), + are named based on the underlying PCI function (the PF, or for VF-SF the PF behind the VF), + with a suffix of S and the user-defined sub-function number from + sfnum. This is analogous to how SR-IOV virtual function devices are named + with a v suffix. + + If the SF's parent PCI function is itself an SR-IOV virtual function (VF-SF), the + name is rooted at the PF and both suffixes are chained, with the v + suffix preceding the S suffix + (e.g. enp193s0f0v0S88). The PF, the VF, and the SF therefore form a + stable, hierarchical sequence regardless of the VF's underlying PCI bus/device/function + numbering. + In some configurations a parent PCI bridge of a given network controller may be associated with a slot. In such case we do not generate this device property to avoid possible naming conflicts. @@ -262,6 +282,7 @@ ID_NET_NAME_PATH=prefix[Pdomain]pbussslot[ffunction][nphys_port_name|ddev_port] ID_NET_NAME_PATH=prefix[Pdomain]pbussslot[ffunction][nphys_port_name|ddev_port]bnumber ID_NET_NAME_PATH=prefix[Pdomain]pbussslot[ffunction][nphys_port_name|ddev_port]uport…[cconfig][iinterface] + ID_NET_NAME_PATH=prefix[Pdomain]pbussslot[ffunction][nphys_port_name|ddev_port]Ssfnum This property describes the device installation location. Different schemes are used depending on the bus type, as described in the table below. For BCMA and USB devices, PCI path @@ -310,6 +331,11 @@ USB port number chain + + … Ssfnum + Auxiliary sub-function (SF) number + + @@ -575,6 +601,22 @@ + + + v261 + + Stable names are now generated for auxiliary sub-function (SF) network devices + (such as mlx5_core SFs). The name is built from the parent PCI Physical Function's + path with an Ssfnum suffix, where + sfnum is the user-defined SF number (the value passed to + devlink port add … sfnum N, exposed by the kernel as + the sfnum sysfs attribute on the auxiliary device). This is analogous to the + vN suffix used for SR-IOV virtual functions; for SFs + hosted on SR-IOV VFs (VF-SF), the two suffixes are chained on top of the PF's base name. + + + + Note that latest may be used to denote the latest scheme known (to this diff --git a/src/shared/netif-naming-scheme.c b/src/shared/netif-naming-scheme.c index ddf3bdde9e..978399ca41 100644 --- a/src/shared/netif-naming-scheme.c +++ b/src/shared/netif-naming-scheme.c @@ -31,6 +31,7 @@ static const NamingScheme naming_schemes[] = { { "v258", NAMING_V258 }, { "v259", NAMING_V259 }, { "v260", NAMING_V260 }, + { "v261", NAMING_V261 }, /* … add more schemes here, as the logic to name devices is updated … */ EXTRA_NET_NAMING_MAP diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h index 52c462a6bb..1848cb570b 100644 --- a/src/shared/netif-naming-scheme.h +++ b/src/shared/netif-naming-scheme.h @@ -44,6 +44,9 @@ typedef enum NamingSchemeFlags { NAMING_USE_INTERFACE_PROPERTY = 1 << 20, /* Use INTERFACE udev property, rather than sysname, when no renaming is requested. */ NAMING_DEVICETREE_ALIASES_WLAN = 1 << 21, /* Generate names from devicetree aliases for WLAN devices */ NAMING_MCTP = 1 << 22, /* Use "mc" prefix for MCTP devices */ + NAMING_SUBFUNC = 1 << 23, /* Generate names for auxiliary sub-function (SF) network + * devices (e.g. mlx5_core SFs), based on the parent PF's + * PCI path and the user-defined sfnum, with an "S" suffix. */ /* And now the masks that combine the features above */ NAMING_V238 = 0, @@ -67,6 +70,7 @@ typedef enum NamingSchemeFlags { NAMING_V258 = NAMING_V257 | NAMING_USE_INTERFACE_PROPERTY, NAMING_V259 = NAMING_V258 | NAMING_DEVICETREE_ALIASES_WLAN, NAMING_V260 = NAMING_V259 | NAMING_MCTP, + NAMING_V261 = NAMING_V260 | NAMING_SUBFUNC, EXTRA_NET_NAMING_SCHEMES diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 2491484cf6..d368fb2337 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -165,6 +165,46 @@ static int get_virtfn_info(sd_device *pcidev, sd_device **ret_physfn_pcidev, cha return -ENOENT; } +static int get_subfunc_info(sd_device *aux_dev, sd_device **ret_parent_pcidev, char **ret_suffix) { + sd_device *parent; + unsigned sfnum; + char *suffix; + int r; + + assert(aux_dev); + assert(ret_parent_pcidev); + assert(ret_suffix); + + /* The auxiliary device must expose an 'sfnum' attribute. This is currently used by the + * mlx5_core driver for sub-function (SF) auxiliary devices. The sfnum is the user-defined + * stable identifier passed to "devlink port add ... sfnum N". */ + r = device_get_sysattr_unsigned_filtered(aux_dev, "sfnum", &sfnum); + if (r < 0) + return r; + + /* Walk one hop up: the auxiliary device's parent must be a PCI function. It can be either + * the PF directly, or an SR-IOV VF — mlx5 also supports SFs hosted on VFs (VF-SF), see + * Documentation/networking/representors.rst in the kernel tree. The VF case is handled by + * the existing virtfn logic in names_pci(), so here we just return the immediate PCI + * parent and a single "S" suffix piece. */ + r = sd_device_get_parent(aux_dev, &parent); + if (r < 0) + return r; + + r = device_in_subsystem(parent, "pci"); + if (r < 0) + return r; + if (r == 0) + return -ENODEV; + + if (asprintf(&suffix, "S%u", sfnum) < 0) + return log_oom_debug(); + + *ret_parent_pcidev = sd_device_ref(parent); + *ret_suffix = suffix; + return 0; +} + static int get_port_specifier(sd_device *dev, char **ret) { const char *phys_port_name; unsigned dev_port; @@ -928,24 +968,56 @@ static int names_devicetree(UdevEvent *event, const char *prefix) { static int names_pci(UdevEvent *event, const char *prefix) { sd_device *parent, *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); - _cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL; - _cleanup_free_ char *virtfn_suffix = NULL; + _cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL, *parent_pcidev = NULL; + _cleanup_free_ char *virtfn_suffix = NULL, *subfunc_suffix = NULL, *combined_suffix = NULL; + const char *suffix = NULL; assert(prefix); - /* check if our direct parent is a PCI device with no other bus in-between */ - if (get_matching_parent(dev, STRV_MAKE("pci"), /* skip_virtio= */ true, &parent) < 0) + /* If the network device's direct parent is an auxiliary device that exposes a stable + * 'sfnum' attribute (currently mlx5_core sub-functions), peel off the SF identity into + * a 'S' suffix piece and pick up the aux device's underlying PCI function as + * 'parent'. The aux device is just a bump on the path; everything below — PF/VF + * resolution, slot/onboard lookup — proceeds the same way as for any PCI-rooted + * network device. */ + if (naming_scheme_has(NAMING_SUBFUNC)) { + sd_device *aux; + + if (get_matching_parent(dev, STRV_MAKE("auxiliary"), + /* skip_virtio= */ false, &aux) >= 0) + (void) get_subfunc_info(aux, &parent_pcidev, &subfunc_suffix); + } + + /* SF: parent is the aux device's PCI function. Otherwise the network device's direct + * parent must itself be a PCI device. */ + if (subfunc_suffix) + parent = parent_pcidev; + else if (get_matching_parent(dev, STRV_MAKE("pci"), /* skip_virtio= */ true, &parent) < 0) return 0; - /* If this is an SR-IOV virtual device, get base name using physical device and add virtfn suffix. */ + /* If parent is an SR-IOV VF, walk to the parent PF and add a 'v' suffix piece. The + * onboard BIOS label is intentionally not exposed for any "child function" (VF, SF, or + * VF-SF), since the label refers to the parent's physical port, not to a logical child. */ + bool is_child_function = !!subfunc_suffix; if (naming_scheme_has(NAMING_SR_IOV_V) && - get_virtfn_info(parent, &physfn_pcidev, &virtfn_suffix) >= 0) + get_virtfn_info(parent, &physfn_pcidev, &virtfn_suffix) >= 0) { parent = physfn_pcidev; - else + is_child_function = true; + } + if (!is_child_function) (void) names_pci_onboard_label(event, parent, prefix); - (void) names_pci_onboard(event, parent, prefix, virtfn_suffix); - (void) names_pci_slot(event, parent, prefix, virtfn_suffix); + /* Compose the final suffix in PF -> [VF ->] SF order, e.g. "v0", "S88", or "v0S88". */ + if (virtfn_suffix && subfunc_suffix) { + combined_suffix = strjoin(virtfn_suffix, subfunc_suffix); + if (!combined_suffix) + return log_oom_debug(); + suffix = combined_suffix; + } else + suffix = virtfn_suffix ?: subfunc_suffix; + + (void) names_pci_onboard(event, parent, prefix, suffix); + (void) names_pci_slot(event, parent, prefix, suffix); return 0; }