diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index ee6d5e875f..59a8bb9229 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -6752,6 +6752,32 @@ qemu-kvm -net nic,model=? /dev/null
+
+
+
+ The iommu
element can be used to add an IOMMU device.
+ Since 2.1.0
+
+
+
+ Example:
+
+
+ ...
+ <devices>
+ <iommu model='intel'/>
+ </devices>
+ ...
+
+
+ model
+ -
+
+ Currently only the intel
model is supported.
+
+
+
+
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index cba2d1223e..348dbfe6b1 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3718,6 +3718,14 @@
+
+
+
+ intel
+
+
+
+
@@ -4187,6 +4195,9 @@
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 4c232e0f84..16e0736e09 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -240,7 +240,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
"shmem",
"tpm",
"panic",
- "memory")
+ "memory",
+ "iommu")
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
"none",
@@ -803,6 +804,9 @@ VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST,
VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST,
"passthrough")
+VIR_ENUM_IMPL(virDomainIOMMUModel, VIR_DOMAIN_IOMMU_MODEL_LAST,
+ "intel")
+
VIR_ENUM_IMPL(virDomainDiskDiscard, VIR_DOMAIN_DISK_DISCARD_LAST,
"default",
"unmap",
@@ -2394,6 +2398,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
case VIR_DOMAIN_DEVICE_MEMORY:
virDomainMemoryDefFree(def->data.memory);
break;
+ case VIR_DOMAIN_DEVICE_IOMMU:
+ VIR_FREE(def->data.iommu);
+ break;
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_NONE:
break;
@@ -2640,6 +2647,8 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainPanicDefFree(def->panics[i]);
VIR_FREE(def->panics);
+ VIR_FREE(def->iommu);
+
VIR_FREE(def->idmap.uidmap);
VIR_FREE(def->idmap.gidmap);
@@ -3180,6 +3189,7 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
/* The following devices do not contain virDomainDeviceInfo */
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_GRAPHICS:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_NONE:
break;
@@ -3543,6 +3553,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_RNG:
case VIR_DOMAIN_DEVICE_MEMORY:
+ case VIR_DOMAIN_DEVICE_IOMMU:
break;
}
#endif
@@ -4604,6 +4615,7 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_MEMORY:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
break;
@@ -13266,6 +13278,39 @@ virDomainMemoryDefParseXML(xmlNodePtr memdevNode,
}
+static virDomainIOMMUDefPtr
+virDomainIOMMUDefParseXML(xmlNodePtr node)
+{
+ virDomainIOMMUDefPtr iommu = NULL, ret = NULL;
+ char *tmp = NULL;
+ int val;
+
+ if (VIR_ALLOC(iommu) < 0)
+ goto cleanup;
+
+ if (!(tmp = virXMLPropString(node, "model"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing model for IOMMU device"));
+ goto cleanup;
+ }
+
+ if ((val = virDomainIOMMUModelTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, _("unknown IOMMU model: %s"), tmp);
+ goto cleanup;
+ }
+
+ iommu->model = val;
+
+ ret = iommu;
+ iommu = NULL;
+
+ cleanup:
+ VIR_FREE(iommu);
+ VIR_FREE(tmp);
+ return ret;
+}
+
+
virDomainDeviceDefPtr
virDomainDeviceDefParse(const char *xmlStr,
const virDomainDef *def,
@@ -13407,6 +13452,10 @@ virDomainDeviceDefParse(const char *xmlStr,
if (!(dev->data.memory = virDomainMemoryDefParseXML(node, ctxt, flags)))
goto error;
break;
+ case VIR_DOMAIN_DEVICE_IOMMU:
+ if (!(dev->data.iommu = virDomainIOMMUDefParseXML(node)))
+ goto error;
+ break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
break;
@@ -17215,6 +17264,21 @@ virDomainDefParseXML(xmlDocPtr xml,
}
VIR_FREE(nodes);
+ if ((n = virXPathNodeSet("./devices/iommu", ctxt, &nodes)) < 0)
+ goto error;
+
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only a single IOMMU device is supported"));
+ goto error;
+ }
+
+ if (n > 0) {
+ if (!(def->iommu = virDomainIOMMUDefParseXML(nodes[0])))
+ goto error;
+ }
+ VIR_FREE(nodes);
+
/* analysis of the user namespace mapping */
if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
goto error;
@@ -18981,6 +19045,23 @@ virDomainDefCheckABIStability(virDomainDefPtr src,
goto error;
}
+ if (!!src->iommu != !!dst->iommu) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target domain IOMMU device count "
+ "does not match source"));
+ goto error;
+ }
+
+ if (src->iommu &&
+ src->iommu->model != dst->iommu->model) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain IOMMU device model '%s' "
+ "does not match source '%s'"),
+ virDomainIOMMUModelTypeToString(dst->iommu->model),
+ virDomainIOMMUModelTypeToString(src->iommu->model));
+ goto error;
+ }
+
/* Coverity is not very happy with this - all dead_error_condition */
#if !STATIC_ANALYSIS
/* This switch statement is here to trigger compiler warning when adding
@@ -19013,6 +19094,7 @@ virDomainDefCheckABIStability(virDomainDefPtr src,
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_MEMORY:
+ case VIR_DOMAIN_DEVICE_IOMMU:
break;
}
#endif
@@ -23576,6 +23658,11 @@ virDomainDefFormatInternal(virDomainDefPtr def,
goto error;
}
+ if (def->iommu) {
+ virBufferAsprintf(buf, "\n",
+ virDomainIOMMUModelTypeToString(def->iommu->model));
+ }
+
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "\n");
@@ -24693,6 +24780,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_SHMEM:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Copying definition of '%d' type "
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index c34fc50340..db3f9e889a 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -151,6 +151,9 @@ typedef virDomainShmemDef *virDomainShmemDefPtr;
typedef struct _virDomainTPMDef virDomainTPMDef;
typedef virDomainTPMDef *virDomainTPMDefPtr;
+typedef struct _virDomainIOMMUDef virDomainIOMMUDef;
+typedef virDomainIOMMUDef *virDomainIOMMUDefPtr;
+
/* Flags for the 'type' field in virDomainDeviceDef */
typedef enum {
VIR_DOMAIN_DEVICE_NONE = 0,
@@ -176,6 +179,7 @@ typedef enum {
VIR_DOMAIN_DEVICE_TPM,
VIR_DOMAIN_DEVICE_PANIC,
VIR_DOMAIN_DEVICE_MEMORY,
+ VIR_DOMAIN_DEVICE_IOMMU,
VIR_DOMAIN_DEVICE_LAST
} virDomainDeviceType;
@@ -207,6 +211,7 @@ struct _virDomainDeviceDef {
virDomainTPMDefPtr tpm;
virDomainPanicDefPtr panic;
virDomainMemoryDefPtr memory;
+ virDomainIOMMUDefPtr iommu;
} data;
};
@@ -2100,6 +2105,15 @@ struct _virDomainKeyWrapDef {
int dea; /* enum virTristateSwitch */
};
+typedef enum {
+ VIR_DOMAIN_IOMMU_MODEL_INTEL,
+
+ VIR_DOMAIN_IOMMU_MODEL_LAST
+} virDomainIOMMUModel;
+
+struct _virDomainIOMMUDef {
+ virDomainIOMMUModel model;
+};
/*
* Guest VM main configuration
*
@@ -2237,6 +2251,7 @@ struct _virDomainDef {
virCPUDefPtr cpu;
virSysinfoDefPtr sysinfo;
virDomainRedirFilterDefPtr redirfilter;
+ virDomainIOMMUDefPtr iommu;
void *namespaceData;
virDomainXMLNamespace ns;
@@ -3001,6 +3016,7 @@ VIR_ENUM_DECL(virDomainTPMModel)
VIR_ENUM_DECL(virDomainTPMBackend)
VIR_ENUM_DECL(virDomainMemoryModel)
VIR_ENUM_DECL(virDomainMemoryBackingModel)
+VIR_ENUM_DECL(virDomainIOMMUModel)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 597ce5f3e8..ba718b8de0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -341,6 +341,8 @@ virDomainHubTypeToString;
virDomainHypervTypeFromString;
virDomainHypervTypeToString;
virDomainInputDefFree;
+virDomainIOMMUModelTypeFromString;
+virDomainIOMMUModelTypeToString;
virDomainIOThreadIDAdd;
virDomainIOThreadIDDefFree;
virDomainIOThreadIDDel;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 28ef5aa60f..f8d9afe25e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7425,6 +7425,7 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("live attach of device '%s' is not supported"),
@@ -7516,6 +7517,7 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("live detach of device '%s' is not supported"),
@@ -7631,6 +7633,7 @@ qemuDomainUpdateDeviceLive(virConnectPtr conn,
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("live update of device '%s' is not supported"),
@@ -7794,6 +7797,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("persistent attach of device '%s' is not supported"),
@@ -7948,6 +7952,7 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("persistent detach of device '%s' is not supported"),
@@ -8046,6 +8051,7 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("persistent update of device '%s' is not supported"),
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 093aaf928d..04e11b4d79 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -3300,6 +3300,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
+ case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("don't know how to remove a %s device"),
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.xml b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.xml
new file mode 100644
index 0000000000..b5b2b5158a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.xml
@@ -0,0 +1,37 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219100
+ 219100
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml
new file mode 100644
index 0000000000..b5b2b5158a
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml
@@ -0,0 +1,37 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219100
+ 219100
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index eb810e3ce4..c81465a5d5 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -886,6 +886,10 @@ mymain(void)
DO_TEST("video-qxl-heads");
DO_TEST("video-qxl-noheads");
+ DO_TEST_FULL("intel-iommu", WHEN_ACTIVE, GIC_NONE,
+ QEMU_CAPS_DEVICE_PCI_BRIDGE,
+ QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE);
+
qemuTestDriverFree(&driver);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;