[libvirt] [PATCH 17/20] qemu: Support newer ivshmem device variants

Martin Kletzander mkletzan at redhat.com
Thu Sep 15 16:14:42 UTC 2016


QEMU added support for ivshmem-plain and ivshmem-doorbell.  Those are
reworked varians of legacy ivshmem that are compatible from the guest
POV, but not from host's POV and have sane specification and handling.

Details about the newer device type can be found in qemu's commit
5400c02b90bb:

  http://git.qemu.org/?p=qemu.git;a=commit;h=5400c02b90bb

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 src/qemu/qemu_command.c                            | 137 ++++++++++++++++++++-
 src/qemu/qemu_command.h                            |  10 ++
 .../qemuxml2argv-shmem-plain-doorbell.args         |  46 +++++++
 .../qemuxml2argv-shmem-plain-doorbell.xml          |  63 ++++++++++
 tests/qemuxml2argvtest.c                           |   3 +
 .../qemuxml2xmlout-shmem-plain-doorbell.xml        |  70 +++++++++++
 tests/qemuxml2xmltest.c                            |   2 +
 7 files changed, 328 insertions(+), 3 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml
 create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem-plain-doorbell.xml

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a28d503943d2..45e5b8e5ce27 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -8597,6 +8597,82 @@ qemuBuildShmemDevLegacyStr(virDomainDefPtr def,
     return NULL;
 }

