]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udev-builtin-net_id.c
Merge pull request #4835 from poettering/unit-name-printf
[thirdparty/systemd.git] / src / udev / udev-builtin-net_id.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2012 Kay Sievers <kay@vrfy.org>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 /*
21 * Predictable network interface device names based on:
22 * - firmware/bios-provided index numbers for on-board devices
23 * - firmware-provided pci-express hotplug slot index number
24 * - physical/geographical location of the hardware
25 * - the interface's MAC address
26 *
27 * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
28 *
29 * Two character prefixes based on the type of interface:
30 * en — Ethernet
31 * sl — serial line IP (slip)
32 * wl — wlan
33 * ww — wwan
34 *
35 * Type of names:
36 * b<number> — BCMA bus core number
37 * c<bus_id> — CCW bus group name, without leading zeros [s390]
38 * o<index>[n<phys_port_name>|d<dev_port>]
39 * — on-board device index number
40 * s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
41 * — hotplug slot index number
42 * x<MAC> — MAC address
43 * [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|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
47 *
48 * All multi-function PCI devices will carry the [f<function>] number in the
49 * device name, including the function 0 device.
50 *
51 * When using PCI geography, The PCI domain is only prepended when it is not 0.
52 *
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
55 * exported.
56 * The usual USB configuration == 1 and interface == 0 values are suppressed.
57 *
58 * PCI Ethernet card with firmware index "1":
59 * ID_NET_NAME_ONBOARD=eno1
60 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
61 *
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
67 *
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
75 *
76 * PCI wlan card:
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
80 *
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
85 *
86 * USB Android phone:
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
90 */
91
92 #include <errno.h>
93 #include <fcntl.h>
94 #include <net/if.h>
95 #include <net/if_arp.h>
96 #include <stdarg.h>
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include <string.h>
100 #include <unistd.h>
101 #include <linux/pci_regs.h>
102
103 #include "dirent-util.h"
104 #include "fd-util.h"
105 #include "fileio.h"
106 #include "stdio-util.h"
107 #include "string-util.h"
108 #include "udev.h"
109
110 #define ONBOARD_INDEX_MAX (16*1024-1)
111
112 enum netname_type{
113 NET_UNDEF,
114 NET_PCI,
115 NET_USB,
116 NET_BCMA,
117 NET_VIRTIO,
118 NET_CCWGROUP,
119 };
120
121 struct netnames {
122 enum netname_type type;
123
124 uint8_t mac[6];
125 bool mac_valid;
126
127 struct udev_device *pcidev;
128 char pci_slot[IFNAMSIZ];
129 char pci_path[IFNAMSIZ];
130 char pci_onboard[IFNAMSIZ];
131 const char *pci_onboard_label;
132
133 char usb_ports[IFNAMSIZ];
134 char bcma_core[IFNAMSIZ];
135 char ccw_group[IFNAMSIZ];
136 };
137
138 /* retrieve on-board index number and label from firmware */
139 static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
140 unsigned dev_port = 0;
141 size_t l;
142 char *s;
143 const char *attr, *port_name;
144 int idx;
145
146 /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
147 attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
148 /* SMBIOS type 41 — Onboard Devices Extended Information */
149 if (!attr)
150 attr = udev_device_get_sysattr_value(names->pcidev, "index");
151 if (!attr)
152 return -ENOENT;
153
154 idx = strtoul(attr, NULL, 0);
155 if (idx <= 0)
156 return -EINVAL;
157
158 /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
159 * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
160 * cut-off, which is somewhere beyond the realistic number of physical network interface a system might
161 * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */
162 if (idx > ONBOARD_INDEX_MAX)
163 return -ENOENT;
164
165 /* kernel provided port index for multiple ports on a single PCI function */
166 attr = udev_device_get_sysattr_value(dev, "dev_port");
167 if (attr)
168 dev_port = strtol(attr, NULL, 10);
169
170 /* kernel provided front panel port name for multiple port PCI device */
171 port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
172
173 s = names->pci_onboard;
174 l = sizeof(names->pci_onboard);
175 l = strpcpyf(&s, l, "o%d", idx);
176 if (port_name)
177 l = strpcpyf(&s, l, "n%s", port_name);
178 else if (dev_port > 0)
179 l = strpcpyf(&s, l, "d%d", dev_port);
180 if (l == 0)
181 names->pci_onboard[0] = '\0';
182
183 names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
184
185 return 0;
186 }
187
188 /* read the 256 bytes PCI configuration space to check the multi-function bit */
189 static bool is_pci_multifunction(struct udev_device *dev) {
190 _cleanup_close_ int fd = -1;
191 const char *filename;
192 uint8_t config[64];
193
194 filename = strjoina(udev_device_get_syspath(dev), "/config");
195 fd = open(filename, O_RDONLY | O_CLOEXEC);
196 if (fd < 0)
197 return false;
198 if (read(fd, &config, sizeof(config)) != sizeof(config))
199 return false;
200
201 /* bit 0-6 header type, bit 7 multi/single function device */
202 if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
203 return true;
204
205 return false;
206 }
207
208 static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
209 struct udev *udev = udev_device_get_udev(names->pcidev);
210 unsigned domain, bus, slot, func, dev_port = 0;
211 size_t l;
212 char *s;
213 const char *attr, *port_name;
214 struct udev_device *pci = NULL;
215 char slots[PATH_MAX];
216 _cleanup_closedir_ DIR *dir = NULL;
217 struct dirent *dent;
218 int hotplug_slot = 0, err = 0;
219
220 if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
221 return -ENOENT;
222
223 /* kernel provided port index for multiple ports on a single PCI function */
224 attr = udev_device_get_sysattr_value(dev, "dev_port");
225 if (attr)
226 dev_port = strtol(attr, NULL, 10);
227
228 /* kernel provided front panel port name for multiple port PCI device */
229 port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
230
231 /* compose a name based on the raw kernel's PCI bus, slot numbers */
232 s = names->pci_path;
233 l = sizeof(names->pci_path);
234 if (domain > 0)
235 l = strpcpyf(&s, l, "P%u", domain);
236 l = strpcpyf(&s, l, "p%us%u", bus, slot);
237 if (func > 0 || is_pci_multifunction(names->pcidev))
238 l = strpcpyf(&s, l, "f%u", func);
239 if (port_name)
240 l = strpcpyf(&s, l, "n%s", port_name);
241 else if (dev_port > 0)
242 l = strpcpyf(&s, l, "d%u", dev_port);
243 if (l == 0)
244 names->pci_path[0] = '\0';
245
246 /* ACPI _SUN — slot user number */
247 pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
248 if (!pci) {
249 err = -ENOENT;
250 goto out;
251 }
252
253 snprintf(slots, sizeof slots, "%s/slots", udev_device_get_syspath(pci));
254 dir = opendir(slots);
255 if (!dir) {
256 err = -errno;
257 goto out;
258 }
259
260 FOREACH_DIRENT_ALL(dent, dir, break) {
261 int i;
262 char *rest, *address, str[PATH_MAX];
263
264 if (dent->d_name[0] == '.')
265 continue;
266 i = strtol(dent->d_name, &rest, 10);
267 if (rest[0] != '\0')
268 continue;
269 if (i < 1)
270 continue;
271
272 snprintf(str, sizeof str, "%s/%s/address", slots, dent->d_name);
273 if (read_one_line_file(str, &address) >= 0) {
274 /* match slot address with device by stripping the function */
275 if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address)))
276 hotplug_slot = i;
277 free(address);
278 }
279
280 if (hotplug_slot > 0)
281 break;
282 }
283
284 if (hotplug_slot > 0) {
285 s = names->pci_slot;
286 l = sizeof(names->pci_slot);
287 if (domain > 0)
288 l = strpcpyf(&s, l, "P%d", domain);
289 l = strpcpyf(&s, l, "s%d", hotplug_slot);
290 if (func > 0 || is_pci_multifunction(names->pcidev))
291 l = strpcpyf(&s, l, "f%d", func);
292 if (port_name)
293 l = strpcpyf(&s, l, "n%s", port_name);
294 else if (dev_port > 0)
295 l = strpcpyf(&s, l, "d%d", dev_port);
296 if (l == 0)
297 names->pci_slot[0] = '\0';
298 }
299 out:
300 udev_device_unref(pci);
301 return err;
302 }
303
304 static int names_pci(struct udev_device *dev, struct netnames *names) {
305 struct udev_device *parent;
306
307 assert(dev);
308 assert(names);
309
310 parent = udev_device_get_parent(dev);
311
312 /* there can only ever be one virtio bus per parent device, so we can
313 safely ignore any virtio buses. see
314 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
315 while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
316 parent = udev_device_get_parent(parent);
317
318 if (!parent)
319 return -ENOENT;
320
321 /* check if our direct parent is a PCI device with no other bus in-between */
322 if (streq_ptr("pci", udev_device_get_subsystem(parent))) {
323 names->type = NET_PCI;
324 names->pcidev = parent;
325 } else {
326 names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
327 if (!names->pcidev)
328 return -ENOENT;
329 }
330 dev_pci_onboard(dev, names);
331 dev_pci_slot(dev, names);
332 return 0;
333 }
334
335 static int names_usb(struct udev_device *dev, struct netnames *names) {
336 struct udev_device *usbdev;
337 char name[256];
338 char *ports;
339 char *config;
340 char *interf;
341 size_t l;
342 char *s;
343
344 assert(dev);
345 assert(names);
346
347 usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
348 if (!usbdev)
349 return -ENOENT;
350
351 /* get USB port number chain, configuration, interface */
352 strscpy(name, sizeof(name), udev_device_get_sysname(usbdev));
353 s = strchr(name, '-');
354 if (!s)
355 return -EINVAL;
356 ports = s+1;
357
358 s = strchr(ports, ':');
359 if (!s)
360 return -EINVAL;
361 s[0] = '\0';
362 config = s+1;
363
364 s = strchr(config, '.');
365 if (!s)
366 return -EINVAL;
367 s[0] = '\0';
368 interf = s+1;
369
370 /* prefix every port number in the chain with "u" */
371 s = ports;
372 while ((s = strchr(s, '.')))
373 s[0] = 'u';
374 s = names->usb_ports;
375 l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
376
377 /* append USB config number, suppress the common config == 1 */
378 if (!streq(config, "1"))
379 l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
380
381 /* append USB interface number, suppress the interface == 0 */
382 if (!streq(interf, "0"))
383 l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
384 if (l == 0)
385 return -ENAMETOOLONG;
386
387 names->type = NET_USB;
388 return 0;
389 }
390
391 static int names_bcma(struct udev_device *dev, struct netnames *names) {
392 struct udev_device *bcmadev;
393 unsigned int core;
394
395 assert(dev);
396 assert(names);
397
398 bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
399 if (!bcmadev)
400 return -ENOENT;
401
402 /* bus num:core num */
403 if (sscanf(udev_device_get_sysname(bcmadev), "bcma%*u:%u", &core) != 1)
404 return -EINVAL;
405 /* suppress the common core == 0 */
406 if (core > 0)
407 xsprintf(names->bcma_core, "b%u", core);
408
409 names->type = NET_BCMA;
410 return 0;
411 }
412
413 static int names_ccw(struct udev_device *dev, struct netnames *names) {
414 struct udev_device *cdev;
415 const char *bus_id;
416 size_t bus_id_len;
417 int rc;
418
419 assert(dev);
420 assert(names);
421
422 /* Retrieve the associated CCW device */
423 cdev = udev_device_get_parent(dev);
424 if (!cdev)
425 return -ENOENT;
426
427 /* Network devices are always grouped CCW devices */
428 if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev)))
429 return -ENOENT;
430
431 /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
432 * identifies the network device on the Linux on System z channel
433 * subsystem. Note that the bus-ID contains lowercase characters.
434 */
435 bus_id = udev_device_get_sysname(cdev);
436 if (!bus_id)
437 return -ENOENT;
438
439 /* Check the length of the bus-ID. Rely on that the kernel provides
440 * a correct bus-ID; alternatively, improve this check and parse and
441 * verify each bus-ID part...
442 */
443 bus_id_len = strlen(bus_id);
444 if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9)
445 return -EINVAL;
446
447 /* Strip leading zeros from the bus id for aesthetic purposes. This
448 * keeps the ccw names stable, yet much shorter in general case of
449 * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is
450 * not prepended when it is zero.
451 */
452 bus_id += strspn(bus_id, ".0");
453
454 /* Store the CCW bus-ID for use as network device name */
455 rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "c%s", bus_id);
456 if (rc >= 0 && rc < (int)sizeof(names->ccw_group))
457 names->type = NET_CCWGROUP;
458 return 0;
459 }
460
461 static int names_mac(struct udev_device *dev, struct netnames *names) {
462 const char *s;
463 unsigned int i;
464 unsigned int a1, a2, a3, a4, a5, a6;
465
466 /* check for NET_ADDR_PERM, skip random MAC addresses */
467 s = udev_device_get_sysattr_value(dev, "addr_assign_type");
468 if (!s)
469 return EXIT_FAILURE;
470 i = strtoul(s, NULL, 0);
471 if (i != 0)
472 return 0;
473
474 s = udev_device_get_sysattr_value(dev, "address");
475 if (!s)
476 return -ENOENT;
477 if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
478 return -EINVAL;
479
480 /* skip empty MAC addresses */
481 if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
482 return -EINVAL;
483
484 names->mac[0] = a1;
485 names->mac[1] = a2;
486 names->mac[2] = a3;
487 names->mac[3] = a4;
488 names->mac[4] = a5;
489 names->mac[5] = a6;
490 names->mac_valid = true;
491 return 0;
492 }
493
494 /* IEEE Organizationally Unique Identifier vendor string */
495 static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
496 char str[32];
497
498 if (!names->mac_valid)
499 return -ENOENT;
500 /* skip commonly misused 00:00:00 (Xerox) prefix */
501 if (memcmp(names->mac, "\0\0\0", 3) == 0)
502 return -EINVAL;
503 xsprintf(str, "OUI:%02X%02X%02X%02X%02X%02X", names->mac[0],
504 names->mac[1], names->mac[2], names->mac[3], names->mac[4],
505 names->mac[5]);
506 udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test);
507 return 0;
508 }
509
510 static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
511 const char *s;
512 const char *p;
513 unsigned int i;
514 const char *devtype;
515 const char *prefix = "en";
516 struct netnames names = {};
517 int err;
518
519 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
520 s = udev_device_get_sysattr_value(dev, "type");
521 if (!s)
522 return EXIT_FAILURE;
523 i = strtoul(s, NULL, 0);
524 switch (i) {
525 case ARPHRD_ETHER:
526 prefix = "en";
527 break;
528 case ARPHRD_SLIP:
529 prefix = "sl";
530 break;
531 default:
532 return 0;
533 }
534
535 /* skip stacked devices, like VLANs, ... */
536 s = udev_device_get_sysattr_value(dev, "ifindex");
537 if (!s)
538 return EXIT_FAILURE;
539 p = udev_device_get_sysattr_value(dev, "iflink");
540 if (!p)
541 return EXIT_FAILURE;
542 if (!streq(s, p))
543 return 0;
544
545 devtype = udev_device_get_devtype(dev);
546 if (devtype) {
547 if (streq("wlan", devtype))
548 prefix = "wl";
549 else if (streq("wwan", devtype))
550 prefix = "ww";
551 }
552
553 err = names_mac(dev, &names);
554 if (err >= 0 && names.mac_valid) {
555 char str[IFNAMSIZ];
556
557 xsprintf(str, "%sx%02x%02x%02x%02x%02x%02x", prefix,
558 names.mac[0], names.mac[1], names.mac[2],
559 names.mac[3], names.mac[4], names.mac[5]);
560 udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
561
562 ieee_oui(dev, &names, test);
563 }
564
565 /* get path names for Linux on System z network devices */
566 err = names_ccw(dev, &names);
567 if (err >= 0 && names.type == NET_CCWGROUP) {
568 char str[IFNAMSIZ];
569
570 if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str))
571 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
572 goto out;
573 }
574
575 /* get PCI based path names, we compose only PCI based paths */
576 err = names_pci(dev, &names);
577 if (err < 0)
578 goto out;
579
580 /* plain PCI device */
581 if (names.type == NET_PCI) {
582 char str[IFNAMSIZ];
583
584 if (names.pci_onboard[0])
585 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
586 udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
587
588 if (names.pci_onboard_label)
589 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
590 udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
591
592 if (names.pci_path[0])
593 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
594 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
595
596 if (names.pci_slot[0])
597 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
598 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
599 goto out;
600 }
601
602 /* USB device */
603 err = names_usb(dev, &names);
604 if (err >= 0 && names.type == NET_USB) {
605 char str[IFNAMSIZ];
606
607 if (names.pci_path[0])
608 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
609 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
610
611 if (names.pci_slot[0])
612 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
613 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
614 goto out;
615 }
616
617 /* Broadcom bus */
618 err = names_bcma(dev, &names);
619 if (err >= 0 && names.type == NET_BCMA) {
620 char str[IFNAMSIZ];
621
622 if (names.pci_path[0])
623 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str))
624 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
625
626 if (names.pci_slot[0])
627 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str))
628 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
629 goto out;
630 }
631 out:
632 return EXIT_SUCCESS;
633 }
634
635 const struct udev_builtin udev_builtin_net_id = {
636 .name = "net_id",
637 .cmd = builtin_net_id,
638 .help = "Network device properties",
639 };