]> xenbits.xensource.com Git - libvirt.git/commitdiff
nodedev: report maxCount for virtual_functions capability
authorLaine Stump <laine@laine.org>
Mon, 23 Nov 2015 19:19:13 +0000 (14:19 -0500)
committerLaine Stump <laine@laine.org>
Tue, 24 Nov 2015 17:31:04 +0000 (12:31 -0500)
A PCI device may have the capability to setup virtual functions (VFs)
but have them currently all disabled. Prior to this patch, if that was
the case the the node device XML for the device wouldn't report any
virtual_functions capability.

With this patch, if a file called "sriov_totalvfs" is found in the
device's sysfs directory, its contents will be interpreted as a
decimal number, and that value will be reported as "maxCount" in a
capability element of the device's XML, e.g.:

   <capability type='virtual_functions' maxCount='7'/>

This will be reported regardless of whether or not any VFs are
currently enabled for the device.

NB: sriov_numvfs (the number of VFs currently active) is also
available in sysfs, but that value is implied by the number of items
in the list that is inside the capability element, so there is no
reason to explicitly provide it as an attribute.

sriov_totalvfs and sriov_numvfs are available in kernels at least as far
back as the 2.6.32 that is in RHEL6.7, but in the case that they
simply aren't there, libvirt will behave as it did prior to this patch
- no maxCount will be displayed, and the virtual_functions capability
will be absent from the device's XML when 0 VFs are enabled.

src/network/bridge_driver.c
src/node_device/node_device_linux_sysfs.c
src/util/virnetdev.c
src/util/virnetdev.h
src/util/virpci.c
src/util/virpci.h

index f838671ad47261151374acbd9e57c38ca3f3a17f..a0f64947f77dfdee83975ed5cc8a55473d7ccaa0 100644 (file)
@@ -2334,6 +2334,7 @@ static int
 networkCreateInterfacePool(virNetworkDefPtr netdef)
 {
     size_t numVirtFns = 0;
+    unsigned int maxVirtFns = 0;
     char **vfNames = NULL;
     virPCIDeviceAddressPtr *virtFns;
 
@@ -2343,8 +2344,8 @@ networkCreateInterfacePool(virNetworkDefPtr netdef)
     if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
        return 0;
 
-    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev,
-                                      &vfNames, &virtFns, &numVirtFns)) < 0) {
+    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
+                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Could not get Virtual functions on %s"),
                        netdef->forward.pfs->dev);
index 6d5a406ec99384943812a7bd7cfb8b07014b1332..431f471f7a0e07a0f3669a26b890ee270ee86fbc 100644 (file)
@@ -150,6 +150,7 @@ nodeDeviceSysfsGetPCISRIOVCaps(const char *sysfsPath,
        VIR_FREE(data->pci_dev.virtual_functions[i]);
     VIR_FREE(data->pci_dev.virtual_functions);
     data->pci_dev.num_virtual_functions = 0;
+    data->pci_dev.max_virtual_functions = 0;
     data->pci_dev.flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
     data->pci_dev.flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
 
@@ -157,11 +158,13 @@ nodeDeviceSysfsGetPCISRIOVCaps(const char *sysfsPath,
         data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
 
     ret = virPCIGetVirtualFunctions(sysfsPath, &data->pci_dev.virtual_functions,
-                                    &data->pci_dev.num_virtual_functions);
+                                    &data->pci_dev.num_virtual_functions,
+                                    &data->pci_dev.max_virtual_functions);
     if (ret < 0)
         return ret;
 
-    if (data->pci_dev.num_virtual_functions > 0)
+    if (data->pci_dev.num_virtual_functions > 0 ||
+        data->pci_dev.max_virtual_functions > 0)
         data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
 
     return ret;
index ade9afad1361ffe941a4a018e44414bd0e00a7e8..e7f44cdd24ac1634f3cd15c9092b51a6058ce822 100644 (file)
@@ -1802,7 +1802,8 @@ int
 virNetDevGetVirtualFunctions(const char *pfname,
                              char ***vfname,
                              virPCIDeviceAddressPtr **virt_fns,
-                             size_t *n_vfname)
+                             size_t *n_vfname,
+                             unsigned int *max_vfs)
 {
     int ret = -1;
     size_t i;
@@ -1812,12 +1813,13 @@ virNetDevGetVirtualFunctions(const char *pfname,
 
     *virt_fns = NULL;
     *n_vfname = 0;
+    *max_vfs = 0;
 
     if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0)
         return ret;
 
     if (virPCIGetVirtualFunctions(pf_sysfs_device_link, virt_fns,
-                                  n_vfname) < 0)
+                                  n_vfname, max_vfs) < 0)
         goto cleanup;
 
     if (VIR_ALLOC_N(*vfname, *n_vfname) < 0)
