[libvirt] [PATCHv2 05/12] nodedev: add iommuGroup to node device object

Laine Stump laine at laine.org
Tue Jun 25 03:05:31 UTC 2013


This includes adding it to the nodedev parser and formatter, docs, and
test.
---
 docs/formatnode.html.in                            | 63 +++++++++++++++-
 docs/schemas/nodedev.rng                           | 11 +++
 src/conf/node_device_conf.c                        | 86 +++++++++++++++++++++-
 src/conf/node_device_conf.h                        |  5 +-
 src/node_device/node_device_udev.c                 | 21 +++++-
 tests/nodedevschemadata/pci_8086_10c9_sriov_pf.xml | 16 ++++
 tests/nodedevxml2xmltest.c                         |  1 +
 7 files changed, 199 insertions(+), 4 deletions(-)
 create mode 100644 tests/nodedevschemadata/pci_8086_10c9_sriov_pf.xml

diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index 11654e5..ad05a70 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -80,6 +80,36 @@
               <dd>Vendor details from the device ROM, including an
                 attribute <code>id</code> with the hexadecimal vendor
                 id, and an optional text name of that vendor.</dd>
+              <dt><code>iommuGroup</code></dt>
+              <dd>
+                This optional element describes the "IOMMU group" this
+                device belongs to. If the element exists, it has a
+                mandatory <code>number</code> attribute which tells
+                the group number used for management of the group (all
+                devices in group "n" will be found in
+                "/sys/kernel/iommu_groups/n"). It will also have a
+                list of <code>address</code> subelements, each
+                containing the PCI address of a device in the same
+                group. The toplevel device will itself be included in
+                this list.
+              </dd>
+              <dt><code>capability</code></dt>
+              <dd>
+                This optional element can occur multiple times. If it
+                exists, it has a mandatory <code>type</code> attribute
+                which will be set to
+                either <code>physical_function</code>
+                or <code>virtual_functions</code>. If the type
+                is <code>physical_function</code>, there will be a
+                single <code>address</code> subelement which contains
+                the PCI address of the SRIOV Physical Function (PF)
+                that is the parent of this device (and this device is,
+                by implication, an SRIOV Virtual Function (VF)). If
+                the type is <code>virtual_functions</code>, then this
+                device is an SRIOV PF, and the capability element will
+                have a list of <code>address</code> subelements, one
+                for each VF on this PF.
+              </dd>
             </dl>
           </dd>
           <dt><code>usb_device</code></dt>
@@ -232,7 +262,38 @@
     <address>00:27:13:6a:fe:00</address>
     <capability type='80203'/>
   </capability>
-</device></pre>
+</device>
+
+<device>
+  <name>pci_0000_02_00_0</name>
+  <path>/sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0</path>
+  <parent>pci_0000_00_04_0</parent>
+  <driver>
+    <name>igb</name>
+  </driver>
+  <capability type='pci'>
+    <domain>0</domain>
+    <bus>2</bus>
+    <slot>0</slot>
+    <function>0</function>
+    <product id='0x10c9'>82576 Gigabit Network Connection</product>
+    <vendor id='0x8086'>Intel Corporation</vendor>
+    <capability type='virt_functions'>
+      <address domain='0x0000' bus='0x02' slot='0x10' function='0x0'/>
+      <address domain='0x0000' bus='0x02' slot='0x10' function='0x2'/>
+      <address domain='0x0000' bus='0x02' slot='0x10' function='0x4'/>
+      <address domain='0x0000' bus='0x02' slot='0x10' function='0x6'/>
+      <address domain='0x0000' bus='0x02' slot='0x11' function='0x0'/>
+      <address domain='0x0000' bus='0x02' slot='0x11' function='0x2'/>
+      <address domain='0x0000' bus='0x02' slot='0x11' function='0x4'/>
+    </capability>
+    <iommuGroup number='12'>
+      <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+      <address domain='0x0000' bus='0x02' slot='0x00' function='0x1'/>
+    </iommuGroup>
+  </capability>
+</device>
+    </pre>
 
   </body>
 </html>
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 1f5dcb9..d2bebff 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -144,6 +144,17 @@
       </element>
     </optional>
 
