3e5111
From 909d3ff4c0e4ab7486c60dade9900462c896d3ba Mon Sep 17 00:00:00 2001
3e5111
Message-Id: <909d3ff4c0e4ab7486c60dade9900462c896d3ba@dist-git>
3e5111
From: Erik Skultety <eskultet@redhat.com>
3e5111
Date: Thu, 18 May 2017 14:02:53 +0200
3e5111
Subject: [PATCH] nodedev: Introduce the mdev capability to a PCI parent device
3e5111
3e5111
The parent device needs to report the generic stuff about the supported
3e5111
mediated devices types, like device API, available instances, type name,
3e5111
etc. Therefore this patch introduces a new nested capability element of
3e5111
type 'mdev_types' with the resulting XML of the following format:
3e5111
3e5111
<device>
3e5111
  ...
3e5111
  <capability type='pci'>
3e5111
    ...
3e5111
    <capability type='mdev_types'>
3e5111
      <type id='vendor_supplied_id'>
3e5111
        <name>optional_vendor_supplied_codename</name>
3e5111
        <deviceAPI>vfio-pci</deviceAPI>
3e5111
        <availableInstances>NUM</availableInstances>
3e5111
      </type>
3e5111
        ...
3e5111
      <type>
3e5111
        ...
3e5111
      </type>
3e5111
    </capability>
3e5111
  </capability>
3e5111
  ...
3e5111
</device>
3e5111
3e5111
https://bugzilla.redhat.com/show_bug.cgi?id=1452072
3e5111
3e5111
Signed-off-by: Erik Skultety <eskultet@redhat.com>
3e5111
(cherry picked from commit 500cbc066a5362834462c4eefb260b7c96a8554f)
3e5111
Signed-off-by: Erik Skultety <eskultet@redhat.com>
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
---
3e5111
 docs/schemas/nodedev.rng                           |  26 +++++
3e5111
 src/conf/node_device_conf.c                        | 101 +++++++++++++++++
3e5111
 src/conf/node_device_conf.h                        |  15 +++
3e5111
 src/conf/virnodedeviceobj.c                        |  20 +++-
3e5111
 src/libvirt_private.syms                           |   1 +
3e5111
 src/node_device/node_device_udev.c                 | 119 +++++++++++++++++++++
3e5111
 .../pci_0000_02_10_7_mdev_types.xml                |  32 ++++++
3e5111
 tests/nodedevxml2xmltest.c                         |   1 +
3e5111
 8 files changed, 313 insertions(+), 2 deletions(-)
3e5111
 create mode 100644 tests/nodedevschemadata/pci_0000_02_10_7_mdev_types.xml
3e5111
3e5111
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
3e5111
index 0f90a73c8..e0a2c5032 100644
3e5111
--- a/docs/schemas/nodedev.rng
3e5111
+++ b/docs/schemas/nodedev.rng
3e5111
@@ -205,6 +205,32 @@
3e5111
     </optional>
3e5111
 
3e5111
     <optional>
3e5111
+      <element name='capability'>
3e5111
+        <attribute name='type'>
3e5111
+          <value>mdev_types</value>
3e5111
+        </attribute>
3e5111
+        <oneOrMore>
3e5111
+          <element name='type'>
3e5111
+            <attribute name='id'>
3e5111
+              <data type='string'/>
3e5111
+            </attribute>
3e5111
+            <optional>
3e5111
+              <element name='name'><text/></element>
3e5111
+            </optional>
3e5111
+            <element name='deviceAPI'>
3e5111
+              <choice>
3e5111
+                <value>vfio-pci</value>
3e5111
+              </choice>
3e5111
+            </element>
3e5111
+            <element name='availableInstances'>
3e5111
+              <ref name='unsignedInt'/>
3e5111
+            </element>
3e5111
+          </element>
3e5111
+        </oneOrMore>
3e5111
+      </element>
3e5111
+   </optional>
3e5111
+
3e5111
+    <optional>
3e5111
       <element name='iommuGroup'>
3e5111
         <attribute name='number'>
3e5111
           <ref name='unsignedInt'/>
