Blob Blame History Raw
From 8f2d9991d50e09ba9af842fb592b37d0c2021a06 Mon Sep 17 00:00:00 2001
From: dirkjacobus <dirkjacobus@gmail.com>
Date: Sun, 11 Nov 2018 23:29:24 -0800
Subject: [PATCH] Netronome biosdevname support (#8)

* Add support for Netronome netdevices

Netronome netdevices also provide multiple ports through the same
function.

* Set devID with phys_port_name index for nfp devices

Netronome netdevices should rather use the index from the phys_port_name
attribute instead of the dev_port/dev_id
attributes.

* Exclude naming Netronome logical devices

Some drivers, like the Netronome nfp driver, expose logical devices such
as representors and switchdev uplink devices.

There isn't currently a naming scheme for such devices, so exclude them
from the biosdevname naming policy.

Split ports also don't have a naming scheme defined for biosdevname, so
its better to exclude them from naming.

Identification of such devices will always be driver dependent.
At the moment, only 'nfp' driver devices are considered for exclusion.
---
 src/bios_device.c |  6 ++++-
 src/eths.c        | 65 ++++++++++++++++++++++++++++++++++++++++-------
 src/eths.h        |  6 +++++
 3 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/src/bios_device.c b/src/bios_device.c
index 3cc528b..4882513 100644
--- a/src/bios_device.c
+++ b/src/bios_device.c
@@ -214,7 +214,7 @@ static void sort_device_list(struct libbiosdevname_state *state)
 	list_splice(&sorted_devices, &state->bios_devices);
 }
 
-/* Check for Mellanox/Chelsio drivers */
+/* Check for multiport drivers */
 int ismultiport(const char *driver)
 {
 	if (!strncmp(driver, "mlx4", 4))
@@ -223,6 +223,8 @@ int ismultiport(const char *driver)
 		return 1;
 	if (!strncmp(driver, "exanic", 6))
 		return 1;
+	if (!strncmp(driver, "nfp", 3))
+		return 1;
 	return 0;
 }
 
@@ -248,6 +250,8 @@ static void match_pci_and_eth_devs(struct libbiosdevname_state *state)
 			/* Ignore if devtype is fcoe */
 			if (netdev_devtype_is_fcoe(n))
 				continue;
+			if (!netdev_is_eligible(n))
+				continue;
 			b = malloc(sizeof(*b));
 			if (!b)
 				continue;
diff --git a/src/eths.c b/src/eths.c
index d2c4d36..688c3af 100644
--- a/src/eths.c
+++ b/src/eths.c
@@ -35,21 +35,67 @@ char *pr_ether(char *buf, const int size, const unsigned char *s)
 	return (buf);
 }
 
-static void eths_get_devid(const char *devname, int *devid)
+static int eths_get_phys_port_name_id(const char *devname)
+{
+	char *portstr = NULL;
+	char path[PATH_MAX];
+	int index = -1;
+
+	/* Only devices that have a phys_port_name of 'pX' are considered here,
+	 * with the index 'X' extracted.
+	 */
+	snprintf(path, sizeof(path), "/sys/class/net/%s/phys_port_name", devname);
+	if (sysfs_read_file(path, &portstr) == 0) {
+		char *res = NULL;
+
+		if (portstr[0] == 'p') {
+			index = strtol(&portstr[1], &res, 10);
+			/* Reset to invalid if the format is unexpected. */
+			if (*res)
+				index = -1;
+		}
+
+		free(portstr);
+	}
+
+	return index;
+}
+
+static void eths_get_dev_eligible(struct network_device *dev)
+{
+	/* By default, all network devices are eligible for naming. Some may
+	 * opt-out explicitly below.
+	 */
+	dev->is_eligible = 1;
+
+	if (dev->drvinfo_valid && strcmp(dev->drvinfo.driver, "nfp") == 0) {
+		dev->is_eligible = (eths_get_phys_port_name_id(dev->kernel_name) >= 0 ? 1 : 0);
+	}
+}
+
+static void eths_get_devid(struct network_device *dev)
 {
 	char path[PATH_MAX];
 	char *devidstr = NULL;
 
-	*devid = -1;
-	snprintf(path, sizeof(path), "/sys/class/net/%s/dev_port", devname);
-	if (sysfs_read_file(path, &devidstr) == 0) {
-		sscanf(devidstr, "%i", devid);
-		free(devidstr);
+	dev->devid = -1;
+
+	/* For some drivers, the phys_port_name index, e.g. pX, is the correct
+	 * dev ID to use instead of the dev_port attribute.
+	 */
+	if (dev->drvinfo_valid && strcmp(dev->drvinfo.driver, "nfp") == 0) {
+		dev->devid = eths_get_phys_port_name_id(dev->kernel_name);
 	} else {
-		snprintf(path, sizeof(path), "/sys/class/net/%s/dev_id", devname);
+		snprintf(path, sizeof(path), "/sys/class/net/%s/dev_port", dev->kernel_name);
 		if (sysfs_read_file(path, &devidstr) == 0) {
-			sscanf(devidstr, "%i", devid);
+			sscanf(devidstr, "%i", &dev->devid);
 			free(devidstr);
+		} else {
+			snprintf(path, sizeof(path), "/sys/class/net/%s/dev_id", dev->kernel_name);
+			if (sysfs_read_file(path, &devidstr) == 0) {
+				sscanf(devidstr, "%i", &dev->devid);
+				free(devidstr);
+			}
 		}
 	}
 }
@@ -224,13 +270,14 @@ static void fill_eth_dev(struct network_device *dev)
 	eths_get_ifindex(dev->kernel_name, &dev->ifindex);
 	eths_get_hwaddr(dev->kernel_name, dev->dev_addr, sizeof(dev->dev_addr), &dev->arphrd_type);
 	eths_get_permaddr(dev->kernel_name, dev->perm_addr, sizeof(dev->perm_addr));
-	eths_get_devid(dev->kernel_name, &dev->devid);
 	devtype = eths_get_devtype(dev);
 	if (devtype > 0)
 		dev->devtype_is_fcoe = 1;
 	rc = eths_get_info(dev->kernel_name, &dev->drvinfo);
 	if (rc == 0)
 		dev->drvinfo_valid = 1;
+	eths_get_devid(dev);
+	eths_get_dev_eligible(dev);
 }
 
 void free_eths(struct libbiosdevname_state *state)
diff --git a/src/eths.h b/src/eths.h
index b695d3d..49e399d 100644
--- a/src/eths.h
+++ b/src/eths.h
@@ -30,6 +30,7 @@ struct network_device {
 	int devid;
 	int devtype_is_fcoe;
 	char *devtype;
+	int is_eligible:1; /* not eligible for naming when 0 */
 };
 
 extern void get_eths(struct libbiosdevname_state *state);
@@ -68,4 +69,9 @@ static inline int netdev_arphrd_type_is_eth(const struct network_device *dev)
         return (dev->arphrd_type == ARPHRD_ETHER);
 }
 
+static inline int netdev_is_eligible(const struct network_device *dev)
+{
+	return (!!dev->is_eligible);
+}
+
 #endif /* __ETHS_H_INCLUDED */
-- 
2.17.2