3e5111
From 8e5ac9cdbe38dd3b3320b97385d8e2cf0e862ef7 Mon Sep 17 00:00:00 2001
3e5111
Message-Id: <8e5ac9cdbe38dd3b3320b97385d8e2cf0e862ef7@dist-git>
3e5111
From: Erik Skultety <eskultet@redhat.com>
3e5111
Date: Thu, 18 May 2017 14:02:54 +0200
3e5111
Subject: [PATCH] nodedev: Introduce mdev capability for mediated devices
3e5111
3e5111
Start discovering the mediated devices on the host system and format the
3e5111
attributes for the mediated device into the XML. Compared to the parent
3e5111
device which reports generic information about the abstract mediated
3e5111
devices types, a child device only reports the type name it has been
3e5111
instantiated from and the IOMMU group number, since that's device
3e5111
specific compared to the rest of the info that can be gathered about
3e5111
mediated devices at the moment.
3e5111
This patch introduces both the formatting and parsing routines, updates
3e5111
nodedev.rng schema, adding a testcase as well.
3e5111
3e5111
The resulting mdev child device XML:
3e5111
<device>
3e5111
  <name>mdev_4b20d080_1b54_4048_85b3_a6a62d165c01</name>
3e5111
  <path>/sys/devices/.../4b20d080-1b54-4048-85b3-a6a62d165c01</path>
3e5111
  <parent>pci_0000_06_00_0</parent>
3e5111
  <driver>
3e5111
    <name>vfio_mdev</name>
3e5111
  </driver>
3e5111
  <capability type='mdev'>
3e5111
    <type id='vendor_supplied_type_id'/>
3e5111
    <iommuGroup number='NUM'/>
3e5111
  <capability/>
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 88ef73e13cddc8c0ff01dfe7a914342f8720c517)
3e5111
Signed-off-by: Erik Skultety <eskultet@redhat.com>
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
---
3e5111
 docs/schemas/nodedev.rng                           | 17 +++++++++
3e5111
 src/conf/node_device_conf.c                        | 41 +++++++++++++++++++++
3e5111
 src/conf/node_device_conf.h                        |  8 ++++
3e5111
 src/node_device/node_device_udev.c                 | 43 +++++++++++++++++++++-
3e5111
 .../mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml  |  8 ++++
3e5111
 tests/nodedevxml2xmltest.c                         |  1 +
3e5111
 6 files changed, 117 insertions(+), 1 deletion(-)
3e5111
 create mode 100644 tests/nodedevschemadata/mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml
3e5111
3e5111
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
3e5111
index e0a2c5032..924f73861 100644
3e5111
--- a/docs/schemas/nodedev.rng
3e5111
+++ b/docs/schemas/nodedev.rng
3e5111
@@ -83,6 +83,7 @@
3e5111
         <ref name="capscsi"/>
3e5111
         <ref name="capstorage"/>
3e5111
         <ref name="capdrm"/>
3e5111
+        <ref name="capmdev"/>
3e5111
       </choice>
3e5111
     </element>
3e5111
   </define>
3e5111
@@ -580,6 +581,22 @@
3e5111
     </element>
3e5111
   </define>
3e5111
 
3e5111
+  <define name='capmdev'>
3e5111
+    <attribute name='type'>
3e5111
+      <value>mdev</value>
3e5111
+    </attribute>
3e5111
+    <element name='type'>
3e5111
+      <attribute name='id'>
3e5111
+        <data type='string'/>
3e5111
+      </attribute>
3e5111
+    </element>
3e5111
+    <element name='iommuGroup'>
3e5111
+      <attribute name='number'>
3e5111
+        <ref name='unsignedInt'/>
3e5111
+      </attribute>
3e5111
+    </element>
3e5111
+  </define>
3e5111
+
3e5111
   <define name='address'>
3e5111
     <element name='address'>
3e5111
       <attribute name='domain'><ref name='hexuint'/></attribute>
3e5111
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
3e5111
index de8ba8f9d..ac61db34c 100644
3e5111
--- a/src/conf/node_device_conf.c
3e5111
+++ b/src/conf/node_device_conf.c
3e5111
@@ -577,6 +577,10 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def)
3e5111
             virBufferEscapeString(&buf, "<type>%s</type>\n", virNodeDevDRMTypeToString(data->drm.type));
3e5111
             break;
3e5111
         case VIR_NODE_DEV_CAP_MDEV:
3e5111
+            virBufferEscapeString(&buf, "<type id='%s'/>\n", data->mdev.type);
3e5111
+            virBufferAsprintf(&buf, "<iommuGroup number='%u'/>\n",
3e5111
+                              data->mdev.iommuGroupNumber);
3e5111
+            break;
3e5111
         case VIR_NODE_DEV_CAP_MDEV_TYPES:
3e5111
         case VIR_NODE_DEV_CAP_FC_HOST:
3e5111
         case VIR_NODE_DEV_CAP_VPORTS:
3e5111
@@ -1647,6 +1651,39 @@ virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
3e5111
 }
3e5111
 
3e5111
 
3e5111
+static int
3e5111
+virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt,
3e5111
+                          virNodeDeviceDefPtr def,
3e5111
+                          xmlNodePtr node,
3e5111
+                          virNodeDevCapMdevPtr mdev)
3e5111
+{
3e5111
+    xmlNodePtr orignode;
3e5111
+    int ret = -1;
3e5111
+
3e5111
+    orignode = ctxt->node;
3e5111
+    ctxt->node = node;
3e5111
+
3e5111
+    if (!(mdev->type = virXPathString("string(./type[1]/@id)", ctxt))) {
3e5111
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3e5111
+                       _("missing type id attribute for '%s'"), def->name);
3e5111
+        goto out;
3e5111
+    }
3e5111
+
3e5111
+    if (virNodeDevCapsDefParseULong("number(./iommuGroup[1]/@number)", ctxt,
3e5111
+                                    &mdev->iommuGroupNumber, def,
3e5111
+                                    _("missing iommuGroup number attribute for "
3e5111
+                                      "'%s'"),
3e5111
+                                    _("invalid iommuGroup number attribute for "
3e5111
+                                      "'%s'")) < 0)
3e5111
+        goto out;
3e5111
+
3e5111
+    ret = 0;
3e5111
+ out:
3e5111
+    ctxt->node = orignode;
3e5111
+    return ret;
3e5111
+}
3e5111
+
3e5111
+
3e5111
 static virNodeDevCapsDefPtr
3e5111
 virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
3e5111
                           virNodeDeviceDefPtr def,
3e5111
@@ -1715,6 +1752,8 @@ virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
3e5111
         ret = virNodeDevCapDRMParseXML(ctxt, def, node, &caps->data.drm);
3e5111
         break;
3e5111
     case VIR_NODE_DEV_CAP_MDEV:
3e5111
+        ret = virNodeDevCapMdevParseXML(ctxt, def, node, &caps->data.mdev);
3e5111
+        break;
3e5111
     case VIR_NODE_DEV_CAP_MDEV_TYPES:
3e5111
     case VIR_NODE_DEV_CAP_FC_HOST:
3e5111
     case VIR_NODE_DEV_CAP_VPORTS:
3e5111
@@ -2037,6 +2076,8 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
3e5111
         VIR_FREE(data->sg.path);
3e5111
         break;
3e5111
     case VIR_NODE_DEV_CAP_MDEV:
3e5111
+        VIR_FREE(data->mdev.type);
3e5111
+        break;
3e5111
     case VIR_NODE_DEV_CAP_MDEV_TYPES:
3e5111
     case VIR_NODE_DEV_CAP_DRM:
3e5111
     case VIR_NODE_DEV_CAP_FC_HOST:
3e5111
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
3e5111
index 18aaff8b5..5743f9d3e 100644
3e5111
--- a/src/conf/node_device_conf.h
3e5111
+++ b/src/conf/node_device_conf.h
3e5111
@@ -143,6 +143,13 @@ struct _virNodeDevCapMdevType {
3e5111
     unsigned int available_instances;
3e5111
 };
3e5111
 
3e5111
+typedef struct _virNodeDevCapMdev virNodeDevCapMdev;
3e5111
+typedef virNodeDevCapMdev *virNodeDevCapMdevPtr;
3e5111
+struct _virNodeDevCapMdev {
3e5111
+    char *type;
3e5111
+    unsigned int iommuGroupNumber;
3e5111
+};
3e5111
+
3e5111
 typedef struct _virNodeDevCapPCIDev virNodeDevCapPCIDev;
3e5111
 typedef virNodeDevCapPCIDev *virNodeDevCapPCIDevPtr;
3e5111
 struct _virNodeDevCapPCIDev {
3e5111
@@ -276,6 +283,7 @@ struct _virNodeDevCapData {
3e5111
         virNodeDevCapStorage storage;
3e5111
         virNodeDevCapSCSIGeneric sg;
3e5111
         virNodeDevCapDRM drm;
3e5111
+        virNodeDevCapMdev mdev;
3e5111
     };
3e5111
 };
3e5111
 