3e5111
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
3e5111
index 90a087a37..de8ba8f9d 100644
3e5111
--- a/src/conf/node_device_conf.c
3e5111
+++ b/src/conf/node_device_conf.c
3e5111
@@ -89,6 +89,19 @@ virNodeDevCapsDefParseString(const char *xpath,
3e5111
 
3e5111
 
3e5111
 void
3e5111
+virNodeDevCapMdevTypeFree(virNodeDevCapMdevTypePtr type)
3e5111
+{
3e5111
+    if (!type)
3e5111
+        return;
3e5111
+
3e5111
+    VIR_FREE(type->id);
3e5111
+    VIR_FREE(type->name);
3e5111
+    VIR_FREE(type->device_api);
3e5111
+    VIR_FREE(type);
3e5111
+}
3e5111
+
3e5111
+
3e5111
+void
3e5111
 virNodeDeviceDefFree(virNodeDeviceDefPtr def)
3e5111
 {
3e5111
     virNodeDevCapsDefPtr caps;
3e5111
@@ -265,6 +278,27 @@ virNodeDeviceCapPCIDefFormat(virBufferPtr buf,
3e5111
         virBufferAsprintf(buf, "<capability type='%s'/>\n",
3e5111
                           virPCIHeaderTypeToString(data->pci_dev.hdrType));
3e5111
     }
3e5111
+    if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) {
3e5111
+        virBufferAddLit(buf, "<capability type='mdev_types'>\n");
3e5111
+        virBufferAdjustIndent(buf, 2);
3e5111
+        for (i = 0; i < data->pci_dev.nmdev_types; i++) {
3e5111
+            virNodeDevCapMdevTypePtr type = data->pci_dev.mdev_types[i];
3e5111
+            virBufferEscapeString(buf, "<type id='%s'>\n", type->id);
3e5111
+            virBufferAdjustIndent(buf, 2);
3e5111
+            if (type->name)
3e5111
+                virBufferEscapeString(buf, "<name>%s</name>\n",
3e5111
+                                      type->name);
3e5111
+            virBufferEscapeString(buf, "<deviceAPI>%s</deviceAPI>\n",
3e5111
+                                  type->device_api);
3e5111
+            virBufferAsprintf(buf,
3e5111
+                              "<availableInstances>%u</availableInstances>\n",
3e5111
+                              type->available_instances);
3e5111
+            virBufferAdjustIndent(buf, -2);
3e5111
+            virBufferAddLit(buf, "</type>\n");
3e5111
+        }
3e5111
+        virBufferAdjustIndent(buf, -2);
3e5111
+        virBufferAddLit(buf, "</capability>\n");
3e5111
+    }
3e5111
     if (data->pci_dev.nIommuGroupDevices) {
3e5111
         virBufferAsprintf(buf, "<iommuGroup number='%d'>\n",
3e5111
                           data->pci_dev.iommuGroupNumber);
3e5111
@@ -1365,6 +1399,67 @@ virNodeDevPCICapSRIOVVirtualParseXML(xmlXPathContextPtr ctxt,
3e5111
 
3e5111
 
3e5111
 static int
3e5111
+virNodeDevPCICapMdevTypesParseXML(xmlXPathContextPtr ctxt,
3e5111
+                                  virNodeDevCapPCIDevPtr pci_dev)
3e5111
+{
3e5111
+    int ret = -1;
3e5111
+    xmlNodePtr orignode = NULL;
3e5111
+    xmlNodePtr *nodes = NULL;
3e5111
+    int nmdev_types = -1;
3e5111
+    virNodeDevCapMdevTypePtr type = NULL;
3e5111
+    size_t i;
3e5111
+
3e5111
+    if ((nmdev_types = virXPathNodeSet("./type", ctxt, &nodes)) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    orignode = ctxt->node;
3e5111
+    for (i = 0; i < nmdev_types; i++) {
3e5111
+        ctxt->node = nodes[i];
3e5111
+
3e5111
+        if (VIR_ALLOC(type) < 0)
3e5111
+            goto cleanup;
3e5111
+
3e5111
+        if (!(type->id = virXPathString("string(./@id[1])", ctxt))) {
3e5111
+            virReportError(VIR_ERR_XML_ERROR, "%s",
3e5111
+                           _("missing 'id' attribute for mediated device's "
3e5111
+                             "<type> element"));
3e5111
+            goto cleanup;
3e5111
+        }
3e5111
+
3e5111
+        if (!(type->device_api = virXPathString("string(./deviceAPI[1])", ctxt))) {
3e5111
+            virReportError(VIR_ERR_XML_ERROR,
3e5111
+                           _("missing device API for mediated device type '%s'"),
3e5111
+                           type->id);
3e5111
+            goto cleanup;
3e5111
+        }
3e5111
+
3e5111
+        if (virXPathUInt("number(./availableInstances)", ctxt,
3e5111
+                         &type->available_instances) < 0) {
3e5111
+            virReportError(VIR_ERR_XML_ERROR,
3e5111
+                           _("missing number of available instances for "
3e5111
+                             "mediated device type '%s'"),
3e5111
+                           type->id);
3e5111
+            goto cleanup;
3e5111
+        }
3e5111
+
3e5111
+        type->name = virXPathString("string(./name)", ctxt);
3e5111
+
3e5111
+        if (VIR_APPEND_ELEMENT(pci_dev->mdev_types,
3e5111
+                               pci_dev->nmdev_types, type) < 0)
3e5111
+            goto cleanup;
3e5111
+    }
3e5111
+
3e5111
+    pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV;
3e5111
+    ret = 0;
3e5111
+ cleanup:
3e5111
+    VIR_FREE(nodes);
3e5111
+    virNodeDevCapMdevTypeFree(type);
3e5111
+    ctxt->node = orignode;
3e5111
+    return ret;
3e5111
+}
3e5111
+
3e5111
+
3e5111
+static int
3e5111
 virNodeDevPCICapabilityParseXML(xmlXPathContextPtr ctxt,
3e5111
                                 xmlNodePtr node,
3e5111
                                 virNodeDevCapPCIDevPtr pci_dev)
3e5111
@@ -1386,6 +1481,9 @@ virNodeDevPCICapabilityParseXML(xmlXPathContextPtr ctxt,
3e5111
     } else if (STREQ(type, "virt_functions") &&
3e5111
                virNodeDevPCICapSRIOVVirtualParseXML(ctxt, pci_dev) < 0) {
3e5111
         goto cleanup;
3e5111
+    } else if (STREQ(type, "mdev_types") &&
3e5111
+        virNodeDevPCICapMdevTypesParseXML(ctxt, pci_dev) < 0) {
3e5111
+        goto cleanup;
3e5111
     } else {
3e5111
         int hdrType = virPCIHeaderTypeFromString(type);
3e5111
 
3e5111
@@ -1898,6 +1996,9 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
3e5111
             VIR_FREE(data->pci_dev.iommuGroupDevices[i]);
3e5111
         VIR_FREE(data->pci_dev.iommuGroupDevices);
3e5111
         virPCIEDeviceInfoFree(data->pci_dev.pci_express);
3e5111
+        for (i = 0; i < data->pci_dev.nmdev_types; i++)
3e5111
+            virNodeDevCapMdevTypeFree(data->pci_dev.mdev_types[i]);
3e5111
+        VIR_FREE(data->pci_dev.mdev_types);
3e5111
         break;
3e5111
     case VIR_NODE_DEV_CAP_USB_DEV:
3e5111
         VIR_FREE(data->usb_dev.product_name);
3e5111
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
3e5111
index e168f2e27..18aaff8b5 100644
3e5111
--- a/src/conf/node_device_conf.h
3e5111
+++ b/src/conf/node_device_conf.h
3e5111
@@ -95,6 +95,7 @@ typedef enum {
3e5111
     VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION     = (1 << 0),
3e5111
     VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION      = (1 << 1),
3e5111
     VIR_NODE_DEV_CAP_FLAG_PCIE                      = (1 << 2),
3e5111
+    VIR_NODE_DEV_CAP_FLAG_PCI_MDEV                  = (1 << 3),
3e5111
 } virNodeDevPCICapFlags;
3e5111
 
3e5111
 typedef enum {
3e5111
@@ -133,6 +134,15 @@ struct _virNodeDevCapSystem {
3e5111
     virNodeDevCapSystemFirmware firmware;
3e5111
 };
3e5111
 
3e5111
+typedef struct _virNodeDevCapMdevType virNodeDevCapMdevType;
3e5111
+typedef virNodeDevCapMdevType *virNodeDevCapMdevTypePtr;
3e5111
+struct _virNodeDevCapMdevType {
3e5111
+    char *id;
3e5111
+    char *name;
3e5111
+    char *device_api;
3e5111
+    unsigned int available_instances;
3e5111
+};
3e5111
+
3e5111
 typedef struct _virNodeDevCapPCIDev virNodeDevCapPCIDev;
3e5111
 typedef virNodeDevCapPCIDev *virNodeDevCapPCIDevPtr;
3e5111
 struct _virNodeDevCapPCIDev {
3e5111
@@ -156,6 +166,8 @@ struct _virNodeDevCapPCIDev {
3e5111
     int numa_node;
3e5111
     virPCIEDeviceInfoPtr pci_express;
3e5111
     int hdrType; /* enum virPCIHeaderType or -1 */
3e5111
+    virNodeDevCapMdevTypePtr *mdev_types;
3e5111
+    size_t nmdev_types;
3e5111
 };
3e5111
 
3e5111
 typedef struct _virNodeDevCapUSBDev virNodeDevCapUSBDev;
3e5111
@@ -340,6 +352,9 @@ virNodeDeviceDefFree(virNodeDeviceDefPtr def);
3e5111
 void
3e5111
 virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps);
3e5111
 
3e5111
+void
3e5111
+virNodeDevCapMdevTypeFree(virNodeDevCapMdevTypePtr type);
3e5111
+
3e5111
 # define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP \
3e5111
                 (VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM        | \
3e5111
                  VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV       | \
3e5111
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c
3e5111
index 21d5d3f75..ac25fb598 100644
3e5111
--- a/src/conf/virnodedeviceobj.c
3e5111
+++ b/src/conf/virnodedeviceobj.c
3e5111
@@ -42,11 +42,13 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *dev,
3e5111
         virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_FC_HOST);
3e5111
     const char *vports_cap =
3e5111
         virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_VPORTS);
3e5111
+    const char *mdev_types =
3e5111
+        virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_MDEV_TYPES);
3e5111
 
3e5111
     while (caps) {
3e5111
-        if (STREQ(cap, virNodeDevCapTypeToString(caps->data.type)))
3e5111
+        if (STREQ(cap, virNodeDevCapTypeToString(caps->data.type))) {
3e5111
             return 1;
3e5111
-        else if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST)
3e5111
+        } else if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) {
3e5111
             if ((STREQ(cap, fc_host_cap) &&
3e5111
                 (caps->data.scsi_host.flags &
3e5111
                  VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST)) ||
3e5111
@@ -54,6 +56,13 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *dev,
3e5111
                 (caps->data.scsi_host.flags &
3e5111
                  VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS)))
3e5111
                 return 1;
3e5111
+        } else if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) {
3e5111
+            if ((STREQ(cap, mdev_types)) &&
3e5111
+                (caps->data.pci_dev.flags &
3e5111
+                 VIR_NODE_DEV_CAP_FLAG_PCI_MDEV))
3e5111
+                return 1;
3e5111
+        }
3e5111
+
3e5111
         caps = caps->next;
3e5111
     }
