udev: fix id_net_name_path for virtio-ccw interfaces (#5357)

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.
This commit is contained in:
Viktor Mihajlovski 2017-02-17 16:18:01 +01:00 committed by Lennart Poettering
parent e4363cd8ae
commit ecc11cf70c
1 changed files with 39 additions and 19 deletions

View 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>]
@ -87,6 +88,11 @@
* /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;
}