udev-builtin-net_id.c revision 971e7fb62548f2c9c4e32684bb13409e6579dc6a
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Predictable network interface device names based on:
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner * - firmware/bios-provided index numbers for on-board devices
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * - firmware-provided pci-express hotplug slot index number
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * - physical/geographical location of the hardware
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * - the interface's MAC address
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Two character prefixes based on the type of interface:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * en -- ethernet
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Type of names:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * o<index> -- on-board device index number
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * s<slot>[f<function>] -- hotplug slot index number
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * x<MAC> -- MAC address
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * p<bus>s<slot>[f<function>] -- PCI geographical location
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * p<bus>s<slot>[f<function>][u<port>][...][c<config>][i<interface>]
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * -- USB port number chain
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering * All multi-function PCI devices will carry the [f<function>] number in the
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * device name, including the function 0 device.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * For USB devices the full chain of port numbers of hubs is composed. If the
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * name gets longer than the maximum number of 15 characters, the name is not
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * The usual USB configuration == 1 and interface == 0 values are suppressed.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * PCI ethernet card with firmware index
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_ONBOARD=eno1
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * PCI ethernet card
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_MAC=enx000000000466
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_PATH=enp5s0
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_SLOT=ens1
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * PCI ethernet card in hotplug slot with firmware index number:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_MAC=enx000000000466
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_PATH=enp5s0
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_SLOT=ens1
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * PCI wlan card:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_MAC=wlx0024d7e31130
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_PATH=wlp3s0
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * USB built-in 3G modem:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_MAC=wwx028037ec0200
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_PATH=wwp0s29u1u4i6
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * USB Android phone:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_MAC=enxd626b3450fb5
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * ID_NET_NAME_PATH=enp0s29u1u2
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* retrieve on-board index number and label from firmware */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* SMBIOS type 41 -- Onboard Devices Extended Information */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "index");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* read the 256 bytes PCI configuration space to check the multi-function bit */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool is_pci_singlefunction(struct udev_device *dev) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (fread(&config, sizeof(config), 1, f) != 1)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* bit 0-6 header type, bit 7 multi/single function device */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if ((config[PCI_HEADER_TYPE] & 0x80) == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct udev *udev = udev_device_get_udev(names->pcidev);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* compose a name based on the raw kernel's PCI bus, slot numbers */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (func == 0 && is_pci_singlefunction(names->pcidev))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%d", bus, slot);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%df%d", bus, slot, func);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* ACPI _SUN -- slot user number */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (read_one_line_file(str, &address) >= 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* match slot address with device by stripping the function */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (func == 0 && is_pci_singlefunction(names->pcidev))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(names->pci_slot, sizeof(names->pci_slot), "s%d", hotplug_slot);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(names->pci_slot, sizeof(names->pci_slot), "s%df%d", hotplug_slot, func);
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssenstatic int names_pci(struct udev_device *dev, struct netnames *names) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* check if our direct parent is a PCI device with no other bus in-between */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (streq("pci", udev_device_get_subsystem(parent))) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int names_usb(struct udev_device *dev, struct netnames *names) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering names->usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* get USB port number chain, configuration, interface */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering util_strscpy(name, sizeof(name), udev_device_get_sysname(names->usbdev));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* prefix every port number in the chain with "u"*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = util_strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* append USB config number, suppress the common config == 1 */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = util_strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* append USB interface number, suppress the interface == 0 */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = util_strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int names_mac(struct udev_device *dev, struct netnames *names) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned int i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* check for NET_ADDR_PERM, skip random MAC addresses */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = udev_device_get_sysattr_value(dev, "addr_assign_type");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = udev_device_get_sysattr_value(dev, "address");
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* skip empty MAC addresses */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* IEEE Organizationally Unique Identifier vendor string */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* skip commonly misused 00:00:00 (Xerox) prefix */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (memcmp(names->mac, "\0\0\0", 3) == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering names->mac[0], names->mac[1], names->mac[2],
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering names->mac[3], names->mac[4], names->mac[5]);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering udev_builtin_hwdb_lookup(dev, str, test);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned int i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* handle only ARPHRD_ETHER devices */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = udev_device_get_sysattr_value(dev, "type");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", prefix,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering names.mac[0], names.mac[1], names.mac[2],
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering names.mac[3], names.mac[4], names.mac[5]);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna /* get PCI based path names, we compose only PCI based paths */
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer /* plain PCI device */
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek /* USB device */
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek if (err >= 0 && names.type == NET_USB) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
8333c77edf8fd1654cd96f3f6ee0f078dd64b58bZbigniew Jędrzejewski-Szmek udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnaconst struct udev_builtin udev_builtin_net_id = {
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek .help = "network device properties",