+char *
+qemuBuildShmemDevStr(virDomainDefPtr def,
+                     virDomainShmemDefPtr shmem,
+                     virQEMUCapsPtr qemuCaps)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (shmem->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN) {
+        if (shmem->server.enabled) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("ivshmem-plain is only supported without server "
+                             "option, try using ivshmem-doorbell instead"));
+            return NULL;
+        }
+
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("ivshmem-plain device is not supported "
+                             "with this QEMU binary"));
+            return NULL;
+        }
+    } else {
+        if (!shmem->server.enabled) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("ivshmem-doorbell is only supported with server "
+                             "option, try using ivshmem-doorbell instead"));
+            return NULL;
+        }
+
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("ivshmem-doorbell device is not supported "
+                             "with this QEMU binary"));
+            return NULL;
+        }
+    }
+
+    if (shmem->server.enabled) {
+        virBufferAddLit(&buf, "ivshmem-doorbell");
+        virBufferAsprintf(&buf, ",id=%s,chardev=char%s",
+                          shmem->info.alias, shmem->info.alias);
+        if (shmem->msi.vectors)
+            virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
+        if (shmem->msi.ioeventfd)
+            virBufferAsprintf(&buf, ",ioeventfd=%s",
+                              virTristateSwitchTypeToString(shmem->msi.ioeventfd));
+    } else {
+        virBufferAddLit(&buf, "ivshmem-plain");
+        virBufferAsprintf(&buf, ",id=%s,memdev=shmmem-%s",
+                          shmem->info.alias, shmem->info.alias);
+
+        virBufferAddLit(&buf, ",master=");
+        switch ((virDomainShmemRole) shmem->role) {
+        case VIR_DOMAIN_SHMEM_ROLE_MASTER:
+            virBufferAddLit(&buf, "on");
+            break;
+        case VIR_DOMAIN_SHMEM_ROLE_PEER:
+            virBufferAddLit(&buf, "off");
+            break;
+        case VIR_DOMAIN_SHMEM_ROLE_DEFAULT:
+        case VIR_DOMAIN_SHMEM_ROLE_LAST:
+            break;
+        }
+    }
+
+    if (qemuBuildDeviceAddressStr(&buf, def, &shmem->info, qemuCaps) < 0) {
+        virBufferFreeAndReset(&buf);
+        return NULL;
+    }
+
+    if (virBufferCheckError(&buf) < 0)
+        return NULL;
+
+    return virBufferContentAndReset(&buf);
+}
+
 static char *
 qemuBuildShmemBackendChrStr(virLogManagerPtr logManager,
                             virCommandPtr cmd,
@@ -8617,6 +8693,51 @@ qemuBuildShmemBackendChrStr(virLogManagerPtr logManager,
     return devstr;
 }

+
+virJSONValuePtr
+qemuBuildShmemBackendMemProps(virDomainShmemDefPtr shmem)
+{
+    char *mem_path = NULL;
+    virJSONValuePtr ret = NULL;
+
+    if (virAsprintf(&mem_path, "/dev/shm/%s", shmem->name) < 0)
+        return NULL;
+
+    virJSONValueObjectCreate(&ret,
+                             "U:size", shmem->size,
+                             "s:mem-path", mem_path,
+                             NULL);
+
+    VIR_FREE(mem_path);
+
+    return ret;
+}
+
+
+static char *
+qemuBuildShmemBackendMemStr(virDomainShmemDefPtr shmem)
+{
+    char *ret = NULL;
+    char *alias = NULL;
+    virJSONValuePtr props = qemuBuildShmemBackendMemProps(shmem);
+
+    if (!props)
+        return NULL;
+
+    if (virAsprintf(&alias, "shmmem-%s", shmem->info.alias) < 0)
+        goto cleanup;
+
+    ret = virQEMUBuildObjectCommandlineFromJSON("memory-backend-file",
+                                                alias,
+                                                props);
+ cleanup:
+    VIR_FREE(alias);
+    virJSONValueFree(props);
+
+    return ret;
+}
+
+
 static int
 qemuBuildShmemCommandLine(virLogManagerPtr logManager,
                           virCommandPtr cmd,
@@ -8663,9 +8784,19 @@ qemuBuildShmemCommandLine(virLogManagerPtr logManager,

     case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
     case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("%s device is not supported with this QEMU binary"),
-                       virDomainShmemModelTypeToString(shmem->model));
+        if (!(devstr = qemuBuildShmemDevStr(def, shmem, qemuCaps)))
+            return -1;
+
+        virCommandAddArgList(cmd, "-device", devstr, NULL);
+        VIR_FREE(devstr);
+
+        if (!shmem->server.enabled) {
+            if (!(devstr = qemuBuildShmemBackendMemStr(shmem)))
+                return -1;
+
+            virCommandAddArgList(cmd, "-object", devstr, NULL);
+            VIR_FREE(devstr);
+        }
         break;

     /* coverity[dead_error_begin] */
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 2f2a6ff877e7..facc833bf886 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -186,4 +186,14 @@ bool qemuCheckCCWS390AddressSupport(const virDomainDef *def,
 virJSONValuePtr qemuBuildHotpluggableCPUProps(const virDomainVcpuDef *vcpu)
     ATTRIBUTE_NONNULL(1);

+virJSONValuePtr qemuBuildShmemBackendMemProps(virDomainShmemDefPtr shmem)
+    ATTRIBUTE_NONNULL(1);
+
+char *qemuBuildShmemDevStr(virDomainDefPtr def,
+                           virDomainShmemDefPtr shmem,
+                           virQEMUCapsPtr qemuCaps)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+
+
+
 #endif /* __QEMU_COMMAND_H__*/
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args
new file mode 100644
index 000000000000..8d58b311a5c8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args
@@ -0,0 +1,46 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-M pc \
+-m 214 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-device ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,master=off,bus=pci.0,\
+addr=0x3 \
+-object memory-backend-file,id=shmmem-shmem0,size=4194304,\
+mem-path=/dev/shm/shmem0 \
+-device ivshmem-plain,id=shmem1,memdev=shmmem-shmem1,master=off,bus=pci.0,\
+addr=0x5 \
+-object memory-backend-file,id=shmmem-shmem1,size=134217728,\
+mem-path=/dev/shm/shmem1 \
+-device ivshmem-plain,id=shmem2,memdev=shmmem-shmem2,master=on,bus=pci.0,\
+addr=0x4 \
+-object memory-backend-file,id=shmmem-shmem2,size=268435456,\
+mem-path=/dev/shm/shmem2 \
+-device ivshmem-doorbell,id=shmem3,chardev=charshmem3,ioeventfd=on,bus=pci.0,\
+addr=0x6 \
+-chardev socket,id=charshmem3,path=/var/lib/libvirt/shmem-shmem3-sock \
+-device ivshmem-doorbell,id=shmem4,chardev=charshmem4,ioeventfd=on,bus=pci.0,\
+addr=0x7 \
+-chardev socket,id=charshmem4,path=/tmp/shmem4-sock \
+-device ivshmem-doorbell,id=shmem5,chardev=charshmem5,ioeventfd=off,bus=pci.0,\
+addr=0x8 \
+-chardev socket,id=charshmem5,path=/tmp/shmem5-sock \
+-device ivshmem-doorbell,id=shmem6,chardev=charshmem6,vectors=16,ioeventfd=on,\
+bus=pci.0,addr=0x9 \
+-chardev socket,id=charshmem6,path=/tmp/shmem6-sock \
+-device ivshmem-doorbell,id=shmem7,chardev=charshmem7,vectors=32,ioeventfd=on,\
+bus=pci.0,addr=0xa \
+-chardev socket,id=charshmem7,path=/tmp/shmem7-sock
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml
new file mode 100644
index 000000000000..23a7b27e87b1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml
@@ -0,0 +1,63 @@
+<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'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='none'/>
+    <shmem name='shmem0'>
+      <model type='ivshmem-plain'/>
+    </shmem>
+    <shmem name='shmem1' role='peer'>
+      <model type='ivshmem-plain'/>
+      <size unit='M'>128</size>
+    </shmem>
+    <shmem name='shmem2' role='master'>
+      <model type='ivshmem-plain'/>
+      <size unit='M'>256</size>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </shmem>
+    <shmem name='shmem3'>
+      <model type='ivshmem-doorbell'/>
+      <size unit='M'>512</size>
+      <server/>
+    </shmem>
+    <shmem name='shmem4'>
+      <model type='ivshmem-doorbell'/>
+      <size unit='M'>1024</size>
+      <server path='/tmp/shmem4-sock'/>
+    </shmem>
+    <shmem name='shmem5'>
+      <model type='ivshmem-doorbell'/>
+      <size unit='M'>2048</size>
+      <server path='/tmp/shmem5-sock'/>
+      <msi ioeventfd='off'/>
+    </shmem>
+    <shmem name='shmem6'>
+      <model type='ivshmem-doorbell'/>
+      <size unit='M'>4096</size>
+      <server path='/tmp/shmem6-sock'/>
+      <msi vectors='16'/>
+    </shmem>
+    <shmem name='shmem7'>
+      <model type='ivshmem-doorbell'/>
+      <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 dbb0e4d56142..3f2c4ea152ba 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1987,6 +1987,9 @@ mymain(void)
     DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS);

     DO_TEST("shmem", QEMU_CAPS_DEVICE_IVSHMEM);
+    DO_TEST("shmem-plain-doorbell", QEMU_CAPS_DEVICE_IVSHMEM,
+            QEMU_CAPS_DEVICE_IVSHMEM_PLAIN,
+            QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
     DO_TEST_FAILURE("shmem", NONE);
     DO_TEST_FAILURE("shmem-invalid-size",
                     QEMU_CAPS_DEVICE_IVSHMEM);
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem-plain-doorbell.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem-plain-doorbell.xml
new file mode 100644
index 000000000000..0b3499335af5
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem-plain-doorbell.xml
@@ -0,0 +1,70 @@
+<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'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='none'/>
+    <shmem name='shmem0' role='peer'>
+      <model type='ivshmem-plain'/>
+      <size unit='M'>4</size>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </shmem>
+    <shmem name='shmem1' role='peer'>
+      <model type='ivshmem-plain'/>
+      <size unit='M'>128</size>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+    </shmem>
+    <shmem name='shmem2' role='master'>
+      <model type='ivshmem-plain'/>
+      <size unit='M'>256</size>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </shmem>
+    <shmem name='shmem3'>
+      <model type='ivshmem-doorbell'/>
+      <server/>
+      <msi ioeventfd='on'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+    </shmem>
+    <shmem name='shmem4'>
+      <model type='ivshmem-doorbell'/>
+      <server path='/tmp/shmem4-sock'/>
+      <msi ioeventfd='on'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+    </shmem>
+    <shmem name='shmem5'>
+      <model type='ivshmem-doorbell'/>
+      <server path='/tmp/shmem5-sock'/>
+      <msi ioeventfd='off'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+    </shmem>
+    <shmem name='shmem6'>
+      <model type='ivshmem-doorbell'/>
+      <server path='/tmp/shmem6-sock'/>
+      <msi vectors='16' ioeventfd='on'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
+    </shmem>
+    <shmem name='shmem7'>
+      <model type='ivshmem-doorbell'/>
+      <server path='/tmp/shmem7-sock'/>
+      <msi vectors='32' ioeventfd='on'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
+    </shmem>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 14c2b0ccf2ce..ce32be47827b 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -812,6 +812,8 @@ mymain(void)
     DO_TEST("tap-vhost", NONE);
     DO_TEST("tap-vhost-incorrect", NONE);
     DO_TEST("shmem", NONE);
+    DO_TEST("shmem-plain-doorbell",
+            QEMU_CAPS_DEVICE_IVSHMEM_PLAIN, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
     DO_TEST("smbios", NONE);
     DO_TEST("smbios-multiple-type2", NONE);

-- 
2.10.0




More information about the libvir-list mailing list