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"
119 enum netname_type type
;
124 struct udev_device
*pcidev
;
125 char pci_slot
[IFNAMSIZ
];
126 char pci_path
[IFNAMSIZ
];
127 char pci_onboard
[IFNAMSIZ
];
128 const char *pci_onboard_label
;
130 char usb_ports
[IFNAMSIZ
];
131 char bcma_core
[IFNAMSIZ
];
132 char ccw_group
[IFNAMSIZ
];
135 /* retrieve on-board index number and label from firmware */
136 static int dev_pci_onboard(struct udev_device
*dev
, struct netnames
*names
) {
137 unsigned dev_port
= 0;
143 /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
144 attr
= udev_device_get_sysattr_value(names
->pcidev
, "acpi_index");
145 /* SMBIOS type 41 -- Onboard Devices Extended Information */
147 attr
= udev_device_get_sysattr_value(names
->pcidev
, "index");
151 idx
= strtoul(attr
, NULL
, 0);
155 /* kernel provided port index for multiple ports on a single PCI function */
156 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
158 dev_port
= strtol(attr
, NULL
, 10);
160 s
= names
->pci_onboard
;
161 l
= sizeof(names
->pci_onboard
);
162 l
= strpcpyf(&s
, l
, "o%d", idx
);
164 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
166 names
->pci_onboard
[0] = '\0';
168 names
->pci_onboard_label
= udev_device_get_sysattr_value(names
->pcidev
, "label");
173 /* read the 256 bytes PCI configuration space to check the multi-function bit */
174 static bool is_pci_multifunction(struct udev_device
*dev
) {
175 _cleanup_close_
int fd
= -1;
176 const char *filename
;
179 filename
= strjoina(udev_device_get_syspath(dev
), "/config");
180 fd
= open(filename
, O_RDONLY
| O_CLOEXEC
);
183 if (read(fd
, &config
, sizeof(config
)) != sizeof(config
))
186 /* bit 0-6 header type, bit 7 multi/single function device */
187 if ((config
[PCI_HEADER_TYPE
] & 0x80) != 0)
193 static int dev_pci_slot(struct udev_device
*dev
, struct netnames
*names
) {
194 struct udev
*udev
= udev_device_get_udev(names
->pcidev
);
195 unsigned domain
, bus
, slot
, func
, dev_port
= 0;
199 struct udev_device
*pci
= NULL
;
200 char slots
[256], str
[256];
201 _cleanup_closedir_
DIR *dir
= NULL
;
203 int hotplug_slot
= 0, err
= 0;
205 if (sscanf(udev_device_get_sysname(names
->pcidev
), "%x:%x:%x.%u", &domain
, &bus
, &slot
, &func
) != 4)
208 /* kernel provided port index for multiple ports on a single PCI function */
209 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
211 dev_port
= strtol(attr
, NULL
, 10);
213 /* compose a name based on the raw kernel's PCI bus, slot numbers */
215 l
= sizeof(names
->pci_path
);
217 l
= strpcpyf(&s
, l
, "P%u", domain
);
218 l
= strpcpyf(&s
, l
, "p%us%u", bus
, slot
);
219 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
220 l
= strpcpyf(&s
, l
, "f%u", func
);
222 l
= strpcpyf(&s
, l
, "d%u", dev_port
);
224 names
->pci_path
[0] = '\0';
226 /* ACPI _SUN -- slot user number */
227 pci
= udev_device_new_from_subsystem_sysname(udev
, "subsystem", "pci");
232 xsprintf(slots
, "%s/slots", udev_device_get_syspath(pci
));
233 dir
= opendir(slots
);
239 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
244 if (dent
->d_name
[0] == '.')
246 i
= strtol(dent
->d_name
, &rest
, 10);
251 xsprintf(str
, "%s/%s/address", slots
, dent
->d_name
);
252 if (read_one_line_file(str
, &address
) >= 0) {
253 /* match slot address with device by stripping the function */
254 if (strneq(address
, udev_device_get_sysname(names
->pcidev
), strlen(address
)))
259 if (hotplug_slot
> 0)
263 if (hotplug_slot
> 0) {
265 l
= sizeof(names
->pci_slot
);
267 l
= strpcpyf(&s
, l
, "P%d", domain
);
268 l
= strpcpyf(&s
, l
, "s%d", hotplug_slot
);
269 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
270 l
= strpcpyf(&s
, l
, "f%d", func
);
272 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
274 names
->pci_slot
[0] = '\0';
277 udev_device_unref(pci
);
281 static int names_pci(struct udev_device
*dev
, struct netnames
*names
) {
282 struct udev_device
*parent
;
287 parent
= udev_device_get_parent(dev
);
289 /* there can only ever be one virtio bus per parent device, so we can
290 safely ignore any virtio buses. see
291 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
292 while (parent
&& streq_ptr("virtio", udev_device_get_subsystem(parent
)))
293 parent
= udev_device_get_parent(parent
);
298 /* check if our direct parent is a PCI device with no other bus in-between */
299 if (streq_ptr("pci", udev_device_get_subsystem(parent
))) {
300 names
->type
= NET_PCI
;
301 names
->pcidev
= parent
;
303 names
->pcidev
= udev_device_get_parent_with_subsystem_devtype(dev
, "pci", NULL
);
307 dev_pci_onboard(dev
, names
);
308 dev_pci_slot(dev
, names
);
312 static int names_usb(struct udev_device
*dev
, struct netnames
*names
) {
313 struct udev_device
*usbdev
;
324 usbdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "usb", "usb_interface");
328 /* get USB port number chain, configuration, interface */
329 strscpy(name
, sizeof(name
), udev_device_get_sysname(usbdev
));
330 s
= strchr(name
, '-');
335 s
= strchr(ports
, ':');
341 s
= strchr(config
, '.');
347 /* prefix every port number in the chain with "u" */
349 while ((s
= strchr(s
, '.')))
351 s
= names
->usb_ports
;
352 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "u", ports
, NULL
);
354 /* append USB config number, suppress the common config == 1 */
355 if (!streq(config
, "1"))
356 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "c", config
, NULL
);
358 /* append USB interface number, suppress the interface == 0 */
359 if (!streq(interf
, "0"))
360 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "i", interf
, NULL
);
362 return -ENAMETOOLONG
;
364 names
->type
= NET_USB
;
368 static int names_bcma(struct udev_device
*dev
, struct netnames
*names
) {
369 struct udev_device
*bcmadev
;
375 bcmadev
= udev_device_get_parent_with_subsystem_devtype(dev
, "bcma", NULL
);
379 /* bus num:core num */
380 if (sscanf(udev_device_get_sysname(bcmadev
), "bcma%*u:%u", &core
) != 1)
382 /* suppress the common core == 0 */
384 xsprintf(names
->bcma_core
, "b%u", core
);
386 names
->type
= NET_BCMA
;
390 static int names_ccw(struct udev_device
*dev
, struct netnames
*names
) {
391 struct udev_device
*cdev
;
399 /* Retrieve the associated CCW device */
400 cdev
= udev_device_get_parent(dev
);
404 /* Network devices are always grouped CCW devices */
405 if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev
)))
408 /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
409 * identifies the network device on the Linux on System z channel
410 * subsystem. Note that the bus-ID contains lowercase characters.
412 bus_id
= udev_device_get_sysname(cdev
);
416 /* Check the length of the bus-ID. Rely on that the kernel provides
417 * a correct bus-ID; alternatively, improve this check and parse and
418 * verify each bus-ID part...
420 bus_id_len
= strlen(bus_id
);
421 if (!bus_id_len
|| bus_id_len
< 8 || bus_id_len
> 9)
424 /* Store the CCW bus-ID for use as network device name */
425 rc
= snprintf(names
->ccw_group
, sizeof(names
->ccw_group
), "ccw%s", bus_id
);
426 if (rc
>= 0 && rc
< (int)sizeof(names
->ccw_group
))
427 names
->type
= NET_CCWGROUP
;
431 static int names_mac(struct udev_device
*dev
, struct netnames
*names
) {
434 unsigned int a1
, a2
, a3
, a4
, a5
, a6
;
436 /* check for NET_ADDR_PERM, skip random MAC addresses */
437 s
= udev_device_get_sysattr_value(dev
, "addr_assign_type");
440 i
= strtoul(s
, NULL
, 0);
444 s
= udev_device_get_sysattr_value(dev
, "address");
447 if (sscanf(s
, "%x:%x:%x:%x:%x:%x", &a1
, &a2
, &a3
, &a4
, &a5
, &a6
) != 6)
450 /* skip empty MAC addresses */
451 if (a1
+ a2
+ a3
+ a4
+ a5
+ a6
== 0)
460 names
->mac_valid
= true;
464 /* IEEE Organizationally Unique Identifier vendor string */
465 static int ieee_oui(struct udev_device
*dev
, struct netnames
*names
, bool test
) {
468 if (!names
->mac_valid
)
470 /* skip commonly misused 00:00:00 (Xerox) prefix */
471 if (memcmp(names
->mac
, "\0\0\0", 3) == 0)
473 xsprintf(str
, "OUI:%02X%02X%02X%02X%02X%02X", names
->mac
[0],
474 names
->mac
[1], names
->mac
[2], names
->mac
[3], names
->mac
[4],
476 udev_builtin_hwdb_lookup(dev
, NULL
, str
, NULL
, test
);
480 static int builtin_net_id(struct udev_device
*dev
, int argc
, char *argv
[], bool test
) {
485 const char *prefix
= "en";
486 struct netnames names
= {};
489 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
490 s
= udev_device_get_sysattr_value(dev
, "type");
493 i
= strtoul(s
, NULL
, 0);
505 /* skip stacked devices, like VLANs, ... */
506 s
= udev_device_get_sysattr_value(dev
, "ifindex");
509 p
= udev_device_get_sysattr_value(dev
, "iflink");
515 devtype
= udev_device_get_devtype(dev
);
517 if (streq("wlan", devtype
))
519 else if (streq("wwan", devtype
))
523 err
= names_mac(dev
, &names
);
524 if (err
>= 0 && names
.mac_valid
) {
527 xsprintf(str
, "%sx%02x%02x%02x%02x%02x%02x", prefix
,
528 names
.mac
[0], names
.mac
[1], names
.mac
[2],
529 names
.mac
[3], names
.mac
[4], names
.mac
[5]);
530 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_MAC", str
);
532 ieee_oui(dev
, &names
, test
);
535 /* get path names for Linux on System z network devices */
536 err
= names_ccw(dev
, &names
);
537 if (err
>= 0 && names
.type
== NET_CCWGROUP
) {
540 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.ccw_group
) < (int)sizeof(str
))
541 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
545 /* get PCI based path names, we compose only PCI based paths */
546 err
= names_pci(dev
, &names
);
550 /* plain PCI device */
551 if (names
.type
== NET_PCI
) {
554 if (names
.pci_onboard
[0])
555 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard
) < (int)sizeof(str
))
556 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_ONBOARD", str
);
558 if (names
.pci_onboard_label
)
559 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard_label
) < (int)sizeof(str
))
560 udev_builtin_add_property(dev
, test
, "ID_NET_LABEL_ONBOARD", str
);
562 if (names
.pci_path
[0])
563 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_path
) < (int)sizeof(str
))
564 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
566 if (names
.pci_slot
[0])
567 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_slot
) < (int)sizeof(str
))
568 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
573 err
= names_usb(dev
, &names
);
574 if (err
>= 0 && names
.type
== NET_USB
) {
577 if (names
.pci_path
[0])
578 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.usb_ports
) < (int)sizeof(str
))
579 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
581 if (names
.pci_slot
[0])
582 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.usb_ports
) < (int)sizeof(str
))
583 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
588 err
= names_bcma(dev
, &names
);
589 if (err
>= 0 && names
.type
== NET_BCMA
) {
592 if (names
.pci_path
[0])
593 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.bcma_core
) < (int)sizeof(str
))
594 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
596 if (names
.pci_slot
[0])
597 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.bcma_core
) < (int)sizeof(str
))
598 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
605 const struct udev_builtin udev_builtin_net_id
= {
607 .cmd
= builtin_net_id
,
608 .help
= "Network device properties",