[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] expose SR IOV physical/virtual function relationships



Attached is a patch that exposes the relationships between physical and virtual functions on SR IOV capable devices.

Dave
>From cc5b72f99cd472aa0c07d8115e0abc970feab704 Mon Sep 17 00:00:00 2001
From: David Allan <dallan redhat com>
Date: Mon, 30 Nov 2009 15:58:47 -0500
Subject: [PATCH 1/2] Add SR IOV physical and virtual function relationships

---
 src/conf/node_device_conf.c               |   16 ++++
 src/conf/node_device_conf.h               |    3 +
 src/node_device/node_device_driver.h      |   10 +++
 src/node_device/node_device_hal.c         |    6 ++
 src/node_device/node_device_linux_sysfs.c |  122 ++++++++++++++++++++++++++++-
 5 files changed, 156 insertions(+), 1 deletions(-)

diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 6003ab1..4b5d17c 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -246,6 +246,7 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
 {
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     virNodeDevCapsDefPtr caps;
+    unsigned int i = 0;
     char *tmp;

     virBufferAddLit(&buf, "<device>\n");
@@ -318,6 +319,16 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
                                       data->pci_dev.vendor_name);
             else
                 virBufferAddLit(&buf, " />\n");
+            if (data->pci_dev.physical_function) {
+                virBufferEscapeString(&buf, "    <physical_function>%s</physical_function>\n",
+                                      data->pci_dev.physical_function);
+            }
+            if (data->pci_dev.num_virtual_functions > 0) {
+                for (i = 0 ; i < data->pci_dev.num_virtual_functions ; i++) {
+                    virBufferEscapeString(&buf, "    <virtual_function>%s</virtual_function>\n",
+                                          data->pci_dev.virtual_functions[i]);
+                }
+            }
             break;
         case VIR_NODE_DEV_CAP_USB_DEV:
             virBufferVSprintf(&buf, "    <bus>%d</bus>\n", data->usb_dev.bus);
@@ -1387,6 +1398,7 @@ out:

 void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
 {
+    int i = 0;
     union _virNodeDevCapData *data = &caps->data;

     switch (caps->type) {
@@ -1402,6 +1414,10 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
     case VIR_NODE_DEV_CAP_PCI_DEV:
         VIR_FREE(data->pci_dev.product_name);
         VIR_FREE(data->pci_dev.vendor_name);
+        VIR_FREE(data->pci_dev.physical_function);
+        for (i = 0 ; i < data->pci_dev.num_virtual_functions ; i++) {
+            VIR_FREE(data->pci_dev.virtual_functions[i]);
+        }
         break;
     case VIR_NODE_DEV_CAP_USB_DEV:
         VIR_FREE(data->usb_dev.product_name);
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index 7a20bd6..11b7539 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -105,6 +105,9 @@ struct _virNodeDevCapsDef {
             unsigned class;
             char *product_name;
             char *vendor_name;
+            char *physical_function;
+            char **virtual_functions;
+            unsigned num_virtual_functions;
         } pci_dev;
         struct {
             unsigned bus;
diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h
index 4f0822c..d358276 100644
--- a/src/node_device/node_device_driver.h
+++ b/src/node_device/node_device_driver.h
@@ -61,6 +61,14 @@ int check_fc_host_linux(union _virNodeDevCapData *d);
 #define check_vport_capable(d) check_vport_capable_linux(d)
 int check_vport_capable_linux(union _virNodeDevCapData *d);

+#define get_physical_function(s,d) get_physical_function_linux(s,d)
+int get_physical_function_linux(const char *sysfs_path,
+                                union _virNodeDevCapData *d);
+
+#define get_virtual_functions(s,d) get_virtual_functions_linux(s,d)
+int get_virtual_functions_linux(const char *sysfs_path,
+                                union _virNodeDevCapData *d);
+
 #define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn)
 int read_wwn_linux(int host, const char *file, char **wwn);

@@ -68,6 +76,8 @@ int read_wwn_linux(int host, const char *file, char **wwn);

 #define check_fc_host(d)
 #define check_vport_capable(d)
+#define get_physical_function(sysfs_path, d)
+#define get_virtual_functions(sysfs_path, d)
 #define read_wwn(host, file, wwn)

 #endif /* __linux__ */
diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c
index 31c1764..7cb931e 100644
--- a/src/node_device/node_device_hal.c
+++ b/src/node_device/node_device_hal.c
@@ -145,14 +145,20 @@ static int gather_pci_cap(LibHalContext *ctx, const char *udi,
             (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot);
             (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function);
         }
+
+        get_physical_function(sysfs_path, d);
+        get_virtual_functions(sysfs_path, d);
+
         VIR_FREE(sysfs_path);
     }
+
     (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor);
     if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0)
         (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name);
     (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product);
     if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0)
         (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);
