[dpdk-dev] [PATCH v2 02/11] bus/vmbus: scan and get the network device
From: Srikanth Kaka <hidden>
Date: 2021-10-08 12:12:37
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Using sysctl, all the devices on the VMBUS are identified by the PMD. On finding the Network device's device id, it is added to VMBUS dev list. v2 - replaced strncpy with memcpy - replaced malloc.h with stdlib.h Signed-off-by: Srikanth Kaka <redacted> Signed-off-by: Vag Singh <redacted> Signed-off-by: Anand Thulasiram <redacted> --- drivers/bus/vmbus/freebsd/vmbus_bus.c | 241 +++++++++++++++----------- drivers/net/netvsc/hn_rxtx.c | 2 +- 2 files changed, 145 insertions(+), 98 deletions(-)
diff --git a/drivers/bus/vmbus/freebsd/vmbus_bus.c b/drivers/bus/vmbus/freebsd/vmbus_bus.c
index 3c924eee14..47b85c18c0 100644
--- a/drivers/bus/vmbus/freebsd/vmbus_bus.c
+++ b/drivers/bus/vmbus/freebsd/vmbus_bus.c@@ -22,8 +22,9 @@ #include "eal_filesystem.h" #include "private.h" -/** Pathname of VMBUS devices directory. */ -#define SYSFS_VMBUS_DEVICES "/sys/bus/vmbus/devices" +#include <sys/bus.h> +#include <sys/types.h> +#include <sys/sysctl.h> /* * GUID associated with network devices
@@ -39,44 +40,15 @@ static const rte_uuid_t vmbus_nic_uuid = { extern struct rte_vmbus_bus rte_vmbus_bus; -/* Read sysfs file to get UUID */ +/* Parse UUID. Caller must pass NULL terminated string */ static int parse_sysfs_uuid(const char *filename, rte_uuid_t uu) { - char buf[BUFSIZ]; - char *cp, *in = buf; - FILE *f; - - f = fopen(filename, "r"); - if (f == NULL) { - VMBUS_LOG(ERR, "cannot open sysfs value %s: %s", - filename, strerror(errno)); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - VMBUS_LOG(ERR, "cannot read sysfs value %s", - filename); - fclose(f); - return -1; - } - fclose(f); - - cp = strchr(buf, '\n'); - if (cp) - *cp = '\0'; - - /* strip { } notation */ - if (buf[0] == '{') { - in = buf + 1; - cp = strchr(in, '}'); - if (cp) - *cp = '\0'; - } + char in[BUFSIZ]; + memcpy(in, filename, BUFSIZ); if (rte_uuid_parse(in, uu) < 0) { - VMBUS_LOG(ERR, "%s %s not a valid UUID", - filename, buf); + VMBUS_LOG(ERR, "%s not a valid UUID", in); return -1; }
@@ -228,35 +200,33 @@ rte_vmbus_unmap_device(struct rte_vmbus_device *dev) vmbus_uio_unmap_resource(dev); } -/* Scan one vmbus sysfs entry, and fill the devices list from it. */ +/* Scan one vmbus entry, and fill the devices list from it. */ static int -vmbus_scan_one(const char *name) +vmbus_scan_one(const char *name, unsigned int unit_num) { struct rte_vmbus_device *dev, *dev2; - char filename[PATH_MAX]; - char dirname[PATH_MAX]; - unsigned long tmp; + char sysctlBuffer[PATH_MAX], sysctlVar[PATH_MAX]; + size_t guid_len = 36, len = PATH_MAX; + char classid[guid_len + 1], deviceid[guid_len + 1]; dev = calloc(1, sizeof(*dev)); if (dev == NULL) return -1; - dev->device.bus = &rte_vmbus_bus.bus; - dev->device.name = strdup(name); - if (!dev->device.name) + /* get class id and device id */ + snprintf(sysctlVar, len, "dev.%s.%u.%%pnpinfo", name, unit_num); + if (sysctlbyname(sysctlVar, &sysctlBuffer, &len, NULL, 0) < 0) goto error; - /* sysfs base directory - * /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df - * or on older kernel - * /sys/bus/vmbus/devices/vmbus_1 + /* pnpinfo: classid=f912ad6d-2b17-48ea-bd65-f927a61c7684 + * deviceid=d34b2567-b9b6-42b9-8778-0a4ec0b955bf */ - snprintf(dirname, sizeof(dirname), "%s/%s", - SYSFS_VMBUS_DEVICES, name); - - /* get device class */ - snprintf(filename, sizeof(filename), "%s/class_id", dirname); - if (parse_sysfs_uuid(filename, dev->class_id) < 0) + if (sysctlBuffer[0] == 'c' && sysctlBuffer[1] == 'l' && + sysctlBuffer[7] == '=') { + memcpy(classid, &sysctlBuffer[8], guid_len); + classid[guid_len] = '\0'; + } + if (parse_sysfs_uuid(classid, dev->class_id) < 0) goto error; /* skip non-network devices */
@@ -265,35 +235,23 @@ vmbus_scan_one(const char *name) return 0; } - /* get device id */ - snprintf(filename, sizeof(filename), "%s/device_id", dirname); - if (parse_sysfs_uuid(filename, dev->device_id) < 0) - goto error; - - /* get relid */ - snprintf(filename, sizeof(filename), "%s/id", dirname); - if (eal_parse_sysfs_value(filename, &tmp) < 0) + if (sysctlBuffer[45] == 'd' && sysctlBuffer[46] == 'e' && + sysctlBuffer[47] == 'v' && sysctlBuffer[53] == '=') { + memcpy(deviceid, &sysctlBuffer[54], guid_len); + deviceid[guid_len] = '\0'; + } + if (parse_sysfs_uuid(deviceid, dev->device_id) < 0) goto error; - dev->relid = tmp; - /* get monitor id */ - snprintf(filename, sizeof(filename), "%s/monitor_id", dirname); - if (eal_parse_sysfs_value(filename, &tmp) < 0) + if (!strcmp(name, "hv_uio")) + dev->uio_num = unit_num; + else + dev->uio_num = -1; + dev->device.bus = &rte_vmbus_bus.bus; + dev->device.numa_node = 0; + dev->device.name = strdup(deviceid); + if (!dev->device.name) goto error; - dev->monitor_id = tmp; - - /* get numa node (if present) */ - snprintf(filename, sizeof(filename), "%s/numa_node", - dirname); - - if (access(filename, R_OK) == 0) { - if (eal_parse_sysfs_value(filename, &tmp) < 0) - goto error; - dev->device.numa_node = tmp; - } else { - /* if no NUMA support, set default to 0 */ - dev->device.numa_node = SOCKET_ID_ANY; - } dev->device.devargs = vmbus_devargs_lookup(dev);
@@ -332,31 +290,120 @@ vmbus_scan_one(const char *name) int rte_vmbus_scan(void) { - struct dirent *e; - DIR *dir; - - dir = opendir(SYSFS_VMBUS_DEVICES); - if (dir == NULL) { - if (errno == ENOENT) - return 0; + struct u_device udev; + struct u_businfo ubus; + int dev_idx, dev_ptr, name2oid[2], oid[CTL_MAXNAME + 12], error; + size_t oidlen, rlen, ub_size; + uintptr_t vmbus_handle = 0; + char *walker, *ep; + char name[16] = "hw.bus.devices"; + char *dd_name, *dd_desc, *dd_drivername, *dd_pnpinfo, *dd_location; + + /* + * devinfo FreeBSD APP logic to fetch all the VMBus devices + * using SYSCTLs + */ + name2oid[0] = 0; + name2oid[1] = 3; + oidlen = sizeof(oid); + error = sysctl(name2oid, 2, oid, &oidlen, name, strlen(name)); + if (error < 0) { + VMBUS_LOG(DEBUG, "can't find hw.bus.devices sysctl node"); + return -ENOENT; + } + oidlen /= sizeof(int); + if (oidlen > CTL_MAXNAME) { + VMBUS_LOG(DEBUG, "hw.bus.devices oid is too large"); + return -EINVAL; + } - VMBUS_LOG(ERR, "opendir %s failed: %s", - SYSFS_VMBUS_DEVICES, strerror(errno)); - return -1; + ub_size = sizeof(ubus); + if (sysctlbyname("hw.bus.info", &ubus, &ub_size, NULL, 0) != 0) { + VMBUS_LOG(DEBUG, "sysctlbyname(\"hw.bus.info\", ...) failed"); + return -EINVAL; + } + if ((ub_size != sizeof(ubus)) || + (ubus.ub_version != BUS_USER_VERSION)) { + VMBUS_LOG(DEBUG, + "kernel bus interface version mismatch: kernel %d expected %d", + ubus.ub_version, BUS_USER_VERSION); + return -EINVAL; } - while ((e = readdir(dir)) != NULL) { - if (e->d_name[0] == '.') - continue; + oid[oidlen++] = ubus.ub_generation; + dev_ptr = oidlen++; + + /* + * Scan devices. + * + * Stop after a fairly insane number to avoid death in the case + * of kernel corruption. + */ + + for (dev_idx = 0; dev_idx < 10000; dev_idx++) { + /* + * Get the device information. + */ + oid[dev_ptr] = dev_idx; + rlen = sizeof(udev); + error = sysctl(oid, oidlen, &udev, &rlen, NULL, 0); + if (error < 0) { + if (errno == ENOENT) /* end of list */ + break; + if (errno != EINVAL) /* gen count skip, restart */ + VMBUS_LOG(DEBUG, "sysctl hw.bus.devices.%d", + dev_idx); + return errno; + } + if (rlen != sizeof(udev)) { + VMBUS_LOG(DEBUG, + "sysctl returned wrong data %zd bytes instead of %zd", + rlen, sizeof(udev)); + return -EINVAL; + } - if (vmbus_scan_one(e->d_name) < 0) - goto error; + walker = udev.dv_fields; + ep = walker + sizeof(udev.dv_fields); + dd_name = NULL; + dd_desc = NULL; + dd_drivername = NULL; + dd_pnpinfo = NULL; + dd_location = NULL; +#define UNPACK(x) \ + do { \ + x = strdup(walker); \ + if (x == NULL) \ + return -ENOMEM; \ + if (walker + strnlen(walker, ep - walker) >= ep) \ + return -EINVAL; \ + walker += strlen(walker) + 1; \ + } while (0) + + UNPACK(dd_name); + UNPACK(dd_desc); + UNPACK(dd_drivername); + UNPACK(dd_pnpinfo); + UNPACK(dd_location); +#undef UNPACK + if (*dd_drivername && !(strcmp(dd_drivername, "vmbus"))) + vmbus_handle = udev.dv_handle; + + if (vmbus_handle && (vmbus_handle == udev.dv_parent) + && *dd_pnpinfo && *dd_name) { + unsigned int driver_len = 0, unit_num = 0; + char *endptr; + + driver_len = strlen(dd_drivername); + unit_num = strtoull(&dd_name[driver_len], &endptr, 10); + VMBUS_LOG(DEBUG, "Device name:%s, pnpinfo:%s", + dd_name, dd_pnpinfo); + + if (vmbus_scan_one(dd_drivername, unit_num) < 0) + goto error; + } } - closedir(dir); return 0; - error: - closedir(dir); return -1; }
diff --git a/drivers/net/netvsc/hn_rxtx.c b/drivers/net/netvsc/hn_rxtx.c
index c6bf7cc132..f306f2f3f0 100644
--- a/drivers/net/netvsc/hn_rxtx.c
+++ b/drivers/net/netvsc/hn_rxtx.c@@ -10,7 +10,7 @@ #include <errno.h> #include <unistd.h> #include <strings.h> -#include <malloc.h> +#include <stdlib.h> #include <rte_ethdev.h> #include <rte_memcpy.h>
--
2.30.1