A device with an attribute 'model', with just one model so far: <devices> ... <iommu model='intel'/> </devices> https://bugzilla.redhat.com/show_bug.cgi?id=1235580 --- docs/formatdomain.html.in | 26 +++++++ docs/schemas/domaincommon.rng | 11 +++ src/conf/domain_conf.c | 90 +++++++++++++++++++++- src/conf/domain_conf.h | 16 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 6 ++ src/qemu/qemu_hotplug.c | 1 + .../qemuxml2argvdata/qemuxml2argv-intel-iommu.xml | 37 +++++++++ .../qemuxml2xmlout-intel-iommu.xml | 37 +++++++++ tests/qemuxml2xmltest.c | 4 + 10 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index ee6d5e8..59a8bb9 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -6752,6 +6752,32 @@ qemu-kvm -net nic,model=? /dev/null </dd> </dl> + <h4><a name="elementsIommu">IOMMU devices</a></h4> + + <p> + The <code>iommu</code> element can be used to add an IOMMU device. + <span class="since">Since 2.1.0</span> + </p> + + <p> + Example: + </p> +<pre> + ... + <devices> + <iommu model='intel'/> + </devices> + ... +</pre> + <dl> + <dt><code>model</code></dt> + <dd> + <p> + Currently only the <code>intel</code> model is supported. + </p> + </dd> + </dl> + <h3><a name="seclabel">Security label</a></h3> <p> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index cba2d12..348dbfe 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3718,6 +3718,14 @@ </optional> </define> + <define name="iommu"> + <element name="iommu"> + <attribute name="model"> + <value>intel</value> + </attribute> + </element> + </define> + <define name="input"> <element name="input"> <choice> @@ -4187,6 +4195,9 @@ <zeroOrMore> <ref name="panic"/> </zeroOrMore> + <optional> + <ref name="iommu"/> + </optional> </interleave> </element> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4c232e0..16e0736 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, "<iommu model='%s'/>\n", + virDomainIOMMUModelTypeToString(def->iommu->model)); + } + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</devices>\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 c34fc50..db3f9e8 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 ad0af76..31b0014 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 28ef5aa..f8d9afe 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 093aaf9..04e11b4 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 0000000..b5b2b51 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.xml @@ -0,0 +1,37 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='2'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </memballoon> + <iommu model='intel'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml new file mode 100644 index 0000000..b5b2b51 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml @@ -0,0 +1,37 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='2'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </memballoon> + <iommu model='intel'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index eb810e3..c81465a 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; -- 2.7.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list