udev-builtin-net_id.c revision 16f948cb208f1db9a1665f07ac9b22e416dc19d4
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers This file is part of systemd.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers Copyright 2012 Kay Sievers <kay@vrfy.org>
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers systemd is free software; you can redistribute it and/or modify it
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers under the terms of the GNU Lesser General Public License as published by
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers the Free Software Foundation; either version 2.1 of the License, or
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers (at your option) any later version.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers systemd is distributed in the hope that it will be useful, but
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers Lesser General Public License for more details.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers You should have received a copy of the GNU Lesser General Public License
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * Predictable network interface device names based on:
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * - firmware/bios-provided index numbers for on-board devices
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * - firmware-provided pci-express hotplug slot index number
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * - physical/geographical location of the hardware
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * - the interface's MAC address
de892aea1c486b59e04884268b612081d1660514Kay Sievers * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
de892aea1c486b59e04884268b612081d1660514Kay Sievers * Two character prefixes based on the type of interface:
de892aea1c486b59e04884268b612081d1660514Kay Sievers * en -- ethernet
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * sl -- serial line IP (slip)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * wl -- wlan
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ww -- wwan
de892aea1c486b59e04884268b612081d1660514Kay Sievers * Type of names:
de892aea1c486b59e04884268b612081d1660514Kay Sievers * b<number> -- BCMA bus core number
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ccw<name> -- CCW bus group name
de892aea1c486b59e04884268b612081d1660514Kay Sievers * o<index> -- on-board device index number
de892aea1c486b59e04884268b612081d1660514Kay Sievers * s<slot>[f<function>][d<dev_port>] -- hotplug slot index number
de892aea1c486b59e04884268b612081d1660514Kay Sievers * x<MAC> -- MAC address
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * -- PCI geographical location
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * -- USB port number chain
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * All multi-function PCI devices will carry the [f<function>] number in the
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * device name, including the function 0 device.
de892aea1c486b59e04884268b612081d1660514Kay Sievers * When using PCI geography, The PCI domain is only prepended when it is not 0.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * For USB devices the full chain of port numbers of hubs is composed. If the
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * name gets longer than the maximum number of 15 characters, the name is not
5b8180d3f6598a1b2f296645690de41d726fd5abKay Sievers * The usual USB configuration == 1 and interface == 0 values are suppressed.
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * PCI ethernet card with firmware index "1":
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_ONBOARD=eno1
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * PCI ethernet card in hotplug slot with firmware index number:
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
5b8180d3f6598a1b2f296645690de41d726fd5abKay Sievers * ID_NET_NAME_MAC=enx000000000466
01d183ddae6fb3445c4519cf1d90c6575f17292eKay Sievers * ID_NET_NAME_PATH=enp5s0
01d183ddae6fb3445c4519cf1d90c6575f17292eKay Sievers * ID_NET_NAME_SLOT=ens1
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * PCI ethernet multi-function card with 2 ports:
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_MAC=enx78e7d1ea46da
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_PATH=enp2s0f0
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_MAC=enx78e7d1ea46dc
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_PATH=enp2s0f1
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * PCI wlan card:
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
5b8180d3f6598a1b2f296645690de41d726fd5abKay Sievers * ID_NET_NAME_MAC=wlx0024d7e31130
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_PATH=wlp3s0
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * USB built-in 3G modem:
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_MAC=wwx028037ec0200
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_PATH=wwp0s29u1u4i6
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * USB Android phone:
de892aea1c486b59e04884268b612081d1660514Kay Sievers * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
de892aea1c486b59e04884268b612081d1660514Kay Sievers * ID_NET_NAME_MAC=enxd626b3450fb5
de892aea1c486b59e04884268b612081d1660514Kay Sievers * ID_NET_NAME_PATH=enp0s29u1u2
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers/* retrieve on-board index number and label from firmware */
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sieversstatic int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers const char *index;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers /* SMBIOS type 41 -- Onboard Devices Extended Information */
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers index = udev_device_get_sysattr_value(names->pcidev, "index");
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers/* read the 256 bytes PCI configuration space to check the multi-function bit */
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sieversstatic bool is_pci_multifunction(struct udev_device *dev) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers filename = strjoina(udev_device_get_syspath(dev), "/config");
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return false;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return false;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers /* bit 0-6 header type, bit 7 multi/single function device */
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return true;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return false;
de892aea1c486b59e04884268b612081d1660514Kay Sieversstatic int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
de892aea1c486b59e04884268b612081d1660514Kay Sievers struct udev *udev = udev_device_get_udev(names->pcidev);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers const char *attr;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
5b8180d3f6598a1b2f296645690de41d726fd5abKay Sievers /* kernel provided multi-device index */
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers attr = udev_device_get_sysattr_value(dev, "dev_port");
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* compose a name based on the raw kernel's PCI bus, slot numbers */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (func > 0 || is_pci_multifunction(names->pcidev))
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* ACPI _SUN -- slot user number */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* match slot address with device by stripping the function */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address)))
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (func > 0 || is_pci_multifunction(names->pcidev))
if (!parent)
return -ENOENT;
return -ENOENT;
char *ports;
char *config;
char *interf;
size_t l;
if (!usbdev)
return -ENOENT;
return -EINVAL;
return -EINVAL;
return -EINVAL;
s = ports;
return -ENAMETOOLONG;
unsigned int core;
if (!bcmadev)
return -ENOENT;
return -EINVAL;
if (core > 0)
const char *bus_id;
int rc;
if (!cdev)
return -ENOENT;
return -ENOENT;
if (!bus_id)
return -ENOENT;
return -EINVAL;
return EXIT_FAILURE;
return -ENOENT;
return -EINVAL;
return -EINVAL;
return -ENOENT;
return -EINVAL;
const char *devtype;
int err;
return EXIT_FAILURE;
case ARPHRD_ETHER:
case ARPHRD_SLIP:
return EXIT_FAILURE;
return EXIT_FAILURE;
if (!streq(s, p))
if (devtype) {
goto out;
if (err < 0)
goto out;
goto out;
if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
goto out;
if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str))
if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str))
goto out;
out:
return EXIT_SUCCESS;