This is needed in order to migrate with ivshmem role='peer' as that is
not allowed to migrate.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/qemu/qemu_driver.c | 39 +++-
src/qemu/qemu_hotplug.c | 247 ++++++++++++++++++++-
src/qemu/qemu_hotplug.h | 6 +
tests/qemuhotplugtest.c | 21 ++
.../qemuhotplug-ivshmem-doorbell-detach.xml | 7 +
.../qemuhotplug-ivshmem-doorbell.xml | 4 +
.../qemuhotplug-ivshmem-plain-detach.xml | 6 +
.../qemuhotplug-ivshmem-plain.xml | 3 +
...muhotplug-base-live+ivshmem-doorbell-detach.xml | 1 +
.../qemuhotplug-base-live+ivshmem-doorbell.xml | 65 ++++++
.../qemuhotplug-base-live+ivshmem-plain-detach.xml | 1 +
.../qemuhotplug-base-live+ivshmem-plain.xml | 58 +++++
12 files changed, 453 insertions(+), 5 deletions(-)
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell-detach.xml
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell.xml
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
create mode 120000
tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell-detach.xml
create mode 100644
tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
create mode 120000
tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain-detach.xml
create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index e29180da4e75..0625df273f2f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7522,6 +7522,15 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
dev->data.memory = NULL;
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ ret = qemuDomainAttachShmemDevice(driver, vm,
+ dev->data.shmem);
+ if (!ret) {
+ alias = dev->data.shmem->info.alias;
+ dev->data.shmem = NULL;
+ }
+ break;
+
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
@@ -7533,7 +7542,6 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
- case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_IOMMU:
@@ -7611,6 +7619,9 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_MEMORY:
ret = qemuDomainDetachMemoryDevice(driver, vm, dev->data.memory);
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ ret = qemuDomainDetachShmemDevice(driver, vm, dev);
+ break;
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
@@ -7622,7 +7633,6 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
- case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_REDIRDEV:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
@@ -7769,6 +7779,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
virDomainControllerDefPtr controller;
virDomainFSDefPtr fs;
virDomainRedirdevDefPtr redirdev;
+ virDomainShmemDefPtr shmem;
switch ((virDomainDeviceType) dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
@@ -7893,6 +7904,18 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
dev->data.redirdev = NULL;
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ shmem = dev->data.shmem;
+ if (virDomainShmemDefFind(vmdef, shmem) >= 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("device is already in the domain
configuration"));
+ return -1;
+ }
+ if (virDomainShmemDefInsert(vmdef, shmem) < 0)
+ return -1;
+ dev->data.shmem = NULL;
+ break;
+
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
case VIR_DOMAIN_DEVICE_VIDEO:
@@ -7902,7 +7925,6 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
- case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
@@ -8049,6 +8071,16 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
virDomainRedirdevDefFree(virDomainRedirdevDefRemove(vmdef, idx));
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ if ((idx = virDomainShmemDefFind(vmdef, dev->data.shmem)) < 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("matching shmem device was not found"));
+ return -1;
+ }
+
+ virDomainShmemDefFree(virDomainShmemDefRemove(vmdef, idx));
+ break;
+
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
@@ -8059,7 +8091,6 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
- case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 72dd93bbe467..e70bf577139b 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2242,6 +2242,141 @@ qemuDomainAttachHostDevice(virConnectPtr conn,
return -1;
}
+
+int
+qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainShmemDefPtr shmem)
+{
+ int ret = -1;
+ char *shmstr = NULL;
+ char *charAlias = NULL;
+ char *memAlias = NULL;
+ bool release_backing = false;
+ bool release_address = true;
+ bool supported = false;
+ virErrorPtr orig_err = NULL;
+ virJSONValuePtr props = NULL;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+
+ switch (shmem->model) {
+ case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
+ supported = virQEMUCapsGet(priv->qemuCaps,
+ QEMU_CAPS_DEVICE_IVSHMEM_PLAIN);
+ break;
+
+ case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
+ supported = virQEMUCapsGet(priv->qemuCaps,
+ QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
+ break;
+
+ default:
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+ _("live attach of shmem model '%s' is not
supported"),
+ virDomainShmemModelTypeToString(shmem->model));
+ return -1;
+ }
+
+ if (!supported) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Device '%s' is not supported by this version of
qemu"),
+ virDomainShmemModelTypeToString(shmem->model));
+ return -1;
+ }
+
+ if (qemuAssignDeviceShmemAlias(vm->def, shmem, -1) < 0)
+ return -1;
+
+ if (qemuDomainPrepareShmemChardev(shmem) < 0)
+ return -1;
+
+ if (VIR_REALLOC_N(vm->def->shmems, vm->def->nshmems + 1) < 0)
+ return -1;
+
+ if ((shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
+ shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
+ (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &shmem->info) < 0))
+ return -1;
+
+ if (!(shmstr = qemuBuildShmemDevStr(vm->def, shmem, priv->qemuCaps)))
+ goto cleanup;
+
+ if (shmem->server.enabled) {
+ if (virAsprintf(&charAlias, "char%s", shmem->info.alias) <
0)
+ goto cleanup;
+ } else {
+ if (!(props = qemuBuildShmemBackendMemProps(shmem)))
+ goto cleanup;
+
+ if (virAsprintf(&memAlias, "shmmem-%s", shmem->info.alias) <
0)
+ goto cleanup;
+ }
+
+ if (virDomainShmemDefInsert(vm->def, shmem) < 0)
+ goto cleanup;
+
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ if (shmem->server.enabled) {
+ if (qemuMonitorAttachCharDev(priv->mon, charAlias,
+ &shmem->server.chr) < 0)
+ goto audit;
+ } else {
+ if (qemuMonitorAddObject(priv->mon, "memory-backend-file",
+ memAlias, props) < 0) {
+ props = NULL;
+ goto audit;
+ }
+ props = NULL;
+ }
+
+ release_backing = true;
+
+ if (qemuMonitorAddDevice(priv->mon, shmstr) < 0)
+ goto audit;
+
+ ret = 0;
+ release_address = false;
+
+ audit:
+ virDomainAuditShmem(vm, shmem, "attach", ret == 0);
+
+ orig_err = virSaveLastError();
+ if (ret < 0 && release_backing) {
+ if (shmem->server.enabled) {
+ if (qemuMonitorDetachCharDev(priv->mon, charAlias) < 0) {
+ VIR_WARN("Unable to remove backing chardev '%s' after failed
"
+ "qemuMonitorAddDevice", charAlias);
+ }
+ } else {
+ if (qemuMonitorDelObject(priv->mon, memAlias) < 0) {
+ VIR_WARN("Unable to remove backing memory '%s' after failed
"
+ "qemuMonitorAddDevice", memAlias);
+ }
+ }
+ }
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ ret = -1;
+
+ cleanup:
+ if (release_address)
+ qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
+
+ if (orig_err) {
+ virSetError(orig_err);
+ virFreeError(orig_err);
+ }
+
+ VIR_FREE(memAlias);
+ VIR_FREE(charAlias);
+ VIR_FREE(shmstr);
+
+ return ret;
+}
+
+
static int
qemuDomainChangeNetBridge(virDomainObjPtr vm,
virDomainNetDefPtr olddev,
@@ -3486,6 +3621,61 @@ qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
}
+static int
+qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainShmemDefPtr shmem)
+{
+ int ret = -1;
+ ssize_t idx = -1;
+ char *charAlias = NULL;
+ char *memAlias = NULL;
+ virObjectEventPtr event = NULL;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+
+ VIR_DEBUG("Removing shmem device %s from domain %p %s",
+ shmem->info.alias, vm, vm->def->name);
+
+ if (shmem->server.enabled) {
+ if (virAsprintf(&charAlias, "char%s", shmem->info.alias) <
0)
+ goto cleanup;
+ } else {
+ if (virAsprintf(&memAlias, "shmmem-%s", shmem->info.alias) <
0)
+ goto cleanup;
+ }
+
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ if (shmem->server.enabled)
+ ret = qemuMonitorDetachCharDev(priv->mon, charAlias);
+ else
+ ret = qemuMonitorDelObject(priv->mon, memAlias);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ goto cleanup;
+
+ virDomainAuditShmem(vm, shmem, "detach", ret == 0);
+
+ if (ret < 0)
+ goto cleanup;
+
+ event = virDomainEventDeviceRemovedNewFromObj(vm, shmem->info.alias);
+ qemuDomainEventQueue(driver, event);
+
+ if ((idx = virDomainShmemDefFind(vm->def, shmem)) >= 0)
+ virDomainShmemDefRemove(vm->def, idx);
+ qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(charAlias);
+ VIR_FREE(memAlias);
+
+ return ret;
+}
+
+
int
qemuDomainRemoveDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
@@ -3517,6 +3707,10 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
ret = qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory);
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ ret = qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem);
+ break;
+
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_FS:
@@ -3530,7 +3724,6 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
- case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_IOMMU:
@@ -4105,6 +4298,58 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
return qemuDomainDetachThisHostDevice(driver, vm, detach);
}
+
+int
+qemuDomainDetachShmemDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev)
+{
+ int ret = -1;
+ virErrorPtr orig_err = NULL;
+ virDomainShmemDefPtr shmem = dev->data.shmem;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+
+ switch (shmem->model) {
+ case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
+ case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
+ break;
+
+ default:
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+ _("live detach of shmem model '%s' is not
supported"),
+ virDomainShmemModelTypeToString(shmem->model));
+ return -1;
+ }
+
+ qemuDomainMarkDeviceForRemoval(vm, &shmem->info);
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ ret = qemuMonitorDelDevice(priv->mon, shmem->info.alias);
+
+ if (ret < 0)
+ orig_err = virSaveLastError();
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ ret = -1;
+
+ if (ret == 0) {
+ if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1) {
+ qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
+ ret = qemuDomainRemoveDevice(driver, vm, dev);
+ }
+ }
+ qemuDomainResetDeviceRemoval(vm);
+
+ if (orig_err) {
+ virSetError(orig_err);
+ virFreeError(orig_err);
+ }
+
+ return ret;
+}
+
+
int
qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index b048cf4688a4..12994e7cd468 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -50,6 +50,9 @@ int qemuDomainAttachHostDevice(virConnectPtr conn,
virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev);
+int qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainShmemDefPtr shmem);
int qemuDomainFindGraphicsIndex(virDomainDefPtr def,
virDomainGraphicsDefPtr dev);
int qemuDomainAttachMemory(virQEMUDriverPtr driver,
@@ -86,6 +89,9 @@ int qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev);
+int qemuDomainDetachShmemDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev);
int qemuDomainAttachLease(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainLeaseDefPtr lease);
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
index 6a9ed992f31d..dda3917a5034 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -74,6 +74,8 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_VIRTIO_SCSI);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE);
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW);
+ virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN);
+ virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
if (event)
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT);
@@ -119,6 +121,9 @@ testQemuHotplugAttach(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_CHR:
ret = qemuDomainAttachChrDevice(&driver, vm, dev->data.chr);
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ ret = qemuDomainAttachShmemDevice(&driver, vm, dev->data.shmem);
+ break;
default:
VIR_TEST_VERBOSE("device type '%s' cannot be attached\n",
virDomainDeviceTypeToString(dev->type));
@@ -141,6 +146,9 @@ testQemuHotplugDetach(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_CHR:
ret = qemuDomainDetachChrDevice(&driver, vm, dev->data.chr);
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ ret = qemuDomainDetachShmemDevice(&driver, vm, dev);
+ break;
default:
VIR_TEST_VERBOSE("device type '%s' cannot be detached\n",
virDomainDeviceTypeToString(dev->type));
@@ -560,6 +568,19 @@ mymain(void)
"human-monitor-command", HMP("OK\\r\\n"),
"device_add", QMP_OK);
+ DO_TEST_ATTACH("base-live", "ivshmem-plain", false, true,
+ "object-add", QMP_OK,
+ "device_add", QMP_OK);
+ DO_TEST_ATTACH("base-live", "ivshmem-doorbell", false, true,
+ "chardev-add", QMP_OK,
+ "device_add", QMP_OK);
+ DO_TEST_DETACH("base-live+ivshmem-plain",
"ivshmem-doorbell-detach", false, true,
+ "device_del", QMP_OK,
+ "chardev-remove", QMP_OK);
+ DO_TEST_DETACH("base-live", "ivshmem-plain-detach", false,
false,
+ "device_del", QMP_OK,
+ "object-del", QMP_OK);
+
qemuTestDriverFree(&driver);
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell-detach.xml
b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell-detach.xml
new file mode 100644
index 000000000000..7c066964d745
--- /dev/null
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell-detach.xml
@@ -0,0 +1,7 @@
+<shmem name='shmem1'>
+ <model type='ivshmem-doorbell'/>
+ <server path='/var/lib/libvirt/shmem-shmem1-sock'/>
+ <msi ioeventfd='on'/>
+ <alias name='shmem1'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x06' function='0x0'/>
+</shmem>
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell.xml
b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell.xml
new file mode 100644
index 000000000000..06cb0c978605
--- /dev/null
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell.xml
@@ -0,0 +1,4 @@
+<shmem name='shmem1'>
+ <model type='ivshmem-doorbell'/>
+ <server/>
+</shmem>
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
new file mode 100644
index 000000000000..338017aa2854
--- /dev/null
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
@@ -0,0 +1,6 @@
+<shmem name='shmem0' role='peer'>
+ <model type='ivshmem-plain'/>
+ <size unit='M'>4</size>
+ <alias name='shmem0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x05' function='0x0'/>
+</shmem>
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
new file mode 100644
index 000000000000..6bd96ff16767
--- /dev/null
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
@@ -0,0 +1,3 @@
+<shmem name='shmem0'>
+ <model type='ivshmem-plain'/>
+</shmem>
diff --git
a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell-detach.xml
b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell-detach.xml
new file mode 120000
index 000000000000..021e5471d197
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell-detach.xml
@@ -0,0 +1 @@
+qemuhotplug-base-live+ivshmem-plain.xml
\ No newline at end of file
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
new file mode 100644
index 000000000000..867192568168
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
@@ -0,0 +1,65 @@
+<domain type='kvm' id='7'>
+ <name>hotplug</name>
+ <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
+ <memory unit='KiB'>4194304</memory>
+ <currentMemory unit='KiB'>4194304</currentMemory>
+ <vcpu placement='static'>4</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/libexec/qemu-kvm</emulator>
+ <controller type='usb' index='0'>
+ <alias name='usb'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <alias name='ide'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='scsi' index='0' model='virtio-scsi'>
+ <alias name='scsi0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'>
+ <alias name='pci'/>
+ </controller>
+ <controller type='virtio-serial' index='0'>
+ <alias name='virtio-serial0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0'/>
+ </controller>
+ <input type='mouse' bus='ps2'>
+ <alias name='input0'/>
+ </input>
+ <input type='keyboard' bus='ps2'>
+ <alias name='input1'/>
+ </input>
+ <memballoon model='none'>
+ <alias name='balloon0'/>
+ </memballoon>
+ <shmem name='shmem0' role='peer'>
+ <model type='ivshmem-plain'/>
+ <size unit='M'>4</size>
+ <alias name='shmem0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x05' function='0x0'/>
+ </shmem>
+ <shmem name='shmem1'>
+ <model type='ivshmem-doorbell'/>
+ <server path='/var/lib/libvirt/shmem-shmem1-sock'/>
+ <msi ioeventfd='on'/>
+ <alias name='shmem1'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x06' function='0x0'/>
+ </shmem>
+ </devices>
+ <seclabel type='none' model='none'/>
+</domain>
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain-detach.xml
b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain-detach.xml
new file mode 120000
index 000000000000..48c1b1755a4e
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain-detach.xml
@@ -0,0 +1 @@
+qemuhotplug-base-live.xml
\ No newline at end of file
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
new file mode 100644
index 000000000000..2873e7153e54
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
@@ -0,0 +1,58 @@
+<domain type='kvm' id='7'>
+ <name>hotplug</name>
+ <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
+ <memory unit='KiB'>4194304</memory>
+ <currentMemory unit='KiB'>4194304</currentMemory>
+ <vcpu placement='static'>4</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/libexec/qemu-kvm</emulator>
+ <controller type='usb' index='0'>
+ <alias name='usb'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <alias name='ide'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='scsi' index='0' model='virtio-scsi'>
+ <alias name='scsi0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'>
+ <alias name='pci'/>
+ </controller>
+ <controller type='virtio-serial' index='0'>
+ <alias name='virtio-serial0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0'/>
+ </controller>
+ <input type='mouse' bus='ps2'>
+ <alias name='input0'/>
+ </input>
+ <input type='keyboard' bus='ps2'>
+ <alias name='input1'/>
+ </input>
+ <memballoon model='none'>
+ <alias name='balloon0'/>
+ </memballoon>
+ <shmem name='shmem0' role='peer'>
+ <model type='ivshmem-plain'/>
+ <size unit='M'>4</size>
+ <alias name='shmem0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x05' function='0x0'/>
+ </shmem>
+ </devices>
+ <seclabel type='none' model='none'/>
+</domain>
--
2.10.0