render / rpms / libvirt

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