3e5111
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
3e5111
index b89099c82..37528ee48 100644
3e5111
--- a/src/node_device/node_device_udev.c
3e5111
+++ b/src/node_device/node_device_udev.c
3e5111
@@ -1073,6 +1073,42 @@ udevProcessSCSIGeneric(struct udev_device *dev,
3e5111
 }
3e5111
 
3e5111
 static int
3e5111
+udevProcessMediatedDevice(struct udev_device *dev,
3e5111
+                          virNodeDeviceDefPtr def)
3e5111
+{
3e5111
+    int ret = -1;
3e5111
+    const char *uuidstr = NULL;
3e5111
+    int iommugrp = -1;
3e5111
+    char *linkpath = NULL;
3e5111
+    char *realpath = NULL;
3e5111
+    virNodeDevCapMdevPtr data = &def->caps->data.mdev;
3e5111
+
3e5111
+    if (virAsprintf(&linkpath, "%s/mdev_type", udev_device_get_syspath(dev)) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    if (virFileResolveLink(linkpath, &realpath) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    if (VIR_STRDUP(data->type, last_component(realpath)) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    uuidstr = udev_device_get_sysname(dev);
3e5111
+    if ((iommugrp = virMediatedDeviceGetIOMMUGroupNum(uuidstr)) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    if (udevGenerateDeviceName(dev, def, NULL) != 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
+    data->iommuGroupNumber = iommugrp;
3e5111
+
3e5111
+    ret = 0;
3e5111
+ cleanup:
3e5111
+    VIR_FREE(linkpath);
3e5111
+    VIR_FREE(realpath);
3e5111
+    return ret;
3e5111
+}
3e5111
+
3e5111
+static int
3e5111
 udevGetDeviceNodes(struct udev_device *device,
3e5111
                    virNodeDeviceDefPtr def)
3e5111
 {
3e5111
@@ -1140,12 +1176,16 @@ udevGetDeviceType(struct udev_device *device,
3e5111
         if (udevHasDeviceProperty(device, "INTERFACE"))
3e5111
             *type = VIR_NODE_DEV_CAP_NET;
3e5111
 
3e5111
-        /* SCSI generic device doesn't set DEVTYPE property */
3e5111
+        /* Neither SCSI generic devices nor mediated devices set DEVTYPE
3e5111
+         * property, therefore we need to rely on the SUBSYSTEM property */
3e5111
         if (udevGetStringProperty(device, "SUBSYSTEM", &subsystem) < 0)
3e5111
             return -1;
3e5111
 
3e5111
         if (STREQ_NULLABLE(subsystem, "scsi_generic"))
3e5111
             *type = VIR_NODE_DEV_CAP_SCSI_GENERIC;
3e5111
+        else if (STREQ_NULLABLE(subsystem, "mdev"))
3e5111
+            *type = VIR_NODE_DEV_CAP_MDEV;
3e5111
+
3e5111
         VIR_FREE(subsystem);
3e5111
     }
3e5111
 
3e5111
@@ -1185,6 +1225,7 @@ static int udevGetDeviceDetails(struct udev_device *device,
3e5111
     case VIR_NODE_DEV_CAP_DRM:
3e5111
         return udevProcessDRMDevice(device, def);
3e5111
     case VIR_NODE_DEV_CAP_MDEV:
3e5111
+        return udevProcessMediatedDevice(device, def);
3e5111
     case VIR_NODE_DEV_CAP_MDEV_TYPES:
3e5111
     case VIR_NODE_DEV_CAP_SYSTEM:
3e5111
     case VIR_NODE_DEV_CAP_FC_HOST:
3e5111
diff --git a/tests/nodedevschemadata/mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml b/tests/nodedevschemadata/mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml
3e5111
new file mode 100644
3e5111
index 000000000..470e5917e
3e5111
--- /dev/null
3e5111
+++ b/tests/nodedevschemadata/mdev_3627463d_b7f0_4fea_b468_f1da537d301b.xml
3e5111
@@ -0,0 +1,8 @@
3e5111
+<device>
3e5111
+  <name>mdev_3627463d_b7f0_4fea_b468_f1da537d301b</name>
3e5111
+  <parent>computer</parent>
3e5111
+  <capability type='mdev'>
3e5111
+    <type id='mtty-1'/>
3e5111
+    <iommuGroup number='12'/>
3e5111
+  </capability>
3e5111
+</device>
3e5111
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
3e5111
index eb5c50b86..26f0d25bc 100644
3e5111
--- a/tests/nodedevxml2xmltest.c
3e5111
+++ b/tests/nodedevxml2xmltest.c
3e5111
@@ -102,6 +102,7 @@ mymain(void)
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
+    DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b");
3e5111
 
3e5111
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
3e5111
 }
3e5111
-- 
3e5111
2.13.0
3e5111