3e5111
     return 0;
3e5111
@@ -468,6 +477,13 @@ virNodeDeviceCapMatch(virNodeDeviceObjPtr devobj,
3e5111
                  VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))
3e5111
                 return true;
3e5111
         }
3e5111
+
3e5111
+        if (cap->data.type == VIR_NODE_DEV_CAP_PCI_DEV) {
3e5111
+            if (type == VIR_NODE_DEV_CAP_MDEV_TYPES &&
3e5111
+                (cap->data.pci_dev.flags &
3e5111
+                 VIR_NODE_DEV_CAP_FLAG_PCI_MDEV))
3e5111
+                return true;
3e5111
+        }
3e5111
     }
3e5111
 
3e5111
     return false;
3e5111
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
3e5111
index 7e1a06db3..343966cd0 100644
3e5111
--- a/src/libvirt_private.syms
3e5111
+++ b/src/libvirt_private.syms
3e5111
@@ -692,6 +692,7 @@ virNetDevIPRouteParseXML;
3e5111
 
3e5111
 
3e5111
 # conf/node_device_conf.h
3e5111
+virNodeDevCapMdevTypeFree;
3e5111
 virNodeDevCapsDefFree;
3e5111
 virNodeDevCapTypeFromString;
3e5111
 virNodeDevCapTypeToString;
