[systemd-devel] [PATCHv4] Read Dell Server NIC partition IDs

jharg93 at gmail.com jharg93 at gmail.com
Mon Nov 16 13:07:17 PST 2015


From: Jordan Hargrave <jharg93 at gmail.com>

Removed SMBIOS specific code and cleaned up linux coding style.

This patch will read the PCI VPD area to detect the physical port
and partition for NICs on Dell Servers.  It creates a new
environment variable of the form
ID_NET_NAME_PARTITION=<PORT>_<PARTITION>

Signed-off-by: Jordan Hargrave <jordan_hargrave at dell.com>
---
 src/udev/udev-builtin-net_id.c | 130 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index ef9c398..affbbf1 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -119,16 +119,130 @@ 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;
 
         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) {
+                if (sscanf(dcm+off, fmt, &port, &df, &pfi, &flag) != 4)
+                        break;
+                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");
+        fd = open(filename, O_RDONLY);
+        if (fd < 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 */
+        dcm = vpd_findtag(buf, len, "DCM");
+        if (dcm != NULL)
+                dev_pci_npar_dcm(dev, names, dcm->len, dcm->data,
+                                 "%1x%1x%2x%6x", 10);
+        else {
+                dcm = vpd_findtag(buf, len, "DC2");
+                if (dcm != 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;
@@ -277,6 +391,8 @@ out:
 
 static int names_pci(struct udev_device *dev, struct netnames *names) {
         struct udev_device *parent;
+        struct udev *udev;
+        char path[256];
 
         assert(dev);
         assert(names);
@@ -301,8 +417,15 @@ static int names_pci(struct udev_device *dev, struct netnames *names) {
                 if (!names->pcidev)
                         return -ENOENT;
         }
+        /* find SR-IOV parent device */
+        udev = udev_device_get_udev(names->pcidev);
+        snprintf(path, sizeof(path), "%s/physfn", udev_device_get_syspath(names->pcidev));
+        names->physdev = udev_device_new_from_syspath(udev, 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 +686,13 @@ 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);
                 goto out;
         }
 
-- 
2.5.0



More information about the systemd-devel mailing list