udev-builtin-net_id.c revision decd634e801bee2c554edb35383cc9d43417a850
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
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - physical/geographical location of the hardware
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - the interface's MAC address
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * Two character prefixes based on the type of interface:
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering * en -- ethernet
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Type of names:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * o<index> -- on-board device index number
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering * s<slot>[f<function>] -- hotplug slot index number
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * x<MAC> -- MAC address
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * p<bus>s<slot>[f<function>] -- PCI geographical location
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * p<bus>s<slot>[f<function>][u<port>][...][c<config>][i<interface>]
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * -- USB port number chain
b93312f5960b276bae915906ccde36f545bae3e0Zbigniew Jędrzejewski-Szmek * All multi-function PCI devices will carry the [f<function>] number in the
b93312f5960b276bae915906ccde36f545bae3e0Zbigniew Jędrzejewski-Szmek * device name, including the function 0 device.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * For USB devices the full chain of port numbers of hubs is composed. If the
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * name gets longer than the maximum number of 15 characters, the name is not
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * The usual USB configuration == 1 and interface == 0 values are suppressed.
23502de3b0891455c8ce499a9eb61b69d060a829Daniel Mack * PCI ethernet card with firmware index "1":
23502de3b0891455c8ce499a9eb61b69d060a829Daniel Mack * ID_NET_NAME_ONBOARD=eno1
23502de3b0891455c8ce499a9eb61b69d060a829Daniel Mack * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * PCI ethernet card in hotplug slot with firmware index number:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=enx000000000466
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=enp5s0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_SLOT=ens1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * PCI ethernet multi-function card with 2 ports:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46da
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=enp2s0f0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46dc
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=enp2s0f1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * PCI wlan card:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=wlx0024d7e31130
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=wlp3s0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * USB built-in 3G modem:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=wwx028037ec0200
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=wwp0s29u1u4i6
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * USB Android phone:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=enxd626b3450fb5
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_PATH=enp0s29u1u2
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* retrieve on-board index number and label from firmware */
f5430a3ef308f3a102899fcaf7fbece757082f2aLennart Poetteringstatic int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering /* SMBIOS type 41 -- Onboard Devices Extended Information */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "index");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering/* read the 256 bytes PCI configuration space to check the multi-function bit */
c0eb11cfd016381fe02875a4ef29c1ade00c94e7Lennart Poetteringstatic bool is_pci_singlefunction(struct udev_device *dev) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev));
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (fread(&config, sizeof(config), 1, f) != 1)
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering /* bit 0-6 header type, bit 7 multi/single function device */
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if ((config[PCI_HEADER_TYPE] & 0x80) == 0)
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmekstatic int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek struct udev *udev = udev_device_get_udev(names->pcidev);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering /* compose a name based on the raw kernel's PCI bus, slot numbers */
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3)
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen if (func == 0 && is_pci_singlefunction(names->pcidev))
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%d", bus, slot);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%df%d", bus, slot, func);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen /* ACPI _SUN -- slot user number */
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek i = strtol(dent->d_name, &rest, 10);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (read_one_line_file(str, &address) >= 0) {
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek /* match slot address with device by stripping the function */
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0)
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (func == 0 && is_pci_singlefunction(names->pcidev))
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen snprintf(names->pci_slot, sizeof(names->pci_slot), "s%d", hotplug_slot);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen snprintf(names->pci_slot, sizeof(names->pci_slot), "s%df%d", hotplug_slot, func);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int names_pci(struct udev_device *dev, struct netnames *names) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* check if our direct parent is a PCI device with no other bus in-between */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (streq("pci", udev_device_get_subsystem(parent))) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
105e151299dc1208855380be2b22d0db2d66ebc6Lennart Poetteringstatic int names_usb(struct udev_device *dev, struct netnames *names) {
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack names->usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* get USB port number chain, configuration, interface */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering util_strscpy(name, sizeof(name), udev_device_get_sysname(names->usbdev));
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering /* prefix every port number in the chain with "u"*/
return -ENAMETOOLONG;
return EXIT_FAILURE;
return -ENOENT;
return -EINVAL;
return -EINVAL;
return -ENOENT;
return -EINVAL;
const char *devtype;
int err;
return EXIT_FAILURE;
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;