<term><varname>ID_NET_NAME_SLOT=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]<constant>u</constant><replaceable>port</replaceable>…[<constant>c</constant><replaceable>config</replaceable>][<constant>i</constant><replaceable>interface</replaceable>]</term>
<term><varname>ID_NET_NAME_SLOT=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]<constant>v</constant><replaceable>slot</replaceable></term>
<term><varname>ID_NET_NAME_SLOT=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]<constant>r</constant><replaceable>slot</replaceable></term>
+ <term><varname>ID_NET_NAME_SLOT=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]<constant>S</constant><replaceable>sfnum</replaceable></term>
<listitem><para>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
<entry>… <constant>r</constant><replaceable>slot</replaceable></entry>
<entry>SR-IOV slot number</entry>
</row>
+
+ <row>
+ <entry>… <constant>S</constant><replaceable>sfnum</replaceable></entry>
+ <entry>Auxiliary sub-function (SF) number</entry>
+ </row>
</tbody>
</tgroup>
</table>
is linked to the particular representor, with any leading zeros removed. The physical port
name and the bus number are ignored.</para>
+ <para>Auxiliary sub-function (SF) network devices, where the network device's parent is an
+ auxiliary device exposing a <constant>sfnum</constant> 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 <constant>S</constant> and the user-defined sub-function number from
+ <constant>sfnum</constant>. This is analogous to how SR-IOV virtual function devices are named
+ with a <constant>v</constant> suffix.</para>
+
+ <para>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 <constant>v</constant>
+ suffix preceding the <constant>S</constant> suffix
+ (e.g. <literal>enp193s0f0v0S88</literal>). The PF, the VF, and the SF therefore form a
+ stable, hierarchical sequence regardless of the VF's underlying PCI bus/device/function
+ numbering.</para>
+
<para>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.</para>
<term><varname>ID_NET_NAME_PATH=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>p</constant><replaceable>bus</replaceable><constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>phys_port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]</term>
<term><varname>ID_NET_NAME_PATH=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>p</constant><replaceable>bus</replaceable><constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>phys_port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]<constant>b</constant><replaceable>number</replaceable></term>
<term><varname>ID_NET_NAME_PATH=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>p</constant><replaceable>bus</replaceable><constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>phys_port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]<constant>u</constant><replaceable>port</replaceable>…[<constant>c</constant><replaceable>config</replaceable>][<constant>i</constant><replaceable>interface</replaceable>]</term>
+ <term><varname>ID_NET_NAME_PATH=</varname><replaceable>prefix</replaceable>[<constant>P</constant><replaceable>domain</replaceable>]<constant>p</constant><replaceable>bus</replaceable><constant>s</constant><replaceable>slot</replaceable>[<constant>f</constant><replaceable>function</replaceable>][<constant>n</constant><replaceable>phys_port_name</replaceable>|<constant>d</constant><replaceable>dev_port</replaceable>]<constant>S</constant><replaceable>sfnum</replaceable></term>
<listitem><para>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
<entry>USB port number chain</entry>
</row>
+ <row>
+ <entry>… <constant>S</constant><replaceable>sfnum</replaceable></entry>
+ <entry>Auxiliary sub-function (SF) number</entry>
+ </row>
+
</tbody>
</tgroup>
</table>
<xi:include href="version-info.xml" xpointer="v260"/>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><constant>v261</constant></term>
+
+ <listitem><para>Stable names are now generated for auxiliary sub-function (SF) network devices
+ (such as <literal>mlx5_core</literal> SFs). The name is built from the parent PCI Physical Function's
+ path with an <literal>S<replaceable>sfnum</replaceable></literal> suffix, where
+ <replaceable>sfnum</replaceable> is the user-defined SF number (the value passed to
+ <command>devlink port add … sfnum <replaceable>N</replaceable></command>, exposed by the kernel as
+ the <constant>sfnum</constant> sysfs attribute on the auxiliary device). This is analogous to the
+ <literal>v<replaceable>N</replaceable></literal> 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.</para>
+
+ <xi:include href="version-info.xml" xpointer="v261"/>
+ </listitem>
+ </varlistentry>
</variablelist>
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
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<sfnum>" 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;
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<sfnum>' 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<N>' 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;
}