This patch implements support for the ivshmem device in QEMU. Signed-off-by: Maxime Leroy <maxime.leroy@xxxxxxxxx> Signed-off-by: Martin Kletzander <mkletzan@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list