1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Kay Sievers <kay@vrfy.org>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 * Predictable network interface device names based on:
24 * - firmware/bios-provided index numbers for on-board devices
25 * - firmware-provided pci-express hotplug slot index number
26 * - physical/geographical location of the hardware
27 * - the interface's MAC address
29 * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
31 * Two character prefixes based on the type of interface:
33 * sl -- serial line IP (slip)
38 * b<number> -- BCMA bus core number
39 * ccw<name> -- CCW bus group name
40 * o<index>[d<dev_port>] -- on-board device index number
41 * s<slot>[f<function>][d<dev_port>] -- hotplug slot index number
42 * x<MAC> -- MAC address
43 * [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
44 * -- PCI geographical location
45 * [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
46 * -- USB port number chain
48 * All multi-function PCI devices will carry the [f<function>] number in the
49 * device name, including the function 0 device.
51 * When using PCI geography, The PCI domain is only prepended when it is not 0.
53 * For USB devices the full chain of port numbers of hubs is composed. If the
54 * name gets longer than the maximum number of 15 characters, the name is not
56 * The usual USB configuration == 1 and interface == 0 values are suppressed.
58 * PCI Ethernet card with firmware index "1":
59 * ID_NET_NAME_ONBOARD=eno1
60 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
62 * PCI Ethernet card in hotplug slot with firmware index number:
63 * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
64 * ID_NET_NAME_MAC=enx000000000466
65 * ID_NET_NAME_PATH=enp5s0
66 * ID_NET_NAME_SLOT=ens1
68 * PCI Ethernet multi-function card with 2 ports:
69 * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
70 * ID_NET_NAME_MAC=enx78e7d1ea46da
71 * ID_NET_NAME_PATH=enp2s0f0
72 * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
73 * ID_NET_NAME_MAC=enx78e7d1ea46dc
74 * ID_NET_NAME_PATH=enp2s0f1
77 * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
78 * ID_NET_NAME_MAC=wlx0024d7e31130
79 * ID_NET_NAME_PATH=wlp3s0
81 * USB built-in 3G modem:
82 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
83 * ID_NET_NAME_MAC=wwx028037ec0200
84 * ID_NET_NAME_PATH=wwp0s29u1u4i6
87 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
88 * ID_NET_NAME_MAC=enxd626b3450fb5
89 * ID_NET_NAME_PATH=enp0s29u1u2
95 #include <net/if_arp.h>
101 #include <linux/pci_regs.h>
105 #include "string-util.h"
118 enum netname_type type
;
123 struct udev_device
*pcidev
;
124 char pci_slot
[IFNAMSIZ
];
125 char pci_path
[IFNAMSIZ
];
126 char pci_onboard
[IFNAMSIZ
];
127 const char *pci_onboard_label
;
129 char usb_ports
[IFNAMSIZ
];
130 char bcma_core
[IFNAMSIZ
];
131 char ccw_group
[IFNAMSIZ
];
134 /* retrieve on-board index number and label from firmware */
135 static int dev_pci_onboard(struct udev_device
*dev
, struct netnames
*names
) {
136 unsigned dev_port
= 0;
142 /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
143 attr
= udev_device_get_sysattr_value(names
->pcidev
, "acpi_index");
144 /* SMBIOS type 41 -- Onboard Devices Extended Information */
146 attr
= udev_device_get_sysattr_value(names
->pcidev
, "index");
150 idx
= strtoul(attr
, NULL
, 0);
154 /* kernel provided port index for multiple ports on a single PCI function */
155 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
157 dev_port
= strtol(attr
, NULL
, 10);
159 s
= names
->pci_onboard
;
160 l
= sizeof(names
->pci_onboard
);
161 l
= strpcpyf(&s
, l
, "o%d", idx
);
163 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
165 names
->pci_onboard
[0] = '\0';
167 names
->pci_onboard_label
= udev_device_get_sysattr_value(names
->pcidev
, "label");
172 /* read the 256 bytes PCI configuration space to check the multi-function bit */
173 static bool is_pci_multifunction(struct udev_device
*dev
) {
174 _cleanup_close_
int fd
= -1;
175 const char *filename
;
178 filename
= strjoina(udev_device_get_syspath(dev
), "/config");
179 fd
= open(filename
, O_RDONLY
| O_CLOEXEC
);
182 if (read(fd
, &config
, sizeof(config
)) != sizeof(config
))
185 /* bit 0-6 header type, bit 7 multi/single function device */
186 if ((config
[PCI_HEADER_TYPE
] & 0x80) != 0)
192 static int dev_pci_slot(struct udev_device
*dev
, struct netnames
*names
) {
193 struct udev
*udev
= udev_device_get_udev(names
->pcidev
);
194 unsigned domain
, bus
, slot
, func
, dev_port
= 0;
198 struct udev_device
*pci
= NULL
;
199 char slots
[256], str
[256];
200 _cleanup_closedir_
DIR *dir
= NULL
;
202 int hotplug_slot
= 0, err
= 0;
204 if (sscanf(udev_device_get_sysname(names
->pcidev
), "%x:%x:%x.%u", &domain
, &bus
, &slot
, &func
) != 4)
207 /* kernel provided port index for multiple ports on a single PCI function */
208 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
210 dev_port
= strtol(attr
, NULL
, 10);
212 /* compose a name based on the raw kernel's PCI bus, slot numbers */
214 l
= sizeof(names
->pci_path
);
216 l
= strpcpyf(&s
, l
, "P%u", domain
);
217 l
= strpcpyf(&s
, l
, "p%us%u", bus
, slot
);
218 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
219 l
= strpcpyf(&s
, l
, "f%u", func
);
221 l
= strpcpyf(&s
, l
, "d%u", dev_port
);
223 names
->pci_path
[0] = '\0';
225 /* ACPI _SUN -- slot user number */
226 pci
= udev_device_new_from_subsystem_sysname(udev
, "subsystem", "pci");
231 snprintf(slots
, sizeof(slots
), "%s/slots", udev_device_get_syspath(pci
));
232 dir
= opendir(slots
);
238 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
243 if (dent
->d_name
[0] == '.')
245 i
= strtol(dent
->d_name
, &rest
, 10);
250 snprintf(str
, sizeof(str
), "%s/%s/address", slots
, dent
->d_name
);
251 if (read_one_line_file(str
, &address
) >= 0) {
252 /* match slot address with device by stripping the function */
253 if (strneq(address
, udev_device_get_sysname(names
->pcidev
), strlen(address
)))
258 if (hotplug_slot
> 0)
262 if (hotplug_slot
> 0) {
264 l
= sizeof(names
->pci_slot
);
266 l
= strpcpyf(&s
, l
, "P%d", domain
);
267 l
= strpcpyf(&s
, l
, "s%d", hotplug_slot
);
268 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
269 l
= strpcpyf(&s
, l
, "f%d", func
);
271 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
273 names
->pci_slot
[0] = '\0';
276 udev_device_unref(pci
);
280 static int names_pci(struct udev_device
*dev
, struct netnames
*names
) {
281 struct udev_device
*parent
;
286 parent
= udev_device_get_parent(dev
);
288 /* there can only ever be one virtio bus per parent device, so we can
289 safely ignore any virtio buses. see
290 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
291 while (parent
&& streq_ptr("virtio", udev_device_get_subsystem(parent
)))
292 parent
= udev_device_get_parent(parent
);
297 /* check if our direct parent is a PCI device with no other bus in-between */
298 if (streq_ptr("pci", udev_device_get_subsystem(parent
))) {
299 names
->type
= NET_PCI
;
300 names
->pcidev
= parent
;
302 names
->pcidev
= udev_device_get_parent_with_subsystem_devtype(dev
, "pci", NULL
);
306 dev_pci_onboard(dev
, names
);
307 dev_pci_slot(dev
, names
);
311 static int names_usb(struct udev_device
*dev
, struct netnames
*names
) {
312 struct udev_device
*usbdev
;
323 usbdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "usb", "usb_interface");
327 /* get USB port number chain, configuration, interface */
328 strscpy(name
, sizeof(name
), udev_device_get_sysname(usbdev
));
329 s
= strchr(name
, '-');
334 s
= strchr(ports
, ':');
340 s
= strchr(config
, '.');
346 /* prefix every port number in the chain with "u" */
348 while ((s
= strchr(s
, '.')))
350 s
= names
->usb_ports
;
351 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "u", ports
, NULL
);
353 /* append USB config number, suppress the common config == 1 */
354 if (!streq(config
, "1"))
355 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "c", config
, NULL
);
357 /* append USB interface number, suppress the interface == 0 */
358 if (!streq(interf
, "0"))
359 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "i", interf
, NULL
);
361 return -ENAMETOOLONG
;
363 names
->type
= NET_USB
;
367 static int names_bcma(struct udev_device
*dev
, struct netnames
*names
) {
368 struct udev_device
*bcmadev
;
374 bcmadev
= udev_device_get_parent_with_subsystem_devtype(dev
, "bcma", NULL
);
378 /* bus num:core num */
379 if (sscanf(udev_device_get_sysname(bcmadev
), "bcma%*u:%u", &core
) != 1)
381 /* suppress the common core == 0 */
383 snprintf(names
->bcma_core
, sizeof(names
->bcma_core
), "b%u", core
);
385 names
->type
= NET_BCMA
;
389 static int names_ccw(struct udev_device
*dev
, struct netnames
*names
) {
390 struct udev_device
*cdev
;
398 /* Retrieve the associated CCW device */
399 cdev
= udev_device_get_parent(dev
);
403 /* Network devices are always grouped CCW devices */
404 if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev
)))
407 /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
408 * identifies the network device on the Linux on System z channel
409 * subsystem. Note that the bus-ID contains lowercase characters.
411 bus_id
= udev_device_get_sysname(cdev
);
415 /* Check the length of the bus-ID. Rely on that the kernel provides
416 * a correct bus-ID; alternatively, improve this check and parse and
417 * verify each bus-ID part...
419 bus_id_len
= strlen(bus_id
);
420 if (!bus_id_len
|| bus_id_len
< 8 || bus_id_len
> 9)
423 /* Store the CCW bus-ID for use as network device name */
424 rc
= snprintf(names
->ccw_group
, sizeof(names
->ccw_group
), "ccw%s", bus_id
);
425 if (rc
>= 0 && rc
< (int)sizeof(names
->ccw_group
))
426 names
->type
= NET_CCWGROUP
;
430 static int names_mac(struct udev_device
*dev
, struct netnames
*names
) {
433 unsigned int a1
, a2
, a3
, a4
, a5
, a6
;
435 /* check for NET_ADDR_PERM, skip random MAC addresses */
436 s
= udev_device_get_sysattr_value(dev
, "addr_assign_type");
439 i
= strtoul(s
, NULL
, 0);
443 s
= udev_device_get_sysattr_value(dev
, "address");
446 if (sscanf(s
, "%x:%x:%x:%x:%x:%x", &a1
, &a2
, &a3
, &a4
, &a5
, &a6
) != 6)
449 /* skip empty MAC addresses */
450 if (a1
+ a2
+ a3
+ a4
+ a5
+ a6
== 0)
459 names
->mac_valid
= true;
463 /* IEEE Organizationally Unique Identifier vendor string */
464 static int ieee_oui(struct udev_device
*dev
, struct netnames
*names
, bool test
) {
467 if (!names
->mac_valid
)
469 /* skip commonly misused 00:00:00 (Xerox) prefix */
470 if (memcmp(names
->mac
, "\0\0\0", 3) == 0)
472 snprintf(str
, sizeof(str
), "OUI:%02X%02X%02X%02X%02X%02X",
473 names
->mac
[0], names
->mac
[1], names
->mac
[2],
474 names
->mac
[3], names
->mac
[4], names
->mac
[5]);
475 udev_builtin_hwdb_lookup(dev
, NULL
, str
, NULL
, test
);
479 static int builtin_net_id(struct udev_device
*dev
, int argc
, char *argv
[], bool test
) {
484 const char *prefix
= "en";
485 struct netnames names
= {};
488 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
489 s
= udev_device_get_sysattr_value(dev
, "type");
492 i
= strtoul(s
, NULL
, 0);
504 /* skip stacked devices, like VLANs, ... */
505 s
= udev_device_get_sysattr_value(dev
, "ifindex");
508 p
= udev_device_get_sysattr_value(dev
, "iflink");
514 devtype
= udev_device_get_devtype(dev
);
516 if (streq("wlan", devtype
))
518 else if (streq("wwan", devtype
))
522 err
= names_mac(dev
, &names
);
523 if (err
>= 0 && names
.mac_valid
) {
526 snprintf(str
, sizeof(str
), "%sx%02x%02x%02x%02x%02x%02x", prefix
,
527 names
.mac
[0], names
.mac
[1], names
.mac
[2],
528 names
.mac
[3], names
.mac
[4], names
.mac
[5]);
529 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_MAC", str
);
531 ieee_oui(dev
, &names
, test
);
534 /* get path names for Linux on System z network devices */
535 err
= names_ccw(dev
, &names
);
536 if (err
>= 0 && names
.type
== NET_CCWGROUP
) {
539 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.ccw_group
) < (int)sizeof(str
))
540 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
544 /* get PCI based path names, we compose only PCI based paths */
545 err
= names_pci(dev
, &names
);
549 /* plain PCI device */
550 if (names
.type
== NET_PCI
) {
553 if (names
.pci_onboard
[0])
554 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard
) < (int)sizeof(str
))
555 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_ONBOARD", str
);
557 if (names
.pci_onboard_label
)
558 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard_label
) < (int)sizeof(str
))
559 udev_builtin_add_property(dev
, test
, "ID_NET_LABEL_ONBOARD", str
);
561 if (names
.pci_path
[0])
562 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_path
) < (int)sizeof(str
))
563 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
565 if (names
.pci_slot
[0])
566 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_slot
) < (int)sizeof(str
))
567 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
572 err
= names_usb(dev
, &names
);
573 if (err
>= 0 && names
.type
== NET_USB
) {
576 if (names
.pci_path
[0])
577 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.usb_ports
) < (int)sizeof(str
))
578 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
580 if (names
.pci_slot
[0])
581 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.usb_ports
) < (int)sizeof(str
))
582 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
587 err
= names_bcma(dev
, &names
);
588 if (err
>= 0 && names
.type
== NET_BCMA
) {
591 if (names
.pci_path
[0])
592 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.bcma_core
) < (int)sizeof(str
))
593 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
595 if (names
.pci_slot
[0])
596 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.bcma_core
) < (int)sizeof(str
))
597 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
604 const struct udev_builtin udev_builtin_net_id
= {
606 .cmd
= builtin_net_id
,
607 .help
= "Network device properties",