diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index a2c82fb916..2be0295bf1 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -159,6 +159,7 @@
ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]bnumber
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
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
@@ -206,6 +207,11 @@
… vslot
SR-VIO slot number
+
+
+ … rslot
+ SR-IOV slot number
+
@@ -226,6 +232,11 @@
v and the virtual device number, with any leading zeros removed. The bus
number is ignored.
+ SR-IOV virtual device representors are named based on the name of the physical device
+ interface, with a suffix of r and the number of the virtual device that
+ is linked to the particular representor, with any leading zeros removed. The physical port
+ name and the bus number are ignored.
+
In some configurations a parent PCI bridge of a given network controller may be associated
with a slot. In such case we don't generate this device property to avoid possible naming conflicts.
@@ -457,6 +468,17 @@
+
+ v254
+
+ Naming was changed for SR-IOV virtual device representors.
+
+ The rslot suffix was added to differentiate SR-IOV
+ virtual device representors attached to a single physical device interface.
+
+
+
+
Note that latest may be used to denote the latest scheme known (to this
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index bb893870e9..707c0d26f3 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -39,6 +39,7 @@ typedef enum NamingSchemeFlags {
NAMING_BRIDGE_MULTIFUNCTION_SLOT = 1 << 14, /* Use PCI hotplug slot information associated with bridge, but only if PCI device is multifunction */
NAMING_DEVICETREE_ALIASES = 1 << 15, /* Generate names from devicetree aliases */
NAMING_USB_HOST = 1 << 16, /* Generate names for usb host */
+ NAMING_SR_IOV_R = 1 << 17, /* Use "r" suffix for SR-IOV VF representors */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
@@ -53,6 +54,7 @@ typedef enum NamingSchemeFlags {
NAMING_V251 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
NAMING_V252 = NAMING_V251 | NAMING_DEVICETREE_ALIASES,
NAMING_V253 = NAMING_V252 | NAMING_USB_HOST,
+ NAMING_V254 = NAMING_V253 | NAMING_SR_IOV_R,
EXTRA_NET_NAMING_SCHEMES
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 998478ec4e..000839cac9 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -80,6 +80,7 @@ typedef struct LinkInfo {
int ifindex;
int iflink;
int iftype;
+ int vf_representor_id;
const char *devtype;
const char *phys_port_name;
struct hw_addr_data hw_addr;
@@ -208,7 +209,10 @@ static int dev_pci_onboard(sd_device *dev, const LinkInfo *info, NetNames *names
s = names->pci_onboard;
l = sizeof(names->pci_onboard);
l = strpcpyf(&s, l, "o%lu", idx);
- if (!isempty(info->phys_port_name))
+ if (naming_scheme_has(NAMING_SR_IOV_R) && info->vf_representor_id >= 0)
+ /* For VF representor append 'r' and not phys_port_name */
+ l = strpcpyf(&s, l, "r%d", info->vf_representor_id);
+ else if (!isempty(info->phys_port_name))
/* kernel provided front panel port name for multiple port PCI device */
l = strpcpyf(&s, l, "n%s", info->phys_port_name);
else if (dev_port > 0)
@@ -391,7 +395,10 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
l = strpcpyf(&s, l, "p%us%u", bus, slot);
if (func > 0 || is_pci_multifunction(names->pcidev) > 0)
l = strpcpyf(&s, l, "f%u", func);
- if (!isempty(info->phys_port_name))
+ if (naming_scheme_has(NAMING_SR_IOV_R) && info->vf_representor_id >= 0)
+ /* For VF representor append 'r' and not phys_port_name */
+ l = strpcpyf(&s, l, "r%d", info->vf_representor_id);
+ else if (!isempty(info->phys_port_name))
/* kernel provided front panel port name for multi-port PCI device */
l = strpcpyf(&s, l, "n%s", info->phys_port_name);
else if (dev_port > 0)
@@ -485,7 +492,10 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
l = strpcpyf(&s, l, "s%"PRIu32, hotplug_slot);
if (func > 0 || is_pci_multifunction(names->pcidev) > 0)
l = strpcpyf(&s, l, "f%u", func);
- if (!isempty(info->phys_port_name))
+ if (naming_scheme_has(NAMING_SR_IOV_R) && info->vf_representor_id >= 0)
+ /* For VF representor append 'r' and not phys_port_name */
+ l = strpcpyf(&s, l, "r%d", info->vf_representor_id);
+ else if (!isempty(info->phys_port_name))
l = strpcpyf(&s, l, "n%s", info->phys_port_name);
else if (dev_port > 0)
l = strpcpyf(&s, l, "d%lu", dev_port);
@@ -1082,7 +1092,10 @@ static int get_link_info(sd_device *dev, LinkInfo *info) {
if (r < 0 && r != -ENOENT)
return r;
- (void) sd_device_get_sysattr_value(dev, "phys_port_name", &info->phys_port_name);
+ r = sd_device_get_sysattr_value(dev, "phys_port_name", &info->phys_port_name);
+ if (r >= 0)
+ /* Check if phys_port_name indicates virtual device representor */
+ (void) sscanf(info->phys_port_name, "pf%*uvf%d", &info->vf_representor_id);
r = sd_device_get_sysattr_value(dev, "address", &s);
if (r < 0 && r != -ENOENT)
@@ -1100,7 +1113,9 @@ static int builtin_net_id(UdevEvent *event, int argc, char *argv[], bool test) {
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
const char *prefix;
NetNames names = {};
- LinkInfo info = {};
+ LinkInfo info = {
+ .vf_representor_id = -1,
+ };
int r;
r = get_link_info(dev, &info);