1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Kay Sievers <kay@vrfy.org>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 * Predictable network interface device names based on:
23 * - firmware/bios-provided index numbers for on-board devices
24 * - firmware-provided pci-express hotplug slot index number
25 * - physical/geographical location of the hardware
26 * - the interface's MAC address
28 * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
30 * Two character prefixes based on the type of interface:
32 * sl — serial line IP (slip)
37 * b<number> — BCMA bus core number
38 * c<bus_id> — bus id of a grouped CCW or CCW device,
39 * with all leading zeros stripped [s390]
40 * o<index>[n<phys_port_name>|d<dev_port>]
41 * — on-board device index number
42 * s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
43 * — hotplug slot index number
44 * x<MAC> — MAC address
45 * [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
46 * — PCI geographical location
47 * [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
48 * — USB port number chain
49 * v<slot> - VIO slot number (IBM PowerVM)
50 * a<vendor><model>i<instance> — Platform bus ACPI instance id
52 * All multi-function PCI devices will carry the [f<function>] number in the
53 * device name, including the function 0 device.
55 * When using PCI geography, The PCI domain is only prepended when it is not 0.
57 * For USB devices the full chain of port numbers of hubs is composed. If the
58 * name gets longer than the maximum number of 15 characters, the name is not
60 * The usual USB configuration == 1 and interface == 0 values are suppressed.
62 * PCI Ethernet card with firmware index "1":
63 * ID_NET_NAME_ONBOARD=eno1
64 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
66 * PCI Ethernet card in hotplug slot with firmware index number:
67 * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
68 * ID_NET_NAME_MAC=enx000000000466
69 * ID_NET_NAME_PATH=enp5s0
70 * ID_NET_NAME_SLOT=ens1
72 * PCI Ethernet multi-function card with 2 ports:
73 * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
74 * ID_NET_NAME_MAC=enx78e7d1ea46da
75 * ID_NET_NAME_PATH=enp2s0f0
76 * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
77 * ID_NET_NAME_MAC=enx78e7d1ea46dc
78 * ID_NET_NAME_PATH=enp2s0f1
81 * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
82 * ID_NET_NAME_MAC=wlx0024d7e31130
83 * ID_NET_NAME_PATH=wlp3s0
85 * USB built-in 3G modem:
86 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
87 * ID_NET_NAME_MAC=wwx028037ec0200
88 * ID_NET_NAME_PATH=wwp0s29u1u4i6
91 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
92 * ID_NET_NAME_MAC=enxd626b3450fb5
93 * ID_NET_NAME_PATH=enp0s29u1u2
95 * s390 grouped CCW interface:
96 * /sys/devices/css0/0.0.0007/0.0.f5f0/group_device/net/encf5f0
97 * ID_NET_NAME_MAC=enx026d3c00000a
98 * ID_NET_NAME_PATH=encf5f0
104 #include <net/if_arp.h>
110 #include <linux/pci_regs.h>
112 #include "dirent-util.h"
116 #include "parse-util.h"
117 #include "stdio-util.h"
118 #include "string-util.h"
120 #include "udev-util.h"
122 #define ONBOARD_INDEX_MAX (16*1024-1)
136 enum netname_type type
;
141 struct udev_device
*pcidev
;
142 char pci_slot
[IFNAMSIZ
];
143 char pci_path
[IFNAMSIZ
];
144 char pci_onboard
[IFNAMSIZ
];
145 const char *pci_onboard_label
;
147 char usb_ports
[IFNAMSIZ
];
148 char bcma_core
[IFNAMSIZ
];
149 char ccw_busid
[IFNAMSIZ
];
150 char vio_slot
[IFNAMSIZ
];
151 char platform_path
[IFNAMSIZ
];
155 struct udev_device
*physfn_pcidev
;
156 char suffix
[IFNAMSIZ
];
159 /* skip intermediate virtio devices */
160 static struct udev_device
*skip_virtio(struct udev_device
*dev
) {
161 struct udev_device
*parent
= dev
;
163 /* there can only ever be one virtio bus per parent device, so we can
164 safely ignore any virtio buses. see
165 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
166 while (parent
&& streq_ptr("virtio", udev_device_get_subsystem(parent
)))
167 parent
= udev_device_get_parent(parent
);
171 static int get_virtfn_info(struct udev_device
*dev
, struct netnames
*names
, struct virtfn_info
*vf_info
) {
173 const char *physfn_link_file
;
174 _cleanup_free_
char *physfn_pci_syspath
= NULL
;
175 _cleanup_free_
char *virtfn_pci_syspath
= NULL
;
177 _cleanup_closedir_
DIR *dir
= NULL
;
178 struct virtfn_info vf_info_local
= {};
181 udev
= udev_device_get_udev(names
->pcidev
);
184 /* Check if this is a virtual function. */
185 physfn_link_file
= strjoina(udev_device_get_syspath(names
->pcidev
), "/physfn");
186 r
= chase_symlinks(physfn_link_file
, NULL
, 0, &physfn_pci_syspath
);
190 /* Get physical function's pci device. */
191 vf_info_local
.physfn_pcidev
= udev_device_new_from_syspath(udev
, physfn_pci_syspath
);
192 if (!vf_info_local
.physfn_pcidev
)
195 /* Find the virtual function number by finding the right virtfn link. */
196 dir
= opendir(physfn_pci_syspath
);
201 FOREACH_DIRENT_ALL(dent
, dir
, break) {
202 _cleanup_free_
char *virtfn_link_file
= NULL
;
203 if (!startswith(dent
->d_name
, "virtfn"))
205 virtfn_link_file
= strjoin(physfn_pci_syspath
, "/", dent
->d_name
);
206 if (!virtfn_link_file
) {
210 if (chase_symlinks(virtfn_link_file
, NULL
, 0, &virtfn_pci_syspath
) < 0)
212 if (streq(udev_device_get_syspath(names
->pcidev
), virtfn_pci_syspath
)) {
213 if (!snprintf_ok(vf_info_local
.suffix
, sizeof(vf_info_local
.suffix
), "v%s", &dent
->d_name
[6])) {
220 if (isempty(vf_info_local
.suffix
)) {
224 *vf_info
= vf_info_local
;
228 udev_device_unref(vf_info_local
.physfn_pcidev
);
232 /* retrieve on-board index number and label from firmware */
233 static int dev_pci_onboard(struct udev_device
*dev
, struct netnames
*names
) {
234 unsigned dev_port
= 0;
237 const char *attr
, *port_name
;
240 /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
241 attr
= udev_device_get_sysattr_value(names
->pcidev
, "acpi_index");
242 /* SMBIOS type 41 — Onboard Devices Extended Information */
244 attr
= udev_device_get_sysattr_value(names
->pcidev
, "index");
248 idx
= strtoul(attr
, NULL
, 0);
252 /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
253 * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
254 * cut-off, which is somewhere beyond the realistic number of physical network interface a system might
255 * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */
256 if (idx
> ONBOARD_INDEX_MAX
)
259 /* kernel provided port index for multiple ports on a single PCI function */
260 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
262 dev_port
= strtol(attr
, NULL
, 10);
264 /* kernel provided front panel port name for multiple port PCI device */
265 port_name
= udev_device_get_sysattr_value(dev
, "phys_port_name");
267 s
= names
->pci_onboard
;
268 l
= sizeof(names
->pci_onboard
);
269 l
= strpcpyf(&s
, l
, "o%d", idx
);
271 l
= strpcpyf(&s
, l
, "n%s", port_name
);
272 else if (dev_port
> 0)
273 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
275 names
->pci_onboard
[0] = '\0';
277 names
->pci_onboard_label
= udev_device_get_sysattr_value(names
->pcidev
, "label");
282 /* read the 256 bytes PCI configuration space to check the multi-function bit */
283 static bool is_pci_multifunction(struct udev_device
*dev
) {
284 _cleanup_close_
int fd
= -1;
285 const char *filename
;
288 filename
= strjoina(udev_device_get_syspath(dev
), "/config");
289 fd
= open(filename
, O_RDONLY
| O_CLOEXEC
);
292 if (read(fd
, &config
, sizeof(config
)) != sizeof(config
))
295 /* bit 0-6 header type, bit 7 multi/single function device */
296 if ((config
[PCI_HEADER_TYPE
] & 0x80) != 0)
302 static bool is_pci_ari_enabled(struct udev_device
*dev
) {
303 return !!udev_device_get_sysattr_value(dev
, "ari_enabled");
306 static int dev_pci_slot(struct udev_device
*dev
, struct netnames
*names
) {
307 struct udev
*udev
= udev_device_get_udev(names
->pcidev
);
308 unsigned domain
, bus
, slot
, func
, dev_port
= 0, hotplug_slot
= 0;
311 const char *attr
, *port_name
;
312 _cleanup_udev_device_unref_
struct udev_device
*pci
= NULL
;
313 struct udev_device
*hotplug_slot_dev
;
314 char slots
[PATH_MAX
];
315 _cleanup_closedir_
DIR *dir
= NULL
;
318 if (sscanf(udev_device_get_sysname(names
->pcidev
), "%x:%x:%x.%u", &domain
, &bus
, &slot
, &func
) != 4)
320 if (is_pci_ari_enabled(names
->pcidev
))
321 /* ARI devices support up to 256 functions on a single device ("slot"), and interpret the
322 * traditional 5-bit slot and 3-bit function number as a single 8-bit function number,
323 * where the slot makes up the upper 5 bits. */
326 /* kernel provided port index for multiple ports on a single PCI function */
327 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
329 dev_port
= strtol(attr
, NULL
, 10);
331 /* kernel provided front panel port name for multiple port PCI device */
332 port_name
= udev_device_get_sysattr_value(dev
, "phys_port_name");
334 /* compose a name based on the raw kernel's PCI bus, slot numbers */
336 l
= sizeof(names
->pci_path
);
338 l
= strpcpyf(&s
, l
, "P%u", domain
);
339 l
= strpcpyf(&s
, l
, "p%us%u", bus
, slot
);
340 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
341 l
= strpcpyf(&s
, l
, "f%u", func
);
343 l
= strpcpyf(&s
, l
, "n%s", port_name
);
344 else if (dev_port
> 0)
345 l
= strpcpyf(&s
, l
, "d%u", dev_port
);
347 names
->pci_path
[0] = '\0';
349 /* ACPI _SUN — slot user number */
350 pci
= udev_device_new_from_subsystem_sysname(udev
, "subsystem", "pci");
354 if (!snprintf_ok(slots
, sizeof slots
, "%s/slots", udev_device_get_syspath(pci
)))
355 return -ENAMETOOLONG
;
357 dir
= opendir(slots
);
361 hotplug_slot_dev
= names
->pcidev
;
362 while (hotplug_slot_dev
) {
363 FOREACH_DIRENT_ALL(dent
, dir
, break) {
367 _cleanup_free_
char *address
= NULL
;
369 if (dent
->d_name
[0] == '.')
371 r
= safe_atou_full(dent
->d_name
, 10, &i
);
375 if (snprintf_ok(str
, sizeof str
, "%s/%s/address", slots
, dent
->d_name
) &&
376 read_one_line_file(str
, &address
) >= 0)
377 /* match slot address with device by stripping the function */
378 if (startswith(udev_device_get_sysname(hotplug_slot_dev
), address
))
381 if (hotplug_slot
> 0)
384 if (hotplug_slot
> 0)
387 hotplug_slot_dev
= udev_device_get_parent_with_subsystem_devtype(hotplug_slot_dev
, "pci", NULL
);
390 if (hotplug_slot
> 0) {
392 l
= sizeof(names
->pci_slot
);
394 l
= strpcpyf(&s
, l
, "P%d", domain
);
395 l
= strpcpyf(&s
, l
, "s%d", hotplug_slot
);
396 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
397 l
= strpcpyf(&s
, l
, "f%d", func
);
399 l
= strpcpyf(&s
, l
, "n%s", port_name
);
400 else if (dev_port
> 0)
401 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
403 names
->pci_slot
[0] = '\0';
409 static int names_vio(struct udev_device
*dev
, struct netnames
*names
) {
410 struct udev_device
*parent
;
411 unsigned busid
, slotid
, ethid
;
414 /* check if our direct parent is a VIO device with no other bus in-between */
415 parent
= udev_device_get_parent(dev
);
419 if (!streq_ptr("vio", udev_device_get_subsystem(parent
)))
422 /* The devices' $DEVPATH number is tied to (virtual) hardware (slot id
423 * selected in the HMC), thus this provides a reliable naming (e.g.
424 * "/devices/vio/30000002/net/eth1"); we ignore the bus number, as
425 * there should only ever be one bus, and then remove leading zeros. */
426 syspath
= udev_device_get_syspath(dev
);
428 if (sscanf(syspath
, "/sys/devices/vio/%4x%4x/net/eth%u", &busid
, &slotid
, ðid
) != 3)
431 xsprintf(names
->vio_slot
, "v%u", slotid
);
432 names
->type
= NET_VIO
;
436 #define _PLATFORM_TEST "/sys/devices/platform/vvvvPPPP"
437 #define _PLATFORM_PATTERN4 "/sys/devices/platform/%4s%4x:%2x/net/eth%u"
438 #define _PLATFORM_PATTERN3 "/sys/devices/platform/%3s%4x:%2x/net/eth%u"
440 static int names_platform(struct udev_device
*dev
, struct netnames
*names
, bool test
) {
441 struct udev_device
*parent
;
443 unsigned model
, instance
, ethid
;
444 const char *syspath
, *pattern
, *validchars
;
446 /* check if our direct parent is a platform device with no other bus in-between */
447 parent
= udev_device_get_parent(dev
);
451 if (!streq_ptr("platform", udev_device_get_subsystem(parent
)))
454 syspath
= udev_device_get_syspath(dev
);
456 /* syspath is too short, to have a valid ACPI instance */
457 if (strlen(syspath
) < sizeof _PLATFORM_TEST
)
460 /* Vendor ID can be either PNP ID (3 chars A-Z) or ACPI ID (4 chars A-Z and numerals) */
461 if (syspath
[sizeof _PLATFORM_TEST
- 1] == ':') {
462 pattern
= _PLATFORM_PATTERN4
;
463 validchars
= UPPERCASE_LETTERS DIGITS
;
465 pattern
= _PLATFORM_PATTERN3
;
466 validchars
= UPPERCASE_LETTERS
;
469 /* Platform devices are named after ACPI table match, and instance id
470 * eg. "/sys/devices/platform/HISI00C2:00");
471 * The Vendor (3 or 4 char), followed by hexdecimal model number : instance id.
474 #pragma GCC diagnostic push
475 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
476 if (sscanf(syspath
, pattern
, vendor
, &model
, &instance
, ðid
) != 4)
478 #pragma GCC diagnostic pop
480 if (!in_charset(vendor
, validchars
))
483 ascii_strlower(vendor
);
485 xsprintf(names
->platform_path
, "a%s%xi%u", vendor
, model
, instance
);
486 names
->type
= NET_PLATFORM
;
490 static int names_pci(struct udev_device
*dev
, struct netnames
*names
) {
491 struct udev_device
*parent
;
492 struct netnames vf_names
= {};
493 struct virtfn_info vf_info
= {};
498 parent
= udev_device_get_parent(dev
);
499 /* skip virtio subsystem if present */
500 parent
= skip_virtio(parent
);
505 /* check if our direct parent is a PCI device with no other bus in-between */
506 if (streq_ptr("pci", udev_device_get_subsystem(parent
))) {
507 names
->type
= NET_PCI
;
508 names
->pcidev
= parent
;
510 names
->pcidev
= udev_device_get_parent_with_subsystem_devtype(dev
, "pci", NULL
);
515 if (get_virtfn_info(dev
, names
, &vf_info
) >= 0) {
516 /* If this is an SR-IOV virtual device, get base name using physical device and add virtfn suffix. */
517 vf_names
.pcidev
= vf_info
.physfn_pcidev
;
518 dev_pci_onboard(dev
, &vf_names
);
519 dev_pci_slot(dev
, &vf_names
);
520 if (vf_names
.pci_onboard
[0])
521 if (strlen(vf_names
.pci_onboard
) + strlen(vf_info
.suffix
) < sizeof(names
->pci_onboard
))
522 strscpyl(names
->pci_onboard
, sizeof(names
->pci_onboard
),
523 vf_names
.pci_onboard
, vf_info
.suffix
, NULL
);
524 if (vf_names
.pci_slot
[0])
525 if (strlen(vf_names
.pci_slot
) + strlen(vf_info
.suffix
) < sizeof(names
->pci_slot
))
526 strscpyl(names
->pci_slot
, sizeof(names
->pci_slot
),
527 vf_names
.pci_slot
, vf_info
.suffix
, NULL
);
528 if (vf_names
.pci_path
[0])
529 if (strlen(vf_names
.pci_path
) + strlen(vf_info
.suffix
) < sizeof(names
->pci_path
))
530 strscpyl(names
->pci_path
, sizeof(names
->pci_path
),
531 vf_names
.pci_path
, vf_info
.suffix
, NULL
);
532 udev_device_unref(vf_info
.physfn_pcidev
);
534 dev_pci_onboard(dev
, names
);
535 dev_pci_slot(dev
, names
);
540 static int names_usb(struct udev_device
*dev
, struct netnames
*names
) {
541 struct udev_device
*usbdev
;
552 usbdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "usb", "usb_interface");
556 /* get USB port number chain, configuration, interface */
557 strscpy(name
, sizeof(name
), udev_device_get_sysname(usbdev
));
558 s
= strchr(name
, '-');
563 s
= strchr(ports
, ':');
569 s
= strchr(config
, '.');
575 /* prefix every port number in the chain with "u" */
577 while ((s
= strchr(s
, '.')))
579 s
= names
->usb_ports
;
580 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "u", ports
, NULL
);
582 /* append USB config number, suppress the common config == 1 */
583 if (!streq(config
, "1"))
584 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "c", config
, NULL
);
586 /* append USB interface number, suppress the interface == 0 */
587 if (!streq(interf
, "0"))
588 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "i", interf
, NULL
);
590 return -ENAMETOOLONG
;
592 names
->type
= NET_USB
;
596 static int names_bcma(struct udev_device
*dev
, struct netnames
*names
) {
597 struct udev_device
*bcmadev
;
603 bcmadev
= udev_device_get_parent_with_subsystem_devtype(dev
, "bcma", NULL
);
607 /* bus num:core num */
608 if (sscanf(udev_device_get_sysname(bcmadev
), "bcma%*u:%u", &core
) != 1)
610 /* suppress the common core == 0 */
612 xsprintf(names
->bcma_core
, "b%u", core
);
614 names
->type
= NET_BCMA
;
618 static int names_ccw(struct udev_device
*dev
, struct netnames
*names
) {
619 struct udev_device
*cdev
;
620 const char *bus_id
, *subsys
;
627 /* Retrieve the associated CCW device */
628 cdev
= udev_device_get_parent(dev
);
629 /* skip virtio subsystem if present */
630 cdev
= skip_virtio(cdev
);
634 /* Network devices are either single or grouped CCW devices */
635 subsys
= udev_device_get_subsystem(cdev
);
636 if (!STRPTR_IN_SET(subsys
, "ccwgroup", "ccw"))
639 /* Retrieve bus-ID of the CCW device. The bus-ID uniquely
640 * identifies the network device on the Linux on System z channel
641 * subsystem. Note that the bus-ID contains lowercase characters.
643 bus_id
= udev_device_get_sysname(cdev
);
647 /* Check the length of the bus-ID. Rely on that the kernel provides
648 * a correct bus-ID; alternatively, improve this check and parse and
649 * verify each bus-ID part...
651 bus_id_len
= strlen(bus_id
);
652 if (!IN_SET(bus_id_len
, 8, 9))
655 /* Strip leading zeros from the bus id for aesthetic purposes. This
656 * keeps the ccw names stable, yet much shorter in general case of
657 * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is
658 * not prepended when it is zero. Preserve the last 0 for 0.0.0000.
660 bus_id_start
= strspn(bus_id
, ".0");
661 bus_id
+= bus_id_start
< bus_id_len
? bus_id_start
: bus_id_len
- 1;
663 /* Store the CCW bus-ID for use as network device name */
664 if (snprintf_ok(names
->ccw_busid
, sizeof(names
->ccw_busid
), "c%s", bus_id
))
665 names
->type
= NET_CCW
;
670 static int names_mac(struct udev_device
*dev
, struct netnames
*names
) {
673 unsigned int a1
, a2
, a3
, a4
, a5
, a6
;
675 /* check for NET_ADDR_PERM, skip random MAC addresses */
676 s
= udev_device_get_sysattr_value(dev
, "addr_assign_type");
679 i
= strtoul(s
, NULL
, 0);
683 s
= udev_device_get_sysattr_value(dev
, "address");
686 if (sscanf(s
, "%x:%x:%x:%x:%x:%x", &a1
, &a2
, &a3
, &a4
, &a5
, &a6
) != 6)
689 /* skip empty MAC addresses */
690 if (a1
+ a2
+ a3
+ a4
+ a5
+ a6
== 0)
699 names
->mac_valid
= true;
703 /* IEEE Organizationally Unique Identifier vendor string */
704 static int ieee_oui(struct udev_device
*dev
, struct netnames
*names
, bool test
) {
707 if (!names
->mac_valid
)
709 /* skip commonly misused 00:00:00 (Xerox) prefix */
710 if (memcmp(names
->mac
, "\0\0\0", 3) == 0)
712 xsprintf(str
, "OUI:%02X%02X%02X%02X%02X%02X", names
->mac
[0],
713 names
->mac
[1], names
->mac
[2], names
->mac
[3], names
->mac
[4],
715 udev_builtin_hwdb_lookup(dev
, NULL
, str
, NULL
, test
);
719 static int builtin_net_id(struct udev_device
*dev
, int argc
, char *argv
[], bool test
) {
724 const char *prefix
= "en";
725 struct netnames names
= {};
728 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
729 s
= udev_device_get_sysattr_value(dev
, "type");
732 i
= strtoul(s
, NULL
, 0);
744 /* skip stacked devices, like VLANs, ... */
745 s
= udev_device_get_sysattr_value(dev
, "ifindex");
748 p
= udev_device_get_sysattr_value(dev
, "iflink");
754 devtype
= udev_device_get_devtype(dev
);
756 if (streq("wlan", devtype
))
758 else if (streq("wwan", devtype
))
762 err
= names_mac(dev
, &names
);
763 if (err
>= 0 && names
.mac_valid
) {
766 xsprintf(str
, "%sx%02x%02x%02x%02x%02x%02x", prefix
,
767 names
.mac
[0], names
.mac
[1], names
.mac
[2],
768 names
.mac
[3], names
.mac
[4], names
.mac
[5]);
769 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_MAC", str
);
771 ieee_oui(dev
, &names
, test
);
774 /* get path names for Linux on System z network devices */
775 err
= names_ccw(dev
, &names
);
776 if (err
>= 0 && names
.type
== NET_CCW
) {
779 if (snprintf_ok(str
, sizeof str
, "%s%s", prefix
, names
.ccw_busid
))
780 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
784 /* get ibmveth/ibmvnic slot-based names. */
785 err
= names_vio(dev
, &names
);
786 if (err
>= 0 && names
.type
== NET_VIO
) {
789 if (snprintf_ok(str
, sizeof str
, "%s%s", prefix
, names
.vio_slot
))
790 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
794 /* get ACPI path names for ARM64 platform devices */
795 err
= names_platform(dev
, &names
, test
);
796 if (err
>= 0 && names
.type
== NET_PLATFORM
) {
799 if (snprintf_ok(str
, sizeof str
, "%s%s", prefix
, names
.platform_path
))
800 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
804 /* get PCI based path names, we compose only PCI based paths */
805 err
= names_pci(dev
, &names
);
809 /* plain PCI device */
810 if (names
.type
== NET_PCI
) {
813 if (names
.pci_onboard
[0] &&
814 snprintf_ok(str
, sizeof str
, "%s%s", prefix
, names
.pci_onboard
))
815 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_ONBOARD", str
);
817 if (names
.pci_onboard_label
&&
818 snprintf_ok(str
, sizeof str
, "%s%s", prefix
, names
.pci_onboard_label
))
819 udev_builtin_add_property(dev
, test
, "ID_NET_LABEL_ONBOARD", str
);
821 if (names
.pci_path
[0] &&
822 snprintf_ok(str
, sizeof str
, "%s%s", prefix
, names
.pci_path
))
823 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
825 if (names
.pci_slot
[0] &&
826 snprintf_ok(str
, sizeof str
, "%s%s", prefix
, names
.pci_slot
))
827 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
832 err
= names_usb(dev
, &names
);
833 if (err
>= 0 && names
.type
== NET_USB
) {
836 if (names
.pci_path
[0] &&
837 snprintf_ok(str
, sizeof str
, "%s%s%s", prefix
, names
.pci_path
, names
.usb_ports
))
838 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
840 if (names
.pci_slot
[0] &&
841 snprintf_ok(str
, sizeof str
, "%s%s%s", prefix
, names
.pci_slot
, names
.usb_ports
))
842 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
847 err
= names_bcma(dev
, &names
);
848 if (err
>= 0 && names
.type
== NET_BCMA
) {
851 if (names
.pci_path
[0] &&
852 snprintf_ok(str
, sizeof str
, "%s%s%s", prefix
, names
.pci_path
, names
.bcma_core
))
853 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
855 if (names
.pci_slot
[0] &&
856 snprintf(str
, sizeof str
, "%s%s%s", prefix
, names
.pci_slot
, names
.bcma_core
))
857 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
864 const struct udev_builtin udev_builtin_net_id
= {
866 .cmd
= builtin_net_id
,
867 .help
= "Network device properties",