Implement iommufdId attribute for hostdev devices that
can be used to specify associated iommufd object when
launching a qemu VM.

Signed-off-by: Nathan Chen <nath...@nvidia.com>
---
 docs/formatdomain.rst             |  9 +++++++++
 src/conf/domain_conf.c            | 20 ++++++++++++++++++++
 src/conf/domain_conf.h            |  1 +
 src/conf/schemas/domaincommon.rng |  9 +++++++++
 src/qemu/qemu_command.c           | 14 ++++++++++++++
 5 files changed, 53 insertions(+)

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 2558df18ef..e2b9be16c9 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -4581,6 +4581,7 @@ or:
        </source>
        <boot order='1'/>
        <rom bar='on' file='/etc/fake/boot.bin'/>
+       <iommufdId>iommufd0</iommufdId>
      </hostdev>
    </devices>
    ...
@@ -4829,6 +4830,14 @@ or:
    device; if PCI ROM loading is disabled through this attribute, attempts to
    tweak the loading process further using the ``bar`` or ``file`` attributes
    will be rejected. :since:`Since 4.3.0 (QEMU and KVM only)`.
+``iommufdId``
+   The ``iommufdId`` element is used to specify using the iommufd interface to
+   propagate DMA mappings to the kernel, instead of legacy VFIO. When the
+   element is present, an iommufd object with its ID specified by ``iommufdId``
+   will be created by the resulting qemu command. Libvirt will open the
+   /dev/iommu and VFIO device cdev, passing the associated file descriptor
+   numbers to the qemu command.
+
 ``address``
    The ``address`` element for USB devices has a ``bus`` and ``device``
    attribute to specify the USB bus and device number the device appears at on
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5ea4d6424b..38d8f2998a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -13581,6 +13581,15 @@ virDomainVideoDefParseXML(virDomainXMLOption *xmlopt,
     return g_steal_pointer(&def);
 }
 
+static void
+virDomainHostdevDefIommufdParseXML(xmlXPathContextPtr ctxt,
+                                   char** iommufdId)
+{
+    g_autofree char *iommufdIdtmp = virXPathString("string(./iommufdId)", 
ctxt);
+    if (iommufdIdtmp)
+        *iommufdId = g_steal_pointer(&iommufdIdtmp);
+}
+
 static virDomainHostdevDef *
 virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt,
                             xmlNodePtr node,
@@ -13655,6 +13664,8 @@ virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt,
     if (virDomainNetTeamingInfoParseXML(ctxt, &def->teaming) < 0)
         goto error;
 
+    virDomainHostdevDefIommufdParseXML(ctxt, &def->iommufdId);
+
     return def;
 
  error:
@@ -21195,6 +21206,11 @@ 
virDomainHostdevDefCheckABIStability(virDomainHostdevDef *src,
         }
     }
 
+    if (src->iommufdId && dst->iommufdId) {
+        if (STRNEQ(src->iommufdId, dst->iommufdId))
+            return false;
+    }
+
     if (!virDomainDeviceInfoCheckABIStability(src->info, dst->info))
         return false;
 
@@ -27554,6 +27570,10 @@ virDomainHostdevDefFormat(virBuffer *buf,
     if (def->shareable)
         virBufferAddLit(buf, "<shareable/>\n");
 
+    if (def->iommufdId) {
+        virBufferAsprintf(buf, "<iommufdId>%s</iommufdId>\n", def->iommufdId);
+    }
+
     virDomainDeviceInfoFormat(buf, def->info, flags | 
VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT
                                                     | 
VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM);
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index edb18632f3..367e7686f1 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -375,6 +375,7 @@ struct _virDomainHostdevDef {
         virDomainHostdevCaps caps;
     } source;
     virDomainNetTeamingInfo *teaming;
+    char *iommufdId;
     virDomainDeviceInfo *info; /* Guest address */
 };
 
diff --git a/src/conf/schemas/domaincommon.rng 
b/src/conf/schemas/domaincommon.rng
index fd19f115f7..662f12c4f1 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -6507,6 +6507,9 @@
         <optional>
           <ref name="address"/>
         </optional>
+        <optional>
+          <ref name="iommufdId"/>
+        </optional>
         <optional>
           <element name="readonly">
             <empty/>
@@ -7761,6 +7764,12 @@
     </element>
   </define>
 
+  <define name="iommufdId">
+    <element name="iommufdId">
+      <text/>
+    </element>
+  </define>
+
   <define name="deviceBoot">
     <element name="boot">
       <attribute name="order">
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index cecd0661ca..6b3e2ffd0d 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4846,6 +4846,7 @@ qemuBuildPCIHostdevDevProps(const virDomainDef *def,
                               "S:failover_pair_id", failover_pair_id,
                               "S:display", qemuOnOffAuto(pcisrc->display),
                               "B:ramfb", ramfb,
+                              "S:iommufd", dev->iommufdId,
                               NULL) < 0)
         return NULL;
 
@@ -5225,6 +5226,8 @@ qemuBuildHostdevCommandLine(virCommand *cmd,
                             virQEMUCaps *qemuCaps)
 {
     size_t i;
+    g_autoptr(virJSONValue) props = NULL;
+    int iommufd = 0;
 
     for (i = 0; i < def->nhostdevs; i++) {
         virDomainHostdevDef *hostdev = def->hostdevs[i];
@@ -5234,6 +5237,17 @@ qemuBuildHostdevCommandLine(virCommand *cmd,
         g_autofree char *vhostfdName = NULL;
         int vhostfd = -1;
 
+        if (hostdev->iommufdId && iommufd == 0) {
+            iommufd = 1;
+            if (qemuMonitorCreateObjectProps(&props, "iommufd",
+                                             hostdev->iommufdId,
+                                             NULL) < 0)
+                return -1;
+
+            if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0)
+                return -1;
+        }
+
         if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
             continue;
 
-- 
2.43.0

Reply via email to