Add vduse live migration features
v3 cover Add vduse live migration features
This series introduces features to the VDUSE (vDPA Device in Userspace) driver to support Live Migration.
Currently, DPDK does not support VDUSE devices live migration because the driver lacks a mechanism to suspend the device and quiesce the rings to initiate the switchover. This series implements the suspend operation to address this limitation.
Furthermore, enabling Live Migration for devices with control virtqueue requires two additional features. Both of them are included in this series.
* Address Spaces ID (ASID) support: This allows QEMU to isolate and intercept the device's CVQ. By doing so, QEMU is able to migrate the device status transparently, without requiring the device to support state save and restore.
* QUEUE_READY: This allows QEMU to control when the dataplane virtqueues are enabled. This ensures the dataplane is started after the device configuration has been fully restored via the CVQ.
It also enables the VIRTIO_NET_F_STATUS feature. This allows the device to signal the driver that it needs to send gratuitous ARP with VIRTIO_NET_S_ANNOUNCE, reducing the Live Migration downtime.
Note that kernel headers are update to v7.3-rc3, not a stable version. This would allow to ack the patches while the kernel uapi is published in 7.3.
v3:
* Include uapi/linux/stddef.h and revert the -D__counted_by from v2.
v2:
* Add -D__counted_by(X)= if the compiler does not support it. It is pulled by the kernel headers.
PATCH v1:
* Move to VDUSE_SET_FEATURES ioctl instead of config space field.
* Add a few bounds control.
* Update kernel headers to v7.3-rc3.
RFC v4:
* Sync headers with Linux's latest existing and proposed UAPI. Both files constants and new ioctl VDUSE_SET_FEATURES.
* Check for more error conditions and clarified some error messages in ready message processing.
* Add relevant release notes.
* Fix cosmetic whitespaces & checkpath errors.
* Fix error path of vhost_user_iotlb_init and vhost_user_iotlb_init_one.
* Fix commits author.
RFC v3:
* Replace incorrect '%lx' DEBUG print format specifier with PRIx64
RFC v2:
* Following latest comments on kernel series about VDUSE features, not checking API version but only check if VDUSE_GET_FEATURES success.
* Move the start and last declarations in the braces as gcc 8 does not like them interleaved with statements. Actually, I think the move was a mistake in the first version.
https://mails.dpdk.org/archives/test-report/2026-February/958175.html
Eugenio Pérez (3):
uapi: import VDUSE and VFIO header from v7.3-rc5 kernel
vhost: Support VDUSE QUEUE_READY feature
vhost: Support vduse suspend feature
Maxime Coquelin (6):
vhost: introduce ASID support
vhost: add VDUSE API version negotiation
vhost: add virtqueues groups support to VDUSE
vhost: add ASID support to VDUSE IOTLB operations
vhost: claim VDUSE support for API version 1
vhost: add net status feature to VDUSE
kernel/linux/uapi/linux/stddef.h | 85 +++++++++++ kernel/linux/uapi/linux/vduse.h | 115 ++++++++++++++- kernel/linux/uapi/linux/vfio.h | 91 +++++++++++- kernel/linux/uapi/version | 2 +- lib/vhost/iotlb.c | 233 ++++++++++++++++++------------ lib/vhost/iotlb.h | 14 +- lib/vhost/vduse.c | 239 +++++++++++++++++++++++++++++-- lib/vhost/vduse.h | 3 +- lib/vhost/vhost.c | 16 +-- lib/vhost/vhost.h | 16 +-- lib/vhost/vhost_user.c | 13 +- 11 files changed, 685 insertions(+), 142 deletions(-) create mode 100644 kernel/linux/uapi/linux/stddef.h
Signature · 1 line
2.55.0
PATCH v3 1/9 uapi: import VDUSE and VFIO header from v7.3-rc5 kernel
This header will be used by the Vhost library.
Including also uapi/linux/stddef.h, which defines __counted_by if the compiler does not support it.
--- kernel/linux/uapi/linux/stddef.h | 85 +++++++++++++++++++++++ kernel/linux/uapi/linux/vduse.h | 115 +++++++++++++++++++++++++++++-- kernel/linux/uapi/linux/vfio.h | 91 +++++++++++++++++++++++- kernel/linux/uapi/version | 2 +- 4 files changed, 284 insertions(+), 9 deletions(-) create mode 100644 kernel/linux/uapi/linux/stddef.h
kernel/linux/uapi/linux/stddef.h new file +85 -0
@@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_STDDEF_H +#define _LINUX_STDDEF_H + +#ifdef __KERNEL__ +#include <linux/compiler_types.h> +#endif + +#ifndef __always_inline +#define __always_inline inline +#endif + +/* Not all C++ standards support type declarations inside an anonymous union */ +#ifndef __cplusplus +#define __struct_group_tag (TAG ) TAG +#else +#define __struct_group_tag (TAG ) +#endif + +/** +* __struct_group() - Create a mirrored named and anonyomous struct +* +* @TAG: The tag name for the named sub-struct (usually empty) +* @NAME: The identifier name of the mirrored sub-struct +* @ATTRS: Any struct attributes (usually empty) +* @MEMBERS: The member declarations for the mirrored structs +* +* Used to create an anonymous union of two structs with identical layout +* and size: one anonymous and one named. The former's members can be used +* normally without sub-struct naming, and the latter can be used to +* reason about the start, end, and size of the group of struct members. +* The named struct can also be explicitly tagged for layer reuse (C only), +* as well as both having struct attributes appended. +*/ +#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \ + union { \ + struct { MEMBERS } ATTRS; \ + struct __struct_group_tag(TAG) { MEMBERS } ATTRS NAME; \ + } ATTRS + +#ifdef __cplusplus +/* sizeof(struct{}) is 1 in C++, not 0, can't use C version of the macro. */ +#define __DECLARE_FLEX_ARRAY (T , member) \ + T member[0] +#else +/** +* __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union +* +* @TYPE: The type of each flexible array element +* @NAME: The name of the flexible array member +* +* In order to have a flexible array member in a union or alone in a +* struct, it needs to be wrapped in an anonymous struct with at least 1 +* named member, but that member can be empty. +*/ +#define __DECLARE_FLEX_ARRAY (TYPE ,NAME ) \ + struct { \ + struct { } __empty_ ## NAME; \ + TYPE NAME[]; \ + } +#endif + +#ifndef __counted_by +#define __counted_by (m) +#endif + +#ifndef __counted_by_le +#define __counted_by_le (m) +#endif + +#ifndef __counted_by_be +#define __counted_by_be (m) +#endif + +#ifndef __counted_by_ptr +#define __counted_by_ptr (m) +#endif + +#ifdef __KERNEL__ +#define __kernel_nonstring __nonstring +#else +#define __kernel_nonstring +#endif + +#endif /* _LINUX_STDDEF_H */
kernel/linux/uapi/linux/vduse.h +109 -6
216 lines not on this page · raw message
kernel/linux/uapi/linux/vfio.h +89 -2
149 lines not on this page · raw message
kernel/linux/uapi/version +1 -1
@@ -1 +1 @@ -v6.16 +v7.3-rc5
Signature · 1 line
2.55.0
Re: [PATCH v3 1/9] uapi: import VDUSE and VFIO header from v7.3-rc5 kernel
Quoted 95 lines · Eugenio Pérez
This header will be used by the Vhost library.
Including also
uapi/linux/stddef.h, which defines__counted_byif the compiler does not support it.Signed-off-by Eugenio Pérez <[email protected]>--- kernel/linux/uapi/linux/stddef.h | 85 +++++++++++++++++++++++ kernel/linux/uapi/linux/vduse.h | 115 +++++++++++++++++++++++++++++-- kernel/linux/uapi/linux/vfio.h | 91 +++++++++++++++++++++++- kernel/linux/uapi/version | 2 +- 4 files changed, 284 insertions(+), 9 deletions(-)create mode 100644
kernel/linux/uapi/linux/stddef.hkernel/linux/uapi/linux/stddef.h new file +75
-0@@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_STDDEF_H +#define _LINUX_STDDEF_H + +#ifdef __KERNEL__ +#include <linux/compiler_types.h> +#endif + +#ifndef __always_inline +#define __always_inline inline +#endif + +/* Not all C++ standards support type declarations inside an anonymous union */ +#ifndef __cplusplus +#define __struct_group_tag (TAG ) TAG +#else +#define __struct_group_tag (TAG ) +#endif + +/** +* __struct_group() - Create a mirrored named and anonyomous struct +* +* @TAG: The tag name for the named sub-struct (usually empty) +* @NAME: The identifier name of the mirrored sub-struct +* @ATTRS: Any struct attributes (usually empty) +* @MEMBERS: The member declarations for the mirrored structs +* +* Used to create an anonymous union of two structs with identical layout +* and size: one anonymous and one named. The former's members can be used +* normally without sub-struct naming, and the latter can be used to +* reason about the start, end, and size of the group of struct members. +* The named struct can also be explicitly tagged for layer reuse (C only), +* as well as both having struct attributes appended. +*/ +#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \ + union { \ + struct { MEMBERS } ATTRS; \ + struct __struct_group_tag(TAG) { MEMBERS } ATTRS NAME; \ + } ATTRS + +#ifdef __cplusplus +/* sizeof(struct{}) is 1 in C++, not 0, can't use C version of the macro. */ +#define __DECLARE_FLEX_ARRAY (T , member) \ + T member[0] +#else +/** +* __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union +* +* @TYPE: The type of each flexible array element +* @NAME: The name of the flexible array member +* +* In order to have a flexible array member in a union or alone in a +* struct, it needs to be wrapped in an anonymous struct with at least 1 +* named member, but that member can be empty. +*/ +#define __DECLARE_FLEX_ARRAY (TYPE ,NAME ) \ + struct { \ + struct { } __empty_ ## NAME; \ + TYPE NAME[]; \ + } +#endif + +#ifndef __counted_by +#define __counted_by (m) +#endif + +#ifndef __counted_by_le +#define __counted_by_le (m) +#endif + +#ifndef __counted_by_be +#define __counted_by_be (m) +#endif + +#ifndef __counted_by_ptr
kernel/linux/uapi/linux/stddef.h line 85
Quoted 10 lines
kernel/linux/uapi/linux/stddef.h new file +10
-0+#define __counted_by_ptr (m) +#endif + +#ifdef __KERNEL__ +#define __kernel_nonstring __nonstring +#else +#define __kernel_nonstring +#endif + +#endif /* _LINUX_STDDEF_H */
Not give my R-by right now as this is imported from a release candidate, but it looks good to me.
Thanks,
Maxime
Re: [PATCH v3 1/9] uapi: import VDUSE and VFIO header from v7.3-rc5 kernel
In reply to Eugenio PérezQuoted 7 lines · Eugenio Pérez
This header will be used by the Vhost library.
Including also
uapi/linux/stddef.h, which defines__counted_byif the compiler does not support it.Signed-off-by Eugenio Pérez <[email protected]>
Unfortunately, we still have a build issue, since linux/vfio.h includes linux/types.h -> linux/posix_types.h -> linux/stddef.h. So our local copy of stddef.h is ignored:
https://github.com/ovsrobot/dpdk/actions/runs/36559664854/job/109377193634#step:19:551
I tried to import both those headers, but I hit a guard for a non sanitised linux/types.h header.
linux/uapi/linux/types.h 2026-09-29 16:24:57.764056484 +0200 renamed from usr/include/linux/types.h 2026-03-04 01:00:00.000000000 +0100 +3 -0
@@ -5,8 +5,13 @@ #include <asm/types.h> #ifndef __ASSEMBLY__ +#ifndef __KERNEL__ +#ifndef __EXPORTED_HEADERS__ +#warning "Attempt to use kernel headers from user space, see
https://kernelnewbies.org/KernelHeaders"
+#endif /* __EXPORTED_HEADERS__ */
+#endif
-#include <linux/posix_types.h>
+#include <uapi/linux/posix_types.h>
#ifdef __SIZEOF_INT128__
typedef __signed__ __int128 __s128 __attribute__((aligned(16)));
We are missing an equivalent of scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ in the devtools/linux-uapi.sh script.
Signature · 1 line
David Marchand
PATCH v3 2/9 vhost: introduce ASID support
In reply to Eugenio PérezFrom: Maxime Coquelin <[email protected]>
Set all ASID = 0 as it is the default when not set explicitly.
--- lib/vhost/iotlb.c | 233 +++++++++++++++++++++++++---------------- lib/vhost/iotlb.h | 14 +-- lib/vhost/vduse.c | 9 +- lib/vhost/vhost.c | 16 +-- lib/vhost/vhost.h | 13 +-- lib/vhost/vhost_user.c | 13 +-- 6 files changed, 177 insertions(+), 121 deletions(-)
lib/vhost/iotlb.c +145 -88
@@ -11,6 +11,16 @@#include "iotlb.h" #include "vhost.h" +struct iotlb { +rte_rwlock_t pending_lock; +struct vhost_iotlb_entry *pool; + TAILQ_HEAD(, vhost_iotlb_entry) list; + TAILQ_HEAD(, vhost_iotlb_entry) pending_list; +int cache_nr; +rte_spinlock_t free_lock; + SLIST_HEAD(, vhost_iotlb_entry) free_list; +}; +struct vhost_iotlb_entry {TAILQ_ENTRY (vhost_iotlb_entry) next;SLIST_ENTRY (vhost_iotlb_entry) next_free;
@@ -85,78 +95,78 @@ vhost_user_iotlb_clear_dump(struct virtio_net *dev, struct vhost_iotlb_entry *no }static struct vhost_iotlb_entry * -vhost_user_iotlb_pool_get (struct virtio_net *dev) +vhost_user_iotlb_pool_get (struct virtio_net *dev,int asid) {struct vhost_iotlb_entry *node; -rte_spinlock_lock (&dev->iotlb_free_lock); - node =SLIST_FIRST (&dev->iotlb_free_list); +rte_spinlock_lock (&dev->iotlb[asid]->free_lock); + node =SLIST_FIRST (&dev->iotlb[asid]->free_list);if (node !=NULL ) -SLIST_REMOVE_HEAD (&dev->iotlb_free_list, next_free); -rte_spinlock_unlock (&dev->iotlb_free_lock); +SLIST_REMOVE_HEAD (&dev->iotlb[asid]->free_list, next_free); +rte_spinlock_unlock (&dev->iotlb[asid]->free_lock);return node; }static void -vhost_user_iotlb_pool_put (struct virtio_net *dev,struct vhost_iotlb_entry *node) +vhost_user_iotlb_pool_put (struct virtio_net *dev,int asid,struct vhost_iotlb_entry *node) { -rte_spinlock_lock (&dev->iotlb_free_lock); -SLIST_INSERT_HEAD (&dev->iotlb_free_list, node, next_free); -rte_spinlock_unlock (&dev->iotlb_free_lock); +rte_spinlock_lock (&dev->iotlb[asid]->free_lock); +SLIST_INSERT_HEAD (&dev->iotlb[asid]->free_list, node, next_free); +rte_spinlock_unlock (&dev->iotlb[asid]->free_lock); }static void -vhost_user_iotlb_cache_random_evict (struct virtio_net *dev); +vhost_user_iotlb_cache_random_evict (struct virtio_net *dev,int asid);static void -vhost_user_iotlb_pending_remove_all (struct virtio_net *dev) +vhost_user_iotlb_pending_remove_all (struct virtio_net *dev,int asid) {struct vhost_iotlb_entry *node, *temp_node; -rte_rwlock_write_lock (&dev->iotlb_pending_lock); +rte_rwlock_write_lock (&dev->iotlb[asid]->pending_lock); - RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb_pending_list, next, temp_node) { -TAILQ_REMOVE (&dev->iotlb_pending_list, node, next); -vhost_user_iotlb_pool_put (dev, node); + RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb[asid]->pending_list, next, temp_node) { +TAILQ_REMOVE (&dev->iotlb[asid]->pending_list, node, next); +vhost_user_iotlb_pool_put (dev, asid, node); } -rte_rwlock_write_unlock (&dev->iotlb_pending_lock); +rte_rwlock_write_unlock (&dev->iotlb[asid]->pending_lock); }bool -vhost_user_iotlb_pending_miss (struct virtio_net *dev,uint64_t iova,uint8_t perm) +vhost_user_iotlb_pending_miss (struct virtio_net *dev,int asid,uint64_t iova,uint8_t perm) {struct vhost_iotlb_entry *node;bool found = false; -rte_rwlock_read_lock (&dev->iotlb_pending_lock); +rte_rwlock_read_lock (&dev->iotlb[asid]->pending_lock); - TAILQ_FOREACH(node, &dev->iotlb_pending_list, next) { + TAILQ_FOREACH(node, &dev->iotlb[asid]->pending_list, next) {if ((node->iova == iova) && (node->perm == perm)) { found = true;break ; } } -rte_rwlock_read_unlock (&dev->iotlb_pending_lock); +rte_rwlock_read_unlock (&dev->iotlb[asid]->pending_lock);return found; }void -vhost_user_iotlb_pending_insert (struct virtio_net *dev,uint64_t iova,uint8_t perm) +vhost_user_iotlb_pending_insert (struct virtio_net *dev,int asid,uint64_t iova,uint8_t perm) {struct vhost_iotlb_entry *node; - node =vhost_user_iotlb_pool_get (dev); + node =vhost_user_iotlb_pool_get (dev, asid);if (node ==NULL ) {VHOST_CONFIG_LOG (dev->ifname,DEBUG ,"IOTLB pool empty, clear entries for pending insertion" ); -if (!TAILQ_EMPTY (&dev->iotlb_pending_list)) -vhost_user_iotlb_pending_remove_all (dev); +if (!TAILQ_EMPTY (&dev->iotlb[asid]->pending_list)) +vhost_user_iotlb_pending_remove_all (dev, asid);else -vhost_user_iotlb_cache_random_evict (dev); - node =vhost_user_iotlb_pool_get (dev); +vhost_user_iotlb_cache_random_evict (dev, asid); + node =vhost_user_iotlb_pool_get (dev, asid);if (node ==NULL ) {VHOST_CONFIG_LOG (dev->ifname,ERR ,"IOTLB pool still empty, pending insertion failure" );
@@ -167,21 +177,22 @@ vhost_user_iotlb_pending_insert(struct virtio_net *dev, uint64_t iova, uint8_t p node->iova = iova; node->perm = perm; -rte_rwlock_write_lock (&dev->iotlb_pending_lock); +rte_rwlock_write_lock (&dev->iotlb[asid]->pending_lock); -TAILQ_INSERT_TAIL (&dev->iotlb_pending_list, node, next); +TAILQ_INSERT_TAIL (&dev->iotlb[asid]->pending_list, node, next); -rte_rwlock_write_unlock (&dev->iotlb_pending_lock); +rte_rwlock_write_unlock (&dev->iotlb[asid]->pending_lock); }void -vhost_user_iotlb_pending_remove (struct virtio_net *dev,uint64_t iova,uint64_t size,uint8_t perm) +vhost_user_iotlb_pending_remove (struct virtio_net *dev,int asid, +uint64_t iova,uint64_t size,uint8_t perm) {struct vhost_iotlb_entry *node, *temp_node; -rte_rwlock_write_lock (&dev->iotlb_pending_lock); +rte_rwlock_write_lock (&dev->iotlb[asid]->pending_lock); -RTE_TAILQ_FOREACH_SAFE (node, &dev->iotlb_pending_list, next, +RTE_TAILQ_FOREACH_SAFE (node, &dev->iotlb[asid]->pending_list, next, temp_node) {if (node->iova < iova)continue ;
@@ -189,53 +200,53 @@ vhost_user_iotlb_pending_remove(struct virtio_net *dev, uint64_t iova, uint64_tcontinue ;if ((node->perm & perm) != node->perm)continue ; -TAILQ_REMOVE (&dev->iotlb_pending_list, node, next); -vhost_user_iotlb_pool_put (dev, node); +TAILQ_REMOVE (&dev->iotlb[asid]->pending_list, node, next); +vhost_user_iotlb_pool_put (dev, asid, node); } -rte_rwlock_write_unlock (&dev->iotlb_pending_lock); +rte_rwlock_write_unlock (&dev->iotlb[asid]->pending_lock); }static void -vhost_user_iotlb_cache_remove_all (struct virtio_net *dev) +vhost_user_iotlb_cache_remove_all (struct virtio_net *dev,int asid) {struct vhost_iotlb_entry *node, *temp_node;vhost_user_iotlb_wr_lock_all (dev); - RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb_list, next, temp_node) { + RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb[asid]->list, next, temp_node) {vhost_user_iotlb_clear_dump (dev, node,NULL ,NULL ); -TAILQ_REMOVE (&dev->iotlb_list, node, next); +TAILQ_REMOVE (&dev->iotlb[asid]->list, node, next);vhost_user_iotlb_remove_notify (dev, node); -vhost_user_iotlb_pool_put (dev, node); +vhost_user_iotlb_pool_put (dev, asid, node); } - dev->iotlb_cache_nr =0 ; + dev->iotlb[asid]->cache_nr =0 ;vhost_user_iotlb_wr_unlock_all (dev); }static void -vhost_user_iotlb_cache_random_evict (struct virtio_net *dev) +vhost_user_iotlb_cache_random_evict (struct virtio_net *dev,int asid) {struct vhost_iotlb_entry *node, *temp_node, *prev_node =NULL ;int entry_idx;vhost_user_iotlb_wr_lock_all (dev); - entry_idx =rte_rand () % dev->iotlb_cache_nr; + entry_idx =rte_rand () % dev->iotlb[asid]->cache_nr; - RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb_list, next, temp_node) { + RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb[asid]->list, next, temp_node) {if (!entry_idx) {struct vhost_iotlb_entry *next_node =RTE_TAILQ_NEXT (node, next);vhost_user_iotlb_clear_dump (dev, node, prev_node, next_node); -TAILQ_REMOVE (&dev->iotlb_list, node, next); +TAILQ_REMOVE (&dev->iotlb[asid]->list, node, next);vhost_user_iotlb_remove_notify (dev, node); -vhost_user_iotlb_pool_put (dev, node); - dev->iotlb_cache_nr--; +vhost_user_iotlb_pool_put (dev, asid, node); + dev->iotlb[asid]->cache_nr--;break ; } prev_node = node;
@@ -246,20 +257,20 @@ vhost_user_iotlb_cache_random_evict(struct virtio_net *dev) }void -vhost_user_iotlb_cache_insert (struct virtio_net *dev,uint64_t iova,uint64_t uaddr, +vhost_user_iotlb_cache_insert (struct virtio_net *dev,int asid,uint64_t iova,uint64_t uaddr,uint64_t uoffset,uint64_t size,uint64_t page_size,uint8_t perm) {struct vhost_iotlb_entry *node, *new_node; - new_node =vhost_user_iotlb_pool_get (dev); + new_node =vhost_user_iotlb_pool_get (dev, asid);if (new_node ==NULL ) {VHOST_CONFIG_LOG (dev->ifname,DEBUG ,"IOTLB pool empty, clear entries for cache insertion" ); -if (!TAILQ_EMPTY (&dev->iotlb_list)) -vhost_user_iotlb_cache_random_evict (dev); +if (!TAILQ_EMPTY (&dev->iotlb[asid]->list)) +vhost_user_iotlb_cache_random_evict (dev, asid);else -vhost_user_iotlb_pending_remove_all (dev); - new_node =vhost_user_iotlb_pool_get (dev); +vhost_user_iotlb_pending_remove_all (dev, asid); + new_node =vhost_user_iotlb_pool_get (dev, asid);if (new_node ==NULL ) {VHOST_CONFIG_LOG (dev->ifname,ERR ,"IOTLB pool still empty, cache insertion failed" );
@@ -276,36 +287,36 @@ vhost_user_iotlb_cache_insert(struct virtio_net *dev, uint64_t iova, uint64_t uavhost_user_iotlb_wr_lock_all (dev); - TAILQ_FOREACH(node, &dev->iotlb_list, next) { + TAILQ_FOREACH(node, &dev->iotlb[asid]->list, next) {/* * Entries must be invalidated before being updated. * So if iova already in list, assume identical. */ if (node->iova == new_node->iova) { -vhost_user_iotlb_pool_put (dev, new_node); +vhost_user_iotlb_pool_put (dev, asid, new_node); goto unlock; }else if (node->iova > new_node->iova) {vhost_user_iotlb_set_dump (dev, new_node);TAILQ_INSERT_BEFORE (node, new_node, next); - dev->iotlb_cache_nr++; + dev->iotlb[asid]->cache_nr++; goto unlock; } }vhost_user_iotlb_set_dump (dev, new_node); -TAILQ_INSERT_TAIL (&dev->iotlb_list, new_node, next); - dev->iotlb_cache_nr++; +TAILQ_INSERT_TAIL (&dev->iotlb[asid]->list, new_node, next); + dev->iotlb[asid]->cache_nr++; unlock: -vhost_user_iotlb_pending_remove (dev, iova, size, perm); +vhost_user_iotlb_pending_remove (dev, asid, iova, size, perm);vhost_user_iotlb_wr_unlock_all (dev); }void -vhost_user_iotlb_cache_remove (struct virtio_net *dev,uint64_t iova,uint64_t size) +vhost_user_iotlb_cache_remove (struct virtio_net *dev,int asid,uint64_t iova,uint64_t size) {struct vhost_iotlb_entry *node, *temp_node, *prev_node =NULL ;
@@ -314,7 +325,7 @@ vhost_user_iotlb_cache_remove(struct virtio_net *dev, uint64_t iova, uint64_t sivhost_user_iotlb_wr_lock_all (dev); - RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb_list, next, temp_node) { + RTE_TAILQ_FOREACH_SAFE(node, &dev->iotlb[asid]->list, next, temp_node) {/* Sorted list */ if (unlikely (iova + size < node->iova))break ;
@@ -324,10 +335,10 @@ vhost_user_iotlb_cache_remove(struct virtio_net *dev, uint64_t iova, uint64_t sivhost_user_iotlb_clear_dump (dev, node, prev_node, next_node); -TAILQ_REMOVE (&dev->iotlb_list, node, next); +TAILQ_REMOVE (&dev->iotlb[asid]->list, node, next);vhost_user_iotlb_remove_notify (dev, node); -vhost_user_iotlb_pool_put (dev, node); - dev->iotlb_cache_nr--; +vhost_user_iotlb_pool_put (dev, asid, node); + dev->iotlb[asid]->cache_nr--; }else { prev_node = node; }
@@ -337,7 +348,8 @@ vhost_user_iotlb_cache_remove(struct virtio_net *dev, uint64_t iova, uint64_t si }uint64_t -vhost_user_iotlb_cache_find (struct virtio_net *dev,uint64_t iova,uint64_t *size,uint8_t perm) +vhost_user_iotlb_cache_find (struct virtio_net *dev,int asid, +uint64_t iova,uint64_t *size,uint8_t perm) {struct vhost_iotlb_entry *node;uint64_t offset, vva =0 , mapped =0 ;
@@ -345,7 +357,7 @@ vhost_user_iotlb_cache_find(struct virtio_net *dev, uint64_t iova, uint64_t *sizif (unlikely (!*size)) goto out; - TAILQ_FOREACH(node, &dev->iotlb_list, next) { + TAILQ_FOREACH(node, &dev->iotlb[asid]->list, next) {/* List sorted by iova */ if (unlikely (iova < node->iova))break ;
@@ -378,25 +390,28 @@ vhost_user_iotlb_cache_find(struct virtio_net *dev, uint64_t iova, uint64_t *siz }void -vhost_user_iotlb_flush_all (struct virtio_net *dev) +vhost_user_iotlb_flush_all (struct virtio_net *dev,int asid) { -vhost_user_iotlb_cache_remove_all (dev); -vhost_user_iotlb_pending_remove_all (dev); +vhost_user_iotlb_cache_remove_all (dev, asid); +vhost_user_iotlb_pending_remove_all (dev, asid); } -int -vhost_user_iotlb_init (struct virtio_net *dev) +static int +vhost_user_iotlb_init_one (struct virtio_net *dev,int asid) {unsigned int i;int socket =0 ; -if (dev->iotlb_pool) { -/* -* The cache has already been initialized, -* just drop all cached and pending entries. -*/ -vhost_user_iotlb_flush_all (dev); -rte_free (dev->iotlb_pool); +if (dev->iotlb[asid] !=NULL ) { +if (dev->iotlb[asid]->pool !=NULL ) { +/* +* The cache has already been initialized, +* just drop all cached and pending entries. +*/ +vhost_user_iotlb_flush_all (dev, asid); +rte_free (dev->iotlb[asid]->pool); + } +rte_free (dev->iotlb[asid]); }#ifdef RTE_LIBRTE_VHOST_NUMA
@@ -404,31 +419,73 @@ vhost_user_iotlb_init(struct virtio_net *dev) socket =0 ;#endif -rte_spinlock_init (&dev->iotlb_free_lock); -rte_rwlock_init (&dev->iotlb_pending_lock); + dev->iotlb[asid] =rte_malloc_socket ("iotlb" ,sizeof (struct iotlb ),0 , socket); +if (!dev->iotlb[asid]) { +VHOST_CONFIG_LOG (dev->ifname,ERR ,"Failed to allocate IOTLB" ); +return -1 ; + } + +rte_spinlock_init (&dev->iotlb[asid]->free_lock); +rte_rwlock_init (&dev->iotlb[asid]->pending_lock); -SLIST_INIT (&dev->iotlb_free_list); -TAILQ_INIT (&dev->iotlb_list); -TAILQ_INIT (&dev->iotlb_pending_list); +SLIST_INIT (&dev->iotlb[asid]->free_list); +TAILQ_INIT (&dev->iotlb[asid]->list); +TAILQ_INIT (&dev->iotlb[asid]->pending_list);if (dev->flags &VIRTIO_DEV_SUPPORT_IOMMU ) { - dev->iotlb_pool =rte_calloc_socket ("iotlb" ,IOTLB_CACHE_SIZE , + dev->iotlb[asid]->pool =rte_calloc_socket ("iotlb_pool" ,IOTLB_CACHE_SIZE ,sizeof (struct vhost_iotlb_entry ),0 , socket); -if (!dev->iotlb_pool) { +if (!dev->iotlb[asid]->pool) {VHOST_CONFIG_LOG (dev->ifname,ERR ,"Failed to create IOTLB cache pool" ); -return -1 ; + goto free_iotlb; }for (i =0 ; i <IOTLB_CACHE_SIZE ; i++) -vhost_user_iotlb_pool_put (dev, &dev->iotlb_pool[i]); +vhost_user_iotlb_pool_put (dev, asid, &dev->iotlb[asid]->pool[i]); } - dev->iotlb_cache_nr =0 ; + dev->iotlb[asid]->cache_nr =0 ; + +return 0 ; + +free_iotlb: +rte_free (dev->iotlb[asid]); + dev->iotlb[asid] =NULL ; +return -1 ; +} + +int +vhost_user_iotlb_init (struct virtio_net *dev) +{ +int i; + +for (i =0 ; i <IOTLB_MAX_ASID ; i++) +if (vhost_user_iotlb_init_one (dev, i) <0 ) + goto fail;return 0 ; +fail: +while (i--) { +rte_free (dev->iotlb[i]->pool); + dev->iotlb[i]->pool =NULL ; +rte_free (dev->iotlb[i]); + dev->iotlb[i] =NULL ; + } + +return -1 ; }void vhost_user_iotlb_destroy (struct virtio_net *dev) { -rte_free (dev->iotlb_pool); +int i; + +for (i =0 ; i <IOTLB_MAX_ASID ; i++) { +if (dev->iotlb[i]) { +rte_free (dev->iotlb[i]->pool); + dev->iotlb[i]->pool =NULL ; + +rte_free (dev->iotlb[i]); + dev->iotlb[i] =NULL ; + } + } }
lib/vhost/iotlb.h +7 -7
@@ -57,16 +57,16 @@ vhost_user_iotlb_wr_unlock_all(struct virtio_net *dev)rte_rwlock_write_unlock (&dev->virtqueue[i]->iotlb_lock); } -void vhost_user_iotlb_cache_insert (struct virtio_net *dev,uint64_t iova,uint64_t uaddr, +void vhost_user_iotlb_cache_insert (struct virtio_net *dev,int asid,uint64_t iova,uint64_t uaddr,uint64_t uoffset,uint64_t size,uint64_t page_size,uint8_t perm); -void vhost_user_iotlb_cache_remove (struct virtio_net *dev,uint64_t iova,uint64_t size); -uint64_t vhost_user_iotlb_cache_find (struct virtio_net *dev,uint64_t iova, +void vhost_user_iotlb_cache_remove (struct virtio_net *dev,int asid,uint64_t iova,uint64_t size); +uint64_t vhost_user_iotlb_cache_find (struct virtio_net *dev,int asid,uint64_t iova,uint64_t *size,uint8_t perm); -bool vhost_user_iotlb_pending_miss (struct virtio_net *dev,uint64_t iova,uint8_t perm); -void vhost_user_iotlb_pending_insert (struct virtio_net *dev,uint64_t iova,uint8_t perm); -void vhost_user_iotlb_pending_remove (struct virtio_net *dev,uint64_t iova, +bool vhost_user_iotlb_pending_miss (struct virtio_net *dev,int asid,uint64_t iova,uint8_t perm); +void vhost_user_iotlb_pending_insert (struct virtio_net *dev,int asid,uint64_t iova,uint8_t perm); +void vhost_user_iotlb_pending_remove (struct virtio_net *dev,int asid,uint64_t iova,uint64_t size,uint8_t perm); -void vhost_user_iotlb_flush_all (struct virtio_net *dev); +void vhost_user_iotlb_flush_all (struct virtio_net *dev,int asid);int vhost_user_iotlb_init (struct virtio_net *dev);void vhost_user_iotlb_destroy (struct virtio_net *dev);
lib/vhost/vduse.c +5 -4
@@ -57,7 +57,7 @@ vduse_iotlb_remove_notify(uint64_t addr, uint64_t offset, uint64_t size) }static int -vduse_iotlb_miss(struct virtio_net *dev, uint64_t iova, uint8_t perm __rte_unused) +vduse_iotlb_miss(struct virtio_net *dev, int asid, uint64_t iova, uint8_t perm __rte_unused) {struct vduse_iotlb_entry entry;uint64_t size, page_size;
@@ -102,7 +102,7 @@ vduse_iotlb_miss(struct virtio_net *dev, uint64_t iova, uint8_t perm __rte_unuse } page_size = (uint64_t )stat.st_blksize; -vhost_user_iotlb_cache_insert (dev, entry.start, (uint64_t )(uintptr_t )mmap_addr, +vhost_user_iotlb_cache_insert (dev, asid, entry.start, (uint64_t )(uintptr_t )mmap_addr, entry.offset, size, page_size, entry.perm); ret =0 ;
@@ -398,7 +398,8 @@ vduse_device_stop(struct virtio_net *dev)for (i =0 ; i < dev->nr_vring; i++)vduse_vring_cleanup (dev, i); -vhost_user_iotlb_flush_all (dev); +for (i =0 ; i <IOTLB_MAX_ASID ; i++) +vhost_user_iotlb_flush_all (dev, i); } static void
@@ -445,7 +446,7 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused)case VDUSE_UPDATE_IOTLB :VHOST_CONFIG_LOG (dev->ifname,INFO ,"\tIOVA range: %" PRIx64" - %" PRIx64, (uint64_t )req.iova.start, (uint64_t )req.iova.last); -vhost_user_iotlb_cache_remove (dev, req.iova.start, +vhost_user_iotlb_cache_remove (dev,0 , req.iova.start, req.iova.last - req.iova.start +1 ); resp.result =VDUSE_REQ_RESULT_OK ;break ;
lib/vhost/vhost.c +8 -8
@@ -62,9 +62,9 @@ static const struct vhost_vq_stats_name_off vhost_vq_stat_strings[] = {#define VHOST_NB_VQ_STATS RTE_DIM(vhost_vq_stat_strings)static int -vhost_iotlb_miss (struct virtio_net *dev,uint64_t iova,uint8_t perm) +vhost_iotlb_miss (struct virtio_net *dev,int asid,uint64_t iova,uint8_t perm) { -return dev->backend_ops->iotlb_miss (dev, iova, perm); +return dev->backend_ops->iotlb_miss (dev, asid, iova, perm); }uint64_t
@@ -78,7 +78,7 @@ __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, tmp_size = *size; - vva =vhost_user_iotlb_cache_find (dev, iova, &tmp_size, perm); + vva =vhost_user_iotlb_cache_find (dev, vq->asid, iova, &tmp_size, perm);if (tmp_size == *size) {if (dev->flags &VIRTIO_DEV_STATS_ENABLED ) vq->stats.iotlb_hits++;
@@ -90,7 +90,7 @@ __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, iova += tmp_size; -if (!vhost_user_iotlb_pending_miss (dev, iova, perm)) { +if (!vhost_user_iotlb_pending_miss (dev, vq->asid, iova, perm)) {/* * iotlb_lock is read-locked for a full burst, * but it only protects the iotlb cache.
@@ -100,12 +100,12 @@ __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,*/ vhost_user_iotlb_rd_unlock (vq); -vhost_user_iotlb_pending_insert (dev, iova, perm); -if (vhost_iotlb_miss (dev, iova, perm)) { +vhost_user_iotlb_pending_insert (dev, vq->asid, iova, perm); +if (vhost_iotlb_miss (dev, vq->asid, iova, perm)) {VHOST_DATA_LOG (dev->ifname,ERR ,"IOTLB miss req failed for IOVA 0x%" PRIx64, iova); -vhost_user_iotlb_pending_remove (dev, iova,1 , perm); +vhost_user_iotlb_pending_remove (dev, vq->asid, iova,1 , perm); }vhost_user_iotlb_rd_lock (vq);
@@ -113,7 +113,7 @@ __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, tmp_size = *size;/* Retry in case of VDUSE, as it is synchronous */ - vva =vhost_user_iotlb_cache_find (dev, iova, &tmp_size, perm); + vva =vhost_user_iotlb_cache_find (dev, vq->asid, iova, &tmp_size, perm);if (tmp_size == *size)return vva;
lib/vhost/vhost.h +5 -8
@@ -85,7 +85,7 @@ struct vhost_virtqueue;typedef void (*vhost_iotlb_remove_notify )(uint64_t addr,uint64_t off,uint64_t size); -typedef int (*vhost_iotlb_miss_cb )(struct virtio_net *dev,uint64_t iova,uint8_t perm); +typedef int (*vhost_iotlb_miss_cb )(struct virtio_net *dev,int asid,uint64_t iova,uint8_t perm);typedef int (*vhost_vring_inject_irq_cb )(struct virtio_net *dev,struct vhost_virtqueue *vq);/**
@@ -326,6 +326,7 @@ struct __rte_cache_aligned vhost_virtqueue {uint16_t batch_copy_nb_elems;struct batch_copy_elem *batch_copy_elems;int numa_node; +int asid;bool used_wrap_counter;bool avail_wrap_counter;
@@ -483,6 +484,8 @@ struct inflight_mem_info {uint64_t size; }; +#define IOTLB_MAX_ASID 2 +/** * Device structure contains all configuration information relating * to the device.
@@ -504,13 +507,7 @@ struct __rte_cache_aligned virtio_net {int linearbuf;struct vhost_virtqueue *virtqueue[VHOST_MAX_VRING ]; -rte_rwlock_t iotlb_pending_lock; -struct vhost_iotlb_entry *iotlb_pool; - TAILQ_HEAD(, vhost_iotlb_entry) iotlb_list; - TAILQ_HEAD(, vhost_iotlb_entry) iotlb_pending_list; -int iotlb_cache_nr; -rte_spinlock_t iotlb_free_lock; - SLIST_HEAD(, vhost_iotlb_entry) iotlb_free_list; +struct iotlb *iotlb[IOTLB_MAX_ASID ];struct inflight_mem_info *inflight_info;#define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
lib/vhost/vhost_user.c +7 -6
@@ -1530,7 +1530,8 @@ vhost_user_set_mem_table(struct virtio_net **pdev,/* Flush IOTLB cache as previous HVAs are now invalid */ if (dev->features & (1ULL <<VIRTIO_F_IOMMU_PLATFORM )) -vhost_user_iotlb_flush_all (dev); +for (i =0 ; i <IOTLB_MAX_ASID ; i++) +vhost_user_iotlb_flush_all (dev, i);free_all_mem_regions (dev);rte_free (dev->mem);
@@ -1830,7 +1831,7 @@ vhost_user_rem_mem_reg(struct virtio_net **pdev,if (dev->async_copy &&rte_vfio_is_enabled ("vfio" ))async_dma_map_region (dev, current_region, false);if (dev->features & (1ULL <<VIRTIO_F_IOMMU_PLATFORM )) -vhost_user_iotlb_cache_remove (dev, +vhost_user_iotlb_cache_remove (dev,0 , current_region->guest_phys_addr, current_region->size);remove_guest_pages (dev, current_region);
@@ -2581,7 +2582,7 @@ vhost_user_get_vring_base(struct virtio_net **pdev, ctx->msg.size =sizeof (ctx->msg.payload.state); ctx->fd_num =0 ; -vhost_user_iotlb_flush_all (dev); +vhost_user_iotlb_flush_all (dev, vq->asid);rte_rwlock_write_lock (&vq->access_lock);vring_invalidate (dev, vq);
@@ -3030,7 +3031,7 @@ vhost_user_iotlb_msg(struct virtio_net **pdev, pg_sz =hua_to_alignment (dev->mem, (void *)(uintptr_t )vva); -vhost_user_iotlb_cache_insert (dev, imsg->iova, vva,0 , len, pg_sz, imsg->perm); +vhost_user_iotlb_cache_insert (dev,0 , imsg->iova, vva,0 , len, pg_sz, imsg->perm);for (i =0 ; i < dev->nr_vring; i++) {struct vhost_virtqueue *vq = dev->virtqueue[i];
@@ -3047,7 +3048,7 @@ vhost_user_iotlb_msg(struct virtio_net **pdev, }break ;case VHOST_IOTLB_INVALIDATE : -vhost_user_iotlb_cache_remove (dev, imsg->iova, imsg->size); +vhost_user_iotlb_cache_remove (dev,0 , imsg->iova, imsg->size);for (i =0 ; i < dev->nr_vring; i++) {struct vhost_virtqueue *vq = dev->virtqueue[i];
@@ -3640,7 +3641,7 @@ vhost_user_msg_handler(int vid, int fd) }static int -vhost_user_iotlb_miss (struct virtio_net *dev,uint64_t iova,uint8_t perm) +vhost_user_iotlb_miss(struct virtio_net *dev, int asid __rte_unused, uint64_t iova, uint8_t perm) {int ret;struct vhu_msg_context ctx = {
Signature · 1 line
2.55.0
Re: [PATCH v3 2/9] vhost: introduce ASID support
Quoted 6 lines · Eugenio Pérez
From: Maxime Coquelin <[email protected]>
Set all ASID = 0 as it is the default when not set explicitly.
Signed-off-by Maxime Coquelin <[email protected]>Signed-off-by Eugenio Pérez <[email protected]>
Quoted 9 lines
--- lib/vhost/iotlb.c | 233 +++++++++++++++++++++++++---------------- lib/vhost/iotlb.h | 14 +-- lib/vhost/vduse.c | 9 +- lib/vhost/vhost.c | 16 +-- lib/vhost/vhost.h | 13 +-- lib/vhost/vhost_user.c | 13 +-- 6 files changed, 177 insertions(+), 121 deletions(-)
I was the original author, so more reviews would be welcome. FWIW:
Thanks,
Maxime
PATCH v3 3/9 vhost: add VDUSE API version negotiation
In reply to Eugenio PérezFrom: Maxime Coquelin <[email protected]>
As preliminary step to support new VDUSE API version introducing ASID support, this patch adds API version negotiation to keep compatibility with older kernels.
--- lib/vhost/vduse.c | 14 ++++++++++++-- lib/vhost/vhost.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-)
lib/vhost/vduse.c +12 -2
@@ -25,7 +25,7 @@#include "vhost.h" #include "virtio_net_ctrl.h" -#define VHOST_VDUSE_API_VERSION 0 +#define VHOST_VDUSE_API_VERSION 0ULL#define VDUSE_CTRL_PATH "/dev/vduse/control"struct vduse {
@@ -680,7 +680,7 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, booluint32_t i, max_queue_pairs, total_queues;struct virtio_net *dev;struct virtio_net_config vnet_config = {{0 }}; -uint64_t ver =VHOST_VDUSE_API_VERSION ; +uint64_t ver;uint64_t features;const char *name = path +strlen ("/dev/vduse/" );bool reconnect = false;
@@ -700,6 +700,15 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, boolreturn -1 ; } +if (ioctl (control_fd,VDUSE_GET_API_VERSION , &ver)) { +VHOST_CONFIG_LOG (name,ERR ,"Failed to get API version: %s" ,strerror (errno)); + ret =-1 ; + goto out_ctrl_close; + } + + ver =RTE_MIN (ver,VHOST_VDUSE_API_VERSION ); +VHOST_CONFIG_LOG (name,INFO ,"Using VDUSE API version %" PRIu64"" , ver); +if (ioctl (control_fd,VDUSE_SET_API_VERSION , &ver)) {VHOST_CONFIG_LOG (name,ERR ,"Failed to set API version: %" PRIu64": %s" , ver,strerror (errno));
@@ -800,6 +809,7 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, boolstrlcpy (dev->ifname, path,sizeof (dev->ifname)); dev->vduse_ctrl_fd = control_fd; dev->vduse_dev_fd = dev_fd; + dev->vduse_api_ver = ver; ret =vduse_reconnect_log_map (dev, !reconnect);if (ret <0 )
lib/vhost/vhost.h +1 -0
@@ -532,6 +532,7 @@ struct __rte_cache_aligned virtio_net {int postcopy_listening;int vduse_ctrl_fd;int vduse_dev_fd; +uint64_t vduse_api_ver;struct vhost_virtqueue *cvq;
Signature · 1 line
2.55.0
Re: [PATCH v3 3/9] vhost: add VDUSE API version negotiation
Quoted 6 lines · Eugenio Pérez
From: Maxime Coquelin <[email protected]>
As preliminary step to support new VDUSE API version introducing ASID support, this patch adds API version negotiation to keep compatibility with older kernels.
Quoted 7 lines
Signed-off-by Maxime Coquelin <[email protected]>Signed-off-by Eugenio Pérez <[email protected]>--- lib/vhost/vduse.c | 14 ++++++++++++-- lib/vhost/vhost.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-)
FWIW:
Thanks,
Maxime
PATCH v3 4/9 vhost: add virtqueues groups support to VDUSE
In reply to Eugenio PérezFrom: Maxime Coquelin <[email protected]>
VDUSE API version 1 introduces the notion of virtqueue groups, which once supported, enables the support of multiple addresses spaces.
For VDUSE networking devices, we need two groups, one for the datapath queues, and one for the control queue.
--- lib/vhost/vduse.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-)
lib/vhost/vduse.c +50 -2
@@ -38,12 +38,24 @@ static const char * const vduse_reqs_str[] = {"VDUSE_GET_VQ_STATE" ,"VDUSE_SET_STATUS" ,"VDUSE_UPDATE_IOTLB" , + "VDUSE_SET_VQ_GROUP_ASID", };#define vduse_req_id_to_str (id) \ (id < RTE_DIM(vduse_reqs_str) ? \ vduse_reqs_str[id] : "Unknown") +static uint64_t vduse_vq_to_group (struct virtio_net *dev,struct vhost_virtqueue *vq) +{ +if (dev->vduse_api_ver <1 ) +return 0 ; + +if (vq == dev->cvq) +return 1 ; + +return 0 ; +} +static int vduse_inject_irq (struct virtio_net *dev,struct vhost_virtqueue *vq) {
@@ -271,6 +283,7 @@ vduse_vring_cleanup(struct virtio_net *dev, unsigned int index) vq->size =0 ; vq->last_used_idx =0 ; vq->last_avail_idx =0 ; + vq->asid =0 ; }/*
@@ -410,6 +423,7 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused)struct vduse_dev_response resp;struct vhost_virtqueue *vq;uint8_t old_status = dev->status; +uint32_t i;int ret;memset (&resp,0 ,sizeof (resp));
@@ -450,6 +464,34 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused) req.iova.last - req.iova.start + 1); resp.result =VDUSE_REQ_RESULT_OK ;break ; +case VDUSE_SET_VQ_GROUP_ASID : +if (dev->vduse_api_ver <1 ) { + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } + +if (req.vq_group_asid.asid >=RTE_DIM (dev->iotlb)) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"Invalid ASID %u for group %u" , + req.vq_group_asid.asid, req.vq_group_asid.group); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } + +VHOST_CONFIG_LOG (dev->ifname,INFO ,"\tAssigning ASID %d to group %d" , + req.vq_group_asid.asid, req.vq_group_asid.group); + +for (i =0 ; i < dev->nr_vring; i++) { + vq = dev->virtqueue[i]; + +if (vduse_vq_to_group (dev, vq) == req.vq_group_asid.group) { + vq->asid = req.vq_group_asid.asid; +VHOST_CONFIG_LOG (dev->ifname,INFO ,"\t\tVQ %d gets ASID %d" , + i, req.vq_group_asid.asid); + } + } + resp.result =VDUSE_REQ_RESULT_OK ; +break ;default : resp.result =VDUSE_REQ_RESULT_FAILED ;break ;
@@ -760,6 +802,10 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, bool dev_config->features = features; dev_config->vq_num = total_queues; dev_config->vq_align =rte_mem_page_size (); +if (ver >=1 ) { + dev_config->ngroups =2 ; + dev_config->nas =2 ; + } dev_config->config_size =sizeof (struct virtio_net_config );memcpy (dev_config->config, &vnet_config,sizeof (vnet_config));
@@ -848,11 +894,15 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, bool vq = dev->virtqueue[i]; vq->reconnect_log = &dev->reconnect_log->vring[i]; +if (i == max_queue_pairs *2 ) + dev->cvq = vq; +if (reconnect)continue ; vq_cfg.index = i; vq_cfg.max_size =1024 ; + vq_cfg.group =vduse_vq_to_group (dev, vq); ret =ioctl (dev->vduse_dev_fd,VDUSE_VQ_SETUP , &vq_cfg);if (ret) {
@@ -861,8 +911,6 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, bool } } - dev->cvq = dev->virtqueue[max_queue_pairs *2 ]; - ret =fdset_add (vduse.fdset, dev->vduse_dev_fd, vduse_events_handler,NULL , dev);if (ret) { VHOST_CONFIG_LOG(name, ERR, "Failed to add fd %d to vduse fdset",
Signature · 1 line
2.55.0
Re: [PATCH v3 4/9] vhost: add virtqueues groups support to VDUSE
Quoted 6 lines · Eugenio Pérez
From: Maxime Coquelin <[email protected]>
VDUSE API version 1 introduces the notion of virtqueue groups, which once supported, enables the support of multiple addresses spaces.
Quoted 9 lines
For VDUSE networking devices, we need two groups, one for the datapath queues, and one for the control queue.
Signed-off-by Maxime Coquelin <[email protected]>Signed-off-by Eugenio Pérez <[email protected]>--- lib/vhost/vduse.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-)
FWIW:
Thanks,
Maxime
PATCH v3 5/9 vhost: add ASID support to VDUSE IOTLB operations
In reply to Eugenio PérezFrom: Maxime Coquelin <[email protected]>
Make use of the newly introduced address space ID when calling Vhost IOTLB API.
--- lib/vhost/vduse.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-)
lib/vhost/vduse.c +33 -6
@@ -71,7 +71,7 @@ vduse_iotlb_remove_notify(uint64_t addr, uint64_t offset, uint64_t size)static int vduse_iotlb_miss(struct virtio_net *dev, int asid, uint64_t iova, uint8_t perm __rte_unused) { -struct vduse_iotlb_entry entry; +struct vduse_iotlb_entry_v2 entry = {};uint64_t size, page_size;struct stat stat;void *mmap_addr;
@@ -79,8 +79,13 @@ vduse_iotlb_miss(struct virtio_net *dev, int asid, uint64_t iova, uint8_t perm _ entry.start = iova; entry.last = iova +1 ; + entry.asid = asid; - ret =ioctl (dev->vduse_dev_fd,VDUSE_IOTLB_GET_FD , &entry); +if (dev->vduse_api_ver <1 ) { + ret =ioctl (dev->vduse_dev_fd,VDUSE_IOTLB_GET_FD , &entry); + }else { + ret =ioctl (dev->vduse_dev_fd,VDUSE_IOTLB_GET_FD2 , &entry); + }if (ret <0 ) {VHOST_CONFIG_LOG (dev->ifname,ERR ,"Failed to get IOTLB entry for 0x%" PRIx64, iova);
@@ -90,6 +95,7 @@ vduse_iotlb_miss(struct virtio_net *dev, int asid, uint64_t iova, uint8_t perm _ fd = ret;VHOST_CONFIG_LOG (dev->ifname,DEBUG ,"New IOTLB entry:" ); +VHOST_CONFIG_LOG (dev->ifname,DEBUG ,"\tASID: %d" , entry.asid);VHOST_CONFIG_LOG (dev->ifname,DEBUG ,"\tIOVA: %" PRIx64" - %" PRIx64, (uint64_t )entry.start, (uint64_t )entry.last);VHOST_CONFIG_LOG (dev->ifname,DEBUG ,"\toffset: %" PRIx64, (uint64_t )entry.offset);
@@ -458,10 +464,31 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused) resp.result =VDUSE_REQ_RESULT_OK ;break ;case VDUSE_UPDATE_IOTLB : -VHOST_CONFIG_LOG (dev->ifname,INFO ,"\tIOVA range: %" PRIx64" - %" PRIx64, - (uint64_t )req.iova.start, (uint64_t )req.iova.last); -vhost_user_iotlb_cache_remove (dev,0 , req.iova.start, - req.iova.last - req.iova.start +1 ); + { +uint64_t start, last; +uint32_t asid; + +if (dev->vduse_api_ver <1 ) { + start = req.iova.start; + last = req.iova.last; + asid =0 ; + }else { + start = req.iova_v2.start; + last = req.iova_v2.last; + asid = req.iova_v2.asid; + } + +if (asid >=RTE_DIM (dev->iotlb)) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"Invalid ASID %u in IOTLB update" , asid); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } + +VHOST_CONFIG_LOG (dev->ifname,INFO ,"\t(ASID %d) IOVA range: %" PRIx64" - %" PRIx64, + asid, start, last); +vhost_user_iotlb_cache_remove (dev, asid, start, last - start +1 ); + } resp.result =VDUSE_REQ_RESULT_OK ;break ;case VDUSE_SET_VQ_GROUP_ASID :
Signature · 1 line
2.55.0
Re: [PATCH v3 5/9] vhost: add ASID support to VDUSE IOTLB operations
Quoted 11 lines · Eugenio Pérez
From: Maxime Coquelin <[email protected]>
Make use of the newly introduced address space ID when calling Vhost IOTLB API.
Signed-off-by Maxime Coquelin <[email protected]>Signed-off-by Eugenio Pérez <[email protected]>--- lib/vhost/vduse.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-)
FWIW:Reviewed-by: Maxime Coquelin <[email protected]>
Thanks,
Maxime
PATCH v3 6/9 vhost: claim VDUSE support for API version 1
In reply to Eugenio PérezFrom: Maxime Coquelin <[email protected]>
--- lib/vhost/vduse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/vhost/vduse.c +1 -1
@@ -25,7 +25,7 @@#include "vhost.h" #include "virtio_net_ctrl.h" -#define VHOST_VDUSE_API_VERSION 0ULL +#define VHOST_VDUSE_API_VERSION 1ULL#define VDUSE_CTRL_PATH "/dev/vduse/control"struct vduse {
Signature · 1 line
2.55.0
Re: [PATCH v3 6/9] vhost: claim VDUSE support for API version 1
Quoted 13 lines · Eugenio Pérez
From: Maxime Coquelin <[email protected]>
Signed-off-by Maxime Coquelin <[email protected]>Signed-off-by Eugenio Pérez <[email protected]>--- lib/vhost/vduse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)lib/vhost/vduse.c +0
-0
lib/vhost/vduse.c line 31
Quoted 8 lines
lib/vhost/vduse.c +1
-1@@ -25,7 +25,7 @@#include "vhost.h" #include "virtio_net_ctrl.h" -#define VHOST_VDUSE_API_VERSION 0ULL +#define VHOST_VDUSE_API_VERSION 1ULL#define VDUSE_CTRL_PATH "/dev/vduse/control"struct vduse {
FWIW:
Thanks,
Maxime
PATCH v3 7/9 vhost: add net status feature to VDUSE
In reply to Eugenio PérezFrom: Maxime Coquelin <[email protected]>
Enable the VIRTIO_NET_F_STATUS feature for VDUSE devices. This allows the device to report link status (e.g., VIRTIO_NET_S_LINK_UP). It also allows the device to signal the driver that it needs to send gratuitous ARP with VIRTIO_NET_S_ANNOUNCE.
--- lib/vhost/vduse.c | 1 + lib/vhost/vduse.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-)
lib/vhost/vduse.c +1 -0
@@ -820,6 +820,7 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, bool goto out_ctrl_close; } + vnet_config.status =VIRTIO_NET_S_LINK_UP ; vnet_config.max_virtqueue_pairs = max_queue_pairs;memset (dev_config,0 ,sizeof (struct vduse_dev_config ));
lib/vhost/vduse.h +2 -1
@@ -7,7 +7,8 @@#include "vhost.h" -#define VDUSE_NET_SUPPORTED_FEATURES VIRTIO_NET_SUPPORTED_FEATURES +#define VDUSE_NET_SUPPORTED_FEATURES (VIRTIO_NET_SUPPORTED_FEATURES | \ + (1ULL << VIRTIO_NET_F_STATUS))int vduse_device_create (const char *path,bool compliant_ol_flags,bool extbuf,bool linearbuf);int vduse_device_destroy (const char *path);
Signature · 1 line
2.55.0
Re: [PATCH v3 7/9] vhost: add net status feature to VDUSE
Quoted 7 lines · Eugenio Pérez
From: Maxime Coquelin <[email protected]>
Enable the
VIRTIO_NET_F_STATUSfeature for VDUSE devices. This allows the device to report link status (e.g.,VIRTIO_NET_S_LINK_UP). It also allows the device to signal the driver that it needs to send gratuitous ARP withVIRTIO_NET_S_ANNOUNCE.
Quoted 7 lines
Signed-off-by Maxime Coquelin <[email protected]>Signed-off-by Eugenio Pérez <[email protected]>--- lib/vhost/vduse.c | 1 + lib/vhost/vduse.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-)
FWIW:
Thanks,
Maxime
PATCH v3 8/9 vhost: Support VDUSE QUEUE_READY feature
In reply to Eugenio PérezAdd support for the VDUSE_F_QUEUE_READY feature.
In VDUSE, the dataplane is enabled only after control virtqueue so the device is fully configured in the destination of a live migration before the dataplane starts. This message signals the VDUSE device when the dataplane queues should be enabled.
--- lib/vhost/vduse.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-- lib/vhost/vhost.h | 1 + 2 files changed, 85 insertions(+), 2 deletions(-)
lib/vhost/vduse.c +84 -2
@@ -39,12 +39,15 @@ static const char * const vduse_reqs_str[] = {"VDUSE_SET_STATUS" ,"VDUSE_UPDATE_IOTLB" ,"VDUSE_SET_VQ_GROUP_ASID" , + "VDUSE_SET_VQ_READY", };#define vduse_req_id_to_str (id) \ (id < RTE_DIM(vduse_reqs_str) ? \ vduse_reqs_str[id] : "Unknown") +static const uint64_t supported_vduse_features =RTE_BIT64 (VDUSE_F_QUEUE_READY ); +static uint64_t vduse_vq_to_group (struct virtio_net *dev,struct vhost_virtqueue *vq) {if (dev->vduse_api_ver <1 )
@@ -519,6 +522,51 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused) } resp.result =VDUSE_REQ_RESULT_OK ;break ; +case VDUSE_SET_VQ_READY : +if (!(dev->status &VIRTIO_DEVICE_STATUS_DRIVER_OK )) { +/* +* dev->notify_ops is NULL if !S_DRIVER_OK, +* vduse_device_start will check the queue readiness. +*/ + resp.result =VDUSE_REQ_RESULT_OK ; +break ; + } +if (!(dev->vduse_features &RTE_BIT64 (VDUSE_F_QUEUE_READY ))) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"Unexpected ready message with no ready feature acked" ); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } + + i = req.vq_ready.num; +if (i >= dev->nr_vring) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"Invalid virtqueue index: %u" , i); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } + + vq = dev->virtqueue[i]; +if (dev->notify_ops ==NULL || dev->notify_ops->vring_state_changed ==NULL ) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"No ops->vring_state_changed" ); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } + + ret = dev->notify_ops->vring_state_changed (dev->vid, i, + req.vq_ready.ready); +VHOST_CONFIG_LOG (dev->ifname,INFO , +"\t\t VQ %d gets ready %d ok %d" , i, + req.vq_ready.ready, ret); +if (ret !=0 ) { + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } + + vq->enabled = req.vq_ready.ready; + resp.result =VDUSE_REQ_RESULT_OK ; +break ;default : resp.result =VDUSE_REQ_RESULT_FAILED ;break ;
@@ -536,7 +584,8 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused)if ((old_status ^ dev->status) &VIRTIO_DEVICE_STATUS_DRIVER_OK ) {if (dev->status &VIRTIO_DEVICE_STATUS_DRIVER_OK ) {/* Poll virtqueues ready states before starting device */ - ret =vduse_wait_for_virtqueues_ready (dev); + ret = dev->vduse_features &RTE_BIT64 (VDUSE_F_QUEUE_READY ) ?0 + :vduse_wait_for_virtqueues_ready (dev);if (ret <0 ) {VHOST_CONFIG_LOG (dev->ifname,ERR ,"Failed to wait for virtqueues ready, aborting device start" );
@@ -742,6 +791,26 @@ vduse_reconnect_start_device(struct virtio_net *dev)return ret; } +/* If some error occurs just continue as if the kernel exposed no features */ +static uint64_t +vduse_device_get_vduse_features (int control_fd,const char *log_name) +{ +uint64_t vduse_kernel_features; +int ret; + + ret =ioctl (control_fd,VDUSE_GET_FEATURES , &vduse_kernel_features); +if (ret <0 ) { +VHOST_CONFIG_LOG (log_name,INFO , +"Failed to get kernel VDUSE features, assuming not supported: %d(%s)" , + errno,strerror (errno)); +return 0 ; + } + +VHOST_CONFIG_LOG (log_name,DEBUG ,"Setting vhost kernel features: %" PRIx64, + vduse_kernel_features & supported_vduse_features); +return vduse_kernel_features & supported_vduse_features; +} +int vduse_device_create (const char *path,bool compliant_ol_flags,bool extbuf,bool linearbuf) {
@@ -750,7 +819,7 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, boolstruct virtio_net *dev;struct virtio_net_config vnet_config = {{0 }};uint64_t ver; -uint64_t features; +uint64_t features, vduse_features =0 ;const char *name = path +strlen ("/dev/vduse/" );bool reconnect = false;
@@ -834,6 +903,18 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, bool dev_config->ngroups =2 ; dev_config->nas =2 ; } + + vduse_features =vduse_device_get_vduse_features (control_fd, name); +if (vduse_features) { + ret =ioctl (control_fd,VDUSE_SET_FEATURES , &vduse_features); +if (ret <0 ) { +VHOST_CONFIG_LOG (name,ERR ,"Failed to set VDUSE features: %s" , +strerror (errno)); +free (dev_config); + goto out_ctrl_close; + } + } + dev_config->config_size =sizeof (struct virtio_net_config );memcpy (dev_config->config, &vnet_config,sizeof (vnet_config));
@@ -884,6 +965,7 @@ vduse_device_create(const char *path, bool compliant_ol_flags, bool extbuf, bool dev->vduse_ctrl_fd = control_fd; dev->vduse_dev_fd = dev_fd; dev->vduse_api_ver = ver; + dev->vduse_features = vduse_features; ret =vduse_reconnect_log_map (dev, !reconnect);if (ret <0 )
lib/vhost/vhost.h +1 -0
@@ -533,6 +533,7 @@ struct __rte_cache_aligned virtio_net {int vduse_ctrl_fd;int vduse_dev_fd;uint64_t vduse_api_ver; +uint64_t vduse_features;struct vhost_virtqueue *cvq;
Signature · 1 line
2.55.0
Re: [PATCH v3 8/9] vhost: Support VDUSE QUEUE_READY feature
Quoted 7 lines · Eugenio Pérez
Add support for the
VDUSE_F_QUEUE_READYfeature.In VDUSE, the dataplane is enabled only after control virtqueue so the device is fully configured in the destination of a live migration before the dataplane starts. This message signals the VDUSE device when the dataplane queues should be enabled.
Quoted 6 lines
Signed-off-by Eugenio Pérez <[email protected]>--- lib/vhost/vduse.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-- lib/vhost/vhost.h | 1 + 2 files changed, 85 insertions(+), 2 deletions(-)
Thanks,
Maxime
PATCH v3 9/9 vhost: Support vduse suspend feature
In reply to Eugenio PérezAdd support for the VDUSE_F_SUSPEND feature.
The suspend feature allows the driver to stop the device from processing the virtqueues. This ensures that the virtqueue state can be fetched reliably in a live migration.
--- lib/vhost/vduse.c | 42 +++++++++++++++++++++++++++++++++++++++++- lib/vhost/vhost.h | 1 + 2 files changed, 42 insertions(+), 1 deletion(-)
lib/vhost/vduse.c +41 -1
@@ -46,7 +46,8 @@ static const char * const vduse_reqs_str[] = { (id <RTE_DIM (vduse_reqs_str) ? \ vduse_reqs_str[id] : "Unknown") -static const uint64_t supported_vduse_features =RTE_BIT64 (VDUSE_F_QUEUE_READY ); +static const uint64_t supported_vduse_features = +RTE_BIT64 (VDUSE_F_QUEUE_READY ) |RTE_BIT64 (VDUSE_F_SUSPEND );static uint64_t vduse_vq_to_group (struct virtio_net *dev,struct vhost_virtqueue *vq) {
@@ -416,6 +417,7 @@ vduse_device_stop(struct virtio_net *dev)vhost_destroy_device_notify (dev); dev->flags &= ~VIRTIO_DEV_READY ; + dev->vduse_suspended = false;for (i =0 ; i < dev->nr_vring; i++)vduse_vring_cleanup (dev, i);
@@ -537,6 +539,12 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused) resp.result =VDUSE_REQ_RESULT_FAILED ;break ; } +if (dev->vduse_suspended) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"SET_VQ_READY received on suspended device" ); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } i = req.vq_ready.num;if (i >= dev->nr_vring) {
@@ -567,11 +575,43 @@ vduse_events_handler(int fd, void *arg, int *close __rte_unused) vq->enabled = req.vq_ready.ready; resp.result =VDUSE_REQ_RESULT_OK ;break ; +case VDUSE_SUSPEND : +if (!(dev->vduse_features &RTE_BIT64 (VDUSE_F_SUSPEND ))) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"Unnegotiated suspend message" ); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } +if (!(dev->status &VIRTIO_DEVICE_STATUS_DRIVER_OK )) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"Unexpected suspend message with no DRIVER_OK" ); + resp.result =VDUSE_REQ_RESULT_FAILED ; +break ; + } +for (i =0 ; dev->notify_ops !=NULL && + dev->notify_ops->vring_state_changed !=NULL && + i < dev->nr_vring; i++) { +if (dev->virtqueue[i] == dev->cvq) +continue ; + + ret = dev->notify_ops->vring_state_changed (dev->vid, i, false); +if (ret) { +VHOST_CONFIG_LOG (dev->ifname,ERR , +"Failed to disable VQ %u for suspend" , i); + resp.result =VDUSE_REQ_RESULT_FAILED ; + goto out; + } + } + dev->vduse_suspended = true; + resp.result =VDUSE_REQ_RESULT_OK ; +break ; +default : resp.result =VDUSE_REQ_RESULT_FAILED ;break ; } +out: resp.request_id = req.request_id; ret =write (dev->vduse_dev_fd, &resp,sizeof (resp));
lib/vhost/vhost.h +1 -0
@@ -534,6 +534,7 @@ struct __rte_cache_aligned virtio_net {int vduse_dev_fd;uint64_t vduse_api_ver;uint64_t vduse_features; +bool vduse_suspended;struct vhost_virtqueue *cvq;
Signature · 1 line
2.55.0
Re: [PATCH v3 9/9] vhost: Support vduse suspend feature
lib/vhost/vduse.c static const char * const vduse_reqs_str[] = {
Quoted 17 lines · Eugenio Pérez
Add support for the
VDUSE_F_SUSPENDfeature.The suspend feature allows the driver to stop the device from processing the virtqueues. This ensures that the virtqueue state can be fetched reliably in a live migration.
Signed-off-by Eugenio Pérez <[email protected]>--- lib/vhost/vduse.c | 42 +++++++++++++++++++++++++++++++++++++++++- lib/vhost/vhost.h | 1 + 2 files changed, 42 insertions(+), 1 deletion(-)lib/vhost/vduse.c +0
-0@@ -46,7 +46,8 @@ static const char * const vduse_reqs_str[] = {
"VDUSE_SUSPEND" entry is missing in this array.
With above comment addressed, feel free to add:
Quoted 24 lines · Eugenio Pérez
This series introduces features to the VDUSE (vDPA Device in Userspace) driver to support Live Migration.
Currently, DPDK does not support VDUSE devices live migration because the driver lacks a mechanism to suspend the device and quiesce the rings to initiate the switchover. This series implements the suspend operation to address this limitation.
Furthermore, enabling Live Migration for devices with control virtqueue requires two additional features. Both of them are included in this series.
* Address Spaces ID (ASID) support: This allows QEMU to isolate and intercept the device's CVQ. By doing so, QEMU is able to migrate the device status transparently, without requiring the device to support state save and restore.
*QUEUE_READY: This allows QEMU to control when the dataplane virtqueues are enabled. This ensures the dataplane is started after the device configuration has been fully restored via the CVQ.It also enables the
VIRTIO_NET_F_STATUSfeature. This allows the device to signal the driver that it needs to send gratuitous ARP withVIRTIO_NET_S_ANNOUNCE, reducing the Live Migration downtime.
Quoted 5 lines
Note that kernel headers are update to v7.3-rc3, not a stable version. This would allow to ack the patches while the kernel uapi is published in 7.3.
v3:
* Includeuapi/linux/stddef.hand revert the -D__counted_by from v2.
FYI, the issue is now fixed in main.
Signature · 1 line
David Marchand
Quoted 31 lines · David Marchand
Quoted 2 lines · Eugenio Pérez
This series introduces features to the VDUSE (vDPA Device in Userspace)
driver
Quoted 9 lines
to support Live Migration.
Currently, DPDK does not support VDUSE devices live migration because the driver lacks a mechanism to suspend the device and quiesce the rings to initiate the switchover. This series implements the suspend operation to address this limitation.
Furthermore, enabling Live Migration for devices with control virtqueue requires two additional features. Both of them are included in this
series.
Quoted 2 lines
* Address Spaces ID (ASID) support: This allows QEMU to isolate and
intercept
Quoted 1 line
the device's CVQ. By doing so, QEMU is able to migrate the device
status
Quoted 3 lines
transparently, without requiring the device to support state save and restore.
*QUEUE_READY: This allows QEMU to control when the dataplane virtqueuesare
Quoted 4 lines
enabled. This ensures the dataplane is started after the device configuration has been fully restored via the CVQ.
It also enables the
VIRTIO_NET_F_STATUSfeature. This allows the deviceto
Quoted 3 lines
signal the driver that it needs to send gratuitous ARP with
VIRTIO_NET_S_ANNOUNCE, reducing the Live Migration downtime.
Quoted 9 lines
Quoted 1 line
Note that kernel headers are update to v7.3-rc3, not a stable version.
This
Quoted 4 lines
would allow to ack the patches while the kernel uapi is published in 7.3.
v3:
* Includeuapi/linux/stddef.hand revert the -D__counted_by from v2.FYI, the issue is now fixed in main.
And I just re-aligned the next-virtio branch to latest main.
Thanks,
Maxime
Quoted 6 lines
--
David Marchand
Quoted 33 lines · Maxime Coquelin
Quoted 29 lines · David Marchand
Quoted 27 lines · Eugenio Pérez
This series introduces features to the VDUSE (vDPA Device in Userspace) driver to support Live Migration.
Currently, DPDK does not support VDUSE devices live migration because the driver lacks a mechanism to suspend the device and quiesce the rings to initiate the switchover. This series implements the suspend operation to address this limitation.
Furthermore, enabling Live Migration for devices with control virtqueue requires two additional features. Both of them are included in this series.
* Address Spaces ID (ASID) support: This allows QEMU to isolate and intercept the device's CVQ. By doing so, QEMU is able to migrate the device status transparently, without requiring the device to support state save and restore.
*QUEUE_READY: This allows QEMU to control when the dataplane virtqueues are enabled. This ensures the dataplane is started after the device configuration has been fully restored via the CVQ.It also enables the
VIRTIO_NET_F_STATUSfeature. This allows the device to signal the driver that it needs to send gratuitous ARP withVIRTIO_NET_S_ANNOUNCE, reducing the Live Migration downtime.Note that kernel headers are update to v7.3-rc3, not a stable version. This would allow to ack the patches while the kernel uapi is published in 7.3.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
v3:
* Includeuapi/linux/stddef.hand revert the -D__counted_by from v2.FYI, the issue is now fixed in main.
And I just re-aligned the next-virtio branch to latest main.
Should I re-send the patches with the reviewed-by to trigger the CI etc or it is not needed?