diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index fa0edd1582b48573b282dc5e03ad4f64962a67c7..e9ff73b6ee2e3dd999c5fa614fe074294f6197a9 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3451,6 +3451,19 @@
+
+
+
+ QEMU's virtio devices have some attributes related to the virtio transport under
+ the driver
element:
+ The iommu
attribute enables the use of emulated IOMMU
+ by the device. The attribute ats
controls the Address
+ Translation Service support for PCIe devices. This is needed to make use
+ of IOTLB support (see IOMMU device ).
+ Possible values are on
or off
.
+ Since 3.5.0
+
+
@@ -5142,6 +5155,12 @@ qemu-kvm -net nic,model=? /dev/null
In general you should leave this option alone, unless you
are very certain you know what you are doing.
+
virtio options
+
+ For virtio interfaces,
+ Virtio-specific options can also be
+ set. (Since 3.5.0 )
+
Offloading options for the host and guest can be configured using
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 5c542c782a48baef1ade3c8046152c36af2765e6..15fd72f8826d58251a11be44e4d3ce4fe8288740 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2686,6 +2686,7 @@
+
@@ -5006,6 +5007,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 710048c62e9b0534dec33fc56313eb30576568c6..22b8653f3277d9822966367560f83e60429d26fb 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1112,6 +1112,46 @@ virDomainXMLOptionGetNamespace(virDomainXMLOptionPtr xmlopt)
return &xmlopt->ns;
}
+static int
+virDomainVirtioOptionsParseXML(xmlXPathContextPtr ctxt,
+ virDomainVirtioOptionsPtr *virtio)
+{
+ char *str = NULL;
+ int ret = -1;
+ int val;
+ virDomainVirtioOptionsPtr res;
+
+ if (VIR_ALLOC(*virtio) < 0)
+ return -1;
+
+ res = *virtio;
+
+ if ((str = virXPathString("string(./driver/@iommu)", ctxt))) {
+ if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid iommu value"));
+ goto cleanup;
+ }
+ res->iommu = val;
+ }
+ VIR_FREE(str);
+
+ if ((str = virXPathString("string(./driver/@ats)", ctxt))) {
+ if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid ats value"));
+ goto cleanup;
+ }
+ res->ats = val;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(str);
+ return ret;
+}
+
virSaveCookieCallbacksPtr
virDomainXMLOptionGetSaveCookie(virDomainXMLOptionPtr xmlopt)
@@ -1966,6 +2006,7 @@ virDomainNetDefClear(virDomainNetDefPtr def)
VIR_FREE(def->ifname);
VIR_FREE(def->ifname_guest);
VIR_FREE(def->ifname_guest_actual);
+ VIR_FREE(def->virtio);
virNetDevIPInfoClear(&def->guestIP);
virNetDevIPInfoClear(&def->hostIP);
@@ -4339,6 +4380,28 @@ virDomainHostdevDefPostParse(virDomainHostdevDefPtr dev,
}
+static int
+virDomainCheckVirtioOptions(virDomainVirtioOptionsPtr virtio)
+{
+ if (!virtio)
+ return 0;
+
+ if (virtio->iommu != VIR_TRISTATE_SWITCH_ABSENT) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("iommu driver option is only supported "
+ "for virtio devices"));
+ return -1;
+ }
+ if (virtio->ats != VIR_TRISTATE_SWITCH_ABSENT) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("ats driver option is only supported "
+ "for virtio devices"));
+ return -1;
+ }
+ return 0;
+}
+
+
static int
virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
const virDomainDef *def,
@@ -4437,6 +4500,13 @@ virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
}
}
+ if (dev->type == VIR_DOMAIN_DEVICE_NET) {
+ virDomainNetDefPtr net = dev->data.net;
+ if (STRNEQ_NULLABLE(net->model, "virtio") &&
+ virDomainCheckVirtioOptions(net->virtio) < 0)
+ return -1;
+ }
+
return 0;
}
@@ -5235,6 +5305,24 @@ virDomainDefValidate(virDomainDefPtr def,
}
+static void
+virDomainVirtioOptionsFormat(virBufferPtr buf,
+ virDomainVirtioOptionsPtr virtio)
+{
+ if (!virtio)
+ return;
+
+ if (virtio->iommu != VIR_TRISTATE_SWITCH_ABSENT) {
+ virBufferAsprintf(buf, " iommu='%s'",
+ virTristateSwitchTypeToString(virtio->iommu));
+ }
+ if (virtio->ats != VIR_TRISTATE_SWITCH_ABSENT) {
+ virBufferAsprintf(buf, " ats='%s'",
+ virTristateSwitchTypeToString(virtio->ats));
+ }
+}
+
+
/* Generate a string representation of a device address
* @info address Device address to stringify
*/
@@ -10381,6 +10469,9 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
goto error;
}
+ if (virDomainVirtioOptionsParseXML(ctxt, &def->virtio) < 0)
+ goto error;
+
cleanup:
ctxt->node = oldnode;
VIR_FREE(macaddr);
@@ -19004,6 +19095,30 @@ virDomainDeviceInfoCheckABIStability(virDomainDeviceInfoPtr src,
}
+static bool
+virDomainVirtioOptionsCheckABIStability(virDomainVirtioOptionsPtr src,
+ virDomainVirtioOptionsPtr dst)
+{
+ if (src->iommu != dst->iommu) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target device iommu option '%s' does not "
+ "match source '%s'"),
+ virTristateSwitchTypeToString(dst->iommu),
+ virTristateSwitchTypeToString(src->iommu));
+ return false;
+ }
+ if (src->ats != dst->ats) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target device ats option '%s' does not "
+ "match source '%s'"),
+ virTristateSwitchTypeToString(dst->ats),
+ virTristateSwitchTypeToString(src->ats));
+ return false;
+ }
+ return true;
+}
+
+
static bool
virDomainDiskDefCheckABIStability(virDomainDiskDefPtr src,
virDomainDiskDefPtr dst)
@@ -19163,6 +19278,10 @@ virDomainNetDefCheckABIStability(virDomainNetDefPtr src,
return false;
}
+ if (src->virtio && dst->virtio &&
+ !virDomainVirtioOptionsCheckABIStability(src->virtio, dst->virtio))
+ return false;
+
if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
return false;
@@ -22118,6 +22237,8 @@ virDomainVirtioNetDriverFormat(char **outstr,
virBufferAsprintf(&buf, " rx_queue_size='%u'",
def->driver.virtio.rx_queue_size);
+ virDomainVirtioOptionsFormat(&buf, def->virtio);
+
if (virBufferCheckError(&buf) < 0)
return -1;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 597fb22cca7546387d61a242307d307ec9bfed38..b3e607bfbdf7195a51070641ddb1a3f48b6674f3 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -156,6 +156,9 @@ typedef virDomainTPMDef *virDomainTPMDefPtr;
typedef struct _virDomainIOMMUDef virDomainIOMMUDef;
typedef virDomainIOMMUDef *virDomainIOMMUDefPtr;
+typedef struct _virDomainVirtioOptions virDomainVirtioOptions;
+typedef virDomainVirtioOptions *virDomainVirtioOptionsPtr;
+
/* Flags for the 'type' field in virDomainDeviceDef */
typedef enum {
VIR_DOMAIN_DEVICE_NONE = 0,
@@ -1040,6 +1043,7 @@ struct _virDomainNetDef {
int linkstate;
unsigned int mtu;
virNetDevCoalescePtr coalesce;
+ virDomainVirtioOptionsPtr virtio;
};
typedef enum {
@@ -2215,6 +2219,12 @@ struct _virDomainIOMMUDef {
virTristateSwitch eim;
virTristateSwitch iotlb;
};
+
+struct _virDomainVirtioOptions {
+ virTristateSwitch iommu;
+ virTristateSwitch ats;
+};
+
/*
* Guest VM main configuration
*
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml b/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml
index c88cf649b1a215a8ac63d605d7968664a643a616..3357bc6d1bc8b1f03045f8ff5a1a3d0cd974320a 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml
@@ -47,6 +47,7 @@
+