From 582e7872e6f2ae02a4148841e8e031da00af67b6 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Mon, 17 Feb 2025 19:05:40 +0100 Subject: [PATCH] libvirt-10.10.0-7.el10 - qemu_migration: Refactor qemuMigrationSrcRestoreDomainState (RHEL-1071) - qemu_migration: Do not automatically resume domain after I/O error (RHEL-1071) - qemucapabilitiestest: Add data for the qemu-10.0 dev cycle on x86_64 (RHEL-78398) - qemucapabilitiestest: Update 'caps_10.0.0_x86_64' to 'v9.2.0-1636-gffaf7f0376' (RHEL-78398) - qemu: capabilies: Introduce QEMU_CAPS_BLOCKDEV_SET_ACTIVE (RHEL-78398) - qemu: monitor: Add monitor backend for 'blockdev-set-active' (RHEL-78398) - qemu: migration: Reactivate block nodes after migration if VM is left paused (RHEL-78398) - conf: change virDomainHostdevInsert() to return void (RHEL-77086) - qemu: fix qemu validation to forbid guest-side IP address for type='vdpa' (RHEL-77086) - qemu: validate that model is virtio for vhostuser and vdpa interfaces in the same place (RHEL-77086) - qemu: automatically set model type='virtio' for interface type='vhostuser' (RHEL-77086) - qemu: do all vhostuser attribute validation in qemu driver (RHEL-77086) - conf/qemu: make element *almost* optional for type=vhostuser (RHEL-77086) - qemu: use switch instead of if in qemuProcessPrepareDomainNetwork() (RHEL-77086) - qemu: make qemuPasstCreateSocketPath() public (RHEL-77086) - qemu: complete vhostuser + passt support (RHEL-77086) - qemu: fail validation if a domain def has vhostuser/passt but no shared mem (RHEL-77086) - docs: improve type='user' docs to higlight differences between SLIRP and passt (RHEL-77086) - docs: document using passt backend with (RHEL-77086) - utils: Canonicalize paths before comparing them (RHEL-79165) Resolves: RHEL-1071, RHEL-77086, RHEL-78398, RHEL-79165 --- ...irDomainHostdevInsert-to-return-void.patch | 158 + ...t-almost-optional-for-type-vhostuser.patch | 170 + ...ackend-with-interface-type-vhostuser.patch | 139 + ...-differences-between-SLIRP-and-passt.patch | 177 + ...-virtio-for-interface-type-vhostuser.patch | 41 + ...roduce-QEMU_CAPS_BLOCKDEV_SET_ACTIVE.patch | 76 + ...emu-complete-vhostuser-passt-support.patch | 663 + ...-attribute-validation-in-qemu-driver.patch | 75 + ...as-vhostuser-passt-but-no-shared-mem.patch | 203 + ...-guest-side-IP-address-for-type-vdpa.patch | 94 + ...ake-qemuPasstCreateSocketPath-public.patch | 51 + ...after-migration-if-VM-is-left-paused.patch | 137 + ...itor-backend-for-blockdev-set-active.patch | 160 + ...f-in-qemuProcessPrepareDomainNetwork.patch | 132 + ...nd-vdpa-interfaces-in-the-same-place.patch | 82 + ...ically-resume-domain-after-I-O-error.patch | 38 + ...r-qemuMigrationSrcRestoreDomainState.patch | 110 + ...or-the-qemu-10.0-dev-cycle-on-x86_64.patch | 54452 ++++++++++++++++ ....0_x86_64-to-v9.2.0-1636-gffaf7f0376.patch | 13228 ++++ ...nicalize-paths-before-comparing-them.patch | 55 + libvirt.spec | 44 +- 21 files changed, 70284 insertions(+), 1 deletion(-) create mode 100644 libvirt-conf-change-virDomainHostdevInsert-to-return-void.patch create mode 100644 libvirt-conf-qemu-make-source-element-almost-optional-for-type-vhostuser.patch create mode 100644 libvirt-docs-document-using-passt-backend-with-interface-type-vhostuser.patch create mode 100644 libvirt-docs-improve-type-user-docs-to-higlight-differences-between-SLIRP-and-passt.patch create mode 100644 libvirt-qemu-automatically-set-model-type-virtio-for-interface-type-vhostuser.patch create mode 100644 libvirt-qemu-capabilies-Introduce-QEMU_CAPS_BLOCKDEV_SET_ACTIVE.patch create mode 100644 libvirt-qemu-complete-vhostuser-passt-support.patch create mode 100644 libvirt-qemu-do-all-vhostuser-attribute-validation-in-qemu-driver.patch create mode 100644 libvirt-qemu-fail-validation-if-a-domain-def-has-vhostuser-passt-but-no-shared-mem.patch create mode 100644 libvirt-qemu-fix-qemu-validation-to-forbid-guest-side-IP-address-for-type-vdpa.patch create mode 100644 libvirt-qemu-make-qemuPasstCreateSocketPath-public.patch create mode 100644 libvirt-qemu-migration-Reactivate-block-nodes-after-migration-if-VM-is-left-paused.patch create mode 100644 libvirt-qemu-monitor-Add-monitor-backend-for-blockdev-set-active.patch create mode 100644 libvirt-qemu-use-switch-instead-of-if-in-qemuProcessPrepareDomainNetwork.patch create mode 100644 libvirt-qemu-validate-that-model-is-virtio-for-vhostuser-and-vdpa-interfaces-in-the-same-place.patch create mode 100644 libvirt-qemu_migration-Do-not-automatically-resume-domain-after-I-O-error.patch create mode 100644 libvirt-qemu_migration-Refactor-qemuMigrationSrcRestoreDomainState.patch create mode 100644 libvirt-qemucapabilitiestest-Add-data-for-the-qemu-10.0-dev-cycle-on-x86_64.patch create mode 100644 libvirt-qemucapabilitiestest-Update-caps_10.0.0_x86_64-to-v9.2.0-1636-gffaf7f0376.patch create mode 100644 libvirt-utils-Canonicalize-paths-before-comparing-them.patch diff --git a/libvirt-conf-change-virDomainHostdevInsert-to-return-void.patch b/libvirt-conf-change-virDomainHostdevInsert-to-return-void.patch new file mode 100644 index 0000000..df240b0 --- /dev/null +++ b/libvirt-conf-change-virDomainHostdevInsert-to-return-void.patch @@ -0,0 +1,158 @@ +From 5083667a7f861364e293904a18bce550d9880536 Mon Sep 17 00:00:00 2001 +Message-ID: <5083667a7f861364e293904a18bce550d9880536.1739815540.git.jdenemar@redhat.com> +From: Laine Stump +Date: Tue, 11 Feb 2025 16:44:49 -0500 +Subject: [PATCH] conf: change virDomainHostdevInsert() to return void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We haven't checked for memalloc failure in many years, and that was +the only reason this function would have ever failed. + +Signed-off-by: Laine Stump +Reviewed-by: Ján Tomko +(cherry picked from commit 956c6684113b46b2350db698dc75604f4c3a4b76) + +https://issues.redhat.com/browse/RHEL-77086 +Signed-off-by: Laine Stump +--- + src/conf/domain_conf.c | 15 +++++---------- + src/conf/domain_conf.h | 2 +- + src/libxl/libxl_domain.c | 5 +---- + src/libxl/libxl_driver.c | 3 +-- + src/lxc/lxc_driver.c | 3 +-- + src/qemu/qemu_driver.c | 3 +-- + src/qemu/qemu_process.c | 3 +-- + 7 files changed, 11 insertions(+), 23 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index d83f1ba240..cba0b162f4 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -14456,12 +14456,10 @@ virDomainChrTargetTypeToString(int deviceType, + return type; + } + +-int ++void + virDomainHostdevInsert(virDomainDef *def, virDomainHostdevDef *hostdev) + { + VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, hostdev); +- +- return 0; + } + + virDomainHostdevDef * +@@ -14877,9 +14875,8 @@ virDomainDiskRemoveByName(virDomainDef *def, const char *name) + int virDomainNetInsert(virDomainDef *def, virDomainNetDef *net) + { + /* hostdev net devices must also exist in the hostdevs array */ +- if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV && +- virDomainHostdevInsert(def, &net->data.hostdev.def) < 0) +- return -1; ++ if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) ++ virDomainHostdevInsert(def, &net->data.hostdev.def); + + VIR_APPEND_ELEMENT(def->nets, def->nnets, net); + return 0; +@@ -19257,10 +19254,8 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, + * where the actual network type is already known to be + * hostdev) must also be in the hostdevs array. + */ +- if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV && +- virDomainHostdevInsert(def, virDomainNetGetActualHostdev(net)) < 0) { +- return NULL; +- } ++ if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV) ++ virDomainHostdevInsert(def, virDomainNetGetActualHostdev(net)); + } + VIR_FREE(nodes); + +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 5237046196..2d38e8fa51 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -3982,7 +3982,7 @@ virDomainNetDef *virDomainNetRemove(virDomainDef *def, size_t i); + virDomainNetDef *virDomainNetRemoveByObj(virDomainDef *def, virDomainNetDef *net); + void virDomainNetRemoveHostdev(virDomainDef *def, virDomainNetDef *net); + +-int virDomainHostdevInsert(virDomainDef *def, virDomainHostdevDef *hostdev); ++void virDomainHostdevInsert(virDomainDef *def, virDomainHostdevDef *hostdev); + virDomainHostdevDef * + virDomainHostdevRemove(virDomainDef *def, size_t i); + int virDomainHostdevFind(virDomainDef *def, virDomainHostdevDef *match, +diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c +index cad6c9ce42..711e22b8df 100644 +--- a/src/libxl/libxl_domain.c ++++ b/src/libxl/libxl_domain.c +@@ -1015,10 +1015,7 @@ libxlNetworkPrepareDevices(virDomainDef *def) + /* Each type='hostdev' network device must also have a + * corresponding entry in the hostdevs array. + */ +- virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net); +- +- if (virDomainHostdevInsert(def, hostdev) < 0) +- return -1; ++ virDomainHostdevInsert(def, virDomainNetGetActualHostdev(net)); + } + } + +diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c +index 29dcee3cfc..b670e697c6 100644 +--- a/src/libxl/libxl_driver.c ++++ b/src/libxl/libxl_driver.c +@@ -3585,8 +3585,7 @@ libxlDomainAttachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) + return -1; + } + +- if (virDomainHostdevInsert(vmdef, hostdev) < 0) +- return -1; ++ virDomainHostdevInsert(vmdef, hostdev); + dev->data.hostdev = NULL; + break; + +diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c +index d682e7168a..9609d7d10c 100644 +--- a/src/lxc/lxc_driver.c ++++ b/src/lxc/lxc_driver.c +@@ -3025,8 +3025,7 @@ lxcDomainAttachDeviceConfig(virDomainDef *vmdef, + _("device is already in the domain configuration")); + return -1; + } +- if (virDomainHostdevInsert(vmdef, hostdev) < 0) +- return -1; ++ virDomainHostdevInsert(vmdef, hostdev); + dev->data.hostdev = NULL; + ret = 0; + break; +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 9a69574f31..379f9fb74f 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -6734,8 +6734,7 @@ qemuDomainAttachDeviceConfig(virDomainDef *vmdef, + _("device is already in the domain configuration")); + return -1; + } +- if (virDomainHostdevInsert(vmdef, hostdev)) +- return -1; ++ virDomainHostdevInsert(vmdef, hostdev); + dev->data.hostdev = NULL; + break; + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 1866c8f4e1..a45f1b5b7d 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -5929,8 +5929,7 @@ qemuProcessPrepareDomainNetwork(virDomainObj *vm) + if (qemuDomainPrepareHostdev(hostdev, priv) < 0) + return -1; + +- if (virDomainHostdevInsert(def, hostdev) < 0) +- return -1; ++ virDomainHostdevInsert(def, hostdev); + } + } + return 0; +-- +2.48.1 diff --git a/libvirt-conf-qemu-make-source-element-almost-optional-for-type-vhostuser.patch b/libvirt-conf-qemu-make-source-element-almost-optional-for-type-vhostuser.patch new file mode 100644 index 0000000..4fa8631 --- /dev/null +++ b/libvirt-conf-qemu-make-source-element-almost-optional-for-type-vhostuser.patch @@ -0,0 +1,170 @@ +From 6cecf1cbd813f6b197920001a422e87d0999442a Mon Sep 17 00:00:00 2001 +Message-ID: <6cecf1cbd813f6b197920001a422e87d0999442a.1739815540.git.jdenemar@redhat.com> +From: Laine Stump +Date: Sun, 9 Feb 2025 22:52:54 -0500 +Subject: [PATCH] conf/qemu: make element *almost* optional for + type=vhostuser +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For some reason, when vhostuser interface support was added in 2014, +the parser required that the XML for the have a +element with type, mode, and path, all 3 also required. This in spite +of the fact that 'unix' is the only possible valid setting for type, +and 95% of the time the mode is set to 'client' (as I understand from +comments in the code, normally a guest will use mode='client' to +connect to an existing socket that is precreated (by OVS?), and the +only use for mode='server' is for test setups where one guest is setup +with a listening vhostuser socket (i.e. 'server') and another guest +connects to that socket (i.e. 'client')). (or maybe one guest connects +to OVS in server mode, and all the others connect in client mode, not +sure - I don't claim to be an expert on vhost-user.) + +So from the point of view of existing vhost-user functionality, it +seems reasonable to make 'type' and 'mode' optional, and by default +fill in the vhostuser part of the NetDef as if they were 'unix' and +'client'. + +In theory, the element itself is also not *directly* required +after this patch, however, the path attribute of *is* +required (for now), so effectively the element is still +required. + +Signed-off-by: Laine Stump +Reviewed-by: Ján Tomko +(cherry picked from commit fb4bfa78589f7f556b6b0a176f109c94516d3cdd) + +https://issues.redhat.com/browse/RHEL-77086 +Signed-off-by: Laine Stump +--- + src/conf/domain_conf.c | 56 ++++++++++++------------------- + src/conf/schemas/domaincommon.rng | 4 ++- + src/qemu/qemu_validate.c | 20 +++++++---- + 3 files changed, 39 insertions(+), 41 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index cba0b162f4..b1e9dda80e 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -9767,50 +9767,38 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, + g_autofree char *vhostuser_type = NULL; + virDomainNetVhostuserMode vhostuser_mode; + +- if (virDomainNetDefParseXMLRequireSource(def, source_node) < 0) +- return NULL; +- +- if (!(vhostuser_type = virXMLPropStringRequired(source_node, "type"))) +- return NULL; +- +- if (STRNEQ_NULLABLE(vhostuser_type, "unix")) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, +- _("Type='%1$s' unsupported for "), +- vhostuser_type); +- return NULL; +- } +- + if (!(def->data.vhostuser = virDomainChrSourceDefNew(xmlopt))) + return NULL; + ++ /* Default (and only valid) value of type is "unix". ++ * Everything else's default value is 0/NULL. ++ */ + def->data.vhostuser->type = VIR_DOMAIN_CHR_TYPE_UNIX; + +- if (!(def->data.vhostuser->data.nix.path = virXMLPropStringRequired(source_node, "path"))) +- return NULL; ++ if (source_node) { ++ if ((vhostuser_type = virXMLPropString(source_node, "type"))) { ++ if (STRNEQ(vhostuser_type, "unix")) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("Type='%1$s' unsupported for "), ++ vhostuser_type); ++ return NULL; ++ } ++ } + +- if (virXMLPropEnum(source_node, "mode", +- virDomainNetVhostuserModeTypeFromString, +- VIR_XML_PROP_REQUIRED | VIR_XML_PROP_NONZERO, +- &vhostuser_mode) < 0) +- return NULL; ++ def->data.vhostuser->data.nix.path = virXMLPropString(source_node, "path"); + +- switch (vhostuser_mode) { +- case VIR_DOMAIN_NET_VHOSTUSER_MODE_CLIENT: +- def->data.vhostuser->data.nix.listen = false; +- break; ++ if (virXMLPropEnum(source_node, "mode", virDomainNetVhostuserModeTypeFromString, ++ VIR_XML_PROP_NONZERO, &vhostuser_mode) < 0) { ++ return NULL; ++ } + +- case VIR_DOMAIN_NET_VHOSTUSER_MODE_SERVER: +- def->data.vhostuser->data.nix.listen = true; +- break; ++ if (vhostuser_mode == VIR_DOMAIN_NET_VHOSTUSER_MODE_SERVER) ++ def->data.vhostuser->data.nix.listen = true; + +- case VIR_DOMAIN_NET_VHOSTUSER_MODE_NONE: +- case VIR_DOMAIN_NET_VHOSTUSER_MODE_LAST: +- break; ++ if (virDomainChrSourceReconnectDefParseXML(&def->data.vhostuser->data.nix.reconnect, ++ source_node, ctxt) < 0) ++ return NULL; + } +- +- if (virDomainChrSourceReconnectDefParseXML(&def->data.vhostuser->data.nix.reconnect, +- source_node, ctxt) < 0) +- return NULL; + } + break; + +diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng +index 7121519ca3..cbc093ca7b 100644 +--- a/src/conf/schemas/domaincommon.rng ++++ b/src/conf/schemas/domaincommon.rng +@@ -3485,7 +3485,9 @@ + vhostuser + + +- ++ ++ ++ + + + +diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c +index b7b2e3d0af..eb8c5366f6 100644 +--- a/src/qemu/qemu_validate.c ++++ b/src/qemu/qemu_validate.c +@@ -1810,12 +1810,20 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net, + } + } + +- if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER && +- net->data.vhostuser->data.nix.listen && +- net->data.vhostuser->data.nix.reconnect.enabled == VIR_TRISTATE_BOOL_YES) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", +- _("'reconnect' attribute is not supported when source mode='server' for ")); +- return -1; ++ if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { ++ if (!net->data.vhostuser->data.nix.path) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Missing required attribute '%1$s' in element '%2$s'"), ++ "path", "source"); ++ return -1; ++ } ++ ++ if (net->data.vhostuser->data.nix.listen && ++ net->data.vhostuser->data.nix.reconnect.enabled == VIR_TRISTATE_BOOL_YES) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("'reconnect' attribute is not supported when source mode='server' for ")); ++ return -1; ++ } + } + + if (!virDomainNetIsVirtioModel(net)) { +-- +2.48.1 diff --git a/libvirt-docs-document-using-passt-backend-with-interface-type-vhostuser.patch b/libvirt-docs-document-using-passt-backend-with-interface-type-vhostuser.patch new file mode 100644 index 0000000..e7b576c --- /dev/null +++ b/libvirt-docs-document-using-passt-backend-with-interface-type-vhostuser.patch @@ -0,0 +1,139 @@ +From 1be247ee9a7df932a3f2ff2126714755433fc94b Mon Sep 17 00:00:00 2001 +Message-ID: <1be247ee9a7df932a3f2ff2126714755433fc94b.1739815540.git.jdenemar@redhat.com> +From: Laine Stump +Date: Fri, 14 Feb 2025 23:35:56 -0500 +Subject: [PATCH] docs: document using passt backend with +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Almost everything is already there (in the section for using passt +with type='user'), so we just need to point to that from the +type='vhostuser' section (and vice versa), and add a bit of glue. + +Also updated a few related details that have changed (e.g. default +model type for vhostuser is now 'virtio', and source type/mode are now +optional), and changed "vhost-user interface" to "vhost-user +connection" because the interface is a virtio interface, and +vhost-user is being used to connect that interface to the outside. + +Signed-off-by: Laine Stump +Reviewed-by: Ján Tomko +(cherry picked from commit 96fd17a99b514e585a94d43d40ab9a74907c7a5b) + +https://issues.redhat.com/browse/RHEL-77086 +Signed-off-by: Laine Stump +--- + docs/formatdomain.rst | 73 ++++++++++++++++++++++++++++++++++++------- + 1 file changed, 62 insertions(+), 11 deletions(-) + +diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst +index 577366b934..c077c09a39 100644 +--- a/docs/formatdomain.rst ++++ b/docs/formatdomain.rst +@@ -5131,6 +5131,15 @@ destined for the host toward the guest instead), and a socket between + passt and QEMU forwards that traffic on to the guest (and back out, + of course). + ++*(:since:`Since 11.1.0 (QEMU and KVM only)` you may prefer to use the ++passt backend with the more efficient and performant type='vhostuser' ++rather than type='user'. All the options related to passt in the ++paragraphs below here also apply when using the passt backend with ++type='vhostuser'; any other details specific to vhostuser are ++described* `here ++`__.) ++ ++ + Similar to SLIRP, passt has an internal DHCP server that provides a + requesting guest with one ipv4 and one ipv6 address. There are default + values for both of these, or you can use the ```` element +@@ -5823,7 +5832,7 @@ following attributes are available for the ``virtio`` NIC driver: + The optional ``queues`` attribute controls the number of queues to be used + for either `Multiqueue + virtio-net `__ or vhost-user (See +- `vhost-user interface`_) network interfaces. Use of multiple packet ++ `vhost-user connection`_) network interfaces. Use of multiple packet + processing queues requires the interface having the + ```` element. Each queue will potentially be handled by + a different processor, resulting in much higher throughput. +@@ -6267,8 +6276,8 @@ similarly named elements used to configure the guest side of the interface + (described above). + + +-vhost-user interface +-^^^^^^^^^^^^^^^^^^^^ ++vhost-user connection ++^^^^^^^^^^^^^^^^^^^^^ + + :since:`Since 1.2.7` the vhost-user enables the communication between a QEMU + virtual machine and other userspace process using the Virtio transport protocol. +@@ -6295,16 +6304,58 @@ plane is based on shared memory. + + ... + +-The ```` element has to be specified along with the type of char device. +-Currently, only type='unix' is supported, where the path (the directory path of +-the socket) and mode attributes are required. Both ``mode='server'`` and +-``mode='client'`` are supported. vhost-user requires the virtio model type, thus +-the ```` element is mandatory. :since:`Since 4.1.0` the element has an +-optional child element ``reconnect`` which configures reconnect timeout if the +-connection is lost. It has two attributes ``enabled`` (which accepts ``yes`` and +-``no``) and ``timeout`` which specifies the amount of seconds after which ++The ```` element has to be specified along with the type of ++char device. Currently, only type='unix' is supported, where the path ++(the directory path of the socket) and mode attributes are ++required. Both ``mode='server'`` and ``mode='client'`` are ++supported. (:since:`Since 11.1.0` the default source type for ++vhostuser interfaces is 'unix' and default mode is 'client', so those ++two attributes are now optional). ++ ++The vhost-user protocol only works with the virtio guest driver, so ++the ```` element ``type`` attribute is mandatory (:since:`Since ++11.1.0` the default model type for vhostuser interfaces is now ++'virtio' so ```` is no longer mandatory). :since:`Since 4.1.0` ++the ```` element has an optional child element ``reconnect`` ++which configures reconnect timeout if the connection is lost. It has ++two attributes ``enabled`` (which accepts ``yes`` and ``no``) and ++``timeout`` which specifies the amount of seconds after which + hypervisor tries to reconnect. + ++ ++vhost-user connection with passt backend ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++:since:`Since 11.1.0 (QEMU and KVM only)` passt can be used as the ++other end of the vhost-user connection. This is a compelling ++alternative, because passt provides all of its network connectivity ++without requiring any elevated privileges or capabilities, and ++vhost-user uses shared memory to make this unprivileged connection ++very high performance as well. You can set a type='vhostuser' ++interface to use passt as the backend by adding ````. When passt is the backend, only a single driver ++queue is supported, and the ```` path/type/mode are all ++implied to be "matching the passt process" so **must not** be ++specified. All of the passt options `described here ++`__, are also ++supported for ``type='vhostuser'`` with the passt backend, e.g. ++setting guest-side IP addresses with ```` and port forwarding with ++`` ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ + Traffic filtering with NWFilter + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +-- +2.48.1 diff --git a/libvirt-docs-improve-type-user-docs-to-higlight-differences-between-SLIRP-and-passt.patch b/libvirt-docs-improve-type-user-docs-to-higlight-differences-between-SLIRP-and-passt.patch new file mode 100644 index 0000000..1038c94 --- /dev/null +++ b/libvirt-docs-improve-type-user-docs-to-higlight-differences-between-SLIRP-and-passt.patch @@ -0,0 +1,177 @@ +From 2e71e35f0d78191d5ea36297877933e58e624a3a Mon Sep 17 00:00:00 2001 +Message-ID: <2e71e35f0d78191d5ea36297877933e58e624a3a.1739815540.git.jdenemar@redhat.com> +From: Laine Stump +Date: Fri, 14 Feb 2025 22:43:03 -0500 +Subject: [PATCH] docs: improve type='user' docs to higlight differences + between SLIRP and passt +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reorganizes the section about and +describes the differences in behavior between SLIRP and passt. + +Resolves: https://issues.redhat.com/browse/RHEL-46601 +Signed-off-by: Laine Stump +Reviewed-by: Ján Tomko +(cherry picked from commit a47a89a9d335c111a9c2fbb3f4e1c3a13001e74b) + +https://issues.redhat.com/browse/RHEL-77086 +Signed-off-by: Laine Stump +--- + docs/formatdomain.rst | 116 ++++++++++++++++++++++++++++-------------- + 1 file changed, 78 insertions(+), 38 deletions(-) + +diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst +index 8d787ef59a..577366b934 100644 +--- a/docs/formatdomain.rst ++++ b/docs/formatdomain.rst +@@ -5072,25 +5072,34 @@ to the interface. + + ... + +-Userspace (SLIRP or passt) connection +-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++Userspace connection using SLIRP ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +-The ``user`` type connects the guest interface to the outside via a ++The ``user`` interface type connects the guest interface to the outside via a + transparent userspace proxy that doesn't require any special system + privileges, making it usable in cases when libvirt itself is running + with no privileges (e.g. libvirt's "session mode" daemon, or when + libvirt is run inside an unprivileged container). + +-By default, this user proxy is done with QEMU's internal SLIRP driver +-which has DHCP & DNS services that give the guest IP addresses +-starting from ``10.0.2.15``, a default route of ``10.0.2.2`` and DNS +-server of ``10.0.2.3``. :since:`Since 3.8.0` it is possible to override +-the default network address by including an ``ip`` element specifying +-an IPv4 address in its one mandatory attribute, +-``address``. Optionally, a second ``ip`` element with a ``family`` +-attribute set to "ipv6" can be specified to add an IPv6 address to the +-interface. ``address``. Optionally, address ``prefix`` can be +-specified. ++By default, this user proxy is done with QEMU's SLIRP driver, a ++userspace proxy built into QEMU that has DHCP & DNS services that give ++the guest an IP address of ``10.0.2.15``, a default route of ++``10.0.2.2`` and DNS server at ``10.0.2.3``. ++ ++:since:`Since 3.8.0` it is possible to override the guest's default ++network address by including an ``ip`` element specifying an IPv4 ++address in its one mandatory attribute, ``address``. Optionally, a ++second ``ip`` element with a ``family`` attribute set to "ipv6" can be ++specified to add an IPv6 address to the interface. ``address``. ++Optionally, an address ``prefix`` can be specified. These settings are ++surprisingly **not** used by SLIRP to set the exact IP address; ++instead they are used to determine what network/subnet the guest's IP ++address should be on, and the guest will be given an address in that ++subnet, but the host portion of the address will still be "2.15". In ++the example below, for example, the guest will be given the IP address ++172.17.2.15 (**note that the '1.1' in the host portion of the address ++has been ignored**), default route of 172.17.2.2, and DNS server ++172.17.2.3. + + :: + +@@ -5100,34 +5109,65 @@ specified. + ... + + +- +- ++ ++ + + + ... + +-:since:`Since 9.0.0` an alternate backend implementation of the +-``user`` interface type can be selected by setting the interface's +-```` subelement ``type`` attribute to ``passt``. In this +-case, the passt transport (https://passt.top) is used. Similar to +-SLIRP, passt has an internal DHCP server that provides a requesting +-guest with one ipv4 and one ipv6 address; it then uses userspace +-proxies and a separate network namespace to provide outgoing +-UDP/TCP/ICMP sessions, and optionally redirect incoming traffic +-destined for the host toward the guest instead. +- +-When the passt backend is used, the ```` attribute +-``logFile`` can be used to tell the passt process for this interface +-where to write its message log, and the ```` attribute ``dev`` +-can tell it to use a particular host interface to derive the routes +-given to the guest for forwarding traffic upstream. Due to the design +-decisions of passt, if using SELinux, the log file is recommended to +-reside in the runtime directory of a user under which the passt +-process will run, most probably ``/run/user/$UID`` where ``$UID`` is +-the UID of the user, e.g. ``qemu``. Beware that libvirt does not +-create this directory if it does not already exist to avoid possible, +-however unlikely, issues, especially since this logfile attribute is +-meant mostly for debugging. ++Userspace connection using passt ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++:since:`Since 9.0.0 (QEMU and KVM only)` an alternate backend ++implementation of the ``user`` interface type can be selected by ++setting the interface's ```` subelement ``type`` attribute to ++``passt``. In this case, the passt transport `(details here) ++`__ is used. passt is run as a separate process ++from QEMU - the passt process handles the details of forwarding ++network traffic back and forth to the physical network (using ++userspace proxies and a separate network namespace to provide outgoing ++UDP/TCP/ICMP sessions, and optionally redirecting incoming traffic ++destined for the host toward the guest instead), and a socket between ++passt and QEMU forwards that traffic on to the guest (and back out, ++of course). ++ ++Similar to SLIRP, passt has an internal DHCP server that provides a ++requesting guest with one ipv4 and one ipv6 address. There are default ++values for both of these, or you can use the ```` element ++(described above, with behavioral differences as outlined below) to ++configure one IPv4 and one IPv6 address that passt's DHCP server can ++provide to the guest. ++ ++Unlike SLIRP, when no ``` address is specified, passt will by ++default provide the guest with an IP address, DNS server, etc. that ++are identical to those settings on the host itself (through the magic ++of the proxies and a separate network namespace, this doesn't create ++any conflict). ++ ++Also different from SLIRP's behavior: if you do specify IP ++address(es), the exact address and netmask/prefix you specify will be ++provided to the guest (i.e. passt doesn't interpret the settings ++as a network address like SLIRP does, but as a host address). In ++example given above, the guest IP would be set to exactly 172.17.1.1. ++ ++Just as with SLIRP, though, once traffic from the guest leaves the ++host towards the rest of the network, it will always appear as if it ++came from the host's IP. ++ ++There are a few other options that are configurable only for the passt ++backend. For example, the ```` attribute ``logFile`` can be ++used to tell the passt process for this interface where to write its ++message log, and the ```` attribute ``dev`` can tell it a ++particular host interface to use when deriving the routes given to the ++guest for forwarding traffic upstream. Due to the design decisions of ++passt, when using SELinux on the host, it is recommended that the log ++file reside in the runtime directory of the user under which the passt ++process will run, most probably ``/run/user/$UID`` (where ``$UID`` is ++the UID of that user), e.g. ``/run/user/1000``. Be aware that libvirt ++does not create this directory if it does not already exist to avoid ++possible, however unlikely, issues with orphaned directories or ++permissions, etc. The logfile attribute is meant mostly for debugging, ++so it shouldn't be set under normal circumstances. + + Additionally, when passt is used, multiple ```` elements + can be added to forward incoming network traffic for the host to this +@@ -5164,7 +5204,7 @@ ports **with the exception of some subset**. + + + +- ++ + + + +-- +2.48.1 diff --git a/libvirt-qemu-automatically-set-model-type-virtio-for-interface-type-vhostuser.patch b/libvirt-qemu-automatically-set-model-type-virtio-for-interface-type-vhostuser.patch new file mode 100644 index 0000000..1cc8d5f --- /dev/null +++ b/libvirt-qemu-automatically-set-model-type-virtio-for-interface-type-vhostuser.patch @@ -0,0 +1,41 @@ +From e1e0d3f8b4b6d6694a57425e6a3f85015cee9225 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Laine Stump +Date: Sun, 9 Feb 2025 18:23:03 -0500 +Subject: [PATCH] qemu: automatically set model type='virtio' for interface + type='vhostuser' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Both vdpa and vhostuser require that the guest device be virtio, and +for interface type='vdpa', we already set if it +is unspecified in the input XML, so let's be just as courteous for +interface type='vhostuser'. + +Signed-off-by: Laine Stump +Reviewed-by: Ján Tomko +(cherry picked from commit c4746418d7e952888c0989db3a5c723d888fc32d) + +https://issues.redhat.com/browse/RHEL-77086 +Signed-off-by: Laine Stump +--- + src/qemu/qemu_postparse.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c +index 049a6ef2dc..892330646a 100644 +--- a/src/qemu/qemu_postparse.c ++++ b/src/qemu/qemu_postparse.c +@@ -100,7 +100,8 @@ qemuDomainDeviceNetDefPostParse(virDomainNetDef *net, + const virDomainDef *def, + virQEMUCaps *qemuCaps) + { +- if (net->type == VIR_DOMAIN_NET_TYPE_VDPA && ++ if ((net->type == VIR_DOMAIN_NET_TYPE_VDPA || ++ net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) && + !virDomainNetGetModelString(net)) { + net->model = VIR_DOMAIN_NET_MODEL_VIRTIO; + } else if (net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV && +-- +2.48.1 diff --git a/libvirt-qemu-capabilies-Introduce-QEMU_CAPS_BLOCKDEV_SET_ACTIVE.patch b/libvirt-qemu-capabilies-Introduce-QEMU_CAPS_BLOCKDEV_SET_ACTIVE.patch new file mode 100644 index 0000000..461e8ab --- /dev/null +++ b/libvirt-qemu-capabilies-Introduce-QEMU_CAPS_BLOCKDEV_SET_ACTIVE.patch @@ -0,0 +1,76 @@ +From a26297c129ec05c129fda6da57ef8b8330d626be Mon Sep 17 00:00:00 2001 +Message-ID: +From: Peter Krempa +Date: Mon, 10 Feb 2025 17:57:01 +0100 +Subject: [PATCH] qemu: capabilies: Introduce QEMU_CAPS_BLOCKDEV_SET_ACTIVE + +The flag signals presence of the 'blockdev-set-active' QMP command. + +Signed-off-by: Peter Krempa +Reviewed-by: Jiri Denemark +(cherry picked from commit b402e167b640bcd242ba518cfd7cbc469dba52e9) + + Conflicts: + src/qemu/qemu_capabilities.c + src/qemu/qemu_capabilities.h + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml + + Some capabilities were not backported: + - QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION_DEPRECATED_PROPS + - QEMU_CAPS_MIGRATE_INCOMING_EXIT_ON_ERROR + - QEMU_CAPS_MACHINE_VIRT_AIA + - QEMU_CAPS_DEVICE_VIRTIO_MEM_CCW + +https://issues.redhat.com/browse/RHEL-78398 +--- + src/qemu/qemu_capabilities.c | 2 ++ + src/qemu/qemu_capabilities.h | 1 + + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 1 + + 3 files changed, 4 insertions(+) + +diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c +index dec3199fce..65e19965dd 100644 +--- a/src/qemu/qemu_capabilities.c ++++ b/src/qemu/qemu_capabilities.c +@@ -721,6 +721,7 @@ VIR_ENUM_IMPL(virQEMUCaps, + "chardev-reconnect-miliseconds", /* QEMU_CAPS_CHARDEV_RECONNECT_MILISECONDS */ + "virtio-ccw.loadparm", /* QEMU_CAPS_VIRTIO_CCW_DEVICE_LOADPARM */ + "netdev-stream-reconnect-miliseconds", /* QEMU_CAPS_NETDEV_STREAM_RECONNECT_MILISECONDS */ ++ "blockdev-set-active", /* QEMU_CAPS_BLOCKDEV_SET_ACTIVE */ + ); + + +@@ -1242,6 +1243,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { + { "query-stats-schemas", QEMU_CAPS_QUERY_STATS_SCHEMAS }, + { "display-reload", QEMU_CAPS_DISPLAY_RELOAD }, + { "snapshot-save", QEMU_CAPS_SNAPSHOT_INTERNAL_QMP }, ++ { "blockdev-set-active", QEMU_CAPS_BLOCKDEV_SET_ACTIVE }, + }; + + struct virQEMUCapsStringFlags virQEMUCapsMigration[] = { +diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h +index 48e4530c95..e93e6a01cc 100644 +--- a/src/qemu/qemu_capabilities.h ++++ b/src/qemu/qemu_capabilities.h +@@ -700,6 +700,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ + QEMU_CAPS_CHARDEV_RECONNECT_MILISECONDS, /* 'reconnect-ms' option for chardevs supported */ + QEMU_CAPS_VIRTIO_CCW_DEVICE_LOADPARM, /* loadparm available on CCW device for multi device boot */ + QEMU_CAPS_NETDEV_STREAM_RECONNECT_MILISECONDS, /* 'reconnect-ms' option for netdev stream supported */ ++ QEMU_CAPS_BLOCKDEV_SET_ACTIVE, /* blockdev-set-active QMP command supported */ + + QEMU_CAPS_LAST /* this must always be the last item */ + } virQEMUCapsFlags; +diff --git a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml +index aed0a58fa7..e09b6e6e1a 100644 +--- a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml ++++ b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml +@@ -210,6 +210,7 @@ + + + ++ + 9002050 + 43100285 + v9.2.0-1636-gffaf7f0376 +-- +2.48.1 diff --git a/libvirt-qemu-complete-vhostuser-passt-support.patch b/libvirt-qemu-complete-vhostuser-passt-support.patch new file mode 100644 index 0000000..06a68cb --- /dev/null +++ b/libvirt-qemu-complete-vhostuser-passt-support.patch @@ -0,0 +1,663 @@ +From cdc86b7722beaf209df71b57f76dfbb30c6c7305 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Laine Stump +Date: Wed, 12 Feb 2025 16:16:44 -0500 +Subject: [PATCH] qemu: complete vhostuser + passt support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + needs to run the +passt command just as is done for interface type='user', but then add +vhostuser bits to the qemu commandline/monitor command. + +There are some changes to the parsing/validation along with changes to +the vhostuser codepath do do the extra stuff for passt. I tried +keeping them separated into different patches, but then the unit test +failed in a strange way deep down in the bowels of the commandline +generation, so this patch both 1) makes the final changes to +parsing/formatting and 2) adds passt stuff at appropriate places for +vhostuser (as well as making a couple of things *not* happen when the +passt backend is chosen). The result is that you can now have: + + + + ... + + +Then as long as you also have the following as a subelement of +: + + + + + +your passt interfaces will benefit from the greatly improved +efficiency of a vhost-user data path, and all without requiring +special privileges or capabilities *anywhere* (i.e. it works for +unprivileged libvirt (qemu:///session) as well as privileged libvirt). + +Resolves: https://issues.redhat.com/browse/RHEL-77086 +Signed-off-by: Laine Stump +Reviewed-by: Ján Tomko +(cherry picked from commit 1e9054b9c79d721a55f413c2983c5370044f8f60) + +https://issues.redhat.com/browse/RHEL-69455 +Signed-off-by: Laine Stump +--- + src/conf/domain_conf.c | 36 ++++++--- + src/conf/domain_validate.c | 77 +++++++------------ + src/conf/schemas/domaincommon.rng | 32 +++++++- + src/qemu/qemu_command.c | 7 +- + src/qemu/qemu_extdevice.c | 6 +- + src/qemu/qemu_hotplug.c | 21 ++++- + src/qemu/qemu_passt.c | 3 + + src/qemu/qemu_process.c | 15 +++- + src/qemu/qemu_validate.c | 7 +- + ...t-user-slirp-portforward.x86_64-latest.err | 2 +- + .../net-vhostuser-passt.x86_64-latest.args | 42 ++++++++++ + .../net-vhostuser-passt.x86_64-latest.xml | 72 +++++++++++++++++ + tests/qemuxmlconfdata/net-vhostuser-passt.xml | 70 +++++++++++++++++ + tests/qemuxmlconftest.c | 1 + + 14 files changed, 317 insertions(+), 74 deletions(-) + create mode 100644 tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.args + create mode 100644 tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml + create mode 100644 tests/qemuxmlconfdata/net-vhostuser-passt.xml + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index b1e9dda80e..095b9bbaa2 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -9448,9 +9448,25 @@ virDomainNetBackendParseXML(xmlNodePtr node, + g_autofree char *tap = virXMLPropString(node, "tap"); + g_autofree char *vhost = virXMLPropString(node, "vhost"); + +- /* The VIR_DOMAIN_NET_BACKEND_DEFAULT really means 'use hypervisor's +- * builtin SLIRP'. It's reported in domain caps and thus we need to accept +- * it. Hence VIR_XML_PROP_NONE instead of VIR_XML_PROP_NONZERO. */ ++ /* In the case of NET_TYPE_USER, backend type can be unspecified ++ * (i.e. VIR_DOMAIN_NET_BACKEND_DEFAULT) and that means 'use ++ * hypervisor's builtin SLIRP (or if that isn't available, use ++ * passt)'. Similarly, it can also be left unspecified in the case ++ * of NET_TYPE_VHOSTUSER, and then it means "use the traditional ++ * vhost-user backend (which auto-detects between connecting to a ++ * socket created by OVS, or connecting to a standalone socket ++ * used (mostly in testing) to connect the vhost-user interface of ++ * one guest directly to the vhost-user interface of another ++ * guest. ++ * ++ * If backend type is set to 'passt', then in both cases a passt ++ * process will be started, and libvirt will connect that to the ++ * guest interface (either communicating everything over the ++ * socket created by passt using a specific-to-passt protocol ++ * (interface type='user'>), or by using the socket for control ++ * plane messages and shared memory for data using the vhost-user ++ * protocol ()). ++ */ + if (virXMLPropEnum(node, "type", virDomainNetBackendTypeFromString, + VIR_XML_PROP_NONE, &def->backend.type) < 0) { + return -1; +@@ -24581,7 +24597,11 @@ virDomainNetDefFormat(virBuffer *buf, + break; + + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: +- if (def->data.vhostuser->type == VIR_DOMAIN_CHR_TYPE_UNIX) { ++ if (def->data.vhostuser->type == VIR_DOMAIN_CHR_TYPE_UNIX && ++ def->backend.type != VIR_DOMAIN_NET_BACKEND_PASST) { ++ /* in the case of BACKEND_PASST, the values of all of these are either ++ * fixed (type, mode, reconnect), or derived from elsewhere (path) ++ */ + virBufferAddLit(&sourceAttrBuf, " type='unix'"); + virBufferEscapeString(&sourceAttrBuf, " path='%s'", + def->data.vhostuser->data.nix.path); +@@ -24592,7 +24612,6 @@ virDomainNetDefFormat(virBuffer *buf, + virDomainChrSourceReconnectDefFormat(&sourceChildBuf, + &def->data.vhostuser->data.nix.reconnect); + } +- + } + break; + +@@ -24654,15 +24673,14 @@ virDomainNetDefFormat(virBuffer *buf, + } + + case VIR_DOMAIN_NET_TYPE_USER: +- if (def->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) +- virBufferEscapeString(&sourceAttrBuf, " dev='%s'", def->sourceDev); +- break; +- + case VIR_DOMAIN_NET_TYPE_NULL: + case VIR_DOMAIN_NET_TYPE_LAST: + break; + } + ++ if (def->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) ++ virBufferEscapeString(&sourceAttrBuf, " dev='%s'", def->sourceDev); ++ + if (def->hostIP.nips || def->hostIP.nroutes) { + if (virDomainNetIPInfoFormat(&sourceChildBuf, &def->hostIP) < 0) + return -1; +diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c +index dacde1f780..597ae3d938 100644 +--- a/src/conf/domain_validate.c ++++ b/src/conf/domain_validate.c +@@ -2157,67 +2157,46 @@ virDomainNetDefValidate(const virDomainNetDef *net) + return -1; + } + +- if (net->type != VIR_DOMAIN_NET_TYPE_USER) { ++ if (net->type != VIR_DOMAIN_NET_TYPE_USER && ++ net->type != VIR_DOMAIN_NET_TYPE_VHOSTUSER) { + if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", +- _("The 'passt' backend can only be used with interface type='user'")); ++ _("The 'passt' backend can only be used with interface type='user' or type='vhostuser'")); + return -1; + } + } + +- if (net->nPortForwards > 0 && +- (net->type != VIR_DOMAIN_NET_TYPE_USER || +- (net->type == VIR_DOMAIN_NET_TYPE_USER && +- net->backend.type != VIR_DOMAIN_NET_BACKEND_PASST))) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", +- _("The element can only be used with and its 'passt' backend")); +- return -1; +- } ++ if (net->nPortForwards > 0) { ++ size_t p; + +- if (!virNetDevBandwidthValidate(net->bandwidth)) { +- return -1; +- } ++ if ((net->type != VIR_DOMAIN_NET_TYPE_USER && ++ net->type != VIR_DOMAIN_NET_TYPE_VHOSTUSER) || ++ net->backend.type != VIR_DOMAIN_NET_BACKEND_PASST) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("The element can only be used with the 'passt' backend of interface type='user' or type='vhostuser'")); ++ return -1; ++ } + +- switch (net->type) { +- case VIR_DOMAIN_NET_TYPE_USER: +- if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) { +- size_t p; +- +- for (p = 0; p < net->nPortForwards; p++) { +- size_t r; +- virDomainNetPortForward *pf = net->portForwards[p]; +- +- for (r = 0; r < pf->nRanges; r++) { +- virDomainNetPortForwardRange *range = pf->ranges[r]; +- +- if (!range->start +- && (range->end || range->to +- || range->exclude != VIR_TRISTATE_BOOL_ABSENT)) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", +- _("The 'range' of a 'portForward' requires 'start' attribute if 'end', 'to', or 'exclude' is specified")); +- return -1; +- } ++ for (p = 0; p < net->nPortForwards; p++) { ++ size_t r; ++ virDomainNetPortForward *pf = net->portForwards[p]; ++ ++ for (r = 0; r < pf->nRanges; r++) { ++ virDomainNetPortForwardRange *range = pf->ranges[r]; ++ ++ if (!range->start ++ && (range->end || range->to ++ || range->exclude != VIR_TRISTATE_BOOL_ABSENT)) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("The 'range' of a 'portForward' requires 'start' attribute if 'end', 'to', or 'exclude' is specified")); ++ return -1; + } + } + } +- break; ++ } + +- case VIR_DOMAIN_NET_TYPE_VHOSTUSER: +- case VIR_DOMAIN_NET_TYPE_NETWORK: +- case VIR_DOMAIN_NET_TYPE_VDPA: +- case VIR_DOMAIN_NET_TYPE_BRIDGE: +- case VIR_DOMAIN_NET_TYPE_CLIENT: +- case VIR_DOMAIN_NET_TYPE_SERVER: +- case VIR_DOMAIN_NET_TYPE_MCAST: +- case VIR_DOMAIN_NET_TYPE_UDP: +- case VIR_DOMAIN_NET_TYPE_INTERNAL: +- case VIR_DOMAIN_NET_TYPE_DIRECT: +- case VIR_DOMAIN_NET_TYPE_HOSTDEV: +- case VIR_DOMAIN_NET_TYPE_VDS: +- case VIR_DOMAIN_NET_TYPE_ETHERNET: +- case VIR_DOMAIN_NET_TYPE_NULL: +- case VIR_DOMAIN_NET_TYPE_LAST: +- break; ++ if (!virNetDevBandwidthValidate(net->bandwidth)) { ++ return -1; + } + + return 0; +diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng +index cbc093ca7b..d433e95d8b 100644 +--- a/src/conf/schemas/domaincommon.rng ++++ b/src/conf/schemas/domaincommon.rng +@@ -3486,8 +3486,36 @@ + + + +- +- ++ ++ ++ ++ unix ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ server ++ client ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index 1f28de6194..24dac0ce0f 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -8617,11 +8617,12 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver, + if (qemuInterfaceVhostuserConnect(cmd, net, qemuCaps) < 0) + goto cleanup; + +- if (virNetDevOpenvswitchGetVhostuserIfname(net->data.vhostuser->data.nix.path, ++ if (net->backend.type != VIR_DOMAIN_NET_BACKEND_PASST && ++ virNetDevOpenvswitchGetVhostuserIfname(net->data.vhostuser->data.nix.path, + net->data.vhostuser->data.nix.listen, +- &net->ifname) < 0) ++ &net->ifname) < 0) { + goto cleanup; +- ++ } + break; + + case VIR_DOMAIN_NET_TYPE_VDPA: +diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c +index 954cb323a4..2384bab7a6 100644 +--- a/src/qemu/qemu_extdevice.c ++++ b/src/qemu/qemu_extdevice.c +@@ -212,13 +212,15 @@ qemuExtDevicesStart(virQEMUDriver *driver, + for (i = 0; i < def->nnets; i++) { + virDomainNetDef *net = def->nets[i]; + +- if (net->type != VIR_DOMAIN_NET_TYPE_USER) ++ if (net->type != VIR_DOMAIN_NET_TYPE_USER && ++ net->type != VIR_DOMAIN_NET_TYPE_VHOSTUSER) { + continue; ++ } + + if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) { + if (qemuPasstStart(vm, net) < 0) + return -1; +- } else { ++ } else if (net->type == VIR_DOMAIN_NET_TYPE_USER) { + if (qemuSlirpStart(vm, net, incomingMigration) < 0) + return -1; + } +diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c +index de0777d330..c8746f5e22 100644 +--- a/src/qemu/qemu_hotplug.c ++++ b/src/qemu/qemu_hotplug.c +@@ -1262,10 +1262,23 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver, + if (!(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias))) + goto cleanup; + +- if (virNetDevOpenvswitchGetVhostuserIfname(net->data.vhostuser->data.nix.path, +- net->data.vhostuser->data.nix.listen, +- &net->ifname) < 0) +- goto cleanup; ++ if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) { ++ ++ /* vhostuser needs socket path in this location, and when ++ * backend is passt, the path is derived from other info, ++ * not taken from config. ++ */ ++ g_free(net->data.vhostuser->data.nix.path); ++ net->data.vhostuser->data.nix.path = qemuPasstCreateSocketPath(vm, net); ++ ++ if (qemuPasstStart(vm, net) < 0) ++ goto cleanup; ++ } else { ++ if (virNetDevOpenvswitchGetVhostuserIfname(net->data.vhostuser->data.nix.path, ++ net->data.vhostuser->data.nix.listen, ++ &net->ifname) < 0) ++ goto cleanup; ++ } + + if (qemuSecuritySetNetdevLabel(driver, vm, net) < 0) + goto cleanup; +diff --git a/src/qemu/qemu_passt.c b/src/qemu/qemu_passt.c +index 8a3ac4e988..b9616d1c63 100644 +--- a/src/qemu/qemu_passt.c ++++ b/src/qemu/qemu_passt.c +@@ -180,6 +180,9 @@ qemuPasstStart(virDomainObj *vm, + + virCommandClearCaps(cmd); + ++ if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_VHOSTUSER) ++ virCommandAddArg(cmd, "--vhost-user"); ++ + virCommandAddArgList(cmd, + "--one-off", + "--socket", passtSocketName, +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 26ca943dfc..7285fd5ce9 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -64,6 +64,7 @@ + #include "qemu_backup.h" + #include "qemu_dbus.h" + #include "qemu_snapshot.h" ++#include "qemu_passt.h" + + #include "cpu/cpu.h" + #include "cpu/cpu_x86.h" +@@ -5932,12 +5933,23 @@ qemuProcessPrepareDomainNetwork(virDomainObj *vm) + } + break; + ++ case VIR_DOMAIN_NET_TYPE_VHOSTUSER: ++ if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) { ++ /* when using the passt backend, the path of the ++ * unix socket is always derived from other info ++ * *not* manually given in the config, but all the ++ * vhostuser code looks for it there. ++ */ ++ g_free(net->data.vhostuser->data.nix.path); ++ net->data.vhostuser->data.nix.path = qemuPasstCreateSocketPath(vm, net); ++ } ++ break; ++ + case VIR_DOMAIN_NET_TYPE_DIRECT: + case VIR_DOMAIN_NET_TYPE_BRIDGE: + case VIR_DOMAIN_NET_TYPE_NETWORK: + case VIR_DOMAIN_NET_TYPE_ETHERNET: + case VIR_DOMAIN_NET_TYPE_USER: +- case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_MCAST: +@@ -5949,7 +5961,6 @@ qemuProcessPrepareDomainNetwork(virDomainObj *vm) + case VIR_DOMAIN_NET_TYPE_LAST: + break; + } +- + } + return 0; + } +diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c +index eb8c5366f6..f33c0c07b4 100644 +--- a/src/qemu/qemu_validate.c ++++ b/src/qemu/qemu_validate.c +@@ -1736,7 +1736,9 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net, + return -1; + } + +- if (net->type == VIR_DOMAIN_NET_TYPE_USER) { ++ if (net->type == VIR_DOMAIN_NET_TYPE_USER || ++ (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER && ++ net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST)) { + virDomainCapsDeviceNet netCaps = { }; + + virQEMUCapsFillDomainDeviceNetCaps(qemuCaps, &netCaps); +@@ -1811,7 +1813,8 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net, + } + + if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { +- if (!net->data.vhostuser->data.nix.path) { ++ if (!net->data.vhostuser->data.nix.path && ++ net->backend.type != VIR_DOMAIN_NET_BACKEND_PASST) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing required attribute '%1$s' in element '%2$s'"), + "path", "source"); +diff --git a/tests/qemuxmlconfdata/net-user-slirp-portforward.x86_64-latest.err b/tests/qemuxmlconfdata/net-user-slirp-portforward.x86_64-latest.err +index eaa934742e..e231677e57 100644 +--- a/tests/qemuxmlconfdata/net-user-slirp-portforward.x86_64-latest.err ++++ b/tests/qemuxmlconfdata/net-user-slirp-portforward.x86_64-latest.err +@@ -1 +1 @@ +-unsupported configuration: The element can only be used with and its 'passt' backend ++unsupported configuration: The element can only be used with the 'passt' backend of interface type='user' or type='vhostuser' +diff --git a/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.args b/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.args +new file mode 100644 +index 0000000000..21d78d6072 +--- /dev/null ++++ b/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.args +@@ -0,0 +1,42 @@ ++LC_ALL=C \ ++PATH=/bin \ ++HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \ ++USER=test \ ++LOGNAME=test \ ++XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \ ++XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \ ++XDG_CONFIG_HOME=/var/lib/libvirt/qemu/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":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \ ++-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \ ++-accel tcg \ ++-cpu qemu64 \ ++-m size=219136k \ ++-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 \ ++-boot strict=on \ ++-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","read-only":false}' \ ++-device '{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-storage","id":"ide0-0-0","bootindex":1}' \ ++-chardev socket,id=charnet0,path=/var/run/libvirt/qemu/passt/-1-QEMUGuest1-net0.socket \ ++-netdev '{"type":"vhost-user","chardev":"charnet0","id":"hostnet0"}' \ ++-device '{"driver":"virtio-net-pci","netdev":"hostnet0","id":"net0","mac":"00:11:22:33:44:55","bus":"pci.0","addr":"0x2"}' \ ++-chardev socket,id=charnet1,path=/var/run/libvirt/qemu/passt/-1-QEMUGuest1-net1.socket \ ++-netdev '{"type":"vhost-user","chardev":"charnet1","id":"hostnet1"}' \ ++-device '{"driver":"virtio-net-pci","netdev":"hostnet1","id":"net1","mac":"00:11:22:33:44:11","bus":"pci.0","addr":"0x3"}' \ ++-chardev socket,id=charnet2,path=/var/run/libvirt/qemu/passt/-1-QEMUGuest1-net2.socket \ ++-netdev '{"type":"vhost-user","chardev":"charnet2","id":"hostnet2"}' \ ++-device '{"driver":"virtio-net-pci","netdev":"hostnet2","id":"net2","mac":"00:11:22:33:44:11","bus":"pci.0","addr":"0x4"}' \ ++-audiodev '{"id":"audio1","driver":"none"}' \ ++-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ ++-msg timestamp=on +diff --git a/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml b/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml +new file mode 100644 +index 0000000000..26aa4c8d05 +--- /dev/null ++++ b/tests/qemuxmlconfdata/net-vhostuser-passt.x86_64-latest.xml +@@ -0,0 +1,72 @@ ++ ++ QEMUGuest1 ++ c7a5fdbd-edaf-9455-926a-d65c16db1809 ++ 219136 ++ 219136 ++ 1 ++ ++ hvm ++ ++ ++ ++ qemu64 ++ ++ ++ destroy ++ restart ++ destroy ++ ++ /usr/bin/qemu-system-x86_64 ++ ++ ++ ++ ++
++ ++ ++ ++
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
++ ++ ++ ++ ++ ++
++ ++ ++ ++ ++ ++
++ ++ ++ ++