[libvirt] [PATCH v3 3/3] qemu: Build command line for ivshmem device

Martin Kletzander mkletzan at redhat.com
Fri Sep 26 10:43:08 UTC 2014


This patch implements support for the ivshmem device in QEMU.

Signed-off-by: Maxime Leroy <maxime.leroy at 6wind.com>
Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 src/qemu/qemu_command.c                            | 118 ++++++++++++++++++++-
 src/qemu/qemu_command.h                            |   1 +
 .../qemuxml2argv-shmem-invalid-size.xml            |  24 +++++
 .../qemuxml2argv-shmem-small-size.xml              |  24 +++++
 tests/qemuxml2argvdata/qemuxml2argv-shmem.args     |  16 +++
 tests/qemuxml2argvtest.c                           |   5 +
 6 files changed, 187 insertions(+), 1 deletion(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid-size.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem.args

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index eb72451..8a96a0e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1029,6 +1029,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
         if (virAsprintf(&def->hubs[i]->info.alias, "hub%zu", i) < 0)
             return -1;
     }
+    for (i = 0; i < def->nshmems; i++) {
+        if (virAsprintf(&def->shmems[i]->info.alias, "shmem%zu", i) < 0)
+            return -1;
+    }
     for (i = 0; i < def->nsmartcards; i++) {
         if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%zu", i) < 0)
             return -1;
@@ -7496,6 +7500,114 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
 }

 static int
+qemuBuildShmemDevCmd(virCommandPtr cmd,
+                     virDomainDefPtr def,
+                     virDomainShmemDefPtr shmem,
+                     virQEMUCapsPtr qemuCaps)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("ivshmem device is not supported "
+                         "with this QEMU binary"));
+        goto error;
+    }
+
+    virBufferAddLit(&buf, "ivshmem");
+    if (shmem->size) {
+        /*
+         * Thanks to our parsing code, we have a guarantee that the
+         * size is power of two and is at least a mebibyte in size.
+         * But because it may change inthe future, the checks are
+         * doubled in here.
+         */
+        if (shmem->size & (shmem->size - 1)) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("shmem size must be a power of two"));
+            goto error;
+        }
+        if (shmem->size < 1024 * 1024) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("shmem size must be at least 1 MiB"));
+            goto error;
+        }
+        virBufferAsprintf(&buf, ",size=%llum",
+                          VIR_DIV_UP(shmem->size, 1024 * 1024));
+    }
+
+    if (!shmem->server.enabled) {
+        virBufferAsprintf(&buf, ",shm=%s", shmem->name);
+    } else {
+        virBufferAsprintf(&buf, ",chardev=char%s", shmem->info.alias);
+        if (shmem->msi.enabled) {
+            virBufferAddLit(&buf, ",msi=on");
+            if (shmem->msi.vectors)
+                virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
+            if (shmem->msi.ioeventfd)
+                virBufferAsprintf(&buf, ",ioeventfd=%s",
+                                  virTristateSwitchTypeToString(shmem->msi.ioeventfd));
+        }
+    }
+
+    if (qemuBuildDeviceAddressStr(&buf, def, &shmem->info, qemuCaps) < 0)
+        goto error;
+
+    if (virBufferCheckError(&buf) < 0)
+        goto error;
+
+    virCommandAddArg(cmd, "-device");
+    virCommandAddArgBuffer(cmd, &buf);
+
+    return 0;
+
+ error:
+    virBufferFreeAndReset(&buf);
+    return -1;
+}
+
+static int
+qemuBuildShmemCommandLine(virCommandPtr cmd,
+                          virDomainDefPtr def,
+                          virDomainShmemDefPtr shmem,
+                          virQEMUCapsPtr qemuCaps)
+{
+    if (qemuBuildShmemDevCmd(cmd, def, shmem, qemuCaps) < 0)
+        return -1;
+
+    if (shmem->server.enabled) {
+        char *devstr = NULL;
+        virDomainChrSourceDef source = {
+            .type = VIR_DOMAIN_CHR_TYPE_UNIX,
+            .data.nix = {
+                .path = shmem->server.path,
+                .listen = false,
+            }
+        };
+
+        if (!shmem->server.path &&
+            virAsprintf(&source.data.nix.path,
+                        "/var/lib/libvirt/shmem-%s-sock",
+                        shmem->name) < 0)
+            return -1;
+
+        devstr = qemuBuildChrChardevStr(&source, shmem->info.alias, qemuCaps);
+
+        if (!shmem->server.path)
+            VIR_FREE(source.data.nix.path);
+
+        if (!devstr)
+            return -1;
+
+        virCommandAddArg(cmd, "-chardev");
+        virCommandAddArg(cmd, devstr);
+        VIR_FREE(devstr);
+    }
+
+    return 0;
+}
+
+static int
 qemuBuildChrDeviceCommandLine(virCommandPtr cmd,
                               virDomainDefPtr def,
                               virDomainChrDefPtr chr,
@@ -9690,6 +9802,11 @@ qemuBuildCommandLine(virConnectPtr conn,
         }
     }

+    for (i = 0; i < def->nshmems; i++) {
+        if (qemuBuildShmemCommandLine(cmd, def, def->shmems[i], qemuCaps))
+            goto error;
+    }
+
     if (mlock) {
         unsigned long long memKB;

@@ -9897,7 +10014,6 @@ qemuBuildChrDeviceStr(char **deviceStr,
     return ret;
 }

-
 /*
  * This method takes a string representing a QEMU command line ARGV set
  * optionally prefixed by a list of environment variables. It then tries
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index aa40c9e..5083223 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -131,6 +131,7 @@ char *qemuBuildDriveDevStr(virDomainDefPtr def,
 char *qemuBuildFSDevStr(virDomainDefPtr domainDef,
                         virDomainFSDefPtr fs,
                         virQEMUCapsPtr qemuCaps);
+
 /* Current, best practice */
 char *qemuBuildControllerDevStr(virDomainDefPtr domainDef,
                                 virDomainControllerDefPtr def,
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-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/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index e55dc50..af9ed4c 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1464,6 +1464,11 @@ mymain(void)

     DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS);

+    DO_TEST("shmem", QEMU_CAPS_PCIDEVICE,
+            QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_IVSHMEM);
+    DO_TEST_FAILURE("shmem", NONE);
+    DO_TEST_FAILURE("shmem-invalid-size", NONE);
+    DO_TEST_FAILURE("shmem-small-size", NONE);
     DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);

     virObjectUnref(driver.config);
-- 
2.1.1




More information about the libvir-list mailing list