+
     return 0;
 }

diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c
index b7cf782..6b9738c 100644
--- a/src/node_device/node_device_linux_sysfs.c
+++ b/src/node_device/node_device_linux_sysfs.c
@@ -29,6 +29,7 @@
 #include "virterror_internal.h"
 #include "memory.h"
 #include "logging.h"
+#include <dirent.h>

 #define VIR_FROM_THIS VIR_FROM_NODEDEV

@@ -70,7 +71,7 @@ int read_wwn_linux(int host, const char *file, char **wwn)
     char buf[64];

     if (open_wwn_file(LINUX_SYSFS_FC_HOST_PREFIX, host, file, &fd) < 0) {
-            goto out;
+        goto out;
     }

     memset(buf, 0, sizeof(buf));
@@ -184,4 +185,123 @@ out:
     return retval;
 }

+
+static int get_sriov_function(const char *device_link,
+                              char **pci_device)
+{
+    char *device_path = NULL, *device_name = NULL;
+    char errbuf[64];
+    int ret = -1;
+
+    VIR_DEBUG("Attempting to resolve device path from device link '%s'\n",
+              device_link);
+
+    if (!virFileExists(device_link)) {
+
+        VIR_DEBUG("SR IOV function link '%s' does not exist\n", device_link);
+        /* Not an SR IOV device, not an error, either. */
+        ret = 0;
+        goto out;
+
+    }
+
+    device_path = realpath(device_link, device_path);
+    if (device_path == NULL) {
+	memset(errbuf, '\0', sizeof(errbuf));
+        VIR_ERROR("Failed to resolve device link '%s': '%s'\n", device_link,
+                  strerror_r(errno, errbuf, sizeof(errbuf)));
+        goto out;
+    }
+
+    VIR_DEBUG("SR IOV device path is '%s'\n", device_path);
+    device_name = basename(device_path);
+    *pci_device = strdup(device_name);
+    if (*pci_device == NULL) {
+        VIR_ERROR0("Failed to allocate memory for PCI device name\n");
+        goto out;
+    }
+
+    VIR_DEBUG("SR IOV function is '%s'\n", *pci_device);
+    ret = 0;
+
+out:
+    VIR_FREE(device_path);
+    return ret;
+}
+
+
+int get_physical_function_linux(const char *sysfs_path,
+                                union _virNodeDevCapData *d ATTRIBUTE_UNUSED)
+{
+    int ret = -1;
+    char *device_link = NULL;
+
+    VIR_DEBUG("Attempting to get SR IOV physical function for device "
+              "with sysfs path '%s'\n", sysfs_path);
+
+    if (virBuildPath(&device_link, sysfs_path, "physfn") == -1) {
+        virReportOOMError(NULL);
+    } else {
+        ret = get_sriov_function(device_link, &d->pci_dev.physical_function);
+    }
+
+    VIR_FREE(device_link);
+    return ret;
+}
+
+
+int get_virtual_functions_linux(const char *sysfs_path,
+                                union _virNodeDevCapData *d)
+{
+    int ret = -1;
+    DIR *dir = NULL;
+    struct dirent *entry = NULL;
+    char *device_link = NULL;
+
+    VIR_DEBUG("Attempting to get SR IOV virtual functions for device"
+              "with sysfs path '%s'\n", sysfs_path);
+
+    dir = opendir(sysfs_path);
+    if (dir == NULL) {
+        goto out;
+    }
+
+    while ((entry = readdir(dir))) {
+        if (STRPREFIX(entry->d_name, "virtfn")) {
+            /* This local is just to avoid lines of code much > 80 col. */
+            unsigned int *num_funcs = &d->pci_dev.num_virtual_functions;
+
+            if (virBuildPath(&device_link, sysfs_path, entry->d_name) == -1) {
+                virReportOOMError(NULL);
+                goto out;
+            }
+
+            VIR_DEBUG("Number of virtual functions: %d\n", *num_funcs);
+            if (VIR_REALLOC_N(d->pci_dev.virtual_functions, (*num_funcs) + 1) != 0) {
+                virReportOOMError(NULL);
+                goto out;
+            }
+
+            if (get_sriov_function(device_link,
+                                   &d->pci_dev.virtual_functions[*num_funcs]) != 0) {
+                VIR_ERROR("Failed to get SR IOV function from device link '%s'\n",
+                          device_link);
+                goto out;
+            } else {
+                (*num_funcs)++;
+            }
+
+            VIR_FREE(device_link);
+        }
+    }
+
+    closedir(dir);
+
+    ret = 0;
+
+out:
+    VIR_FREE(device_link);
+    return 0;
+}
+
 #endif /* __linux__ */
-- 
1.6.5.2


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]