Skip to content

Commit

Permalink
udev: net_id: Use devicetree aliases when available
Browse files Browse the repository at this point in the history
Devicetree firmware contains an "aliases" node, containing various
aliases for devices described by the firmware. For ethernet devices,
these are named "ethernet0", "ethernet1", etc. They provide a convenient
means of numbering ethernet devices, especially on systems with no other
stable number other than the address. In particular, U-Boot already uses
these aliases to name its ethernet devices.

Previously, there have been attempts (such as [1]) to add support for
these aliases to Linux. However, these patches have been rejected
because it is the maintainers' view that naming policy be left to
userspace. Well, systemd is userspace, so here we are.

In terms of implementation, apparently there can be multiple device
trees at once. I have decided to dodge this problem for now, and just
use /proc/device-tree. If it is desired to support multiple device trees
later, then the scheme can be modified to include the device tree's
index. For example, /sys/firmware/devicetree/base2/aliases/ethernet3
might be named enb2d3.

For the moment we only support "ethernetX" aliases. Future patches might
want to also handle "canX" and "wifiX".

It is common on boards with only one ethernet device to use an alias of
just "ethernet". In this case, the index is an implicit 0. In case the
author of the firmware made a mistake, we check to ensure that aliases
of "ethernet" and "ethernet0" do not both exist.

[1] https://patchwork.kernel.org/project/linux-arm-kernel/patch/1399390594-1409-1-git-send-email-boris.brezillon@free-electrons.com/

Closes: #17625
  • Loading branch information
sean-anderson-seco committed Aug 9, 2022
1 parent 746cf89 commit 57f39cf
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 2 deletions.
37 changes: 35 additions & 2 deletions man/systemd.net-naming-scheme.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,36 @@
<variablelist>
<varlistentry>
<term><varname>ID_NET_NAME_ONBOARD=<replaceable>prefix</replaceable><constant>o</constant><replaceable>number</replaceable></varname></term>
<term><varname>ID_NET_NAME_ONBOARD=<replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></varname></term>

<listitem><para>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 <constant>o</constant>, and a number
specified by the firmware. This is only available for PCI devices.</para>
for on-board devices. Different schemes are used depending on the fiemware type, as described in the table below.</para>

<table>
<title>Onboard naming schemes</title>

<tgroup cols='2'>
<thead>
<row>
<entry>Format</entry>
<entry>Description</entry>
</row>
</thead>

<tbody>
<row>
<entry><replaceable>prefix</replaceable><constant>o</constant><replaceable>number</replaceable></entry>
<entry>PCI onboard index</entry>
</row>

<row>
<entry><replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></entry>
<entry>Devicetree alias index</entry>
</row>

</tbody>
</tgroup>
</table>
</listitem>
</varlistentry>

Expand Down Expand Up @@ -415,6 +441,13 @@
</listitem>
</varlistentry>

<varlistentry>
<term><constant>v252</constant></term>

<listitem><para>Added naming scheme for platform devices with devicetree aliases.</para>
</listitem>
</varlistentry>

</variablelist>

<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
Expand Down
1 change: 1 addition & 0 deletions src/shared/netif-naming-scheme.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/shared/netif-naming-scheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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

Expand Down
99 changes: 99 additions & 0 deletions src/udev/udev-builtin-net_id.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/pci_regs.h>

#include "alloc-util.h"
#include "chase-symlinks.h"
#include "device-util.h"
#include "dirent-util.h"
#include "fd-util.h"
Expand Down Expand Up @@ -52,6 +53,7 @@ typedef enum NetNameType {
NET_XENVIF,
NET_PLATFORM,
NET_NETDEVSIM,
NET_DEVICETREE,
} NetNameType;

typedef struct NetNames {
Expand All @@ -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 */
Expand Down Expand Up @@ -600,6 +603,93 @@ static int names_platform(sd_device *dev, NetNames *names, bool test) {
return 0;
}

#define DEVICETREE_ALIASES "/proc/device-tree/aliases"

static int dev_devicetree_onboard(sd_device *dev, NetNames *names) {
const char *alias, *ofnode_path, *ofnode_syspath, *parent_syspath;
_cleanup_free_ char *devicetree_syspath = NULL;
sd_device *aliases, *ofnode, *parent;
int r;
unsigned index;

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_get_syspath(parent, &parent_syspath);
if (r < 0)
return r;

r = sd_device_new_child(&ofnode, parent, "/of_node");
if (r < 0)
return r;

r = sd_device_get_syspath(ofnode, &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;

r = sd_device_new_from_syspath(&aliases, strjoina(devicetree_syspath, "/aliases"));
if (r < 0)
return r;

FOREACH_DEVICE_SYSATTR(aliases, alias) {
const char *alias_path, *alias_index, *conflict = "ethernet";

alias_index = startswith(alias, "ethernet");
if (!alias_index)
continue;

r = sd_device_get_sysattr_value(aliases, alias, &alias_path);
if (r < 0)
continue;

/* ofnode_path lacks a leading /, so we need to adjust */
if (*alias_path != '/' || !streq(ofnode_path, alias_path + 1))
continue;

/* If there's no index, we default to 0... */
if (streq(alias, "ethernet")) {
conflict = "ethernet0";
} else {
r = safe_atou(alias_index, &index);
if (r < 0)
return log_device_debug_errno(dev, r,
"could not get index of alias %s\n", alias);
}

/* ...but make sure we don't have an alias conflict */
if (!index && !sd_device_get_sysattr_value(aliases, conflict, &alias_path)) {
log_device_debug(dev, "ethernet alias conflict: %s and %s both exist\n",
alias, conflict);
return -EINVAL;
}

xsprintf(names->devicetree_onboard, "d%u", index);
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;
Expand Down Expand Up @@ -1036,6 +1126,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];
Expand Down

0 comments on commit 57f39cf

Please sign in to comment.