+    <optional>
+      <element name='iommuGroup'>
+        <attribute name='number'>
+          <ref name='unsignedInt'/>
+        </attribute>
+        <oneOrMore>
+          <ref name='address'/>
+        </oneOrMore>
+      </element>
+    </optional>
+
   </define>
 
   <define name='capusbdev'>
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 548cd8f..96742ef 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -1,6 +1,7 @@
 /*
  * node_device_conf.c: config handling for node devices
  *
+ * Copyright (C) 2009-2013 Red Hat, Inc.
  * Copyright (C) 2008 Virtual Iron Software, Inc.
  * Copyright (C) 2008 David F. Lively
  *
@@ -31,6 +32,7 @@
 #include "viralloc.h"
 #include "virstring.h"
 #include "node_device_conf.h"
+#include "device_conf.h"
 #include "virxml.h"
 #include "virbuffer.h"
 #include "viruuid.h"
@@ -330,6 +332,20 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def)
                 }
                 virBufferAddLit(&buf, "    </capability>\n");
             }
+            if (data->pci_dev.nIommuGroupDevices) {
+                virBufferAsprintf(&buf, "    <iommuGroup number='%d'>\n",
+                                  data->pci_dev.iommuGroupNumber);
+                for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
+                    virBufferAsprintf(&buf,
+                                      "      <address domain='0x%.4x' bus='0x%.2x' "
+                                      "slot='0x%.2x' function='0x%.1x'/>\n",
+                                      data->pci_dev.iommuGroupDevices[i]->domain,
+                                      data->pci_dev.iommuGroupDevices[i]->bus,
+                                      data->pci_dev.iommuGroupDevices[i]->slot,
+                                      data->pci_dev.iommuGroupDevices[i]->function);
+                }
+                virBufferAddLit(&buf, "    </iommuGroup>\n");
+            }
             break;
         case VIR_NODE_DEV_CAP_USB_DEV:
             virBufferAsprintf(&buf, "    <bus>%d</bus>\n", data->usb_dev.bus);
@@ -966,12 +982,71 @@ out:
 }
 
 static int
+virNodeDevCapPciDevIommuGroupParseXML(xmlXPathContextPtr ctxt,
+                                      xmlNodePtr iommuGroupNode,
+                                      union _virNodeDevCapData *data)
+{
+    xmlNodePtr origNode = ctxt->node;
+    xmlNodePtr *addrNodes = NULL;
+    char *numberStr = NULL;
+    int nAddrNodes, ii, ret = -1;
+    virPCIDeviceAddressPtr pciAddr = NULL;
+
+    ctxt->node = iommuGroupNode;
+
+    numberStr = virXMLPropString(iommuGroupNode, "number");
+    if (!numberStr) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       "%s", _("missing iommuGroup number attribute"));
+        goto cleanup;
+    }
+    if (virStrToLong_ui(numberStr, NULL, 10,
+                        &data->pci_dev.iommuGroupNumber) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("invalid iommuGroup number attribute '%s'"),
+                       numberStr);
+        goto cleanup;
+    }
+
+    if ((nAddrNodes = virXPathNodeSet("./address", ctxt, &addrNodes)) < 0)
+        goto cleanup;
+
+    for (ii = 0; ii < nAddrNodes; ii++) {
+        virDevicePCIAddress addr = { 0, 0, 0, 0, 0 };
+        if (virDevicePCIAddressParseXML(addrNodes[ii], &addr) < 0)
+            goto cleanup;
+        if (VIR_ALLOC(pciAddr) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+        pciAddr->domain = addr.domain;
+        pciAddr->bus = addr.bus;
+        pciAddr->slot = addr.slot;
+        pciAddr->function = addr.function;
+        if (VIR_APPEND_ELEMENT(data->pci_dev.iommuGroupDevices,
+                               data->pci_dev.nIommuGroupDevices,
+                               pciAddr) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+cleanup:
+    ctxt->node = origNode;
+    VIR_FREE(addrNodes);
+    VIR_FREE(pciAddr);
+    return ret;
+}
+
+
+static int
 virNodeDevCapPciDevParseXML(xmlXPathContextPtr ctxt,
                             virNodeDeviceDefPtr def,
                             xmlNodePtr node,
                             union _virNodeDevCapData *data)
 {
-    xmlNodePtr orignode;
+    xmlNodePtr orignode, iommuGroupNode;
     int ret = -1;
 
     orignode = ctxt->node;
@@ -1016,6 +1091,12 @@ virNodeDevCapPciDevParseXML(xmlXPathContextPtr ctxt,
     data->pci_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
     data->pci_dev.product_name = virXPathString("string(./product[1])", ctxt);
 
+    if ((iommuGroupNode = virXPathNode("./iommuGroup[1]", ctxt))) {
+        if (virNodeDevCapPciDevIommuGroupParseXML(ctxt, iommuGroupNode,
+                                                  data) < 0) {
+            goto out;
+        }
+    }
     ret = 0;
 out:
     ctxt->node = orignode;
@@ -1385,6 +1466,9 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
         for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
             VIR_FREE(data->pci_dev.virtual_functions[i]);
         }
+        for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
+            VIR_FREE(data->pci_dev.iommuGroupDevices[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 17240be..ec35da2 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -1,7 +1,7 @@
 /*
  * node_device_conf.h: config handling for node devices
  *
- * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2009-2013 Red Hat, Inc.
  * Copyright (C) 2008 Virtual Iron Software, Inc.
  * Copyright (C) 2008 David F. Lively
  *
@@ -112,6 +112,9 @@ struct _virNodeDevCapsDef {
             virPCIDeviceAddressPtr *virtual_functions;
             unsigned int num_virtual_functions;
             unsigned int flags;
+            virPCIDeviceAddressPtr *iommuGroupDevices;
+            size_t nIommuGroupDevices;
+            unsigned int iommuGroupNumber;
         } pci_dev;
         struct {
             unsigned int bus;
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index b94be80..9bb4a17 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -421,7 +421,8 @@ static int udevProcessPCI(struct udev_device *device,
 {
     const char *syspath = NULL;
     union _virNodeDevCapData *data = &def->caps->data;
-    int ret = -1;
+    virPCIDeviceAddress addr;
+    int tmpGroup, ret = -1;
     char *p;
     int rc;
 
@@ -501,6 +502,24 @@ static int udevProcessPCI(struct udev_device *device,
     else if (!rc && (data->pci_dev.num_virtual_functions > 0))
         data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
 
+    /* iommu group */
+    addr.domain = data->pci_dev.domain;
+    addr.bus = data->pci_dev.bus;
+    addr.slot = data->pci_dev.slot;
+    addr.function = data->pci_dev.function;
+    tmpGroup = virPCIGetIOMMUGroupNum(&addr);
+    if (tmpGroup == -1) {
+        /* error was already reported */
+        goto out;
+        /* -2 return means there is no iommu_group data */
+    } else if (tmpGroup >= 0) {
+        if (virPCIGetIOMMUGroupAddresses(&addr, &data->pci_dev.iommuGroupDevices,
+                                         &data->pci_dev.nIommuGroupDevices) < 0) {
+            goto out;
+        }
+        data->pci_dev.iommuGroupNumber = tmpGroup;
+    }
+
     ret = 0;
 
 out:
diff --git a/tests/nodedevschemadata/pci_8086_10c9_sriov_pf.xml b/tests/nodedevschemadata/pci_8086_10c9_sriov_pf.xml
new file mode 100644
index 0000000..eff8932
--- /dev/null
+++ b/tests/nodedevschemadata/pci_8086_10c9_sriov_pf.xml
@@ -0,0 +1,16 @@
+<device>
+  <name>pci_0000_02_00_0</name>
+  <parent>pci_0000_00_04_0</parent>
+  <capability type='pci'>
+    <domain>0</domain>
+    <bus>2</bus>
+    <slot>0</slot>
+    <function>0</function>
+    <product id='0x10c9'>82576 Gigabit Network Connection</product>
+    <vendor id='0x8086'>Intel Corporation</vendor>
+    <iommuGroup number='12'>
+      <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+      <address domain='0x0000' bus='0x02' slot='0x00' function='0x1'/>
+    </iommuGroup>
+  </capability>
+</device>
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index e81c617..ed49857 100644
--- a/tests/nodedevxml2xmltest.c
+++ b/tests/nodedevxml2xmltest.c
@@ -78,6 +78,7 @@ mymain(void)
     DO_TEST("net_00_13_02_b9_f9_d3");
     DO_TEST("net_00_15_58_2f_e9_55");
     DO_TEST("pci_1002_71c4");
+    DO_TEST("pci_8086_10c9_sriov_pf");
     DO_TEST("pci_8086_27c5_scsi_host_0");
     DO_TEST("pci_8086_27c5_scsi_host_scsi_device_lun0");
     DO_TEST("pci_8086_27c5_scsi_host_scsi_host");
-- 
1.7.11.7




More information about the libvir-list mailing list