3e5111
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
3e5111
index d4489e2a5..b89099c82 100644
3e5111
--- a/src/node_device/node_device_udev.c
3e5111
+++ b/src/node_device/node_device_udev.c
3e5111
@@ -314,6 +314,119 @@ static int udevTranslatePCIIds(unsigned int vendor,
3e5111
 }
3e5111
 
3e5111
 
3e5111
+static int
3e5111
+udevFillMdevType(struct udev_device *device,
3e5111
+                 const char *dir,
3e5111
+                 virNodeDevCapMdevTypePtr type)
3e5111
+{
3e5111
+    int ret = -1;
3e5111
+    char *attrpath = NULL;
3e5111
+
3e5111
+#define MDEV_GET_SYSFS_ATTR(attr_name, cb, ...)                             \
3e5111
+    do {                                                                    \
3e5111
+        if (virAsprintf(&attrpath, "%s/%s", dir, #attr_name) < 0)           \
3e5111
+            goto cleanup;                                                   \
3e5111
+                                                                            \
3e5111
+        if (cb(device, attrpath, __VA_ARGS__) < 0)                          \
3e5111
+            goto cleanup;                                                   \
3e5111
+                                                                            \
3e5111
+        VIR_FREE(attrpath);                                                 \
3e5111
+    } while (0)                                                             \
3e5111
+
3e5111
+    if (VIR_STRDUP(type->id, last_component(dir)) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    /* query udev for the attributes under subdirectories using the relative
3e5111
+     * path stored in @dir, i.e. 'mdev_supported_types/<type_id>'
3e5111
+     */
3e5111
+    MDEV_GET_SYSFS_ATTR(name, udevGetStringSysfsAttr, &type->name);
3e5111
+    MDEV_GET_SYSFS_ATTR(device_api, udevGetStringSysfsAttr, &type->device_api);
3e5111
+    MDEV_GET_SYSFS_ATTR(available_instances, udevGetUintSysfsAttr,
3e5111
+                        &type->available_instances, 10);
3e5111
+
3e5111
+#undef MDEV_GET_SYSFS_ATTR
3e5111
+
3e5111
+    ret = 0;
3e5111
+ cleanup:
3e5111
+    VIR_FREE(attrpath);
3e5111
+    return ret;
3e5111
+}
3e5111
+
3e5111
+
3e5111
+static int
3e5111
+udevPCIGetMdevTypesCap(struct udev_device *device,
3e5111
+                       virNodeDevCapPCIDevPtr pcidata)
3e5111
+{
3e5111
+    int ret = -1;
3e5111
+    int dirret = -1;
3e5111
+    DIR *dir = NULL;
3e5111
+    struct dirent *entry;
3e5111
+    char *path = NULL;
3e5111
+    char *tmppath = NULL;
3e5111
+    virNodeDevCapMdevTypePtr type = NULL;
3e5111
+    virNodeDevCapMdevTypePtr *types = NULL;
3e5111
+    size_t ntypes = 0;
3e5111
+    size_t i;
3e5111
+
3e5111
+    if (virAsprintf(&path, "%s/mdev_supported_types",
3e5111
+                    udev_device_get_syspath(device)) < 0)
3e5111
+        return -1;
3e5111
+
3e5111
+    if ((dirret = virDirOpenIfExists(&dir, path)) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    if (dirret == 0) {
3e5111
+        ret = 0;
3e5111
+        goto cleanup;
3e5111
+    }
3e5111
+
3e5111
+    if (VIR_ALLOC(types) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    /* UDEV doesn't report attributes under subdirectories by default but is
3e5111
+     * able to query them if the path to the attribute is relative to the
3e5111
+     * device's base path, e.g. /sys/devices/../0000:00:01.0/ is the device's
3e5111
+     * base path as udev reports it, but we're interested in attributes under
3e5111
+     * /sys/devices/../0000:00:01.0/mdev_supported_types/<type>/. So, we need to
3e5111
+     * scan the subdirectories ourselves.
3e5111
+     */
3e5111
+    while ((dirret = virDirRead(dir, &entry, path)) > 0) {
3e5111
+        if (VIR_ALLOC(type) < 0)
3e5111
+            goto cleanup;
3e5111
+
3e5111
+        /* construct the relative mdev type path bit for udev */
3e5111
+        if (virAsprintf(&tmppath, "mdev_supported_types/%s", entry->d_name) < 0)
3e5111
+            goto cleanup;
3e5111
+
3e5111
+        if (udevFillMdevType(device, tmppath, type) < 0)
3e5111
+            goto cleanup;
3e5111
+
3e5111
+        if (VIR_APPEND_ELEMENT(types, ntypes, type) < 0)
3e5111
+            goto cleanup;
3e5111
+
3e5111
+        VIR_FREE(tmppath);
3e5111
+    }
3e5111
+
3e5111
+    if (dirret < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    VIR_STEAL_PTR(pcidata->mdev_types, types);
3e5111
+    pcidata->nmdev_types = ntypes;
3e5111
+    pcidata->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV;
3e5111
+    ntypes = 0;
3e5111
+    ret = 0;
3e5111
+ cleanup:
3e5111
+    virNodeDevCapMdevTypeFree(type);
3e5111
+    for (i = 0; i < ntypes; i++)
3e5111
+        virNodeDevCapMdevTypeFree(types[i]);
3e5111
+    VIR_FREE(types);
3e5111
+    VIR_FREE(path);
3e5111
+    VIR_FREE(tmppath);
3e5111
+    VIR_DIR_CLOSE(dir);
3e5111
+    return ret;
3e5111
+}
3e5111
+
3e5111
+
3e5111
 static int udevProcessPCI(struct udev_device *device,
3e5111
                           virNodeDeviceDefPtr def)
3e5111
 {
3e5111
@@ -404,6 +517,12 @@ static int udevProcessPCI(struct udev_device *device,
3e5111
         }
3e5111
     }
3e5111
 
3e5111
+    /* check whether the device is mediated devices framework capable, if so,
3e5111
+     * process it
3e5111
+     */
3e5111
+    if (udevPCIGetMdevTypesCap(device, pci_dev) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
     ret = 0;
3e5111
 
3e5111
  cleanup:
3e5111
diff --git a/tests/nodedevschemadata/pci_0000_02_10_7_mdev_types.xml b/tests/nodedevschemadata/pci_0000_02_10_7_mdev_types.xml
3e5111
new file mode 100644
3e5111
index 000000000..a2d57569a
3e5111
--- /dev/null
3e5111
+++ b/tests/nodedevschemadata/pci_0000_02_10_7_mdev_types.xml
3e5111
@@ -0,0 +1,32 @@
3e5111
+<device>
3e5111
+  <name>pci_0000_02_10_7</name>
3e5111
+  <parent>pci_0000_00_04_0</parent>
3e5111
+  <capability type='pci'>
3e5111
+    <domain>0</domain>
3e5111
+    <bus>2</bus>
3e5111
+    <slot>16</slot>
3e5111
+    <function>7</function>
3e5111
+    <product id='0x10ca'>82576 Virtual Function</product>
3e5111
+    <vendor id='0x8086'>Intel Corporation</vendor>
3e5111
+    <capability type='mdev_types'>
3e5111
+      <type id='foo1'>
3e5111
+        <name>bar1</name>
3e5111
+        <deviceAPI>vfio-pci</deviceAPI>
3e5111
+        <availableInstances>1</availableInstances>
3e5111
+      </type>
3e5111
+      <type id='foo2'>
3e5111
+        <name>bar2</name>
3e5111
+        <deviceAPI>vfio-pci</deviceAPI>
3e5111
+        <availableInstances>2</availableInstances>
3e5111
+      </type>
3e5111
+    </capability>
3e5111
+    <iommuGroup number='31'>
3e5111
+      <address domain='0x0000' bus='0x02' slot='0x10' function='0x7'/>
3e5111
+    </iommuGroup>
3e5111
+    <numa node='0'/>
3e5111
+    <pci-express>
3e5111
+      <link validity='cap' port='0' speed='2.5' width='4'/>
3e5111
+      <link validity='sta' width='0'/>
3e5111
+    </pci-express>
3e5111
+  </capability>
3e5111
+</device>
3e5111
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
3e5111
index 5e1ae170c..eb5c50b86 100644
3e5111
--- a/tests/nodedevxml2xmltest.c
3e5111
+++ b/tests/nodedevxml2xmltest.c
3e5111
@@ -101,6 +101,7 @@ mymain(void)
3e5111
     DO_TEST("pci_0000_02_10_7_sriov_pf_vfs_all");
3e5111
     DO_TEST("pci_0000_02_10_7_sriov_pf_vfs_all_header_type");
3e5111
     DO_TEST("drm_renderD129");
3e5111
+    DO_TEST("pci_0000_02_10_7_mdev_types");
3e5111
 
3e5111
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
3e5111
 }
3e5111
-- 
3e5111
2.13.0
3e5111