On Fri, Jul 31, 2026 at 06:16:07PM +0200, Laurent Vivier wrote: > Allow the guest to negotiate multiple virtqueue pairs by advertising > 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. > > Replace the VHOST_USER_RX_QUEUE, VHOST_USER_TX_QUEUE, > VHOST_USER_IS_QUEUE_TX(), and VHOST_USER_IS_QUEUE_RX() macros with a > general set of QPAIR_* macros in passt.h that translate between queue > pair numbers and virtqueue indices. These are needed now that queue > indices are no longer limited to 0 and 1. > > Add a queue pair parameter to vu_send_single(), propagating it to the > virtqueue selection. All callers currently pass QPAIR_DEFAULT (0): > only the first RX queue is used for receiving. The guest kernel > selects which TX queue to use for transmission. Full multi-RX-queue > load balancing will be implemented separately. > > Signed-off-by: Laurent Vivier Reviewed-by: David Gibson [snip] > /** > - * vu_send_single() - Send a buffer to the front-end using the RX virtqueue > - * @c: execution context > + * vu_send_single() - Send a buffer to the front-end using a specified virtqueue > + * @c: Execution context > + * @qpair: Queue pair on which to send the buffer > * @buf: address of the buffer > * @size: size of the buffer > * > * Return: number of bytes sent, -1 if there is an error > */ > -int vu_send_single(const struct ctx *c, const void *buf, size_t size) > +int vu_send_single(const struct ctx *c, unsigned int qpair, const void *buf, size_t size) > { > struct vu_dev *vdev = c->vdev; > - struct vu_virtq *vq = &vdev->vq[VHOST_USER_RX_QUEUE]; > struct vu_virtq_element elem[VIRTQUEUE_MAX_SIZE]; > struct iovec in_sg[VIRTQUEUE_MAX_SIZE]; > + struct vu_virtq *vq; Nit: belongs one line lower down... > size_t total, in_total; > int elem_cnt; > int i; > > + vq = &vdev->vq[QPAIR_TOGUEST_QUEUE(qpair)]; > + ... or you could put this expression in the initialiser and it wouldn't move at all. > trace("vu_send_single size %zu", size); > > if (!vu_queue_enabled(vq) || !vu_queue_started(vq)) { > diff --git a/vu_common.h b/vu_common.h > index 817384175a1d..f5603d9ddeb6 100644 > --- a/vu_common.h > +++ b/vu_common.h > @@ -23,7 +23,8 @@ void vu_flush(const struct vu_dev *vdev, struct vu_virtq *vq, > struct vu_virtq_element *elem, int elem_cnt, size_t frame_len); > void vu_kick_cb(struct vu_dev *vdev, union epoll_ref ref, > const struct timespec *now); > -int vu_send_single(const struct ctx *c, const void *buf, size_t size); > +int vu_send_single(const struct ctx *c, unsigned int qpair, const void *buf, > + size_t size); > void vu_pad(const struct iovec *iov, size_t cnt, size_t frame_len); > > #endif /* VU_COMMON_H */ > -- > 2.54.0 > -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson