From: Jordan Hargrave <jhar...@gmail.com> This patch will integrate some of the features of biosdevname into systemd. The code detects the port and index for detecting NIC partitions. This creates a new environment variable, ID_NET_NAME_PARTITION of the format <PORT>_<PARTITION>
The patch will also decode SMBIOS slot number for NIC, and store in the variable ID_NET_NAME_SMBIOS_SLOT. Systemd does not have a method for naming ports on a multi-port card plugged into a slot. Signed-off-by: Jordan Hargrave <jordan_hargr...@dell.com> --- src/udev/udev-builtin-net_id.c | 208 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index ef9c398..db9e133 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -119,16 +119,132 @@ struct netnames { bool mac_valid; struct udev_device *pcidev; + struct udev_device *physdev; char pci_slot[IFNAMSIZ]; char pci_path[IFNAMSIZ]; char pci_onboard[IFNAMSIZ]; const char *pci_onboard_label; + int npar_port; + int npar_pfi; + int smbios_slot; char usb_ports[IFNAMSIZ]; char bcma_core[IFNAMSIZ]; char ccw_group[IFNAMSIZ]; }; +#define FLAG_IOV 0x80 +#define FLAG_NPAR 0x1000 + +#define VPDI_TAG 0x82 +#define VPDR_TAG 0x90 + +struct vpd_tag +{ + char cc[2]; + unsigned char len; + char data[1]; +}; + +/* Read VPD tag ID */ +static int vpd_readtag(int fd, int *len) +{ + unsigned char tag, tlen[2]; + + if (read(fd, &tag, 1) != 1) + return -1; + if (tag == 0x00 || tag == 0xFF || tag == 0x7F) + return -1; + if (tag & 0x80) { + if (read(fd, tlen, 2) != 2) + return -1; + *len = tlen[0] + (tlen[1] << 8); + return tag; + } + *len = (tag & 0x7); + return (tag & ~0x7); +} + +static void *vpd_findtag(void *buf, int len, const char *sig) +{ + int off, siglen; + struct vpd_tag *t; + + off = 0; + siglen = strlen(sig); + while (off < len) { + t = (struct vpd_tag *)((unsigned char *)buf + off); + if (!memcmp(t->data, sig, siglen)) + return t; + off += (t->len + 3); + } + return NULL; +} + +static void dev_pci_npar_dcm(struct udev_device *dev, struct netnames *names, + int len, const char *dcm, + const char *fmt, int step) +{ + int domain, bus, slot, func, off, mydf; + int port, df, pfi, flag; + + if (sscanf(udev_device_get_sysname(names->physdev), "%x:%x:%x.%u", + &domain, &bus, &slot, &func) != 4) + return; + mydf = (slot << 3) + func; + for (off=3; off<len; off+=step) { + sscanf(dcm+off, fmt, &port, &df, &pfi, &flag); + if ((flag & FLAG_NPAR) && mydf == df) { + names->npar_port = port; + names->npar_pfi = pfi; + } + } +} + +static void dev_pci_npar(struct udev_device *dev, struct netnames *names) { + const char *filename; + int len, fd; + struct vpd_tag *dcm; + void *buf; + + /* Search for VPD or IOV VPD */ + filename = strjoina(udev_device_get_syspath(names->physdev), "/vpd"); + if ((fd = open(filename, O_RDONLY)) < 0) { + return; + } + if (vpd_readtag(fd, &len) != VPDI_TAG) { + goto done; + } + lseek(fd, len, SEEK_CUR); + + /* Check VPD-R */ + if (vpd_readtag(fd, &len) != VPDR_TAG) { + goto done; + } + buf = alloca(len); + if (read(fd, buf, len) != len) { + goto done; + } + + /* Check for DELL VPD tag */ + if (!vpd_findtag(buf, len, "DSV1028VPDR.VER")) { + goto done; + } + + /* Find DCM/DC2 tag */ + if ((dcm = vpd_findtag(buf, len, "DCM")) != NULL) { + dev_pci_npar_dcm(dev, names, dcm->len, dcm->data, + "%1x%1x%2x%6x", 10); + } + else if ((dcm = vpd_findtag(buf, len, "DC2")) != NULL) { + dev_pci_npar_dcm(dev, names, dcm->len, dcm->data, + "%1x%2x%2x%6x", 11); + } + done: + close(fd); + return; +} + /* 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; @@ -187,6 +303,79 @@ static bool is_pci_multifunction(struct udev_device *dev) { return false; } +enum { + SLOT_USAGE_OTHER=1, + SLOT_USAGE_UNKNOWN=2, + SLOT_USAGE_AVAILABLE=3, + SLOT_USAGE_INUSE=4, +}; + +struct smbios_type9 { + unsigned char hdr_type; + unsigned char hdr_len; + unsigned short hdr_handle; + + unsigned char ref; + unsigned char type; + unsigned char buswidth; + unsigned char usage; + unsigned char length; + unsigned short id; + unsigned char flags1; + unsigned char flags2; + unsigned short seg; + unsigned char bus; + unsigned char devfn; +} __attribute__((packed)); + +static int dev_pci_smbios_slot(struct udev_device *dev, + struct netnames *names, + int dev_port) { + int domain, bus, slot, func; + struct smbios_type9 t9; + char path[256]; + int n, fd, rc; + struct udev_device *parent; + uint8_t hdr; + + for(n=0; ; n++) { + snprintf(path, sizeof(path), + "/sys/firmware/dmi/entries/9-%u/raw", n); + if ((fd = open(path, O_RDONLY)) < 0) { + break; + } + /* Read SMBIOS slot data */ + rc = read(fd, &t9, sizeof(t9)); + close(fd); + if (rc != sizeof(t9)) { + continue; + } + /* Ignore slots not marked in use */ + if (t9.usage != SLOT_USAGE_INUSE) + continue; + /* Ignore 00:00.0 and FF:1F.7 */ + if (t9.bus == 0 && t9.devfn == 0) + continue; + if (t9.bus == 0xFF && t9.devfn == 0xFF) + continue; + /* Scan parent until we find match */ + parent = names->physdev; + do { + if (sscanf(udev_device_get_sysname(parent), + "%x:%x:%x.%u", &domain, &bus, + &slot, &func) != 4) + break; + if (domain == t9.seg && + bus == t9.bus && + slot == (t9.devfn >> 3) && + func == (t9.devfn & 7)) { + names->smbios_slot = t9.id; + } + } while ((parent = udev_device_get_parent(parent)) != NULL); + } + return 0; +} + static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { struct udev *udev = udev_device_get_udev(names->pcidev); unsigned domain, bus, slot, func, dev_port = 0; @@ -207,6 +396,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { if (attr) dev_port = strtol(attr, NULL, 10); + if (dev_pci_smbios_slot(dev, names, dev_port)) + return 0; + /* compose a name based on the raw kernel's PCI bus, slot numbers */ s = names->pci_path; l = sizeof(names->pci_path); @@ -277,6 +469,7 @@ out: static int names_pci(struct udev_device *dev, struct netnames *names) { struct udev_device *parent; + char path[256]; assert(dev); assert(names); @@ -301,8 +494,14 @@ static int names_pci(struct udev_device *dev, struct netnames *names) { if (!names->pcidev) return -ENOENT; } + /* find SR-IOV parent device */ + snprintf(path, sizeof(path), "%s/physfn", udev_device_get_syspath(names->pcidev)); + names->physdev = udev_device_new_from_syspath(names->pcidev, path); + if (!names->physdev) + names->physdev = names->pcidev; dev_pci_onboard(dev, names); dev_pci_slot(dev, names); +dev_pci_npar(dev, names); return 0; } @@ -563,6 +762,15 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool if (names.pci_slot[0]) if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str)) udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + + + if (names.npar_port) + if (snprintf(str, sizeof(str), "%d_%d", names.npar_port, names.npar_pfi) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_PARTITION", str); + + if (names.smbios_slot) + if (snprintf(str, sizeof(str), "%d", names.smbios_slot) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_SMBIOS_SLOT", str); goto out; } -- 2.5.0 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel