the “traditional” or “classic” naming scheme of the nineties with iface names eth0, eth1, wlan0, wlan1, etc.
Interfaces get their names assigned by the kernel on a first-come, first-serve policy as they are probed by the network
interface drivers. With nowadays complex hardware, this way of naming is no longer predictable if more than one interface of
a kind (ethernet, wlan, …) exists in the machine.
some custom schemes working towards alleviating the problem mentioned above. Programs like
and (which uses udev) used config files like and
assigned interface names based on the MAC address – which comes with another set of problems. These custom schemes
seem to be no longer in use.
the predictable network interface devices names introduced in udev. Note that udev is developed as a part of
systemd but can be used completely without systemd (at least at the time of writing).
The authoritative documentation on the persistent naming on freedesktop.org is marked as obsolete and refers to the
systemd.net-naming-scheme man page.
Unfortunately, I can’t wrap my head around that man page completely.
Luckily, the same page, at the end, refers to some source code of udev, .
The header comment in this C source is promising.
I suspected that this comment had been reduced over time and dug out an ancient revision with a more verbose
header comment:
/*
* Predictable network interface device names based on:
* - firmware/bios-provided index numbers for on-board devices
* - firmware-provided pci-express hotplug slot index number
* - physical/geographical location of the hardware
* - the interface's MAC address
*
* http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
*
* Two character prefixes based on the type of interface:
* en — Ethernet
* sl — serial line IP (slip)
* wl — wlan
* ww — wwan
*
* Type of names:
* b<number> — BCMA bus core number
* c<bus_id> — bus id of a grouped CCW or CCW device,
* with all leading zeros stripped [s390]
* o<index>[n<phys_port_name>|d<dev_port>]
* — on-board device index number
* s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
* — hotplug slot index number
* x<MAC> — MAC address
* [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
* — PCI geographical location
* [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
* — USB port number chain
* v<slot> - VIO slot number (IBM PowerVM)
* a<vendor><model>i<instance> — Platform bus ACPI instance id
* *
* All multi-function PCI devices will carry the [f<function>] number in the
* device name, including the function 0 device.
*
* When using PCI geography, The PCI domain is only prepended when it is not 0.
*
* For USB devices the full chain of port numbers of hubs is composed. If the
* name gets longer than the maximum number of 15 characters, the name is not
* exported.
* The usual USB configuration == 1 and interface == 0 values are suppressed.
*
* PCI Ethernet card with firmware index "1":
* ID_NET_NAME_ONBOARD=eno1
* ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
*
* PCI Ethernet card in hotplug slot with firmware index number:
* /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
* ID_NET_NAME_MAC=enx000000000466
* ID_NET_NAME_PATH=enp5s0
* ID_NET_NAME_SLOT=ens1
*
* PCI Ethernet multi-function card with 2 ports:
* /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
* ID_NET_NAME_MAC=enx78e7d1ea46da
* ID_NET_NAME_PATH=enp2s0f0
* /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
* ID_NET_NAME_MAC=enx78e7d1ea46dc
* ID_NET_NAME_PATH=enp2s0f1
*
* PCI wlan card:
* /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
* ID_NET_NAME_MAC=wlx0024d7e31130
* ID_NET_NAME_PATH=wlp3s0
*
* USB built-in 3G modem:
* /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
* ID_NET_NAME_MAC=wwx028037ec0200
* ID_NET_NAME_PATH=wwp0s29u1u4i6
*
* USB Android phone:
* /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
* ID_NET_NAME_MAC=enxd626b3450fb5
* ID_NET_NAME_PATH=enp0s29u1u2
*
* s390 grouped CCW interface:
* /sys/devices/css0/0.0.0007/0.0.f5f0/group_device/net/encf5f0
* ID_NET_NAME_MAC=enx026d3c00000a
* ID_NET_NAME_PATH=encf5f0
*/
Still, I can’t figure out completely how the persistent naming works. Poking around in the code in the vicinity of
I hit on the relevant code in
(the revision current at the time of writing):
if (enable_name_policy() && config->name_policy)
for (NamePolicy *policy = config->name_policy; *policy != _NAMEPOLICY_INVALID; policy++) {
const char *new_name = NULL;
switch (*policy) {
case NAMEPOLICY_KERNEL:
if (link->name_assign_type != NET_NAME_PREDICTABLE)
continue;
/* The kernel claims to have given a predictable name, keep it. */
log_link_debug(link, "Policy *%s*: keeping predictable kernel name",
name_policy_to_string(*policy));
goto no_rename;
case NAMEPOLICY_KEEP:
if (!IN_SET(link->name_assign_type, NET_NAME_USER, NET_NAME_RENAMED))
continue;
log_link_debug(link, "Policy *%s*: keeping existing userspace name",
name_policy_to_string(*policy));
goto no_rename;
case NAMEPOLICY_DATABASE:
(void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
break;
case NAMEPOLICY_ONBOARD:
(void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
break;
case NAMEPOLICY_SLOT:
(void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
break;
case NAMEPOLICY_PATH:
(void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
break;
case NAMEPOLICY_MAC:
(void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
break;
default:
assert_not_reached();
}
if (ifname_valid(new_name)) {
log_link_debug(link, "Policy *%s* yields \"%s\".", name_policy_to_string(*policy), new_name);
link->new_name = new_name;
return 0;
}
}
if (link->config->name) {
log_link_debug(link, "Policies didn't yield a name, using specified Name=%s.", link->config->name);
link->new_name = link->config->name;
return 0;
}
log_link_debug(link, "Policies didn't yield a name and Name= is not given, not renaming.");
no_rename:
if (!naming_scheme_has(NAMING_USE_INTERFACE_PROPERTY))
return sd_device_get_sysname(device, &link->new_name);
link->new_name = link->ifname;
return 0;
}
The code shows that the first match in the switch statement wins, with the following cases:
NAMEPOLICY_KERNEL
NAMEPOLICY_KEEP
ID_NET_NAME_FROM_DATABASE
ID_NET_NAME_ONBOARD
ID_NET_NAME_SLOT
ID_NET_NAME_PATH
ID_NET_NAME_MAC
With the device info can be retrieved from the udev database. I.e., I know that I have
one ethernet controller in my laptop, so I can list its properties with :
I haven’t checked the code of thoroughly, but I suspect that
causes the switch statement to branch into ,
where it jumps out of the switch in , which is why my
ethernet interface is assigned the interface name .
Without , would be the first hit, resulting
in the interface name .