]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: fix id_net_name_path for virtio-ccw interfaces (#5357)
authorViktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
Fri, 17 Feb 2017 15:18:01 +0000 (16:18 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 17 Feb 2017 15:18:01 +0000 (16:18 +0100)
The CCW id_net_name_path detection didn't account for virtio
interfaces on the CCW bus. As a result the default interface
names for virtio-ccw interfaces would use the old eth<x>
format instead of enc<busid>.

Since virtio-pci interface naming follows the naming rules
of the parent bus, the names_ccw() logic was changed to apply
the CCW interface naming rules to virtio interfaces as well,
e.g. enc2000 for an interface with a CCW bus id 0.0.2000.
As virtio interfaces are apt to get the otherwise unusual
CCW bus id 0.0.0000, the last '0' is now preserved in this
case.

The virtio subsystem skipping loop has been moved from
names_pci() into a function skip_virtio() that can be reused
for all bus types with virtio network devices.

Since virtio-ccw interfaces use single CCW addresses the ccwgroup
requirement was relaxed and the C definitions were changed
accordingly.

src/udev/udev-builtin-net_id.c

index 5be158f5272d3999f9a95bf9a104b410e7fbc97d..b5a88c667cc49b9bbc88e075e697b31387c1a5a5 100644 (file)
@@ -34,7 +34,8 @@
  *
  * Type of names:
  *   b<number>                             — BCMA bus core number
- *   c<bus_id>                             — CCW bus group name, without leading zeros [s390]
+ *   c<bus_id>                             — bus id of a grouped CCW or CCW device,
+ *                                           with all leading zeros stripped [s390]
  *   o<index>[n<phys_port_name>|d<dev_port>]
  *                                         — on-board device index number
  *   s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
  *   /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
  *   ID_NET_NAME_MAC=enxd626b3450fb5
  *   ID_NET_NAME_PATH=enp0s29u1u2
+ *
+ * s390 grouped CCW interface:
+ *  /sys/devices/css0/0.0.0007/0.0.f5f0/group_device/net/encf5f0
+ *  ID_NET_NAME_MAC=enx026d3c00000a
+ *  ID_NET_NAME_PATH=encf5f0
  */
 
 #include <errno.h>
@@ -115,7 +121,7 @@ enum netname_type{
         NET_USB,
         NET_BCMA,
         NET_VIRTIO,
-        NET_CCWGROUP,
+        NET_CCW,
 };
 
 struct netnames {
@@ -132,9 +138,21 @@ struct netnames {
 
         char usb_ports[IFNAMSIZ];
         char bcma_core[IFNAMSIZ];
-        char ccw_group[IFNAMSIZ];
+        char ccw_busid[IFNAMSIZ];
 };
 
+/* skip intermediate virtio devices */
+static struct udev_device *skip_virtio(struct udev_device *dev) {
+        struct udev_device *parent = dev;
+
+        /* there can only ever be one virtio bus per parent device, so we can
+           safely ignore any virtio buses. see
+           <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
+        while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
+                parent = udev_device_get_parent(parent);
+        return parent;
+}
+
 /* retrieve on-board index number and label from firmware */
 static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
         unsigned dev_port = 0;
@@ -308,12 +326,8 @@ static int names_pci(struct udev_device *dev, struct netnames *names) {
         assert(names);
 
         parent = udev_device_get_parent(dev);
-
-        /* there can only ever be one virtio bus per parent device, so we can
-           safely ignore any virtio buses. see
-           <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
-        while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
-                parent = udev_device_get_parent(parent);
+        /* skip virtio subsystem if present */
+        parent = skip_virtio(parent);
 
         if (!parent)
                 return -ENOENT;
@@ -414,21 +428,26 @@ static int names_ccw(struct  udev_device *dev, struct netnames *names) {
         struct udev_device *cdev;
         const char *bus_id;
         size_t bus_id_len;
+        size_t bus_id_start;
         int rc;
+        char *subsys;
 
         assert(dev);
         assert(names);
 
         /* Retrieve the associated CCW device */
         cdev = udev_device_get_parent(dev);
+        /* skip virtio subsystem if present */
+        cdev = skip_virtio(cdev);
         if (!cdev)
                 return -ENOENT;
 
-        /* Network devices are always grouped CCW devices */
-        if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev)))
+        /* Network devices are either single or grouped CCW devices */
+        subsys = udev_device_get_subsystem(cdev);
+        if (!STRPTR_IN_SET(subsys, "ccwgroup", "ccw"))
                 return -ENOENT;
 
-        /* Retrieve bus-ID of the grouped CCW device.  The bus-ID uniquely
+        /* Retrieve bus-ID of the CCW device.  The bus-ID uniquely
          * identifies the network device on the Linux on System z channel
          * subsystem.  Note that the bus-ID contains lowercase characters.
          */
@@ -447,14 +466,15 @@ static int names_ccw(struct  udev_device *dev, struct netnames *names) {
         /* Strip leading zeros from the bus id for aesthetic purposes. This
          * keeps the ccw names stable, yet much shorter in general case of
          * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is
-         * not prepended when it is zero.
+         * not prepended when it is zero. Preserve the last 0 for 0.0.0000.
          */
-        bus_id += strspn(bus_id, ".0");
+        bus_id_start = strspn(bus_id, ".0");
+        bus_id += bus_id_start < bus_id_len ? bus_id_start : bus_id_len - 1;
 
         /* Store the CCW bus-ID for use as network device name */
-        rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "c%s", bus_id);
-        if (rc >= 0 && rc < (int)sizeof(names->ccw_group))
-                names->type = NET_CCWGROUP;
+        rc = snprintf(names->ccw_busid, sizeof(names->ccw_busid), "c%s", bus_id);
+        if (rc >= 0 && rc < (int)sizeof(names->ccw_busid))
+                names->type = NET_CCW;
         return 0;
 }
 
@@ -564,10 +584,10 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool
 
         /* get path names for Linux on System z network devices */
         err = names_ccw(dev, &names);
-        if (err >= 0 && names.type == NET_CCWGROUP) {
+        if (err >= 0 && names.type == NET_CCW) {
                 char str[IFNAMSIZ];
 
-                if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str))
+                if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_busid) < (int)sizeof(str))
                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
                 goto out;
         }