@@ -1987,7 +1989,8 @@ int
 virNetDevGetVirtualFunctions(const char *pfname ATTRIBUTE_UNUSED,
                              char ***vfname ATTRIBUTE_UNUSED,
                              virPCIDeviceAddressPtr **virt_fns ATTRIBUTE_UNUSED,
-                             size_t *n_vfname ATTRIBUTE_UNUSED)
+                             size_t *n_vfname ATTRIBUTE_UNUSED,
+                             unsigned int *max_vfs ATTRIBUTE_UNUSED)
 {
     virReportSystemError(ENOSYS, "%s",
                          _("Unable to get virtual functions on this platform"));
index 772ae75682a95024a5572f29fa871975dec95eea..e7719d58a41004ca05dfb63b36625ba9c6744b15 100644 (file)
@@ -163,9 +163,10 @@ int virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
 int virNetDevGetVirtualFunctions(const char *pfname,
                                  char ***vfname,
                                  virPCIDeviceAddressPtr **virt_fns,
-                                 size_t *n_vfname)
+                                 size_t *n_vfname,
+                                 unsigned int *max_vfs)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
+    ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_RETURN_CHECK;
 
 int virNetDevLinkDump(const char *ifname, int ifindex,
                       void **nlData, struct nlattr **tb,
index 35b145931a88059c3a83fc9152763a6b520bbbff..bececb5796af865e90645af0cda0773ccf7724cc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * virpci.c: helper APIs for managing host PCI devices
  *
- * Copyright (C) 2009-2014 Red Hat, Inc.
+ * Copyright (C) 2009-2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -2514,18 +2514,36 @@ virPCIGetPhysicalFunction(const char *vf_sysfs_path,
 int
 virPCIGetVirtualFunctions(const char *sysfs_path,
                           virPCIDeviceAddressPtr **virtual_functions,
-                          size_t *num_virtual_functions)
+                          size_t *num_virtual_functions,
+                          unsigned int *max_virtual_functions)
 {
     int ret = -1;
     size_t i;
     char *device_link = NULL;
     virPCIDeviceAddress *config_addr = NULL;
+    char *totalvfs_file = NULL, *totalvfs_str = NULL;
 
     VIR_DEBUG("Attempting to get SR IOV virtual functions for device"
               "with sysfs path '%s'", sysfs_path);
 
     *virtual_functions = NULL;
     *num_virtual_functions = 0;
+    *max_virtual_functions = 0;
+
+    if (virAsprintf(&totalvfs_file, "%s/sriov_totalvfs", sysfs_path) < 0)
+       goto error;
+    if (virFileExists(totalvfs_file)) {
+        char *end = NULL; /* so that terminating \n doesn't create error */
+
+        if (virFileReadAll(totalvfs_file, 16, &totalvfs_str) < 0)
+            goto error;
+        if (virStrToLong_ui(totalvfs_str, &end, 10, max_virtual_functions) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Unrecognized value in %s: %s"),
+                           totalvfs_file, totalvfs_str);
+            goto error;
+        }
+    }
 
     do {
         /* look for virtfn%d links until one isn't found */
@@ -2553,6 +2571,8 @@ virPCIGetVirtualFunctions(const char *sysfs_path,
  cleanup:
     VIR_FREE(device_link);
     VIR_FREE(config_addr);
+    VIR_FREE(totalvfs_file);
+    VIR_FREE(totalvfs_str);
     return ret;
 
  error:
@@ -2594,6 +2614,7 @@ virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link,
     int ret = -1;
     size_t i;
     size_t num_virt_fns = 0;
+    unsigned int max_virt_fns = 0;
     virPCIDeviceAddressPtr vf_bdf = NULL;
     virPCIDeviceAddressPtr *virt_fns = NULL;
 
@@ -2602,7 +2623,7 @@ virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link,
         return ret;
 
     if (virPCIGetVirtualFunctions(pf_sysfs_device_link, &virt_fns,
-                                  &num_virt_fns) < 0) {
+                                  &num_virt_fns, &max_virt_fns) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Error getting physical function's '%s' "
                          "virtual_functions"), pf_sysfs_device_link);
@@ -2738,7 +2759,8 @@ virPCIGetPhysicalFunction(const char *vf_sysfs_path ATTRIBUTE_UNUSED,
 int
 virPCIGetVirtualFunctions(const char *sysfs_path ATTRIBUTE_UNUSED,
                           virPCIDeviceAddressPtr **virtual_functions ATTRIBUTE_UNUSED,
-                          size_t *num_virtual_functions ATTRIBUTE_UNUSED)
+                          size_t *num_virtual_functions ATTRIBUTE_UNUSED,
+                          unsigned int *max_virtual_functions ATTRIBUTE_UNUSED)
 {
     virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
     return -1;
index 64b9e96040ebbfb9a994c8bc76cebfe81bde56ef..6516f058c781299b1fa1dcb98b10915b13090679 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * virpci.h: helper APIs for managing host PCI devices
  *
- * Copyright (C) 2009, 2011-2014 Red Hat, Inc.
+ * Copyright (C) 2009, 2011-2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -171,7 +171,8 @@ int virPCIGetPhysicalFunction(const char *sysfs_path,
 
 int virPCIGetVirtualFunctions(const char *sysfs_path,
                               virPCIDeviceAddressPtr **virtual_functions,
-                              size_t *num_virtual_functions);
+                              size_t *num_virtual_functions,
+                              unsigned int *max_virtual_functions);
 
 int virPCIIsVirtualFunction(const char *vf_sysfs_device_link);