vlib: retrieve the root bus of a given pci device
Added a function to parse sysfs, determine the root bus & domain of a given pci
device.
Type: improvement
Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
Change-Id: I36778116ecaa2d591617450fe5ae0bdb46b4424b
diff --git a/src/vlib/linux/pci.c b/src/vlib/linux/pci.c
index 1e5ab67..d968fe2 100644
--- a/src/vlib/linux/pci.c
+++ b/src/vlib/linux/pci.c
@@ -55,6 +55,7 @@
#include <linux/vfio.h>
#include <sys/eventfd.h>
+#define SYSFS_DEVICES_PCI "/sys/devices/pci"
static const char *sysfs_pci_dev_path = "/sys/bus/pci/devices";
static const char *sysfs_pci_drv_path = "/sys/bus/pci/drivers";
static char *sysfs_mod_vfio_noiommu =
@@ -383,6 +384,64 @@
return di;
}
+clib_error_t *__attribute__ ((weak))
+vlib_pci_get_device_root_bus (vlib_pci_addr_t *addr, vlib_pci_addr_t *root_bus)
+{
+ u8 *rel_path = 0, *abs_path = 0, *link_path = 0;
+ unformat_input_t input;
+ u32 fd = open (sysfs_pci_dev_path, O_RDONLY);
+ u32 size = 0;
+ u32 domain = 0, bus;
+ clib_error_t *err = NULL;
+
+ if (fd < 0)
+ return clib_error_return_unix (0, "failed to open %s", sysfs_pci_dev_path);
+
+ vec_alloc (rel_path, PATH_MAX);
+ vec_alloc (abs_path, PATH_MAX);
+
+ link_path =
+ format (0, "%s/%U", sysfs_pci_dev_path, format_vlib_pci_addr, addr);
+ size = readlinkat (fd, (char *) link_path, (char *) rel_path, PATH_MAX);
+ if (size < 0)
+ {
+ err = clib_error_return_unix (0, "failed to read %s", rel_path);
+ goto done;
+ }
+
+ rel_path[size] = '\0';
+ vec_free (link_path);
+
+ link_path = format (0, "%s/%s", sysfs_pci_dev_path, rel_path);
+ if (!realpath ((char *) link_path, (char *) abs_path))
+ {
+ err = clib_error_return_unix (0, "failed to resolve %s", link_path);
+ goto done;
+ }
+
+ unformat_init_string (&input, (char *) abs_path,
+ clib_strnlen ((char *) abs_path, PATH_MAX));
+
+ if (!unformat (&input, SYSFS_DEVICES_PCI "%x:%x/%s", &domain, &bus,
+ link_path))
+ {
+ err = clib_error_return (0, "unknown input '%U'", format_unformat_error,
+ input);
+ goto done;
+ }
+
+ root_bus->domain = domain;
+ root_bus->bus = bus;
+
+done:
+ vec_free (abs_path);
+ vec_free (link_path);
+ vec_free (rel_path);
+ close (fd);
+
+ return err;
+}
+
static int
directory_exists (char *path)
{
diff --git a/src/vlib/pci/pci.c b/src/vlib/pci/pci.c
index 18d93ac..5535eb1 100644
--- a/src/vlib/pci/pci.c
+++ b/src/vlib/pci/pci.c
@@ -61,6 +61,12 @@
return 0;
}
+clib_error_t *__attribute__ ((weak))
+vlib_pci_get_device_root_bus (vlib_pci_addr_t *addr, vlib_pci_addr_t *root_bus)
+{
+ return 0;
+}
+
vlib_pci_addr_t * __attribute__ ((weak)) vlib_pci_get_all_dev_addrs ()
{
return 0;
diff --git a/src/vlib/pci/pci.h b/src/vlib/pci/pci.h
index 01f7d5b..1dc4ce6 100644
--- a/src/vlib/pci/pci.h
+++ b/src/vlib/pci/pci.h
@@ -96,9 +96,11 @@
typedef u32 vlib_pci_dev_handle_t;
-vlib_pci_device_info_t *vlib_pci_get_device_info (vlib_main_t * vm,
- vlib_pci_addr_t * addr,
- clib_error_t ** error);
+vlib_pci_device_info_t *vlib_pci_get_device_info (vlib_main_t *vm,
+ vlib_pci_addr_t *addr,
+ clib_error_t **error);
+clib_error_t *vlib_pci_get_device_root_bus (vlib_pci_addr_t *addr,
+ vlib_pci_addr_t *root_bus);
vlib_pci_addr_t *vlib_pci_get_all_dev_addrs ();
vlib_pci_addr_t *vlib_pci_get_addr (vlib_main_t * vm,
vlib_pci_dev_handle_t h);