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

Laine Stump laine at laine.org
Wed Jun 26 04:53:47 UTC 2013


I just realized that I had only implemented this for the udev nodeDevice
driver, but not the HAL driver. I can easily add the same code into the
HAL driver, but don't have any system to test building it on.

Should I put that code in untested, or leave the HAL driver without this
functionality? (Does anyone still use HAL?)


On 06/24/2013 11:05 PM, Laine Stump wrote:
> 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");




More information about the libvir-list mailing list