]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udev-builtin-net_id.c
Merge pull request #2435 from evverx/tests-setup-selinux
[thirdparty/systemd.git] / src / udev / udev-builtin-net_id.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Kay Sievers <kay@vrfy.org>
7
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.
12
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.
17
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/>.
20 ***/
21
22 /*
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
28 *
29 * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
30 *
31 * Two character prefixes based on the type of interface:
32 * en -- Ethernet
33 * sl -- serial line IP (slip)
34 * wl -- wlan
35 * ww -- wwan
36 *
37 * Type of names:
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
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 "fd-util.h"
104 #include "fileio.h"
105 #include "stdio-util.h"
106 #include "string-util.h"
107 #include "udev.h"
108
109 #define ONBOARD_INDEX_MAX (16*1024-1)
110
111 enum netname_type{
112 NET_UNDEF,
113 NET_PCI,
114 NET_USB,
115 NET_BCMA,
116 NET_VIRTIO,
117 NET_CCWGROUP,
118 };
119
120 struct netnames {
121 enum netname_type type;
122
123 uint8_t mac[6];
124 bool mac_valid;
125
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;
131
132 char usb_ports[IFNAMSIZ];
133 char bcma_core[IFNAMSIZ];
134 char ccw_group[IFNAMSIZ];
135 };
136
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;
140 size_t l;
141 char *s;
142 const char *attr;
143 int idx;
144
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 */
148 if (!attr)
149 attr = udev_device_get_sysattr_value(names->pcidev, "index");
150 if (!attr)
151 return -ENOENT;
152
153 idx = strtoul(attr, NULL, 0);
154 if (idx <= 0)
155 return -EINVAL;
156
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)
162 return -ENOENT;
163
164 /* kernel provided port index for multiple ports on a single PCI function */
165 attr = udev_device_get_sysattr_value(dev, "dev_port");
166 if (attr)
167 dev_port = strtol(attr, NULL, 10);
168
169 s = names->pci_onboard;
170 l = sizeof(names->pci_onboard);
171 l = strpcpyf(&s, l, "o%d", idx);
172 if (dev_port > 0)
173 l = strpcpyf(&s, l, "d%d", dev_port);
174 if (l == 0)
175 names->pci_onboard[0] = '\0';
176
177 names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
178
179 return 0;
180 }
181
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;
186 uint8_t config[64];
187
188 filename = strjoina(udev_device_get_syspath(dev), "/config");
189 fd = open(filename, O_RDONLY | O_CLOEXEC);
190 if (fd < 0)
191 return false;
192 if (read(fd, &config, sizeof(config)) != sizeof(config))
193 return false;
194
195 /* bit 0-6 header type, bit 7 multi/single function device */
196 if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
197 return true;
198
199 return false;
200 }
201
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;
205 size_t l;
206 char *s;
207 const char *attr;
208 struct udev_device *pci = NULL;
209 char slots[256], str[256];
210 _cleanup_closedir_ DIR *dir = NULL;
211 struct dirent *dent;
212 int hotplug_slot = 0, err = 0;
213
214 if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
215 return -ENOENT;
216
217 /* kernel provided port index for multiple ports on a single PCI function */
218 attr = udev_device_get_sysattr_value(dev, "dev_port");
219 if (attr)
220 dev_port = strtol(attr, NULL, 10);
221
222 /* compose a name based on the raw kernel's PCI bus, slot numbers */
223 s = names->pci_path;
224 l = sizeof(names->pci_path);
225 if (domain > 0)
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);
230 if (dev_port > 0)
231 l = strpcpyf(&s, l, "d%u", dev_port);
232 if (l == 0)
233 names->pci_path[0] = '\0';
234
235 /* ACPI _SUN -- slot user number */
236 pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
237 if (!pci) {
238 err = -ENOENT;
239 goto out;
240 }
241 xsprintf(slots, "%s/slots", udev_device_get_syspath(pci));
242 dir = opendir(slots);
243 if (!dir) {
244 err = -errno;
245 goto out;
246 }
247
248 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
249 int i;
250 char *rest;
251 char *address;
252
253 if (dent->d_name[0] == '.')
254 continue;
255 i = strtol(dent->d_name, &rest, 10);
256 if (rest[0] != '\0')
257 continue;
258 if (i < 1)
259 continue;
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)))
264 hotplug_slot = i;
265 free(address);
266 }
267
268 if (hotplug_slot > 0)
269 break;
270 }
271
272 if (hotplug_slot > 0) {
273 s = names->pci_slot;
274 l = sizeof(names->pci_slot);
275 if (domain > 0)
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);
280 if (dev_port > 0)
281 l = strpcpyf(&s, l, "d%d", dev_port);
282 if (l == 0)
283 names->pci_slot[0] = '\0';
284 }
285 out:
286 udev_device_unref(pci);
287 return err;
288 }
289
290 static int names_pci(struct udev_device *dev, struct netnames *names) {
291 struct udev_device *parent;
292
293 assert(dev);
294 assert(names);
295
296 parent = udev_device_get_parent(dev);
297
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);
303
304 if (!parent)
305 return -ENOENT;
306
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;
311 } else {
312 names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
313 if (!names->pcidev)
314 return -ENOENT;
315 }
316 dev_pci_onboard(dev, names);
317 dev_pci_slot(dev, names);
318 return 0;
319 }
320
321 static int names_usb(struct udev_device *dev, struct netnames *names) {
322 struct udev_device *usbdev;
323 char name[256];
324 char *ports;
325 char *config;
326 char *interf;
327 size_t l;
328 char *s;
329
330 assert(dev);
331 assert(names);
332
333 usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
334 if (!usbdev)
335 return -ENOENT;
336
337 /* get USB port number chain, configuration, interface */
338 strscpy(name, sizeof(name), udev_device_get_sysname(usbdev));
339 s = strchr(name, '-');
340 if (!s)
341 return -EINVAL;
342 ports = s+1;
343
344 s = strchr(ports, ':');
345 if (!s)
346 return -EINVAL;
347 s[0] = '\0';
348 config = s+1;
349
350 s = strchr(config, '.');
351 if (!s)
352 return -EINVAL;
353 s[0] = '\0';
354 interf = s+1;
355
356 /* prefix every port number in the chain with "u" */
357 s = ports;
358 while ((s = strchr(s, '.')))
359 s[0] = 'u';
360 s = names->usb_ports;
361 l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
362
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);
366
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);
370 if (l == 0)
371 return -ENAMETOOLONG;
372
373 names->type = NET_USB;
374 return 0;
375 }
376
377 static int names_bcma(struct udev_device *dev, struct netnames *names) {
378 struct udev_device *bcmadev;
379 unsigned int core;
380
381 assert(dev);
382 assert(names);
383
384 bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
385 if (!bcmadev)
386 return -ENOENT;
387
388 /* bus num:core num */
389 if (sscanf(udev_device_get_sysname(bcmadev), "bcma%*u:%u", &core) != 1)
390 return -EINVAL;
391 /* suppress the common core == 0 */
392 if (core > 0)
393 xsprintf(names->bcma_core, "b%u", core);
394
395 names->type = NET_BCMA;
396 return 0;
397 }
398
399 static int names_ccw(struct udev_device *dev, struct netnames *names) {
400 struct udev_device *cdev;
401 const char *bus_id;
402 size_t bus_id_len;
403 int rc;
404
405 assert(dev);
406 assert(names);
407
408 /* Retrieve the associated CCW device */
409 cdev = udev_device_get_parent(dev);
410 if (!cdev)
411 return -ENOENT;
412
413 /* Network devices are always grouped CCW devices */
414 if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev)))
415 return -ENOENT;
416
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.
420 */
421 bus_id = udev_device_get_sysname(cdev);
422 if (!bus_id)
423 return -ENOENT;
424
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...
428 */
429 bus_id_len = strlen(bus_id);
430 if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9)
431 return -EINVAL;
432
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;
437 return 0;
438 }
439
440 static int names_mac(struct udev_device *dev, struct netnames *names) {
441 const char *s;
442 unsigned int i;
443 unsigned int a1, a2, a3, a4, a5, a6;
444
445 /* check for NET_ADDR_PERM, skip random MAC addresses */
446 s = udev_device_get_sysattr_value(dev, "addr_assign_type");
447 if (!s)
448 return EXIT_FAILURE;
449 i = strtoul(s, NULL, 0);
450 if (i != 0)
451 return 0;
452
453 s = udev_device_get_sysattr_value(dev, "address");
454 if (!s)
455 return -ENOENT;
456 if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
457 return -EINVAL;
458
459 /* skip empty MAC addresses */
460 if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
461 return -EINVAL;
462
463 names->mac[0] = a1;
464 names->mac[1] = a2;
465 names->mac[2] = a3;
466 names->mac[3] = a4;
467 names->mac[4] = a5;
468 names->mac[5] = a6;
469 names->mac_valid = true;
470 return 0;
471 }
472
473 /* IEEE Organizationally Unique Identifier vendor string */
474 static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
475 char str[32];
476
477 if (!names->mac_valid)
478 return -ENOENT;
479 /* skip commonly misused 00:00:00 (Xerox) prefix */
480 if (memcmp(names->mac, "\0\0\0", 3) == 0)
481 return -EINVAL;
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],
484 names->mac[5]);
485 udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test);
486 return 0;
487 }
488
489 static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
490 const char *s;
491 const char *p;
492 unsigned int i;
493 const char *devtype;
494 const char *prefix = "en";
495 struct netnames names = {};
496 int err;
497
498 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
499 s = udev_device_get_sysattr_value(dev, "type");
500 if (!s)
501 return EXIT_FAILURE;
502 i = strtoul(s, NULL, 0);
503 switch (i) {
504 case ARPHRD_ETHER:
505 prefix = "en";
506 break;
507 case ARPHRD_SLIP:
508 prefix = "sl";
509 break;
510 default:
511 return 0;
512 }
513
514 /* skip stacked devices, like VLANs, ... */
515 s = udev_device_get_sysattr_value(dev, "ifindex");
516 if (!s)
517 return EXIT_FAILURE;
518 p = udev_device_get_sysattr_value(dev, "iflink");
519 if (!p)
520 return EXIT_FAILURE;
521 if (!streq(s, p))
522 return 0;
523
524 devtype = udev_device_get_devtype(dev);
525 if (devtype) {
526 if (streq("wlan", devtype))
527 prefix = "wl";
528 else if (streq("wwan", devtype))
529 prefix = "ww";
530 }
531
532 err = names_mac(dev, &names);
533 if (err >= 0 && names.mac_valid) {
534 char str[IFNAMSIZ];
535
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);
540
541 ieee_oui(dev, &names, test);
542 }
543
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) {
547 char str[IFNAMSIZ];
548
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);
551 goto out;
552 }
553
554 /* get PCI based path names, we compose only PCI based paths */
555 err = names_pci(dev, &names);
556 if (err < 0)
557 goto out;
558
559 /* plain PCI device */
560 if (names.type == NET_PCI) {
561 char str[IFNAMSIZ];
562
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);
566
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);
570
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);
574
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);
578 goto out;
579 }
580
581 /* USB device */
582 err = names_usb(dev, &names);
583 if (err >= 0 && names.type == NET_USB) {
584 char str[IFNAMSIZ];
585
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);
589
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);
593 goto out;
594 }
595
596 /* Broadcom bus */
597 err = names_bcma(dev, &names);
598 if (err >= 0 && names.type == NET_BCMA) {
599 char str[IFNAMSIZ];
600
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);
604
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);
608 goto out;
609 }
610 out:
611 return EXIT_SUCCESS;
612 }
613
614 const struct udev_builtin udev_builtin_net_id = {
615 .name = "net_id",
616 .cmd = builtin_net_id,
617 .help = "Network device properties",
618 };