diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index e5a3d7a313..3d5b3326b1 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -98,10 +98,36 @@
ID_NET_NAME_ONBOARD=prefixonumber
+ ID_NET_NAME_ONBOARD=prefixdnumber
This name is set based on the numeric ordering information given by the firmware
- for on-board devices. The name consists of the prefix, letter o, and a number
- specified by the firmware. This is only available for PCI devices.
+ for on-board devices. Different schemes are used depending on the fiemware type, as described in the table below.
+
+
+ Onboard naming schemes
+
+
+
+
+ Format
+ Description
+
+
+
+
+
+ prefixonumber
+ PCI onboard index
+
+
+
+ prefixdnumber
+ Devicetree alias index
+
+
+
+
+
@@ -415,6 +441,13 @@
+
+ v252
+
+ Added naming scheme for platform devices with devicetree aliases.
+
+
+
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 e95072e048..18748e5376 100644
--- a/src/shared/netif-naming-scheme.c
+++ b/src/shared/netif-naming-scheme.c
@@ -24,6 +24,7 @@ static const NamingScheme naming_schemes[] = {
{ "v249", NAMING_V249 },
{ "v250", NAMING_V250 },
{ "v251", NAMING_V251 },
+ { "v252", NAMING_V252 },
/* … 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 5303348e06..4fa9170969 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -37,6 +37,7 @@ typedef enum NamingSchemeFlags {
NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */
NAMING_XEN_VIF = 1 << 13, /* Generate names for Xen netfront devices */
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 */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
@@ -49,6 +50,7 @@ typedef enum NamingSchemeFlags {
NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY,
NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF,
NAMING_V251 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
+ NAMING_V252 = NAMING_V251 | NAMING_DEVICETREE_ALIASES,
EXTRA_NET_NAMING_SCHEMES
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 45387b2bdb..ef1f398927 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -23,6 +23,7 @@
#include
#include "alloc-util.h"
+#include "chase-symlinks.h"
#include "device-util.h"
#include "dirent-util.h"
#include "fd-util.h"
@@ -52,6 +53,7 @@ typedef enum NetNameType {
NET_XENVIF,
NET_PLATFORM,
NET_NETDEVSIM,
+ NET_DEVICETREE,
} NetNameType;
typedef struct NetNames {
@@ -70,6 +72,7 @@ typedef struct NetNames {
char xen_slot[ALTIFNAMSIZ];
char platform_path[ALTIFNAMSIZ];
char netdevsim_path[ALTIFNAMSIZ];
+ char devicetree_onboard[ALTIFNAMSIZ];
} NetNames;
/* skip intermediate virtio devices */
@@ -600,6 +603,90 @@ static int names_platform(sd_device *dev, NetNames *names, bool test) {
return 0;
}
+static int dev_devicetree_onboard(sd_device *dev, NetNames *names) {
+ const char *alias, *ofnode_path, *ofnode_syspath;
+ _cleanup_free_ char *devicetree_syspath = NULL;
+ _cleanup_(sd_device_unrefp) sd_device *aliases_dev = NULL, *ofnode_dev = NULL;
+ sd_device *parent;
+ int r;
+
+ if (!naming_scheme_has(NAMING_DEVICETREE_ALIASES))
+ return 0;
+
+ /* check if our direct parent has an of_node */
+ r = sd_device_get_parent(dev, &parent);
+ if (r < 0)
+ return r;
+
+ r = sd_device_new_child(&ofnode_dev, parent, "of_node");
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_syspath(ofnode_dev, &ofnode_syspath);
+ if (r < 0)
+ return r;
+
+ r = chase_symlinks("/proc/device-tree", NULL, 0, &devicetree_syspath, NULL);
+ if (r < 0)
+ return r;
+
+ /*
+ * Example paths:
+ * devicetree_syspath = /sys/firmware/devicetree/base
+ * ofnode_syspath = /sys/firmware/devicetree/base/soc/ethernet@deadbeef
+ * ofnode_path = soc/ethernet@deadbeef
+ */
+ ofnode_path = path_startswith(ofnode_syspath, devicetree_syspath);
+ if (!ofnode_path)
+ return -ENOENT;
+
+ /* Get back our leading / to match the contents of the aliases */
+ ofnode_path--;
+ assert(path_is_absolute(ofnode_path));
+
+ r = sd_device_new_from_syspath(&aliases_dev, strjoina(devicetree_syspath, "/aliases"));
+ if (r < 0)
+ return r;
+
+ FOREACH_DEVICE_SYSATTR(aliases_dev, alias) {
+ const char *alias_path, *alias_index, *conflict;
+ unsigned i;
+
+ alias_index = startswith(alias, "ethernet");
+ if (!alias_index)
+ continue;
+
+ if (sd_device_get_sysattr_value(aliases_dev, alias, &alias_path) < 0)
+ continue;
+
+ if (!path_equal(ofnode_path, alias_path))
+ continue;
+
+ /* If there's no index, we default to 0... */
+ if (isempty(alias_index)) {
+ i = 0;
+ conflict = "ethernet0";
+ } else {
+ r = safe_atou(alias_index, &i);
+ if (r < 0)
+ return log_device_debug_errno(dev, r,
+ "Could not get index of alias %s: %m", alias);
+ conflict = "ethernet";
+ }
+
+ /* ...but make sure we don't have an alias conflict */
+ if (i == 0 && sd_device_get_sysattr_value(aliases_dev, conflict, NULL) >= 0)
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
+ "Ethernet alias conflict: ethernet and ethernet0 both exist");
+
+ xsprintf(names->devicetree_onboard, "d%u", i);
+ names->type = NET_DEVICETREE;
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
static int names_pci(sd_device *dev, const LinkInfo *info, NetNames *names) {
_cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL;
_cleanup_free_ char *virtfn_suffix = NULL;
@@ -1036,6 +1123,15 @@ static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
ieee_oui(dev, &info, test);
}
+ /* get devicetree aliases; only ethernet supported for now */
+ if (streq(prefix, "en") && dev_devicetree_onboard(dev, &names) >= 0 &&
+ names.type == NET_DEVICETREE) {
+ char str[ALTIFNAMSIZ];
+
+ if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.devicetree_onboard))
+ udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
+ }
+
/* get path names for Linux on System z network devices */
if (names_ccw(dev, &names) >= 0 && names.type == NET_CCW) {
char str[ALTIFNAMSIZ];