From 119c2da39b45127373288b6ffa5855c2c6c5bce9 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 17 2022 08:45:10 +0000 Subject: import libvirt-8.0.0-8.el9_0 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbb5a7e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/libvirt-8.0.0.tar.xz diff --git a/.libvirt.metadata b/.libvirt.metadata new file mode 100644 index 0000000..76dff0f --- /dev/null +++ b/.libvirt.metadata @@ -0,0 +1 @@ +e440412e9b45d7e24f0ef492d8edf5cf2cbd3f4c SOURCES/libvirt-8.0.0.tar.xz diff --git a/SOURCES/libvirt-Make-systemd-unit-ordering-more-robust.patch b/SOURCES/libvirt-Make-systemd-unit-ordering-more-robust.patch new file mode 100644 index 0000000..be38df5 --- /dev/null +++ b/SOURCES/libvirt-Make-systemd-unit-ordering-more-robust.patch @@ -0,0 +1,89 @@ +From ee1ce580f5373070e4b6a50d1ae4a3218c737a72 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Martin Kletzander +Date: Mon, 14 Feb 2022 12:37:37 +0100 +Subject: [PATCH] Make systemd unit ordering more robust + +Since libvirt-guests script/service can operate on various URIs and we do +support both socket activation and traditional services, the ordering should be +specified for all the possible sockets and services. + +Also remove the Wants= dependency since do not want to start any service. We +cannot know which one libvirt-guests is configured, so we'd have to start all +the daemons which would break if unused colliding services are not +masked (libvirtd.service in the modular case and all the modular daemon service +units in the monolithic scenario). Fortunately we can assume that the system is +configured properly to start services/sockets that are of interest to the user. +That also works with the setup described in https://libvirt.org/daemons.html . + +To make it even more robust we add the daemon service into the machine units +created for individual domains as it was missing there. + +https://bugzilla.redhat.com/show_bug.cgi?id=1868537 + +Signed-off-by: Martin Kletzander +Reviewed-by: Michal Privoznik +(cherry picked from commit 4e42686adef8b9e9266f0099ddcd25bc95c4ed43) +Signed-off-by: Martin Kletzander +--- + src/util/virsystemd.c | 8 ++++++-- + tools/libvirt-guests.service.in | 12 +++++++++++- + 2 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c +index a86d4c6bb9..f156c2f39a 100644 +--- a/src/util/virsystemd.c ++++ b/src/util/virsystemd.c +@@ -441,8 +441,10 @@ int virSystemdCreateMachine(const char *name, + nicindexes, nnicindexes, sizeof(int)); + gprops = g_variant_new_parsed("[('Slice', <%s>)," + " ('After', <['libvirtd.service']>)," ++ " ('After', <['virt%sd.service']>)," + " ('Before', <['virt-guest-shutdown.target']>)]", +- slicename); ++ slicename, ++ drivername); + message = g_variant_new("(s@ayssus@ai@a(sv))", + name, + guuid, +@@ -489,8 +491,10 @@ int virSystemdCreateMachine(const char *name, + uuid, 16, sizeof(unsigned char)); + gprops = g_variant_new_parsed("[('Slice', <%s>)," + " ('After', <['libvirtd.service']>)," ++ " ('After', <['virt%sd.service']>)," + " ('Before', <['virt-guest-shutdown.target']>)]", +- slicename); ++ slicename, ++ drivername); + message = g_variant_new("(s@ayssus@a(sv))", + name, + guuid, +diff --git a/tools/libvirt-guests.service.in b/tools/libvirt-guests.service.in +index 1a9b233e11..3cf6476196 100644 +--- a/tools/libvirt-guests.service.in ++++ b/tools/libvirt-guests.service.in +@@ -1,10 +1,20 @@ + [Unit] + Description=Suspend/Resume Running libvirt Guests +-Wants=libvirtd.service + Requires=virt-guest-shutdown.target + After=network.target + After=time-sync.target ++After=libvirtd.socket ++After=virtqemud.socket ++After=virtlxcd.socket ++After=virtvboxd.socket ++After=virtvzd.socket ++After=virtxend.socket + After=libvirtd.service ++After=virtqemud.service ++After=virtlxcd.service ++After=virtvboxd.service ++After=virtvzd.service ++After=virtxend.service + After=virt-guest-shutdown.target + Documentation=man:libvirt-guests(8) + Documentation=https://libvirt.org +-- +2.35.1 + diff --git a/SOURCES/libvirt-RHEL-Fix-virConnectGetMaxVcpus-output.patch b/SOURCES/libvirt-RHEL-Fix-virConnectGetMaxVcpus-output.patch new file mode 100644 index 0000000..245859e --- /dev/null +++ b/SOURCES/libvirt-RHEL-Fix-virConnectGetMaxVcpus-output.patch @@ -0,0 +1,46 @@ +From 16b9ab85b004308e1d99db4ed4769a5fa56e2dfa Mon Sep 17 00:00:00 2001 +Message-Id: <16b9ab85b004308e1d99db4ed4769a5fa56e2dfa@dist-git> +From: =?UTF-8?q?J=C3=A1n=20Tomko?= +Date: Mon, 27 Aug 2018 13:09:38 +0200 +Subject: [PATCH] RHEL: Fix virConnectGetMaxVcpus output +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +https://bugzilla.redhat.com/show_bug.cgi?id=1092363 + +RHEL-only. + +Ignore the maximum vcpu limit (KVM_CAP_MAX_VCPUS) on RHEL, +since RHEL QEMU treats the recommended limit (KVM_CAP_NR_VCPUS) +as the maximum, see: +https://bugzilla.redhat.com/show_bug.cgi?id=998708 + +(cherry picked from commit 7dff909fa34bdd93ad200dbffe70c0c1ee931925) +Signed-off-by: Ján Tomko + +https: //bugzilla.redhat.com/show_bug.cgi?id=1582222 +Reviewed-by: Andrea Bolognani +--- + src/util/virhostcpu.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c +index a07c00a0e9..35f41daef2 100644 +--- a/src/util/virhostcpu.c ++++ b/src/util/virhostcpu.c +@@ -1166,6 +1166,11 @@ virHostCPUGetKVMMaxVCPUs(void) + return -1; + } + ++/* Ignore KVM_CAP_MAX_VCPUS on RHEL - the recommended maximum ++ * is treated as a hard limit. ++ */ ++# undef KVM_CAP_MAX_VCPUS ++ + # ifdef KVM_CAP_MAX_VCPUS + /* at first try KVM_CAP_MAX_VCPUS to determine the maximum count */ + if ((ret = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_MAX_VCPUS)) > 0) +-- +2.34.1 + diff --git a/SOURCES/libvirt-Revert-report-error-when-virProcessGetStatInfo-is-unable-to-parse-data.patch b/SOURCES/libvirt-Revert-report-error-when-virProcessGetStatInfo-is-unable-to-parse-data.patch new file mode 100644 index 0000000..f2ab83f --- /dev/null +++ b/SOURCES/libvirt-Revert-report-error-when-virProcessGetStatInfo-is-unable-to-parse-data.patch @@ -0,0 +1,104 @@ +From 81f1508d99d4740e7a2a092128d651cf245a554e Mon Sep 17 00:00:00 2001 +Message-Id: <81f1508d99d4740e7a2a092128d651cf245a554e@dist-git> +From: Michal Privoznik +Date: Tue, 18 Jan 2022 12:40:09 +0100 +Subject: [PATCH] Revert "report error when virProcessGetStatInfo() is unable + to parse data" + +This reverts commit 938382b60ae5bd1f83b5cb09e1ce68b9a88f679a. + +Turns out, the commit did more harm than good. It changed +semantics on some public APIs. For instance, while +qemuDomainGetInfo() previously did not returned an error it does +now. While the calls to virProcessGetStatInfo() is guarded with +virDomainObjIsActive() it doesn't necessarily mean that QEMU's +PID is still alive. QEMU might be gone but we just haven't +realized it (e.g. because the eof handler thread is waiting for a +job). + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2041610 +Signed-off-by: Michal Privoznik +Reviewed-by: Andrea Bolognani +(cherry picked from commit 105dace22cc7b5b18d72a4dcad4a2cf386ce5c99) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2043579 +Signed-off-by: Michal Privoznik +--- + src/ch/ch_driver.c | 2 ++ + src/qemu/qemu_driver.c | 7 ++++++- + src/util/virprocess.c | 8 ++------ + 3 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c +index 3cbc668489..53e0872207 100644 +--- a/src/ch/ch_driver.c ++++ b/src/ch/ch_driver.c +@@ -1073,6 +1073,8 @@ chDomainHelperGetVcpus(virDomainObj *vm, + if (virProcessGetStatInfo(&vcpuinfo->cpuTime, + &vcpuinfo->cpu, NULL, + vm->pid, vcpupid) < 0) { ++ virReportSystemError(errno, "%s", ++ _("cannot get vCPU placement & pCPU time")); + return -1; + } + } +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 65ac5ef367..d3d76c003f 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -1359,6 +1359,8 @@ qemuDomainHelperGetVcpus(virDomainObj *vm, + if (virProcessGetStatInfo(&vcpuinfo->cpuTime, + &vcpuinfo->cpu, NULL, + vm->pid, vcpupid) < 0) { ++ virReportSystemError(errno, "%s", ++ _("cannot get vCPU placement & pCPU time")); + return -1; + } + } +@@ -2519,6 +2521,8 @@ qemuDomainGetInfo(virDomainPtr dom, + if (virDomainObjIsActive(vm)) { + if (virProcessGetStatInfo(&(info->cpuTime), NULL, NULL, + vm->pid, 0) < 0) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("cannot read cputime for domain")); + goto cleanup; + } + } +@@ -10526,7 +10530,8 @@ qemuDomainMemoryStatsInternal(virQEMUDriver *driver, + } + + if (virProcessGetStatInfo(NULL, NULL, &rss, vm->pid, 0) < 0) { +- virResetLastError(); ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("cannot get RSS for domain")); + } else { + stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS; + stats[ret].val = rss; +diff --git a/src/util/virprocess.c b/src/util/virprocess.c +index 85d8c8e747..b559a4257e 100644 +--- a/src/util/virprocess.c ++++ b/src/util/virprocess.c +@@ -1784,10 +1784,7 @@ virProcessGetStatInfo(unsigned long long *cpuTime, + virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_STIME], NULL, 10, &systime) < 0 || + virStrToLong_l(proc_stat[VIR_PROCESS_STAT_RSS], NULL, 10, &rss) < 0 || + virStrToLong_i(proc_stat[VIR_PROCESS_STAT_PROCESSOR], NULL, 10, &cpu) < 0) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("cannot parse process status data for pid '%d/%d'"), +- (int) pid, (int) tid); +- return -1; ++ VIR_WARN("cannot parse process status data"); + } + + /* We got jiffies +@@ -1884,8 +1881,7 @@ virProcessGetStatInfo(unsigned long long *cpuTime G_GNUC_UNUSED, + pid_t pid G_GNUC_UNUSED, + pid_t tid G_GNUC_UNUSED) + { +- virReportSystemError(ENOSYS, "%s", +- _("Process statistics data is not supported on this platform")); ++ errno = ENOSYS; + return -1; + } + +-- +2.35.0 + diff --git a/SOURCES/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch b/SOURCES/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch new file mode 100644 index 0000000..a2ecb09 --- /dev/null +++ b/SOURCES/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch @@ -0,0 +1,75 @@ +From f45c99be9258f2d97c1f19b93ae8f5e73f4cb486 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jim Fehlig +Date: Mon, 10 Jan 2022 11:42:58 -0700 +Subject: [PATCH] build: Only install libvirt-guests when building libvirtd + +libvirt-guests was already moved to the libvirt daemon package in commit +d800c50349. It only needs to be installed when building libvirtd. + +Signed-off-by: Jim Fehlig +Reviewed-by: Andrea Bolognani +(cherry picked from commit 3be5ba11a2c6fcb2dfdffa03ab4f847113f36b85) + +https://bugzilla.redhat.com/show_bug.cgi?id=2042529 +--- + tools/meson.build | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/tools/meson.build b/tools/meson.build +index 22fa3604ba..2d0aecb90b 100644 +--- a/tools/meson.build ++++ b/tools/meson.build +@@ -297,29 +297,31 @@ if conf.has('WITH_SANLOCK') + ) + endif + +-configure_file( +- input: 'libvirt-guests.sh.in', +- output: '@BASENAME@', +- configuration: tools_conf, +- install: true, +- install_dir: libexecdir, +- install_mode: 'rwxrwxr-x', +-) +- +-if init_script == 'systemd' +- install_data( +- 'libvirt-guests.sysconf', +- install_dir: sysconfdir / 'sysconfig', +- rename: 'libvirt-guests', +- ) +- ++if conf.has('WITH_LIBVIRTD') + configure_file( +- input: 'libvirt-guests.service.in', ++ input: 'libvirt-guests.sh.in', + output: '@BASENAME@', + configuration: tools_conf, + install: true, +- install_dir: prefix / 'lib' / 'systemd' / 'system', ++ install_dir: libexecdir, ++ install_mode: 'rwxrwxr-x', + ) ++ ++ if init_script == 'systemd' ++ install_data( ++ 'libvirt-guests.sysconf', ++ install_dir: sysconfdir / 'sysconfig', ++ rename: 'libvirt-guests', ++ ) ++ ++ configure_file( ++ input: 'libvirt-guests.service.in', ++ output: '@BASENAME@', ++ configuration: tools_conf, ++ install: true, ++ install_dir: prefix / 'lib' / 'systemd' / 'system', ++ ) ++ endif + endif + + if bash_completion_dep.found() +-- +2.35.0 + diff --git a/SOURCES/libvirt-docs-Add-man-page-for-libvirt-guests.patch b/SOURCES/libvirt-docs-Add-man-page-for-libvirt-guests.patch new file mode 100644 index 0000000..de5f819 --- /dev/null +++ b/SOURCES/libvirt-docs-Add-man-page-for-libvirt-guests.patch @@ -0,0 +1,217 @@ +From 8363046dd5f3e018aaea7b6d9b711fb3d1e417cc Mon Sep 17 00:00:00 2001 +Message-Id: <8363046dd5f3e018aaea7b6d9b711fb3d1e417cc@dist-git> +From: Jim Fehlig +Date: Fri, 7 Jan 2022 14:35:10 -0700 +Subject: [PATCH] docs: Add man page for libvirt-guests + +Signed-off-by: Jim Fehlig +Reviewed-by: Andrea Bolognani +(cherry picked from commit 161727417a91bdddf8f3167cf70c3de2829be81c) + +https://bugzilla.redhat.com/show_bug.cgi?id=2042529 +--- + docs/manpages/index.rst | 1 + + docs/manpages/libvirt-guests.rst | 151 +++++++++++++++++++++++++++++++ + docs/manpages/meson.build | 1 + + libvirt.spec.in | 1 + + tools/libvirt-guests.service.in | 2 +- + 5 files changed, 155 insertions(+), 1 deletion(-) + create mode 100644 docs/manpages/libvirt-guests.rst + +diff --git a/docs/manpages/index.rst b/docs/manpages/index.rst +index fb4a36d46a..8fd0d90041 100644 +--- a/docs/manpages/index.rst ++++ b/docs/manpages/index.rst +@@ -41,6 +41,7 @@ Tools + * `virt-admin(1) `__ - daemon administration interface + * `virsh(1) `__ - management user interface + * `virt-qemu-run(1) `__ - run standalone QEMU instances ++* `libvirt-guests(8) `__ - suspend/resume running libvirt guests + + Key codes + ========= +diff --git a/docs/manpages/libvirt-guests.rst b/docs/manpages/libvirt-guests.rst +new file mode 100644 +index 0000000000..76045ed11a +--- /dev/null ++++ b/docs/manpages/libvirt-guests.rst +@@ -0,0 +1,151 @@ ++============== ++libvirt-guests ++============== ++ ++------------------------------------- ++suspend/resume running libvirt guests ++------------------------------------- ++ ++:Manual section: 8 ++:Manual group: Virtualization Support ++ ++.. contents:: ++ ++SYNOPSIS ++======== ++ ++``libvirt-guests`` *COMMAND* ++ ++ ++DESCRIPTION ++=========== ++ ++``libvirt-guests`` is a service that can be used to coordinate guest and host ++lifecyle actions. By default, ``libvirt-guests`` will suspend running guests ++when the host shuts down, and restore them to their pre-shutdown state when ++the host reboots. ++ ++``libvirt-guests`` is typically under control of systemd. When ++``libvirt-guests.service`` is enabled, systemd will call ``libvirt-guests`` ++with the ``start`` *COMMAND* when the host boots. Conversely, systemd will call ++``libvirt-guests`` with the ``stop`` *COMMAND* when the host shuts down. ++ ++``libvirt-guests`` can be used directly. In addition to the ``start`` and ++``stop`` *COMMAND*\s, it also supports ``status``, ``restart``, ``condrestart``, ++``try-restart``, ``reload``, ``force-reload``, ``gueststatus``, and ++``shutdown`` *COMMAND*\s. ++ ++ ++FILES ++===== ++ ++``libvirt-guests`` defines several variables to control service behavior. ++The default vaule of these variables can be overridden in: ++ ++* ``@SYSCONFDIR@/sysconfig/libvirt-guests`` ++ ++The following variables are supported: ++ ++- URIS=default ++ ++ URIs to check for running guests. Example: ++ ``URIS='default xen:///system xen+tcp://host/system lxc:///system'`` ++ ++- ON_BOOT=start ++ ++ Action taken on host boot ++ ++ * start ++ ++ All guests which were running on shutdown are started on boot regardless ++ of their autostart settings ++ ++ * ignore ++ ++ ``libvirt-guests`` won't start any guest on boot, however, guests marked ++ as autostart will still be automatically started by libvirtd ++ ++- START_DELAY=0 ++ ++ Number of seconds to wait between each guest start. Set to 0 to allow parallel ++ startup. ++ ++- ON_SHUTDOWN=suspend ++ ++ Action taken on host shutdown ++ ++ * suspend ++ ++ All running guests are suspended using virsh managedsave ++ ++ * shutdown ++ ++ All running guests are asked to shutdown. Please be careful with this ++ settings since there is no way to distinguish between a guest which is ++ stuck or ignores shutdown requests and a guest which just needs a long ++ time to shutdown. When setting ON_SHUTDOWN=shutdown, you must also set ++ SHUTDOWN_TIMEOUT to a value suitable for your guests. ++ ++- PARALLEL_SHUTDOWN=0 ++ ++ Number of guests will be shutdown concurrently, taking effect when ++ "ON_SHUTDOWN" is set to "shutdown". If Set to 0, guests will be shutdown one ++ after another. Number of guests on shutdown at any time will not exceed number ++ set in this variable. ++ ++- SHUTDOWN_TIMEOUT=300 ++ ++ Number of seconds we're willing to wait for a guest to shut down. If parallel ++ shutdown is enabled, this timeout applies as a timeout for shutting down all ++ guests on a single URI defined in the variable URIS. If this is 0, then there ++ is no time out (use with caution, as guests might not respond to a shutdown ++ request). The default value is 300 seconds (5 minutes). ++ ++- BYPASS_CACHE=0 ++ ++ If non-zero, try to bypass the file system cache when saving and ++ restoring guests, even though this may give slower operation for ++ some file systems. ++ ++- SYNC_TIME=0 ++ ++ If non-zero, try to sync guest time on domain resume. Be aware, that ++ this requires guest agent with support for time synchronization ++ running in the guest. By default, this functionality is turned off. ++ ++ ++BUGS ++==== ++ ++Please report all bugs you discover. This should be done via either: ++ ++#. the mailing list ++ ++ `https://libvirt.org/contact.html `_ ++ ++#. the bug tracker ++ ++ `https://libvirt.org/bugs.html `_ ++ ++Alternatively, you may report bugs to your software distributor / vendor. ++ ++ ++AUTHORS ++======= ++ ++Please refer to the AUTHORS file distributed with libvirt. ++ ++ ++LICENSE ++======= ++ ++``libvirt-guests`` is distributed under the terms of the GNU LGPL v2.1+. ++This is free software; see the source for copying conditions. There ++is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR ++PURPOSE ++ ++ ++SEE ALSO ++======== ++ ++libvirtd(8), `https://libvirt.org/ `_ +diff --git a/docs/manpages/meson.build b/docs/manpages/meson.build +index 150f45d296..bad9b62a2e 100644 +--- a/docs/manpages/meson.build ++++ b/docs/manpages/meson.build +@@ -21,6 +21,7 @@ docs_man_files = [ + { 'name': 'virt-qemu-run', 'section': '1', 'install': conf.has('WITH_QEMU') }, + { 'name': 'virt-xml-validate', 'section': '1', 'install': true }, + ++ { 'name': 'libvirt-guests', 'section': '8', 'install': conf.has('WITH_LIBVIRTD') }, + { 'name': 'libvirtd', 'section': '8', 'install': conf.has('WITH_LIBVIRTD') }, + { 'name': 'virt-sanlock-cleanup', 'section': '8', 'install': conf.has('WITH_SANLOCK') }, + { 'name': 'virt-ssh-helper', 'section': '8', 'install': conf.has('WITH_LIBVIRTD') }, +diff --git a/tools/libvirt-guests.service.in b/tools/libvirt-guests.service.in +index 10c664016a..1a9b233e11 100644 +--- a/tools/libvirt-guests.service.in ++++ b/tools/libvirt-guests.service.in +@@ -6,7 +6,7 @@ After=network.target + After=time-sync.target + After=libvirtd.service + After=virt-guest-shutdown.target +-Documentation=man:libvirtd(8) ++Documentation=man:libvirt-guests(8) + Documentation=https://libvirt.org + + [Service] +-- +2.35.0 + diff --git a/SOURCES/libvirt-nwfilter-hold-filter-update-lock-when-creating-deleting-bindings.patch b/SOURCES/libvirt-nwfilter-hold-filter-update-lock-when-creating-deleting-bindings.patch new file mode 100644 index 0000000..d9f6fab --- /dev/null +++ b/SOURCES/libvirt-nwfilter-hold-filter-update-lock-when-creating-deleting-bindings.patch @@ -0,0 +1,77 @@ +From bbab997f4307da65856dedd3f319037ce442d17e Mon Sep 17 00:00:00 2001 +Message-Id: +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Thu, 24 Feb 2022 18:41:29 +0000 +Subject: [PATCH] nwfilter: hold filter update lock when creating/deleting + bindings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The nwfilter update lock is historically acquired by the virt +drivers in order to achieve serialization between nwfilter +define/undefine, and instantiation/teardown of filters. + +When running in the modular daemons, however, the mutex that +the virt drivers are locking is in a completely different +process from the mutex that the nwfilter driver is locking. + +Serialization is lost and thus call from the virt driver to +virNWFilterBindingCreateXML can deadlock with a concurrent +call to the virNWFilterDefineXML method. + +The solution is surprisingly easy, the update lock simply +needs acquiring in the virNWFilterBindingCreateXML method +and virNWFilterBindingUndefine method instead of in the +virt drivers. + +The only semantic difference here is that when a virtual +machine has multiple NICs, the instantiation and teardown +of filters is no longer serialized for the whole VM, but +rather for each NIC. This should not be a problem since +the virt drivers already need to cope with tearing down +a partially created VM where only some of the NICs are +setup. + +Reviewed-by: Laine Stump +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 65dc79f50b96b34b2253601b8972d5ca90658f33) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2044379 +Signed-off-by: Michal Privoznik +--- + src/nwfilter/nwfilter_driver.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c +index 200451d6b1..a4479fc9fe 100644 +--- a/src/nwfilter/nwfilter_driver.c ++++ b/src/nwfilter/nwfilter_driver.c +@@ -760,12 +760,15 @@ nwfilterBindingCreateXML(virConnectPtr conn, + if (!(ret = virGetNWFilterBinding(conn, def->portdevname, def->filter))) + goto cleanup; + ++ virNWFilterReadLockFilterUpdates(); + if (virNWFilterInstantiateFilter(driver, def) < 0) { ++ virNWFilterUnlockFilterUpdates(); + virNWFilterBindingObjListRemove(driver->bindings, obj); + virObjectUnref(ret); + ret = NULL; + goto cleanup; + } ++ virNWFilterUnlockFilterUpdates(); + virNWFilterBindingObjSave(obj, driver->bindingDir); + + cleanup: +@@ -802,7 +805,9 @@ nwfilterBindingDelete(virNWFilterBindingPtr binding) + if (virNWFilterBindingDeleteEnsureACL(binding->conn, def) < 0) + goto cleanup; + ++ virNWFilterReadLockFilterUpdates(); + virNWFilterTeardownFilter(def); ++ virNWFilterUnlockFilterUpdates(); + virNWFilterBindingObjDelete(obj, driver->bindingDir); + virNWFilterBindingObjListRemove(driver->bindings, obj); + +-- +2.35.1 + diff --git a/SOURCES/libvirt-qemu-Validate-domain-definition-even-on-migration.patch b/SOURCES/libvirt-qemu-Validate-domain-definition-even-on-migration.patch new file mode 100644 index 0000000..a20b9bc --- /dev/null +++ b/SOURCES/libvirt-qemu-Validate-domain-definition-even-on-migration.patch @@ -0,0 +1,71 @@ +From 84cedeca547585a51f6044186d241a501ff757d2 Mon Sep 17 00:00:00 2001 +Message-Id: <84cedeca547585a51f6044186d241a501ff757d2@dist-git> +From: Michal Privoznik +Date: Mon, 31 Jan 2022 12:55:47 +0100 +Subject: [PATCH] qemu: Validate domain definition even on migration + +When we are about to spawn QEMU, we validate the domain +definition against qemuCaps. Except when domain is/was already +running before (i.e. on incoming migration, snapshots, resume +from a file). However, especially on incoming migration it may +happen that the destination QEMU is different to the source +QEMU, e.g. the destination QEMU may have some devices disabled. + +And we have a function that validates devices/features requested +in domain XML against the desired QEMU capabilities (aka +qemuCaps) - it's virDomainDefValidate() which calls +qemuValidateDomainDef() and qemuValidateDomainDeviceDef() +subsequently. + +But the problem here is that the validation function is +explicitly skipped over in specific scenarios (like incoming +migration, restore from a snapshot or previously saved file). + +This in turn means that we may spawn QEMU and request +device/features it doesn't support. When that happens QEMU fails +to load migration stream: + + qemu-kvm: ... 'virtio-mem-pci' is not a valid device model name + +(NB, while the example shows one particular device, the problem +is paramount) + +This problem is easier to run into since we are slowly moving +validation from qemu_command.c into said validation functions. + +The solution is simple: do the validation in all cases. And while +it may happen that users would be unable to migrate/restore a +guest due to a bug in our validator, spawning QEMU without +validation is worse (especially when you consider that users can +supply their own XMLs for migrate/restore operations - these were +never validated). + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2048435 +Signed-off-by: Michal Privoznik +Reviewed-by: Peter Krempa +(cherry picked from commit 517b8c12b98d7ac0bb4d582e0b491d50d776eb6d) +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 5c9ca0fe4f..5c6657a876 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -5411,11 +5411,7 @@ qemuProcessStartValidate(virQEMUDriver *driver, + + } + +- /* Checks below should not be executed when starting a qemu process for a +- * VM that was running before (migration, snapshots, save). It's more +- * important to start such VM than keep the configuration clean */ +- if ((flags & VIR_QEMU_PROCESS_START_NEW) && +- virDomainDefValidate(vm->def, 0, driver->xmlopt, qemuCaps) < 0) ++ if (virDomainDefValidate(vm->def, 0, driver->xmlopt, qemuCaps) < 0) + return -1; + + if (qemuProcessStartValidateGraphics(vm) < 0) +-- +2.35.1 + diff --git a/SOURCES/libvirt-qemu-fix-hotplug-for-multiqueue-vdpa-net-device.patch b/SOURCES/libvirt-qemu-fix-hotplug-for-multiqueue-vdpa-net-device.patch new file mode 100644 index 0000000..50000ad --- /dev/null +++ b/SOURCES/libvirt-qemu-fix-hotplug-for-multiqueue-vdpa-net-device.patch @@ -0,0 +1,90 @@ +From 68b294cf8e9c5e0f0f14b14e63178b2bf7a9f7e2 Mon Sep 17 00:00:00 2001 +Message-Id: <68b294cf8e9c5e0f0f14b14e63178b2bf7a9f7e2@dist-git> +From: Jonathon Jongsma +Date: Tue, 29 Mar 2022 14:24:36 -0500 +Subject: [PATCH] qemu: fix hotplug for multiqueue vdpa net device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While commit a5e659f0 removed the restriction against multiple queues +for the vdpa net device, there were some missing pieces. Configuring a +device statically and then starting the domain worked as expected, but +hotplugging a device didn't have the expected multiqueue support +enabled. Add the missing bits. + +Consider the following device xml: + + + + + + + +Without this patch, hotplugging the above XML description resulted in +the following: + {"execute":"netdev_add","arguments":{"type":"vhost-vdpa","vhostdev":"/dev/fdset/0","id":"hostnet1"},"id":"libvirt-392"} + {"execute":"device_add","arguments":{"driver":"virtio-net-pci","netdev":"hostnet1","id":"net1","mac":"00:11:22:33:44:03","bus":"pci.5","addr":"0x0"},"id":"libvirt-393"} + +With the patch, hotplugging results in the following: + {"execute":"netdev_add","arguments":{"type":"vhost-vdpa","vhostdev":"/dev/fdset/0","queues":2,"id":"hostnet1"},"id":"libvirt-392"} + {"execute":"device_add","arguments":{"driver":"virtio-net-pci","mq":true,"vectors":6,"netdev":"hostnet1","id":"net1","mac":"00:11:22:33:44:03","bus":"pci.5","addr":"0x0"},"id":"libvirt-393"} + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2024406 + +Signed-off-by: Jonathon Jongsma +Reviewed-by: Ján Tomko + +(cherry picked from commit 3832db21084661d00438dfbb4bad865816157dd9) +Signed-off-by: Jonathon Jongsma +--- + src/qemu/qemu_command.c | 4 ++++ + src/qemu/qemu_hotplug.c | 3 +++ + tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args | 2 +- + 3 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index 509bab08ef..ee0e611513 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -4349,6 +4349,10 @@ qemuBuildHostNetProps(virDomainNetDef *net, + if (virJSONValueObjectAdd(&netprops, "s:type", "vhost-vdpa", NULL) < 0 || + virJSONValueObjectAppendString(netprops, "vhostdev", vdpadev) < 0) + return NULL; ++ ++ if (net->driver.virtio.queues > 1 && ++ virJSONValueObjectAppendNumberUlong(netprops, "queues", net->driver.virtio.queues) < 0) ++ return NULL; + break; + + case VIR_DOMAIN_NET_TYPE_HOSTDEV: +diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c +index 04c6600f26..c10493e212 100644 +--- a/src/qemu/qemu_hotplug.c ++++ b/src/qemu/qemu_hotplug.c +@@ -1364,6 +1364,9 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver, + break; + + case VIR_DOMAIN_NET_TYPE_VDPA: ++ queueSize = net->driver.virtio.queues; ++ if (!queueSize) ++ queueSize = 1; + if (qemuDomainAdjustMaxMemLock(vm, false) < 0) + goto cleanup; + adjustmemlock = true; +diff --git a/tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args b/tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args +index 61ba85a847..3e45ab6870 100644 +--- a/tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args ++++ b/tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args +@@ -29,7 +29,7 @@ XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ + -boot strict=on \ + -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 \ + -add-fd set=0,fd=1732,opaque=/dev/vhost-vdpa-0 \ +--netdev vhost-vdpa,vhostdev=/dev/fdset/0,id=hostnet0 \ ++-netdev vhost-vdpa,vhostdev=/dev/fdset/0,queues=2,id=hostnet0 \ + -device virtio-net-pci,mq=on,vectors=6,netdev=hostnet0,id=net0,mac=52:54:00:95:db:c0,bus=pci.0,addr=0x2 \ + -audiodev '{"id":"audio1","driver":"none"}' \ + -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-- +2.35.1 + diff --git a/SOURCES/libvirt-qemu-fix-inactive-snapshot-revert.patch b/SOURCES/libvirt-qemu-fix-inactive-snapshot-revert.patch new file mode 100644 index 0000000..ae4c4cf --- /dev/null +++ b/SOURCES/libvirt-qemu-fix-inactive-snapshot-revert.patch @@ -0,0 +1,41 @@ +From 1911ebd62779701aae271dd3e047415bfd2cd303 Mon Sep 17 00:00:00 2001 +Message-Id: <1911ebd62779701aae271dd3e047415bfd2cd303@dist-git> +From: =?UTF-8?q?J=C3=A1n=20Tomko?= +Date: Thu, 20 Jan 2022 14:53:33 +0100 +Subject: [PATCH] qemu: fix inactive snapshot revert +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The commit splitting out the qemuSnapshotRevertInactive function +dropped the 'defined = true' line by accident and instead +returned -1, leaving the user with a cryptic error: +error: An error occurred, but the cause is unknown + +https://bugzilla.redhat.com/show_bug.cgi?id=2039136 +https://gitlab.com/libvirt/libvirt/-/issues/266 + +Fixes: 85e4a13c3f19078fb6af5ffb4a80022c142cbc7e +Signed-off-by: Ján Tomko +(cherry picked from commit 76deb656132bb8817ddae4b7f417930c4db824c9) +Signed-off-by: Ján Tomko +--- + src/qemu/qemu_snapshot.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c +index f92e00f9c0..ac7bab90f8 100644 +--- a/src/qemu/qemu_snapshot.c ++++ b/src/qemu/qemu_snapshot.c +@@ -2193,7 +2193,7 @@ qemuSnapshotRevertInactive(virDomainObj *vm, + + if (*inactiveConfig) { + virDomainObjAssignDef(vm, inactiveConfig, false, NULL); +- return -1; ++ defined = true; + } + + if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING | +-- +2.35.0 + diff --git a/SOURCES/libvirt-qemu-lxc-remove-use-to-nwfilter-update-lock.patch b/SOURCES/libvirt-qemu-lxc-remove-use-to-nwfilter-update-lock.patch new file mode 100644 index 0000000..6699b1c --- /dev/null +++ b/SOURCES/libvirt-qemu-lxc-remove-use-to-nwfilter-update-lock.patch @@ -0,0 +1,222 @@ +From 7bcd75ca73d8eda05fafa8342309a8fd058cd326 Mon Sep 17 00:00:00 2001 +Message-Id: <7bcd75ca73d8eda05fafa8342309a8fd058cd326@dist-git> +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Thu, 24 Feb 2022 19:02:32 +0000 +Subject: [PATCH] qemu,lxc: remove use to nwfilter update lock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now that the virNWFilterBinding APIs are using the nwfilter +update lock directly, there is no need for the virt drivers +to do it themselves. + +Reviewed-by: Laine Stump +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 5f8b090f421cd6a6c46f44905431491e2d3cf8f5) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2044379 +Signed-off-by: Michal Privoznik +--- + src/lxc/lxc_driver.c | 6 ------ + src/qemu/qemu_driver.c | 18 ------------------ + src/qemu/qemu_migration.c | 3 --- + src/qemu/qemu_process.c | 4 ---- + 4 files changed, 31 deletions(-) + +diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c +index 7bc39120ee..e581c62668 100644 +--- a/src/lxc/lxc_driver.c ++++ b/src/lxc/lxc_driver.c +@@ -971,8 +971,6 @@ static int lxcDomainCreateWithFiles(virDomainPtr dom, + + virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1); + +- virNWFilterReadLockFilterUpdates(); +- + if (!(vm = lxcDomObjFromDomain(dom))) + goto cleanup; + +@@ -1014,7 +1012,6 @@ static int lxcDomainCreateWithFiles(virDomainPtr dom, + cleanup: + virDomainObjEndAPI(&vm); + virObjectEventStateQueue(driver->domainEventState, event); +- virNWFilterUnlockFilterUpdates(); + return ret; + } + +@@ -1080,8 +1077,6 @@ lxcDomainCreateXMLWithFiles(virConnectPtr conn, + if (flags & VIR_DOMAIN_START_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + +- virNWFilterReadLockFilterUpdates(); +- + if (!(caps = virLXCDriverGetCapabilities(driver, false))) + goto cleanup; + +@@ -1138,7 +1133,6 @@ lxcDomainCreateXMLWithFiles(virConnectPtr conn, + cleanup: + virDomainObjEndAPI(&vm); + virObjectEventStateQueue(driver->domainEventState, event); +- virNWFilterUnlockFilterUpdates(); + return dom; + } + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index d3d76c003f..00a86b6c7c 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -1603,8 +1603,6 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, + if (flags & VIR_DOMAIN_START_AUTODESTROY) + start_flags |= VIR_QEMU_PROCESS_START_AUTODESTROY; + +- virNWFilterReadLockFilterUpdates(); +- + if (!(def = virDomainDefParseString(xml, driver->xmlopt, + NULL, parse_flags))) + goto cleanup; +@@ -1658,7 +1656,6 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, + virDomainObjEndAPI(&vm); + virObjectEventStateQueue(driver->domainEventState, event); + virObjectEventStateQueue(driver->domainEventState, event2); +- virNWFilterUnlockFilterUpdates(); + return dom; + } + +@@ -5773,8 +5770,6 @@ qemuDomainRestoreFlags(virConnectPtr conn, + VIR_DOMAIN_SAVE_PAUSED, -1); + + +- virNWFilterReadLockFilterUpdates(); +- + fd = qemuSaveImageOpen(driver, NULL, path, &def, &data, + (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0, + &wrapperFd, false, false); +@@ -5846,7 +5841,6 @@ qemuDomainRestoreFlags(virConnectPtr conn, + if (vm && ret < 0) + qemuDomainRemoveInactiveJob(driver, vm); + virDomainObjEndAPI(&vm); +- virNWFilterUnlockFilterUpdates(); + return ret; + } + +@@ -6395,8 +6389,6 @@ qemuDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) + VIR_DOMAIN_START_BYPASS_CACHE | + VIR_DOMAIN_START_FORCE_BOOT, -1); + +- virNWFilterReadLockFilterUpdates(); +- + if (!(vm = qemuDomainObjFromDomain(dom))) + goto cleanup; + +@@ -6425,7 +6417,6 @@ qemuDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) + + cleanup: + virDomainObjEndAPI(&vm); +- virNWFilterUnlockFilterUpdates(); + return ret; + } + +@@ -7811,8 +7802,6 @@ qemuDomainAttachDeviceFlags(virDomainPtr dom, + virDomainObj *vm = NULL; + int ret = -1; + +- virNWFilterReadLockFilterUpdates(); +- + if (!(vm = qemuDomainObjFromDomain(dom))) + goto cleanup; + +@@ -7835,7 +7824,6 @@ qemuDomainAttachDeviceFlags(virDomainPtr dom, + + cleanup: + virDomainObjEndAPI(&vm); +- virNWFilterUnlockFilterUpdates(); + return ret; + } + +@@ -7865,8 +7853,6 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, + VIR_DOMAIN_AFFECT_CONFIG | + VIR_DOMAIN_DEVICE_MODIFY_FORCE, -1); + +- virNWFilterReadLockFilterUpdates(); +- + cfg = virQEMUDriverGetConfig(driver); + + if (!(vm = qemuDomainObjFromDomain(dom))) +@@ -7943,7 +7929,6 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, + if (dev != dev_copy) + virDomainDeviceDefFree(dev_copy); + virDomainObjEndAPI(&vm); +- virNWFilterUnlockFilterUpdates(); + return ret; + } + +@@ -13644,8 +13629,6 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, + virDomainObj *vm = NULL; + int ret = -1; + +- virNWFilterReadLockFilterUpdates(); +- + if (!(vm = qemuDomObjFromSnapshot(snapshot))) + goto cleanup; + +@@ -13656,7 +13639,6 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, + + cleanup: + virDomainObjEndAPI(&vm); +- virNWFilterUnlockFilterUpdates(); + return ret; + } + +diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c +index 2635ef1162..358cb9c3b5 100644 +--- a/src/qemu/qemu_migration.c ++++ b/src/qemu/qemu_migration.c +@@ -2779,8 +2779,6 @@ qemuMigrationDstPrepareAny(virQEMUDriver *driver, + int rv; + g_autofree char *tlsAlias = NULL; + +- virNWFilterReadLockFilterUpdates(); +- + if (flags & VIR_MIGRATE_OFFLINE) { + if (flags & (VIR_MIGRATE_NON_SHARED_DISK | + VIR_MIGRATE_NON_SHARED_INC)) { +@@ -3101,7 +3099,6 @@ qemuMigrationDstPrepareAny(virQEMUDriver *driver, + virDomainObjEndAPI(&vm); + virObjectEventStateQueue(driver->domainEventState, event); + qemuMigrationCookieFree(mig); +- virNWFilterUnlockFilterUpdates(); + virErrorRestore(&origErr); + return ret; + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 5c6657a876..914f9bef8b 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -8986,7 +8986,6 @@ qemuProcessReconnect(void *opaque) + qemuDomainRemoveInactiveJob(driver, obj); + } + virDomainObjEndAPI(&obj); +- virNWFilterUnlockFilterUpdates(); + virIdentitySetCurrent(NULL); + return; + +@@ -9038,8 +9037,6 @@ qemuProcessReconnectHelper(virDomainObj *obj, + data->obj = obj; + data->identity = virIdentityGetCurrent(); + +- virNWFilterReadLockFilterUpdates(); +- + /* this lock and reference will be eventually transferred to the thread + * that handles the reconnect */ + virObjectLock(obj); +@@ -9062,7 +9059,6 @@ qemuProcessReconnectHelper(virDomainObj *obj, + qemuDomainRemoveInactiveJobLocked(src->driver, obj); + + virDomainObjEndAPI(&obj); +- virNWFilterUnlockFilterUpdates(); + g_clear_object(&data->identity); + VIR_FREE(data); + return -1; +-- +2.35.1 + diff --git a/SOURCES/libvirt-qemu-support-firmware-descriptor-flash-mode-for-optional-NVRAM.patch b/SOURCES/libvirt-qemu-support-firmware-descriptor-flash-mode-for-optional-NVRAM.patch new file mode 100644 index 0000000..822b859 --- /dev/null +++ b/SOURCES/libvirt-qemu-support-firmware-descriptor-flash-mode-for-optional-NVRAM.patch @@ -0,0 +1,471 @@ +From 3cde498c98be902fc8fe87c895dfeaaa95352b38 Mon Sep 17 00:00:00 2001 +Message-Id: <3cde498c98be902fc8fe87c895dfeaaa95352b38@dist-git> +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Thu, 3 Feb 2022 13:43:18 +0000 +Subject: [PATCH] qemu: support firmware descriptor flash 'mode' for optional + NVRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently the 'nvram_template' entry is mandatory when parsing the +firmware descriptor based on flash. QEMU is extending the firmware +descriptor spec to make the 'nvram_template' optional, depending +on the value of a new 'mode' field: + + - "split" + * "executable" contains read-only CODE + * "nvram_template" contains read-write VARS + + - "combined" + * "executable" contains read-write CODE and VARs + * "nvram_template" not present + + - "stateless" + * "executable" contains read-only CODE and VARs + * "nvram_template" not present + +In the latter case, the guest OS can write vars but the +firmware will make no attempt to persist them, so any changes +will be lost at poweroff. + +For now we parse this new 'mode' but discard any firmware +which is not 'mode=split' when matching for a domain. + +In the tests we have a mixture of files with and without the +mode attribute. + +Reviewed-by: Michal Privoznik +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 32b9d8b0ae00669555f01f91ee11612a636c4b69) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2057769 +--- + src/qemu/qemu_firmware.c | 79 ++++++++++++++++--- + .../share/qemu/firmware/50-ovmf-sb-keys.json | 33 ++++++++ + .../out/usr/share/qemu/firmware/61-ovmf.json | 31 ++++++++ + .../out/usr/share/qemu/firmware/70-aavmf.json | 28 +++++++ + .../qemu/firmware/45-ovmf-sev-stateless.json | 31 ++++++++ + .../qemu/firmware/55-ovmf-sb-combined.json | 33 ++++++++ + .../usr/share/qemu/firmware/60-ovmf-sb.json | 1 + + tests/qemufirmwaretest.c | 31 ++++++-- + 8 files changed, 246 insertions(+), 21 deletions(-) + create mode 100644 tests/qemufirmwaredata/out/usr/share/qemu/firmware/50-ovmf-sb-keys.json + create mode 100644 tests/qemufirmwaredata/out/usr/share/qemu/firmware/61-ovmf.json + create mode 100644 tests/qemufirmwaredata/out/usr/share/qemu/firmware/70-aavmf.json + create mode 100644 tests/qemufirmwaredata/usr/share/qemu/firmware/45-ovmf-sev-stateless.json + create mode 100644 tests/qemufirmwaredata/usr/share/qemu/firmware/55-ovmf-sb-combined.json + +diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c +index 529ab8d68e..7911d45aa0 100644 +--- a/src/qemu/qemu_firmware.c ++++ b/src/qemu/qemu_firmware.c +@@ -59,6 +59,22 @@ VIR_ENUM_IMPL(qemuFirmwareOSInterface, + ); + + ++typedef enum { ++ QEMU_FIRMWARE_FLASH_MODE_SPLIT, ++ QEMU_FIRMWARE_FLASH_MODE_COMBINED, ++ QEMU_FIRMWARE_FLASH_MODE_STATELESS, ++ ++ QEMU_FIRMWARE_FLASH_MODE_LAST, ++} qemuFirmwareFlashMode; ++ ++VIR_ENUM_DECL(qemuFirmwareFlashMode); ++VIR_ENUM_IMPL(qemuFirmwareFlashMode, ++ QEMU_FIRMWARE_FLASH_MODE_LAST, ++ "split", ++ "combined", ++ "stateless", ++); ++ + typedef struct _qemuFirmwareFlashFile qemuFirmwareFlashFile; + struct _qemuFirmwareFlashFile { + char *filename; +@@ -68,6 +84,7 @@ struct _qemuFirmwareFlashFile { + + typedef struct _qemuFirmwareMappingFlash qemuFirmwareMappingFlash; + struct _qemuFirmwareMappingFlash { ++ qemuFirmwareFlashMode mode; + qemuFirmwareFlashFile executable; + qemuFirmwareFlashFile nvram_template; + }; +@@ -359,9 +376,31 @@ qemuFirmwareMappingFlashParse(const char *path, + virJSONValue *doc, + qemuFirmwareMappingFlash *flash) + { ++ virJSONValue *mode; + virJSONValue *executable; + virJSONValue *nvram_template; + ++ if (!(mode = virJSONValueObjectGet(doc, "mode"))) { ++ /* Historical default */ ++ flash->mode = QEMU_FIRMWARE_FLASH_MODE_SPLIT; ++ } else { ++ const char *modestr = virJSONValueGetString(mode); ++ int modeval; ++ if (!modestr) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("Firmware flash mode value was malformed")); ++ return -1; ++ } ++ modeval = qemuFirmwareFlashModeTypeFromString(modestr); ++ if (modeval < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Firmware flash mode value '%s' unexpected"), ++ modestr); ++ return -1; ++ } ++ flash->mode = modeval; ++ } ++ + if (!(executable = virJSONValueObjectGet(doc, "executable"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("missing 'executable' in '%s'"), +@@ -372,15 +411,17 @@ qemuFirmwareMappingFlashParse(const char *path, + if (qemuFirmwareFlashFileParse(path, executable, &flash->executable) < 0) + return -1; + +- if (!(nvram_template = virJSONValueObjectGet(doc, "nvram-template"))) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("missing 'nvram-template' in '%s'"), +- path); +- return -1; +- } ++ if (flash->mode == QEMU_FIRMWARE_FLASH_MODE_SPLIT) { ++ if (!(nvram_template = virJSONValueObjectGet(doc, "nvram-template"))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("missing 'nvram-template' in '%s'"), ++ path); ++ return -1; ++ } + +- if (qemuFirmwareFlashFileParse(path, nvram_template, &flash->nvram_template) < 0) +- return -1; ++ if (qemuFirmwareFlashFileParse(path, nvram_template, &flash->nvram_template) < 0) ++ return -1; ++ } + + return 0; + } +@@ -693,10 +734,12 @@ qemuFirmwareMappingFlashFormat(virJSONValue *mapping, + g_autoptr(virJSONValue) executable = NULL; + g_autoptr(virJSONValue) nvram_template = NULL; + +- if (!(executable = qemuFirmwareFlashFileFormat(flash->executable))) ++ if (virJSONValueObjectAppendString(mapping, ++ "mode", ++ qemuFirmwareFlashModeTypeToString(flash->mode)) < 0) + return -1; + +- if (!(nvram_template = qemuFirmwareFlashFileFormat(flash->nvram_template))) ++ if (!(executable = qemuFirmwareFlashFileFormat(flash->executable))) + return -1; + + if (virJSONValueObjectAppend(mapping, +@@ -704,11 +747,15 @@ qemuFirmwareMappingFlashFormat(virJSONValue *mapping, + &executable) < 0) + return -1; + ++ if (flash->mode == QEMU_FIRMWARE_FLASH_MODE_SPLIT) { ++ if (!(nvram_template = qemuFirmwareFlashFileFormat(flash->nvram_template))) ++ return -1; + +- if (virJSONValueObjectAppend(mapping, ++ if (virJSONValueObjectAppend(mapping, + "nvram-template", +- &nvram_template) < 0) +- return -1; ++ &nvram_template) < 0) ++ return -1; ++ } + + return 0; + } +@@ -1053,6 +1100,12 @@ qemuFirmwareMatchDomain(const virDomainDef *def, + return false; + } + ++ if (fw->mapping.device == QEMU_FIRMWARE_DEVICE_FLASH && ++ fw->mapping.data.flash.mode != QEMU_FIRMWARE_FLASH_MODE_SPLIT) { ++ VIR_DEBUG("Discarding loader without split flash"); ++ return false; ++ } ++ + if (def->sec) { + switch ((virDomainLaunchSecurity) def->sec->sectype) { + case VIR_DOMAIN_LAUNCH_SECURITY_SEV: +diff --git a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/50-ovmf-sb-keys.json b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/50-ovmf-sb-keys.json +new file mode 100644 +index 0000000000..c251682cd9 +--- /dev/null ++++ b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/50-ovmf-sb-keys.json +@@ -0,0 +1,33 @@ ++{ ++ "interface-types": [ ++ "uefi" ++ ], ++ "mapping": { ++ "device": "flash", ++ "mode": "split", ++ "executable": { ++ "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd", ++ "format": "raw" ++ }, ++ "nvram-template": { ++ "filename": "/usr/share/OVMF/OVMF_VARS.secboot.fd", ++ "format": "raw" ++ } ++ }, ++ "targets": [ ++ { ++ "architecture": "x86_64", ++ "machines": [ ++ "pc-q35-*" ++ ] ++ } ++ ], ++ "features": [ ++ "acpi-s3", ++ "amd-sev", ++ "enrolled-keys", ++ "requires-smm", ++ "secure-boot", ++ "verbose-dynamic" ++ ] ++} +diff --git a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/61-ovmf.json b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/61-ovmf.json +new file mode 100644 +index 0000000000..2a9aa23efb +--- /dev/null ++++ b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/61-ovmf.json +@@ -0,0 +1,31 @@ ++{ ++ "interface-types": [ ++ "uefi" ++ ], ++ "mapping": { ++ "device": "flash", ++ "mode": "split", ++ "executable": { ++ "filename": "/usr/share/OVMF/OVMF_CODE.fd", ++ "format": "raw" ++ }, ++ "nvram-template": { ++ "filename": "/usr/share/OVMF/OVMF_VARS.fd", ++ "format": "raw" ++ } ++ }, ++ "targets": [ ++ { ++ "architecture": "x86_64", ++ "machines": [ ++ "pc-i440fx-*", ++ "pc-q35-*" ++ ] ++ } ++ ], ++ "features": [ ++ "acpi-s3", ++ "amd-sev", ++ "verbose-dynamic" ++ ] ++} +diff --git a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/70-aavmf.json b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/70-aavmf.json +new file mode 100644 +index 0000000000..9bd5ac2868 +--- /dev/null ++++ b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/70-aavmf.json +@@ -0,0 +1,28 @@ ++{ ++ "interface-types": [ ++ "uefi" ++ ], ++ "mapping": { ++ "device": "flash", ++ "mode": "split", ++ "executable": { ++ "filename": "/usr/share/AAVMF/AAVMF_CODE.fd", ++ "format": "raw" ++ }, ++ "nvram-template": { ++ "filename": "/usr/share/AAVMF/AAVMF_VARS.fd", ++ "format": "raw" ++ } ++ }, ++ "targets": [ ++ { ++ "architecture": "aarch64", ++ "machines": [ ++ "virt-*" ++ ] ++ } ++ ], ++ "features": [ ++ ++ ] ++} +diff --git a/tests/qemufirmwaredata/usr/share/qemu/firmware/45-ovmf-sev-stateless.json b/tests/qemufirmwaredata/usr/share/qemu/firmware/45-ovmf-sev-stateless.json +new file mode 100644 +index 0000000000..5a619f3ab0 +--- /dev/null ++++ b/tests/qemufirmwaredata/usr/share/qemu/firmware/45-ovmf-sev-stateless.json +@@ -0,0 +1,31 @@ ++{ ++ "description": "OVMF for x86_64, with SEV, without SB, without SMM, with NO varstore", ++ "interface-types": [ ++ "uefi" ++ ], ++ "mapping": { ++ "device": "flash", ++ "mode": "stateless", ++ "executable": { ++ "filename": "/usr/share/OVMF/OVMF.sev.fd", ++ "format": "raw" ++ } ++ }, ++ "targets": [ ++ { ++ "architecture": "x86_64", ++ "machines": [ ++ "pc-q35-*" ++ ] ++ } ++ ], ++ "features": [ ++ "acpi-s3", ++ "amd-sev", ++ "amd-sev-es", ++ "verbose-dynamic" ++ ], ++ "tags": [ ++ ++ ] ++} +diff --git a/tests/qemufirmwaredata/usr/share/qemu/firmware/55-ovmf-sb-combined.json b/tests/qemufirmwaredata/usr/share/qemu/firmware/55-ovmf-sb-combined.json +new file mode 100644 +index 0000000000..eb3332e4ab +--- /dev/null ++++ b/tests/qemufirmwaredata/usr/share/qemu/firmware/55-ovmf-sb-combined.json +@@ -0,0 +1,33 @@ ++{ ++ "description": "OVMF with SB+SMM, SB enabled, MS certs enrolled", ++ "interface-types": [ ++ "uefi" ++ ], ++ "mapping": { ++ "device": "flash", ++ "mode": "combined", ++ "executable": { ++ "filename": "/usr/share/OVMF/OVMF.secboot.fd", ++ "format": "raw" ++ } ++ }, ++ "targets": [ ++ { ++ "architecture": "x86_64", ++ "machines": [ ++ "pc-q35-*" ++ ] ++ } ++ ], ++ "features": [ ++ "acpi-s3", ++ "amd-sev", ++ "enrolled-keys", ++ "requires-smm", ++ "secure-boot", ++ "verbose-dynamic" ++ ], ++ "tags": [ ++ ++ ] ++} +diff --git a/tests/qemufirmwaredata/usr/share/qemu/firmware/60-ovmf-sb.json b/tests/qemufirmwaredata/usr/share/qemu/firmware/60-ovmf-sb.json +index 5e8a94ae78..a5273a5e8b 100644 +--- a/tests/qemufirmwaredata/usr/share/qemu/firmware/60-ovmf-sb.json ++++ b/tests/qemufirmwaredata/usr/share/qemu/firmware/60-ovmf-sb.json +@@ -5,6 +5,7 @@ + ], + "mapping": { + "device": "flash", ++ "mode": "split", + "executable": { + "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd", + "format": "raw" +diff --git a/tests/qemufirmwaretest.c b/tests/qemufirmwaretest.c +index cad4b6d383..fc3416b2ae 100644 +--- a/tests/qemufirmwaretest.c ++++ b/tests/qemufirmwaretest.c +@@ -17,22 +17,31 @@ static int + testParseFormatFW(const void *opaque) + { + const char *filename = opaque; +- g_autofree char *path = NULL; ++ g_autofree char *inpath = NULL; ++ g_autofree char *outpath = NULL; + g_autoptr(qemuFirmware) fw = NULL; +- g_autofree char *buf = NULL; + g_autoptr(virJSONValue) json = NULL; + g_autofree char *expected = NULL; + g_autofree char *actual = NULL; ++ g_autofree char *buf = NULL; + +- path = g_strdup_printf("%s/qemufirmwaredata/%s", abs_srcdir, filename); ++ inpath = g_strdup_printf("%s/qemufirmwaredata/%s", abs_srcdir, filename); ++ outpath = g_strdup_printf("%s/qemufirmwaredata/out/%s", abs_srcdir, filename); + +- if (!(fw = qemuFirmwareParse(path))) ++ if (!(fw = qemuFirmwareParse(inpath))) + return -1; + +- if (virFileReadAll(path, +- 1024 * 1024, /* 1MiB */ +- &buf) < 0) +- return -1; ++ if (virFileExists(outpath)) { ++ if (virFileReadAll(outpath, ++ 1024 * 1024, /* 1MiB */ ++ &buf) < 0) ++ return -1; ++ } else { ++ if (virFileReadAll(inpath, ++ 1024 * 1024, /* 1MiB */ ++ &buf) < 0) ++ return -1; ++ } + + if (!(json = virJSONValueFromString(buf))) + return -1; +@@ -60,7 +69,9 @@ testFWPrecedence(const void *opaque G_GNUC_UNUSED) + const char *expected[] = { + PREFIX "/share/qemu/firmware/40-bios.json", + SYSCONFDIR "/qemu/firmware/40-ovmf-sb-keys.json", ++ PREFIX "/share/qemu/firmware/45-ovmf-sev-stateless.json", + PREFIX "/share/qemu/firmware/50-ovmf-sb-keys.json", ++ PREFIX "/share/qemu/firmware/55-ovmf-sb-combined.json", + PREFIX "/share/qemu/firmware/61-ovmf.json", + PREFIX "/share/qemu/firmware/70-aavmf.json", + NULL +@@ -218,7 +229,9 @@ mymain(void) + } while (0) + + DO_PARSE_TEST("usr/share/qemu/firmware/40-bios.json"); ++ DO_PARSE_TEST("usr/share/qemu/firmware/45-ovmf-sev-stateless.json"); + DO_PARSE_TEST("usr/share/qemu/firmware/50-ovmf-sb-keys.json"); ++ DO_PARSE_TEST("usr/share/qemu/firmware/55-ovmf-sb-combined.json"); + DO_PARSE_TEST("usr/share/qemu/firmware/60-ovmf-sb.json"); + DO_PARSE_TEST("usr/share/qemu/firmware/61-ovmf.json"); + DO_PARSE_TEST("usr/share/qemu/firmware/70-aavmf.json"); +@@ -250,6 +263,8 @@ mymain(void) + DO_SUPPORTED_TEST("pc-q35-3.1", VIR_ARCH_X86_64, true, + "/usr/share/seabios/bios-256k.bin:NULL:" + "/usr/share/OVMF/OVMF_CODE.secboot.fd:/usr/share/OVMF/OVMF_VARS.secboot.fd:" ++ "/usr/share/OVMF/OVMF.sev.fd:NULL:" ++ "/usr/share/OVMF/OVMF.secboot.fd:NULL:" + "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd", + VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS, + VIR_DOMAIN_OS_DEF_FIRMWARE_EFI); +-- +2.35.1 + diff --git a/SOURCES/libvirt-qemu-support-multiqueue-for-vdpa-net-device.patch b/SOURCES/libvirt-qemu-support-multiqueue-for-vdpa-net-device.patch new file mode 100644 index 0000000..83d9be3 --- /dev/null +++ b/SOURCES/libvirt-qemu-support-multiqueue-for-vdpa-net-device.patch @@ -0,0 +1,186 @@ +From 563e17f59f088d4ba76e7a95ea8958792ae165e2 Mon Sep 17 00:00:00 2001 +Message-Id: <563e17f59f088d4ba76e7a95ea8958792ae165e2@dist-git> +From: Jonathon Jongsma +Date: Tue, 1 Mar 2022 16:55:21 -0600 +Subject: [PATCH] qemu: support multiqueue for vdpa net device + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2024406 + +Signed-off-by: Jonathon Jongsma +Reviewed-by: Martin Kletzander + +(cherry picked from commit a5e659f071ae5f5fc9aadb46ad7c31736425f8cf) +Signed-off-by: Jonathon Jongsma +--- + src/qemu/qemu_domain.c | 3 +- + .../net-vdpa-multiqueue.x86_64-latest.args | 36 +++++++++++++++++++ + .../qemuxml2argvdata/net-vdpa-multiqueue.xml | 30 ++++++++++++++++ + tests/qemuxml2argvtest.c | 1 + + .../net-vdpa-multiqueue.xml | 36 +++++++++++++++++++ + tests/qemuxml2xmltest.c | 1 + + 6 files changed, 106 insertions(+), 1 deletion(-) + create mode 100644 tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args + create mode 100644 tests/qemuxml2argvdata/net-vdpa-multiqueue.xml + create mode 100644 tests/qemuxml2xmloutdata/net-vdpa-multiqueue.xml + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index a8401bac30..68052769af 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -4511,7 +4511,8 @@ qemuDomainValidateActualNetDef(const virDomainNetDef *net, + actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || + actualType == VIR_DOMAIN_NET_TYPE_DIRECT || + actualType == VIR_DOMAIN_NET_TYPE_ETHERNET || +- actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER)) { ++ actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER || ++ actualType == VIR_DOMAIN_NET_TYPE_VDPA)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("interface %s - multiqueue is not supported for network interfaces of type %s"), + macstr, virDomainNetTypeToString(actualType)); +diff --git a/tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args b/tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args +new file mode 100644 +index 0000000000..61ba85a847 +--- /dev/null ++++ b/tests/qemuxml2argvdata/net-vdpa-multiqueue.x86_64-latest.args +@@ -0,0 +1,36 @@ ++LC_ALL=C \ ++PATH=/bin \ ++HOME=/tmp/lib/domain--1-QEMUGuest1 \ ++USER=test \ ++LOGNAME=test \ ++XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ ++XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ ++XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ ++/usr/bin/qemu-system-x86_64 \ ++-name guest=QEMUGuest1,debug-threads=on \ ++-S \ ++-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tmp/lib/domain--1-QEMUGuest1/master-key.aes"}' \ ++-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram \ ++-accel tcg \ ++-cpu qemu64 \ ++-m 214 \ ++-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \ ++-overcommit mem-lock=off \ ++-smp 1,sockets=1,cores=1,threads=1 \ ++-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ ++-display none \ ++-no-user-config \ ++-nodefaults \ ++-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ ++-mon chardev=charmonitor,id=monitor,mode=control \ ++-rtc base=utc \ ++-no-shutdown \ ++-no-acpi \ ++-boot strict=on \ ++-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 \ ++-add-fd set=0,fd=1732,opaque=/dev/vhost-vdpa-0 \ ++-netdev vhost-vdpa,vhostdev=/dev/fdset/0,id=hostnet0 \ ++-device virtio-net-pci,mq=on,vectors=6,netdev=hostnet0,id=net0,mac=52:54:00:95:db:c0,bus=pci.0,addr=0x2 \ ++-audiodev '{"id":"audio1","driver":"none"}' \ ++-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ ++-msg timestamp=on +diff --git a/tests/qemuxml2argvdata/net-vdpa-multiqueue.xml b/tests/qemuxml2argvdata/net-vdpa-multiqueue.xml +new file mode 100644 +index 0000000000..6e369c1916 +--- /dev/null ++++ b/tests/qemuxml2argvdata/net-vdpa-multiqueue.xml +@@ -0,0 +1,30 @@ ++ ++ QEMUGuest1 ++ c7a5fdbd-edaf-9455-926a-d65c16db1809 ++ 219136 ++ 219136 ++ 1 ++ ++ hvm ++ ++ ++ ++ destroy ++ restart ++ destroy ++ ++ /usr/bin/qemu-system-x86_64 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c +index cc67d806e4..1abb5d0124 100644 +--- a/tests/qemuxml2argvtest.c ++++ b/tests/qemuxml2argvtest.c +@@ -1652,6 +1652,7 @@ mymain(void) + DO_TEST_FAILURE("net-hostdev-fail", + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST_CAPS_LATEST("net-vdpa"); ++ DO_TEST_CAPS_LATEST("net-vdpa-multiqueue"); + + DO_TEST("hostdev-pci-multifunction", + QEMU_CAPS_KVM, +diff --git a/tests/qemuxml2xmloutdata/net-vdpa-multiqueue.xml b/tests/qemuxml2xmloutdata/net-vdpa-multiqueue.xml +new file mode 100644 +index 0000000000..0876d5df62 +--- /dev/null ++++ b/tests/qemuxml2xmloutdata/net-vdpa-multiqueue.xml +@@ -0,0 +1,36 @@ ++ ++ QEMUGuest1 ++ c7a5fdbd-edaf-9455-926a-d65c16db1809 ++ 219136 ++ 219136 ++ 1 ++ ++ hvm ++ ++ ++ ++ destroy ++ restart ++ destroy ++ ++ /usr/bin/qemu-system-x86_64 ++ ++
++ ++ ++
++ ++ ++ ++ ++ ++ ++ ++
++ ++ ++ ++