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 "stdio-util.h"
106 #include "string-util.h"
109 #define ONBOARD_INDEX_MAX (16*1024-1)
121 enum netname_type type
;
126 struct udev_device
*pcidev
;
127 char pci_slot
[IFNAMSIZ
];
128 char pci_path
[IFNAMSIZ
];
129 char pci_onboard
[IFNAMSIZ
];
130 const char *pci_onboard_label
;
132 char usb_ports
[IFNAMSIZ
];
133 char bcma_core
[IFNAMSIZ
];
134 char ccw_group
[IFNAMSIZ
];
137 /* retrieve on-board index number and label from firmware */
138 static int dev_pci_onboard(struct udev_device
*dev
, struct netnames
*names
) {
139 unsigned dev_port
= 0;
145 /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
146 attr
= udev_device_get_sysattr_value(names
->pcidev
, "acpi_index");
147 /* SMBIOS type 41 -- Onboard Devices Extended Information */
149 attr
= udev_device_get_sysattr_value(names
->pcidev
, "index");
153 idx
= strtoul(attr
, NULL
, 0);
157 /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
158 * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
159 * cut-off, which is somewhere beyond the realistic number of physical network interface a system might
160 * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */
161 if (idx
> ONBOARD_INDEX_MAX
)
164 /* kernel provided port index for multiple ports on a single PCI function */
165 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
167 dev_port
= strtol(attr
, NULL
, 10);
169 s
= names
->pci_onboard
;
170 l
= sizeof(names
->pci_onboard
);
171 l
= strpcpyf(&s
, l
, "o%d", idx
);
173 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
175 names
->pci_onboard
[0] = '\0';
177 names
->pci_onboard_label
= udev_device_get_sysattr_value(names
->pcidev
, "label");
182 /* read the 256 bytes PCI configuration space to check the multi-function bit */
183 static bool is_pci_multifunction(struct udev_device
*dev
) {
184 _cleanup_close_
int fd
= -1;
185 const char *filename
;
188 filename
= strjoina(udev_device_get_syspath(dev
), "/config");
189 fd
= open(filename
, O_RDONLY
| O_CLOEXEC
);
192 if (read(fd
, &config
, sizeof(config
)) != sizeof(config
))
195 /* bit 0-6 header type, bit 7 multi/single function device */
196 if ((config
[PCI_HEADER_TYPE
] & 0x80) != 0)
202 static int dev_pci_slot(struct udev_device
*dev
, struct netnames
*names
) {
203 struct udev
*udev
= udev_device_get_udev(names
->pcidev
);
204 unsigned domain
, bus
, slot
, func
, dev_port
= 0;
208 struct udev_device
*pci
= NULL
;
209 char slots
[256], str
[256];
210 _cleanup_closedir_
DIR *dir
= NULL
;
212 int hotplug_slot
= 0, err
= 0;
214 if (sscanf(udev_device_get_sysname(names
->pcidev
), "%x:%x:%x.%u", &domain
, &bus
, &slot
, &func
) != 4)
217 /* kernel provided port index for multiple ports on a single PCI function */
218 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
220 dev_port
= strtol(attr
, NULL
, 10);
222 /* compose a name based on the raw kernel's PCI bus, slot numbers */
224 l
= sizeof(names
->pci_path
);
226 l
= strpcpyf(&s
, l
, "P%u", domain
);
227 l
= strpcpyf(&s
, l
, "p%us%u", bus
, slot
);
228 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
229 l
= strpcpyf(&s
, l
, "f%u", func
);
231 l
= strpcpyf(&s
, l
, "d%u", dev_port
);
233 names
->pci_path
[0] = '\0';
235 /* ACPI _SUN -- slot user number */
236 pci
= udev_device_new_from_subsystem_sysname(udev
, "subsystem", "pci");
241 xsprintf(slots
, "%s/slots", udev_device_get_syspath(pci
));
242 dir
= opendir(slots
);
248 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
253 if (dent
->d_name
[0] == '.')
255 i
= strtol(dent
->d_name
, &rest
, 10);
260 xsprintf(str
, "%s/%s/address", slots
, dent
->d_name
);
261 if (read_one_line_file(str
, &address
) >= 0) {
262 /* match slot address with device by stripping the function */
263 if (strneq(address
, udev_device_get_sysname(names
->pcidev
), strlen(address
)))
268 if (hotplug_slot
> 0)
272 if (hotplug_slot
> 0) {
274 l
= sizeof(names
->pci_slot
);
276 l
= strpcpyf(&s
, l
, "P%d", domain
);
277 l
= strpcpyf(&s
, l
, "s%d", hotplug_slot
);
278 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
279 l
= strpcpyf(&s
, l
, "f%d", func
);
281 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
283 names
->pci_slot
[0] = '\0';
286 udev_device_unref(pci
);
290 static int names_pci(struct udev_device
*dev
, struct netnames
*names
) {
291 struct udev_device
*parent
;
296 parent
= udev_device_get_parent(dev
);
298 /* there can only ever be one virtio bus per parent device, so we can
299 safely ignore any virtio buses. see
300 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
301 while (parent
&& streq_ptr("virtio", udev_device_get_subsystem(parent
)))
302 parent
= udev_device_get_parent(parent
);
307 /* check if our direct parent is a PCI device with no other bus in-between */
308 if (streq_ptr("pci", udev_device_get_subsystem(parent
))) {
309 names
->type
= NET_PCI
;
310 names
->pcidev
= parent
;
312 names
->pcidev
= udev_device_get_parent_with_subsystem_devtype(dev
, "pci", NULL
);
316 dev_pci_onboard(dev
, names
);
317 dev_pci_slot(dev
, names
);
321 static int names_usb(struct udev_device
*dev
, struct netnames
*names
) {
322 struct udev_device
*usbdev
;
333 usbdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "usb", "usb_interface");
337 /* get USB port number chain, configuration, interface */
338 strscpy(name
, sizeof(name
), udev_device_get_sysname(usbdev
));
339 s
= strchr(name
, '-');
344 s
= strchr(ports
, ':');
350 s
= strchr(config
, '.');
356 /* prefix every port number in the chain with "u" */
358 while ((s
= strchr(s
, '.')))
360 s
= names
->usb_ports
;
361 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "u", ports
, NULL
);
363 /* append USB config number, suppress the common config == 1 */
364 if (!streq(config
, "1"))
365 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "c", config
, NULL
);
367 /* append USB interface number, suppress the interface == 0 */
368 if (!streq(interf
, "0"))
369 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "i", interf
, NULL
);
371 return -ENAMETOOLONG
;
373 names
->type
= NET_USB
;
377 static int names_bcma(struct udev_device
*dev
, struct netnames
*names
) {
378 struct udev_device
*bcmadev
;
384 bcmadev
= udev_device_get_parent_with_subsystem_devtype(dev
, "bcma", NULL
);
388 /* bus num:core num */
389 if (sscanf(udev_device_get_sysname(bcmadev
), "bcma%*u:%u", &core
) != 1)
391 /* suppress the common core == 0 */
393 xsprintf(names
->bcma_core
, "b%u", core
);
395 names
->type
= NET_BCMA
;
399 static int names_ccw(struct udev_device
*dev
, struct netnames
*names
) {
400 struct udev_device
*cdev
;
408 /* Retrieve the associated CCW device */
409 cdev
= udev_device_get_parent(dev
);
413 /* Network devices are always grouped CCW devices */
414 if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev
)))
417 /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
418 * identifies the network device on the Linux on System z channel
419 * subsystem. Note that the bus-ID contains lowercase characters.
421 bus_id
= udev_device_get_sysname(cdev
);
425 /* Check the length of the bus-ID. Rely on that the kernel provides
426 * a correct bus-ID; alternatively, improve this check and parse and
427 * verify each bus-ID part...
429 bus_id_len
= strlen(bus_id
);
430 if (!bus_id_len
|| bus_id_len
< 8 || bus_id_len
> 9)
433 /* Store the CCW bus-ID for use as network device name */
434 rc
= snprintf(names
->ccw_group
, sizeof(names
->ccw_group
), "ccw%s", bus_id
);
435 if (rc
>= 0 && rc
< (int)sizeof(names
->ccw_group
))
436 names
->type
= NET_CCWGROUP
;
440 static int names_mac(struct udev_device
*dev
, struct netnames
*names
) {
443 unsigned int a1
, a2
, a3
, a4
, a5
, a6
;
445 /* check for NET_ADDR_PERM, skip random MAC addresses */
446 s
= udev_device_get_sysattr_value(dev
, "addr_assign_type");
449 i
= strtoul(s
, NULL
, 0);
453 s
= udev_device_get_sysattr_value(dev
, "address");
456 if (sscanf(s
, "%x:%x:%x:%x:%x:%x", &a1
, &a2
, &a3
, &a4
, &a5
, &a6
) != 6)
459 /* skip empty MAC addresses */
460 if (a1
+ a2
+ a3
+ a4
+ a5
+ a6
== 0)
469 names
->mac_valid
= true;
473 /* IEEE Organizationally Unique Identifier vendor string */
474 static int ieee_oui(struct udev_device
*dev
, struct netnames
*names
, bool test
) {
477 if (!names
->mac_valid
)
479 /* skip commonly misused 00:00:00 (Xerox) prefix */
480 if (memcmp(names
->mac
, "\0\0\0", 3) == 0)
482 xsprintf(str
, "OUI:%02X%02X%02X%02X%02X%02X", names
->mac
[0],
483 names
->mac
[1], names
->mac
[2], names
->mac
[3], names
->mac
[4],
485 udev_builtin_hwdb_lookup(dev
, NULL
, str
, NULL
, test
);
489 static int builtin_net_id(struct udev_device
*dev
, int argc
, char *argv
[], bool test
) {
494 const char *prefix
= "en";
495 struct netnames names
= {};
498 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
499 s
= udev_device_get_sysattr_value(dev
, "type");
502 i
= strtoul(s
, NULL
, 0);
514 /* skip stacked devices, like VLANs, ... */
515 s
= udev_device_get_sysattr_value(dev
, "ifindex");
518 p
= udev_device_get_sysattr_value(dev
, "iflink");
524 devtype
= udev_device_get_devtype(dev
);
526 if (streq("wlan", devtype
))
528 else if (streq("wwan", devtype
))
532 err
= names_mac(dev
, &names
);
533 if (err
>= 0 && names
.mac_valid
) {
536 xsprintf(str
, "%sx%02x%02x%02x%02x%02x%02x", prefix
,
537 names
.mac
[0], names
.mac
[1], names
.mac
[2],
538 names
.mac
[3], names
.mac
[4], names
.mac
[5]);
539 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_MAC", str
);
541 ieee_oui(dev
, &names
, test
);
544 /* get path names for Linux on System z network devices */
545 err
= names_ccw(dev
, &names
);
546 if (err
>= 0 && names
.type
== NET_CCWGROUP
) {
549 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.ccw_group
) < (int)sizeof(str
))
550 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
554 /* get PCI based path names, we compose only PCI based paths */
555 err
= names_pci(dev
, &names
);
559 /* plain PCI device */
560 if (names
.type
== NET_PCI
) {
563 if (names
.pci_onboard
[0])
564 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard
) < (int)sizeof(str
))
565 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_ONBOARD", str
);
567 if (names
.pci_onboard_label
)
568 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard_label
) < (int)sizeof(str
))
569 udev_builtin_add_property(dev
, test
, "ID_NET_LABEL_ONBOARD", str
);
571 if (names
.pci_path
[0])
572 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_path
) < (int)sizeof(str
))
573 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
575 if (names
.pci_slot
[0])
576 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_slot
) < (int)sizeof(str
))
577 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
582 err
= names_usb(dev
, &names
);
583 if (err
>= 0 && names
.type
== NET_USB
) {
586 if (names
.pci_path
[0])
587 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.usb_ports
) < (int)sizeof(str
))
588 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
590 if (names
.pci_slot
[0])
591 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.usb_ports
) < (int)sizeof(str
))
592 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
597 err
= names_bcma(dev
, &names
);
598 if (err
>= 0 && names
.type
== NET_BCMA
) {
601 if (names
.pci_path
[0])
602 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.bcma_core
) < (int)sizeof(str
))
603 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
605 if (names
.pci_slot
[0])
606 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.bcma_core
) < (int)sizeof(str
))
607 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
614 const struct udev_builtin udev_builtin_net_id
= {
616 .cmd
= builtin_net_id
,
617 .help
= "Network device properties",