On Wed, 3 Dec 2025 19:54:30 +0100
Laurent Vivier
Advertise multi-queue support in vhost-user by setting VIRTIO_NET_F_MQ and VHOST_USER_PROTOCOL_F_MQ feature flags, and increase VHOST_USER_MAX_VQS from 2 to 32, supporting up to 16 queue pairs.
Currently, only the first RX queue (queue 0) is used for receiving packets. The guest kernel selects which TX queue to use for transmission. Full multi-RX queue load balancing will be implemented in future work.
Update the QEMU usage hint to show the required parameters for enabling multiqueue: queues parameter on the netdev, and mq=true on the virtio-net device.
Signed-off-by: Laurent Vivier
--- tap.c | 7 +++++-- vhost_user.c | 10 ++++++---- virtio.h | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tap.c b/tap.c index 2cda8c9772b8..591b49491aa3 100644 --- a/tap.c +++ b/tap.c @@ -1314,8 +1314,11 @@ static void tap_backend_show_hints(struct ctx *c) break; case MODE_VU: info("You can start qemu with:"); - info(" kvm ... -chardev socket,id=chr0,path=%s -netdev vhost-user,id=netdev0,chardev=chr0 -device virtio-net,netdev=netdev0 -object memory-backend-memfd,id=memfd0,share=on,size=$RAMSIZE -numa node,memdev=memfd0\n", - c->sock_path); + info(" kvm ... -chardev socket,id=chr0,path=%s " + "-netdev vhost-user,id=netdev0,chardev=chr0,queues=$QUEUES " + "-device virtio-net,netdev=netdev0,mq=true " + "-object memory-backend-memfd,id=memfd0,share=on,size=$RAMSIZE " + "-numa node,memdev=memfd0\n", c->sock_path); break; } } diff --git a/vhost_user.c b/vhost_user.c index aa7c869d9e56..845fdb551c84 100644 --- a/vhost_user.c +++ b/vhost_user.c @@ -323,6 +323,7 @@ static bool vu_get_features_exec(struct vu_dev *vdev, uint64_t features = 1ULL << VIRTIO_F_VERSION_1 | 1ULL << VIRTIO_NET_F_MRG_RXBUF | + 1ULL << VIRTIO_NET_F_MQ | 1ULL << VHOST_F_LOG_ALL | 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
@@ -767,7 +768,8 @@ static void vu_check_queue_msg_file(struct vhost_user_msg *vmsg) int idx = vmsg->payload.u64 & VHOST_USER_VRING_IDX_MASK;
if (idx >= VHOST_USER_MAX_VQS) - die("Invalid vhost-user queue index: %u", idx); + die("Invalid vhost-user queue index: %u (maximum %u)", idx, + VHOST_USER_MAX_VQS);
if (nofd) { vmsg_close_fds(vmsg); @@ -896,7 +898,8 @@ static bool vu_get_protocol_features_exec(struct vu_dev *vdev, uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK | 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD | 1ULL << VHOST_USER_PROTOCOL_F_DEVICE_STATE | - 1ULL << VHOST_USER_PROTOCOL_F_RARP; + 1ULL << VHOST_USER_PROTOCOL_F_RARP | + 1ULL << VHOST_USER_PROTOCOL_F_MQ;
(void)vdev; vmsg_set_reply_u64(vmsg, features); @@ -935,10 +938,9 @@ static bool vu_get_queue_num_exec(struct vu_dev *vdev, { (void)vdev;
- /* NOLINTNEXTLINE(misc-redundant-expression) */ vmsg_set_reply_u64(vmsg, VHOST_USER_MAX_VQS / 2);
- debug("VHOST_USER_MAX_VQS %u", VHOST_USER_MAX_VQS / 2); + debug("queue num %u", VHOST_USER_MAX_VQS / 2);
Nit, if you respin: this "queue num %u" message doesn't carry any context at all. Actually, why is it needed? It's defined at build time anyway. If it's needed maybe "Using up to %u vhost-user queue pairs"?
return true; } diff --git a/virtio.h b/virtio.h index 12caaa0b6def..176c935cecc7 100644 --- a/virtio.h +++ b/virtio.h @@ -88,7 +88,7 @@ struct vu_dev_region { uint64_t mmap_addr; };
-#define VHOST_USER_MAX_VQS 2 +#define VHOST_USER_MAX_VQS 32
/* * Set a reasonable maximum number of ram slots, which will be supported by
-- Stefano