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