This patch adds parsing/formatting code as well as documentation for
shared memory devices. This will currently be only accessible in QEMU
using it's ivshmem device, but is designed as generic as possible to
allow future expansion for other hypervisors.
In the devices section in the domain XML users may specify:
- For shmem device using a server:
<shmem name='shmem0'>
<server path='/tmp/socket-ivshmem0'/>
<size unit='M'>32</size>
<msi vectors='32' ioeventfd='on'/>
</shmem>
- For ivshmem device not using an ivshmem server:
<shmem name='shmem1'>
<size unit='M'>32</size>
</shmem>
Most of the configuration is made optional so it also allows
specifications like:
<shmem name='shmem1/>
<shmem name='shmem2'>
<server/>
</shmem>
Signed-off-by: Maxime Leroy <maxime.leroy(a)6wind.com>
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
docs/formatdomain.html.in | 52 +++++
docs/schemas/domaincommon.rng | 39 ++++
src/conf/domain_conf.c | 210 ++++++++++++++++++++-
src/conf/domain_conf.h | 24 +++
src/qemu/qemu_hotplug.c | 1 +
.../qemuxml2argv-shmem-invalid-size.xml | 24 +++
.../qemuxml2argv-shmem-invalid.xml | 24 +++
.../qemuxml2argv-shmem-msi-only.xml | 24 +++
.../qemuxml2argv-shmem-small-size.xml | 24 +++
tests/qemuxml2argvdata/qemuxml2argv-shmem.args | 16 ++
tests/qemuxml2argvdata/qemuxml2argv-shmem.xml | 51 +++++
tests/qemuxml2argvtest.c | 5 +
tests/qemuxml2xmltest.c | 1 +
13 files changed, 494 insertions(+), 1 deletion(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid-size.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index bb72452..7bdb1bd 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -5560,6 +5560,58 @@ qemu-kvm -net nic,model=? /dev/null
</dd>
</dl>
+ <h4><a name="elementsShmem">Shared memory
device</a></h4>
+
+ <p>
+ A shared memory device allows to share a memory region between
+ different virtual machines and the host.
+ <span class="since">Since 1.2.9, QEMU and KVM only</span>
+ </p>
+
+<pre>
+ ...
+ <devices>
+ <shmem name='my_shmem0'>
+ <size unit='M'>4</size>
+ </shmem>
+ <shmem name='shmem_server'>
+ <size unit='M'>2</size>
+ <server path='/tmp/socket-shmem'/>
+ <msi vectors='32' ioeventfd='on'/>
+ </shmem>
+ </devices>
+ ...
+</pre>
+
+ <dl>
+ <dt><code>shmem</code></dt>
+ <dd>
+ The <code>shmem</code> element has one mandatory attribute,
+ <code>name</code> to identify the shared memory.
+ </dd>
+ <dt><code>size</code></dt>
+ <dd>
+ The optional <code>size</code> element specifies the size of the
shared
+ memory. This must be power of 2 and greater than or equal to 1 MiB.
+ </dd>
+ <dt><code>server</code></dt>
+ <dd>
+ The optional <code>server</code> element can be used to configure a
server
+ socket the device is supposed to connect to. The optional
+ <code>path</code> attribute specifies the path to the unix socket and
+ defaults to <code>/var/lib/libvirt/shmem/$shmem_name-sock</code>.
+ </dd>
+ <dt><code>msi</code></dt>
+ <dd>
+ The optional <code>msi</code> element enables/disables (values
"on"/"off",
+ respectively) MSI interrupts. This option can currently be used only
+ together with the <code>server</code> element. The
<code>vectors</code>
+ attribute can be used to specify the number of interrupt
+ vectors. The <code>ioeventd</code> attribute enables/disables (values
+ "on"/"off", respectively) ioeventfd.
+ </dd>
+ </dl>
+
<h3><a name="seclabel">Security label</a></h3>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index b6b309d..6864d54 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3214,6 +3214,44 @@
</optional>
</element>
</define>
+
+ <define name="shmem">
+ <element name="shmem">
+ <attribute name="name"/>
+ <interleave>
+ <optional>
+ <element name="size">
+ <ref name="scaledInteger"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="server">
+ <optional>
+ <attribute name="path">
+ <ref name="absFilePath"/>
+ </attribute>
+ </optional>
+ </element>
+ </optional>
+ <optional>
+ <element name="msi">
+ <optional>
+ <ref name="ioeventfd"/>
+ </optional>
+ <optional>
+ <attribute name="vectors">
+ <ref name="unsignedInt"/>
+ </attribute>
+ </optional>
+ </element>
+ </optional>
+ <optional>
+ <ref name="address"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
<define name="memballoon">
<element name="memballoon">
<attribute name="model">
@@ -3800,6 +3838,7 @@
<ref name="redirfilter"/>
<ref name="rng"/>
<ref name="tpm"/>
+ <ref name="shmem"/>
</choice>
</zeroOrMore>
<optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0a7d0b8..ab615fb 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -255,7 +255,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
"chr",
"memballoon",
"nvram",
- "rng")
+ "rng",
+ "shmem")
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
"none",
@@ -1720,6 +1721,17 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
VIR_FREE(def);
}
+void virDomainShmemDefFree(virDomainShmemDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainDeviceInfoClear(&def->info);
+ VIR_FREE(def->server.path);
+ VIR_FREE(def->name);
+ VIR_FREE(def);
+}
+
void virDomainVideoDefFree(virDomainVideoDefPtr def)
{
if (!def)
@@ -1921,6 +1933,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
case VIR_DOMAIN_DEVICE_NVRAM:
virDomainNVRAMDefFree(def->data.nvram);
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ virDomainShmemDefFree(def->data.shmem);
+ break;
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_NONE:
break;
@@ -2181,6 +2196,10 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainRedirFilterDefFree(def->redirfilter);
+ for (i = 0; i < def->nshmems; i++)
+ virDomainShmemDefFree(def->shmems[i]);
+ VIR_FREE(def->shmems);
+
if (def->namespaceData && def->ns.free)
(def->ns.free)(def->namespaceData);
@@ -2613,6 +2632,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
return &device->data.memballoon->info;
case VIR_DOMAIN_DEVICE_NVRAM:
return &device->data.nvram->info;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ return &device->data.shmem->info;
case VIR_DOMAIN_DEVICE_RNG:
return &device->data.rng->info;
@@ -2828,6 +2849,12 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
return -1;
}
+ device.type = VIR_DOMAIN_DEVICE_SHMEM;
+ for (i = 0; i < def->nshmems; i++) {
+ device.data.shmem = def->shmems[i];
+ if (cb(def, &device, &def->shmems[i]->info, opaque) < 0)
+ return -1;
+ }
/* Coverity is not very happy with this - all dead_error_condition */
#if !STATIC_ANALYSIS
@@ -2856,6 +2883,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
+ case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_RNG:
break;
@@ -9591,6 +9619,110 @@ virDomainNVRAMDefParseXML(xmlNodePtr node,
return NULL;
}
+static virDomainShmemDefPtr
+virDomainShmemDefParseXML(xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ unsigned int flags)
+{
+ char *tmp = NULL;
+ virDomainShmemDefPtr def = NULL;
+ virDomainShmemDefPtr ret = NULL;
+ xmlNodePtr msi = NULL;
+ xmlNodePtr save = ctxt->node;
+ xmlNodePtr server = NULL;
+
+
+ if (VIR_ALLOC(def) < 0)
+ return NULL;
+
+ ctxt->node = node;
+
+ if (!(def->name = virXMLPropString(node, "name"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("shmem element must contain 'name'
attribute"));
+ goto cleanup;
+ }
+
+ if (virDomainParseScaledValue("./size[1]", ctxt, &def->size,
+ 1, ULLONG_MAX, false) < 0)
+ goto cleanup;
+
+ if ((server = virXPathNode("./server", ctxt))) {
+ def->server.enabled = true;
+
+ if ((tmp = virXMLPropString(server, "path")))
+ def->server.path = virFileSanitizePath(tmp);
+ VIR_FREE(tmp);
+
+ /*
+ * We can always safely remove this check, but until the
+ * server starting part is in it is better to directly disable
+ * it rather then just ignoring it.
+ */
+ if ((tmp = virXMLPropString(server, "start"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Unsupported start attribute for "
+ "shmem server element"));
+ goto cleanup;
+ }
+ }
+
+ if ((msi = virXPathNode("./msi", ctxt))) {
+ def->msi.enabled = true;
+
+ if ((tmp = virXMLPropString(msi, "vectors")) &&
+ virStrToLong_uip(tmp, NULL, 0, &def->msi.vectors) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid number of vectors for shmem:
'%s'"),
+ tmp);
+ goto cleanup;
+ }
+ VIR_FREE(tmp);
+
+ if ((tmp = virXMLPropString(msi, "ioeventfd")) &&
+ (def->msi.ioeventfd = virTristateSwitchTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid msi ioeventfd setting for shmem:
'%s'"),
+ tmp);
+ goto cleanup;
+ }
+ VIR_FREE(tmp);
+ }
+
+ /* msi option is only relevant with a server */
+ if (def->msi.enabled && !def->server.enabled) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("msi option is only supported with a server"));
+ goto cleanup;
+ }
+
+ /* size should be a power of two */
+ if (def->size && def->size & (def->size - 1)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("shmem size must be a power of two"));
+ goto cleanup;
+ }
+ /* and greater than 1MiB (for now); the formatting code depends on
+ * it and must be adjusted in case this condition changes */
+ if (def->size && def->size < 1024 * 1024) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("shmem size must be at least 1 MiB"));
+ goto cleanup;
+ }
+
+ if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+ goto cleanup;
+
+
+ ret = def;
+ def = NULL;
+ cleanup:
+ ctxt->node = save;
+ VIR_FREE(tmp);
+ virDomainShmemDefFree(def);
+ return ret;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
@@ -10447,6 +10579,10 @@ virDomainDeviceDefParse(const char *xmlStr,
if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
goto error;
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ if (!(dev->data.shmem = virDomainShmemDefParseXML(node, ctxt, flags)))
+ goto error;
+ break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
break;
@@ -13575,6 +13711,25 @@ virDomainDefParseXML(xmlDocPtr xml,
VIR_FREE(nodes);
}
+ /* analysis of the shmem devices */
+ if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0) {
+ goto error;
+ }
+ if (n && VIR_ALLOC_N(def->shmems, n) < 0)
+ goto error;
+
+ node = ctxt->node;
+ for (i = 0; i < n; i++) {
+ virDomainShmemDefPtr shmem;
+ ctxt->node = nodes[i];
+ shmem = virDomainShmemDefParseXML(nodes[i], ctxt, flags);
+ if (!shmem)
+ goto error;
+
+ def->shmems[def->nshmems++] = shmem;
+ }
+ ctxt->node = node;
+ VIR_FREE(nodes);
/* analysis of the user namespace mapping */
if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
@@ -17264,6 +17419,54 @@ static int virDomainPanicDefFormat(virBufferPtr buf,
}
static int
+virDomainShmemDefFormat(virBufferPtr buf,
+ virDomainShmemDefPtr def,
+ unsigned int flags)
+{
+ virBufferAsprintf(buf, "<shmem name='%s'", def->name);
+
+ if (!def->size &&
+ !def->server.enabled &&
+ !def->msi.enabled &&
+ !virDomainDeviceInfoIsSet(&def->info, flags)) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ } else {
+ virBufferAddLit(buf, ">\n");
+ }
+
+ virBufferAdjustIndent(buf, 2);
+
+ if (def->size)
+ virBufferAsprintf(buf, "<size
unit='M'>%llu</size>\n",
+ VIR_DIV_UP(def->size, 1024 * 1024));
+
+ if (def->server.enabled) {
+ virBufferAddLit(buf, "<server");
+ virBufferEscapeString(buf, " path='%s'", def->server.path);
+ virBufferAddLit(buf, "/>\n");
+ }
+
+ if (def->msi.enabled) {
+ virBufferAddLit(buf, "<msi");
+ if (def->msi.vectors)
+ virBufferAsprintf(buf, " vectors='%u'",
def->msi.vectors);
+ if (def->msi.ioeventfd)
+ virBufferAsprintf(buf, " ioeventfd='%s'",
+ virTristateSwitchTypeToString(def->msi.ioeventfd));
+ virBufferAddLit(buf, "/>\n");
+ }
+
+ if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+ return -1;
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</shmem>\n");
+
+ return 0;
+}
+
+static int
virDomainRNGDefFormat(virBufferPtr buf,
virDomainRNGDefPtr def,
unsigned int flags)
@@ -18883,6 +19086,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virDomainPanicDefFormat(buf, def->panic) < 0)
goto error;
+ for (n = 0; n < def->nshmems; n++)
+ if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0)
+ goto error;
+
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</devices>\n");
@@ -20248,6 +20455,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
+ case VIR_DOMAIN_DEVICE_SHMEM:
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 d97b1f8..acb3adf 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -136,6 +136,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr;
typedef struct _virDomainChrSourceDef virDomainChrSourceDef;
typedef virDomainChrSourceDef *virDomainChrSourceDefPtr;
+typedef struct _virDomainShmemDef virDomainShmemDef;
+typedef virDomainShmemDef *virDomainShmemDefPtr;
+
/* Flags for the 'type' field in virDomainDeviceDef */
typedef enum {
VIR_DOMAIN_DEVICE_NONE = 0,
@@ -157,6 +160,7 @@ typedef enum {
VIR_DOMAIN_DEVICE_MEMBALLOON,
VIR_DOMAIN_DEVICE_NVRAM,
VIR_DOMAIN_DEVICE_RNG,
+ VIR_DOMAIN_DEVICE_SHMEM,
VIR_DOMAIN_DEVICE_LAST
} virDomainDeviceType;
@@ -184,6 +188,7 @@ struct _virDomainDeviceDef {
virDomainMemballoonDefPtr memballoon;
virDomainNVRAMDefPtr nvram;
virDomainRNGDefPtr rng;
+ virDomainShmemDefPtr shmem;
} data;
};
@@ -1491,6 +1496,21 @@ struct _virDomainNVRAMDef {
virDomainDeviceInfo info;
};
+struct _virDomainShmemDef {
+ char *name;
+ unsigned long long size;
+ struct {
+ bool enabled;
+ char *path;
+ } server;
+ struct {
+ bool enabled;
+ unsigned vectors;
+ virTristateSwitch ioeventfd;
+ } msi;
+ virDomainDeviceInfo info;
+};
+
typedef enum {
VIR_DOMAIN_SMBIOS_NONE = 0,
VIR_DOMAIN_SMBIOS_EMULATE,
@@ -2067,6 +2087,9 @@ struct _virDomainDef {
size_t nrngs;
virDomainRNGDefPtr *rngs;
+ size_t nshmems;
+ virDomainShmemDefPtr *shmems;
+
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
@@ -2264,6 +2287,7 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
void virDomainHubDefFree(virDomainHubDefPtr def);
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def);
void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def);
+void virDomainShmemDefFree(virDomainShmemDefPtr def);
void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
virDomainDeviceDefPtr virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
const virDomainDef *def,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index d631887..3a654e4 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2859,6 +2859,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_RNG:
+ case VIR_DOMAIN_DEVICE_SHMEM:
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-shmem-invalid-size.xml
b/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid-size.xml
new file mode 100644
index 0000000..992f8fd
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid-size.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>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='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='none'/>
+ <shmem name='shmem0'>
+ <size unit='K'>12345</size>
+ </shmem>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid.xml
b/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid.xml
new file mode 100644
index 0000000..a5bfb97
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>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='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='none'/>
+ <shmem name='shmem0'>
+ <server start="yes"/>
+ </shmem>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
new file mode 100644
index 0000000..d70279c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>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='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='none'/>
+ <shmem name='shmem0'>
+ <msi/>
+ </shmem>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml
b/tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml
new file mode 100644
index 0000000..8f99b14
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>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='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='none'/>
+ <shmem name='shmem0'>
+ <size unit='K'>16</size>
+ </shmem>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem.args
b/tests/qemuxml2argvdata/qemuxml2argv-shmem.args
new file mode 100644
index 0000000..a3d3cc8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem.args
@@ -0,0 +1,16 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
+/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb \
+-device ivshmem,shm=shmem0 \
+-device ivshmem,size=128m,shm=shmem1 \
+-device ivshmem,size=256m,shm=shmem2 \
+-device ivshmem,size=512m,chardev=charshmem3 \
+-chardev socket,id=charshmem3,path=/var/lib/libvirt/shmem-shmem3-sock \
+-device ivshmem,size=1024m,chardev=charshmem4 \
+-chardev socket,id=charshmem4,path=/tmp/shmem4-sock \
+-device ivshmem,size=2048m,chardev=charshmem5,msi=on,ioeventfd=off \
+-chardev socket,id=charshmem5,path=/tmp/shmem5-sock \
+-device ivshmem,size=4096m,chardev=charshmem6,msi=on,vectors=16 \
+-chardev socket,id=charshmem6,path=/tmp/shmem6-sock \
+-device ivshmem,size=8192m,chardev=charshmem7,msi=on,vectors=32,ioeventfd=on \
+-chardev socket,id=charshmem7,path=/tmp/shmem7-sock
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
new file mode 100644
index 0000000..fd79c89
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
@@ -0,0 +1,51 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>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='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='none'/>
+ <shmem name='shmem0'/>
+ <shmem name='shmem1'>
+ <size unit='M'>128</size>
+ </shmem>
+ <shmem name='shmem2'>
+ <size unit='M'>256</size>
+ </shmem>
+ <shmem name='shmem3'>
+ <size unit='M'>512</size>
+ <server/>
+ </shmem>
+ <shmem name='shmem4'>
+ <size unit='M'>1024</size>
+ <server path='/tmp/shmem4-sock'/>
+ </shmem>
+ <shmem name='shmem5'>
+ <size unit='M'>2048</size>
+ <server path='/tmp/shmem5-sock'/>
+ <msi ioeventfd='off'/>
+ </shmem>
+ <shmem name='shmem6'>
+ <size unit='M'>4096</size>
+ <server path='/tmp/shmem6-sock'/>
+ <msi vectors='16'/>
+ </shmem>
+ <shmem name='shmem7'>
+ <size unit='M'>8192</size>
+ <server path='/tmp/shmem7-sock'/>
+ <msi vectors='32' ioeventfd='on'/>
+ </shmem>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index ab923d0..60c4405 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1462,6 +1462,11 @@ mymain(void)
DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS);
+ DO_TEST_PARSE_ERROR("shmem-invalid", NONE);
+ DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);
+ DO_TEST_PARSE_ERROR("shmem-invalid-size", NONE);
+ DO_TEST_PARSE_ERROR("shmem-small-size", NONE);
+
virObjectUnref(driver.config);
virObjectUnref(driver.caps);
virObjectUnref(driver.xmlopt);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 56a371e..c63f14f 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -403,6 +403,7 @@ mymain(void)
DO_TEST("bios-nvram");
DO_TEST("tap-vhost");
+ DO_TEST("shmem");
virObjectUnref(driver.caps);
virObjectUnref(driver.xmlopt);
--
2.1.1