[systemd-devel] [PATCH] Add support for detecting NIC partitions on Dell Servers
jharg93 at gmail.com
jharg93 at gmail.com
Mon Nov 9 09:52:54 PST 2015
From: Jordan Hargrave <jharg93 at 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_hargrave at 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
More information about the systemd-devel
mailing list