From 938d30aa98df887797c9e05074a562ddacdcdf5e Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Wed, 29 Aug 2018 04:07:55 +0300 Subject: [PATCH 1/4] udev: Introduce predictable naming for InfiniBand NICs We've long neglected IP-over-InfiniBand network interfaces, let's treat them the same way we treat anyone else. IPoIB interfaces will retain the 'ib' prefix; otherwise the naming scheme is the same one we use for other network interfaces. E.g. a IPoIB network device provided by a PCI card at bus 21 slot 0 function 6 will be named 'ibp21s0f6'. --- src/udev/udev-builtin-net_id.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index cb49ade4d8..239a825ae5 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -11,6 +11,7 @@ * * Two character prefixes based on the type of interface: * en — Ethernet + * ib — InfiniBand * sl — serial line IP (slip) * wl — wlan * ww — wwan @@ -67,6 +68,12 @@ * ID_NET_NAME_MAC=wlx0024d7e31130 * ID_NET_NAME_PATH=wlp3s0 * + * PCI IB host adapter with 2 ports: + * /sys/devices/pci0000:00/0000:00:03.0/0000:15:00.0/net/ibp21s0f0 + * ID_NET_NAME_PATH=ibp21s0f0 + * /sys/devices/pci0000:00/0000:00:03.0/0000:15:00.1/net/ibp21s0f1 + * ID_NET_NAME_PATH=ibp21s0f1 + * * USB built-in 3G modem: * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6 * ID_NET_NAME_MAC=wwx028037ec0200 @@ -704,7 +711,9 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool struct netnames names = {}; int err; - /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */ + /* handle only ARPHRD_ETHER, ARPHRD_SLIP + * and ARPHRD_INFINIBAND devices + */ s = udev_device_get_sysattr_value(dev, "type"); if (!s) return EXIT_FAILURE; @@ -713,6 +722,9 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool case ARPHRD_ETHER: prefix = "en"; break; + case ARPHRD_INFINIBAND: + prefix = "ib"; + break; case ARPHRD_SLIP: prefix = "sl"; break; From a0d415da3ac345bb656ce5cabc38fde61f6b23e1 Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Wed, 29 Aug 2018 04:20:43 +0300 Subject: [PATCH 2/4] udev: Disable HW-address-based naming for IB NICs An InfiniBand network address is 20 bytes long. Only the least significant 8 bytes can be interpreted as a persistent hardware unit identifier; the other 12 are transiently derived at runtime from metadata specific to the protocol stack. However, since the network interface name length is hard-capped by IFNAMSIZ at 16 chars and the 2-byte type prefix with '\0' at the end leave us only at 13, we cannot squeeze a descriptive representation of a HW address into an interface name. Thus, it makes the most sense to drop the scheme for IPoIB interfaces entirely. Currently udev just gets confused and does what it has been taught to do: fetches the first six bytes and puts them into a permanent device attribute. --- src/udev/udev-builtin-net_id.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 239a825ae5..d808ddcfeb 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -658,6 +658,23 @@ static int names_mac(struct udev_device *dev, struct netnames *names) { unsigned int i; unsigned int a1, a2, a3, a4, a5, a6; + /* Some kinds of devices tend to have hardware addresses + * that are impossible to use in an iface name. + */ + s = udev_device_get_sysattr_value(dev, "type"); + if (!s) + return EXIT_FAILURE; + i = strtoul(s, NULL, 0); + switch (i) { + /* The persistent part of a hardware address of an InfiniBand NIC + * is 8 bytes long. We cannot fit this much in an iface name. + */ + case ARPHRD_INFINIBAND: + return -EINVAL; + default: + break; + } + /* check for NET_ADDR_PERM, skip random MAC addresses */ s = udev_device_get_sysattr_value(dev, "addr_assign_type"); if (!s) From cdd63a03ce15e9df94a137a993196ee48813e16a Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Tue, 18 Sep 2018 12:47:20 +0300 Subject: [PATCH 3/4] udev: Provide a fallback for IPoIB device port numbers In older kernels IPoIB network devices expose the port number via the sysfs attribute 'dev_id', which is not intended to be used this way. Let's support both options for a while. --- src/udev/udev-builtin-net_id.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index d808ddcfeb..b0bb0884be 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -291,7 +291,7 @@ static bool is_pci_ari_enabled(struct udev_device *dev) { } static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { - unsigned domain, bus, slot, func, dev_port = 0, hotplug_slot = 0; + unsigned type, domain, bus, slot, func, dev_port = 0, hotplug_slot = 0; size_t l; char *s; const char *attr, *port_name; @@ -311,8 +311,22 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { /* kernel provided port index for multiple ports on a single PCI function */ attr = udev_device_get_sysattr_value(dev, "dev_port"); - if (attr) + if (attr) { dev_port = strtol(attr, NULL, 10); + /* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously + * provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port', + * which thus stays initialized as 0. */ + if (dev_port == 0) { + attr = udev_device_get_sysattr_value(dev, "type"); + /* The 'type' attribute always exists. */ + type = strtoul(attr, NULL, 10); + if (type == ARPHRD_INFINIBAND) { + attr = udev_device_get_sysattr_value(dev, "dev_id"); + if (attr) + dev_port = strtol(attr, NULL, 16); + } + } + } /* kernel provided front panel port name for multiple port PCI device */ port_name = udev_device_get_sysattr_value(dev, "phys_port_name"); From b8e8823e63276458231dbfeca21dff07b3981f4b Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Tue, 18 Sep 2018 13:01:46 +0300 Subject: [PATCH 4/4] udev: Fix "strtol" -> "strtoul" for unsigned source values --- src/udev/udev-builtin-net_id.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index b0bb0884be..a92e246446 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -246,7 +246,7 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { /* kernel provided port index for multiple ports on a single PCI function */ attr = udev_device_get_sysattr_value(dev, "dev_port"); if (attr) - dev_port = strtol(attr, NULL, 10); + dev_port = strtoul(attr, NULL, 10); /* kernel provided front panel port name for multiple port PCI device */ port_name = udev_device_get_sysattr_value(dev, "phys_port_name"); @@ -312,7 +312,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { /* kernel provided port index for multiple ports on a single PCI function */ attr = udev_device_get_sysattr_value(dev, "dev_port"); if (attr) { - dev_port = strtol(attr, NULL, 10); + dev_port = strtoul(attr, NULL, 10); /* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously * provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port', * which thus stays initialized as 0. */ @@ -323,7 +323,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { if (type == ARPHRD_INFINIBAND) { attr = udev_device_get_sysattr_value(dev, "dev_id"); if (attr) - dev_port = strtol(attr, NULL, 16); + dev_port = strtoul(attr, NULL, 16); } } }