diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index c70377ba48..10a692de25 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -6829,6 +6829,7 @@ qemu-kvm -net nic,model=? /dev/null
<size unit='M'>4</size>
</shmem>
<shmem name='shmem_server'>
+ <model type='ivshmem'/>
<size unit='M'>2</size>
<server path='/tmp/socket-shmem'/>
<msi vectors='32' ioeventfd='on'/>
@@ -6843,6 +6844,13 @@ qemu-kvm -net nic,model=? /dev/null
The shmem element has one mandatory attribute,
name to identify the shared memory.
+
model
+
+ Attribute type of the optional element model
+ specifies the model of the underlying device providing the
+ shmem device. Currently the only supported model is
+ ivshmem.
+
size
The optional size element specifies the size of the shared
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index dba9187aa7..99e0eb6cb4 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3591,6 +3591,15 @@
+
+
+
+
+ ivshmem
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 03506cbec1..108a48ee97 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -844,6 +844,9 @@ VIR_ENUM_IMPL(virDomainBlockJob, VIR_DOMAIN_BLOCK_JOB_TYPE_LAST,
VIR_ENUM_IMPL(virDomainMemoryModel, VIR_DOMAIN_MEMORY_MODEL_LAST,
"", "dimm")
+VIR_ENUM_IMPL(virDomainShmemModel, VIR_DOMAIN_SHMEM_MODEL_LAST,
+ "ivshmem")
+
static virClassPtr virDomainObjClass;
static virClassPtr virDomainXMLOptionClass;
static void virDomainObjDispose(void *obj);
@@ -12351,6 +12354,20 @@ virDomainShmemDefParseXML(xmlNodePtr node,
ctxt->node = node;
+ tmp = virXPathString("string(./model/@type)", ctxt);
+ if (tmp) {
+ /* If there's none, we will automatically have the first one
+ * (as default). Unfortunately this has to be done for
+ * compatibility reasons. */
+ if ((def->model = virDomainShmemModelTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unknown shmem model type '%s'"), tmp);
+ goto cleanup;
+ }
+
+ VIR_FREE(tmp);
+ }
+
if (!(def->name = virXMLPropString(node, "name"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("shmem element must contain 'name' attribute"));
@@ -14939,6 +14956,9 @@ virDomainShmemDefEquals(virDomainShmemDefPtr src,
if (src->size != dst->size)
return false;
+ if (src->model != dst->model)
+ return false;
+
if (src->server.enabled != dst->server.enabled)
return false;
@@ -18927,6 +18947,15 @@ virDomainShmemDefCheckABIStability(virDomainShmemDefPtr src,
return false;
}
+ if (src->model != dst->model) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target shared memory model '%s' does not match "
+ "source model '%s'"),
+ virDomainShmemModelTypeToString(dst->model),
+ virDomainShmemModelTypeToString(src->model));
+ return false;
+ }
+
if (src->size != dst->size) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target shared memory size '%llu' does not match "
@@ -21980,20 +22009,13 @@ virDomainShmemDefFormat(virBufferPtr buf,
virDomainShmemDefPtr def,
unsigned int flags)
{
- virBufferEscapeString(buf, "name);
-
- if (!def->size &&
- !def->server.enabled &&
- !def->msi.enabled &&
- !virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
- virBufferAddLit(buf, "/>\n");
- return 0;
- } else {
- virBufferAddLit(buf, ">\n");
- }
+ virBufferEscapeString(buf, "\n", def->name);
virBufferAdjustIndent(buf, 2);
+ virBufferAsprintf(buf, "\n",
+ virDomainShmemModelTypeToString(def->model));
+
if (def->size)
virBufferAsprintf(buf, "%llu\n", def->size >> 20);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 24aa79cdc9..d2a9289e07 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1562,9 +1562,16 @@ struct _virDomainNVRAMDef {
virDomainDeviceInfo info;
};
+typedef enum {
+ VIR_DOMAIN_SHMEM_MODEL_IVSHMEM,
+
+ VIR_DOMAIN_SHMEM_MODEL_LAST
+} virDomainShmemModel;
+
struct _virDomainShmemDef {
char *name;
unsigned long long size;
+ int model; /* enum virDomainShmemModel */
struct {
bool enabled;
virDomainChrSourceDef chr;
@@ -3084,6 +3091,7 @@ VIR_ENUM_DECL(virDomainTPMBackend)
VIR_ENUM_DECL(virDomainMemoryModel)
VIR_ENUM_DECL(virDomainMemoryBackingModel)
VIR_ENUM_DECL(virDomainIOMMUModel)
+VIR_ENUM_DECL(virDomainShmemModel)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 162fda54f9..74dd5271a8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -474,6 +474,8 @@ virDomainShmemDefFind;
virDomainShmemDefFree;
virDomainShmemDefInsert;
virDomainShmemDefRemove;
+virDomainShmemModelTypeFromString;
+virDomainShmemModelTypeToString;
virDomainShutdownReasonTypeFromString;
virDomainShutdownReasonTypeToString;
virDomainShutoffReasonTypeFromString;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index b68da3db5f..5ed288c02a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -8525,7 +8525,16 @@ qemuBuildShmemCommandLine(virLogManagerPtr logManager,
return -1;
}
- if (!(devstr = qemuBuildShmemDevLegacyStr(def, shmem, qemuCaps)))
+ switch ((virDomainShmemModel)shmem->model) {
+ case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
+ devstr = qemuBuildShmemDevLegacyStr(def, shmem, qemuCaps);
+ break;
+
+ case VIR_DOMAIN_SHMEM_MODEL_LAST:
+ break;
+ }
+
+ if (!devstr)
return -1;
virCommandAddArgList(cmd, "-device", devstr, NULL);
VIR_FREE(devstr);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
index 5bc4904489..b56e9e1878 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
@@ -28,6 +28,7 @@
+ 512
@@ -41,6 +42,7 @@
+ 4096
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem.xml
index 1197f361e3..5602913648 100644
--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem.xml
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem.xml
@@ -22,39 +22,47 @@
+
+ 128
+ 256
+ 512
+ 1024
+ 2048
+ 4096
+ 8192