udev-builtin-net_id.c revision 3c123e0899b56c0587db36420da5e049c56d9e19
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Predictable network interface device names based on:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - firmware/bios-provided index numbers for on-board devices
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - firmware-provided pci-express hotplug slot index number
a0166609f782da91710dea9183d1bf138538db37Tom Gundersen * - physical/geographical location of the hardware
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * - the interface's MAC address
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Two character prefixes based on the type of interface:
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * en -- ethernet
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * Type of names:
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * o<index> -- on-board device index number
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * s<slot>[f<function>][d<dev_id>] -- hotplug slot index number
51323288fc628a5cac50914df915545d685b793eLennart Poettering * x<MAC> -- MAC address
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * p<bus>s<slot>[f<function>][d<dev_id>] -- PCI geographical location
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * -- USB port number chain
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * All multi-function PCI devices will carry the [f<function>] number in the
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * device name, including the function 0 device.
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * For USB devices the full chain of port numbers of hubs is composed. If the
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * name gets longer than the maximum number of 15 characters, the name is not
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * The usual USB configuration == 1 and interface == 0 values are suppressed.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * PCI ethernet card with firmware index "1":
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_ONBOARD=eno1
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * PCI ethernet card in hotplug slot with firmware index number:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=enx000000000466
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_PATH=enp5s0
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_SLOT=ens1
a0166609f782da91710dea9183d1bf138538db37Tom Gundersen * PCI ethernet multi-function card with 2 ports:
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46da
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * ID_NET_NAME_PATH=enp2s0f0
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46dc
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * ID_NET_NAME_PATH=enp2s0f1
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * PCI wlan card:
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=wlx0024d7e31130
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_PATH=wlp3s0
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * USB built-in 3G modem:
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=wwx028037ec0200
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_PATH=wwp0s29u1u4i6
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * USB Android phone:
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_MAC=enxd626b3450fb5
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_PATH=enp0s29u1u2
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack/* retrieve on-board index number and label from firmware */
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mackstatic int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack const char *index;
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering /* SMBIOS type 41 -- Onboard Devices Extended Information */
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "index");
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering/* read the 256 bytes PCI configuration space to check the multi-function bit */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poetteringstatic bool is_pci_multifunction(struct udev_device *dev) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (fread(&config, sizeof(config), 1, f) != 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* bit 0-6 header type, bit 7 multi/single function device */
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering struct udev *udev = udev_device_get_udev(names->pcidev);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned int dev_id = 0;
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* kernel provided multi-device index */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering attr = udev_device_get_sysattr_value(dev, "dev_id");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* compose a name based on the raw kernel's PCI bus, slot numbers */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = util_strpcpyf(&s, sizeof(names->pci_path), "p%ds%d", bus, slot);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (func > 0 || is_pci_multifunction(names->pcidev))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* ACPI _SUN -- slot user number */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek i = strtol(dent->d_name, &rest, 10);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (read_one_line_file(str, &address) >= 0) {
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek /* match slot address with device by stripping the function */
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0)
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek l = util_strpcpyf(&s, sizeof(names->pci_slot), "s%d", hotplug_slot);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (func > 0 || is_pci_multifunction(names->pcidev))
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek l = util_strpcpyf(&s, l, "f%d", func);
51323288fc628a5cac50914df915545d685b793eLennart Poetteringstatic int names_pci(struct udev_device *dev, struct netnames *names) {
51323288fc628a5cac50914df915545d685b793eLennart Poettering /* check if our direct parent is a PCI device with no other bus in-between */
51323288fc628a5cac50914df915545d685b793eLennart Poettering if (streq("pci", udev_device_get_subsystem(parent))) {
return -ENOENT;
char *ports;
char *config;
char *interf;
size_t l;
return -ENOENT;
return -EINVAL;
return -EINVAL;
return -EINVAL;
s = ports;
return -ENAMETOOLONG;
return EXIT_FAILURE;
return -ENOENT;
return -EINVAL;
return -EINVAL;
return -ENOENT;
return -EINVAL;
const char *devtype;
int err;
return EXIT_FAILURE;
return EXIT_FAILURE;
return EXIT_FAILURE;
if (strcmp(s, p) != 0)
if (devtype) {
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))
out:
return EXIT_SUCCESS;