From: David Gibson <david@gibson.dropbear.id.au>
To: Ammar Yasser <aerosound161@gmail.com>
Cc: passt-dev@passt.top, eperezma@redhat.com
Subject: Re: [RFC v3 8/8] tap: Implement pasta vhost TX
Date: Mon, 10 Aug 2026 19:18:53 +1000 [thread overview]
Message-ID: <anmXfIZgONLCtTxl@zatzit> (raw)
In-Reply-To: <20260802132155.870796-9-aerosound161@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 6434 bytes --]
On Sun, Aug 02, 2026 at 01:21:55PM +0000, Ammar Yasser wrote:
> Callers will specify whether vhost should be used or no by passing the
> vhost argument to tap_send_frames_pasta. If specified, sending will go
> through a function called tap_send_frames_vhost, which pops a descriptor
> from the queue shared with the kernel and sets the address of that
> descriptor to be the base address of a single iov from the group of
> buffers_per_frame * nframes iovs we pass to the function
>
> Signed-off-by: Ammar Yasser <aerosound161@gmail.com>
Sorry, didn't spot this earlier in the series: if these are based on
Eugenio's earlier patches, they should have his Signed-off-by in
addition to your own.
> ---
> tap.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 107 insertions(+), 1 deletion(-)
>
> diff --git a/tap.c b/tap.c
> index e177eef..66bb71d 100644
> --- a/tap.c
> +++ b/tap.c
> @@ -361,7 +361,32 @@ void tap_icmp6_send(const struct ctx *c,
> }
>
> /**
> - * tap_send_frames_pasta() - Send multiple frames to the pasta tap
> + * tx_reap() - Reclaim the descriptors the kernel has already processed
> + */
> +static void tx_reap(void) {
> + struct vring_used *used = &vring_used_all[1].used;
> + uint16_t used_idx = le16toh(used->idx);
> +
> + smp_rmb();
> +
> + /* increment last_used_idx until it reaches the kernel's used index */
> + while (vqs[1].last_used_idx != used_idx) {
> + uint16_t desc_id = le32toh(used->ring[vqs[1].last_used_idx % VHOST_NDESCS].id);
> +
> + for (;;) {
> + /* keep going until we find a descriptor without the next flag */
> + vqs[1].num_free++;
> + if (!(le16toh(vring_desc[1][desc_id].flags) & VRING_DESC_F_NEXT))
> + break;
> + /* this descriptor wasn't the last, set desc_id to the next one and keep going */
> + desc_id = le16toh(vring_desc[1][desc_id].next);
> + }
> + vqs[1].last_used_idx++;
> + }
> +}
> +
> +/**
> + * tap_send_frames_vhost() - Send multiple frames to the pasta tap
> * @c: Execution context
> * @iov: Array of buffers
> * @bufs_per_frame: Number of buffers (iovec entries) per frame
> @@ -371,6 +396,84 @@ void tap_icmp6_send(const struct ctx *c,
> * @bufs_per_frame contiguous buffers representing a single frame.
> *
> * Return: number of frames successfully sent
> + */
> +static size_t tap_send_frames_vhost(const struct ctx *c,
> + const struct iovec *iov,
> + size_t bufs_per_frame, size_t nframes)
> +{
> + size_t i;
> + size_t processed_frames = 0;
Reverse christmas tree.
> +
> + /* update our local counters first */
> + tx_reap();
> +
> + #define AVAIL_Q(i)(vring_avail_all[i].avail)
# for preprocessor directives should always go in column 0.
> +
> + for (i = 0; i < nframes; i++) {
> + size_t j;
> +
> + if (vqs[1].num_free < bufs_per_frame)
> + break;
IIRC, we were discussing during the last call that at least for the
first version it's fine if we synchronously wait for buffers to be
available. Since then it occurred to me that another acceptable
option would be to simply drop frames if there are no available
buffers (this is kind of how IP is designed to work - congestion is
reported implicitly as packet loss). Do whichever is easier for now
and it can be refined later.
> +
> + /* set the index of the avail ring in the tx queue to be our last_used_idx */
> + uint16_t head = vqs[1].next_free % VHOST_NDESCS;
No inline decls.
> + AVAIL_Q(1).ring[(AVAIL_Q(1).idx + i) % VHOST_NDESCS] = htole16(head);
> +
> + /* we will be consuming bufs_per_frame descriptors for every frame, decrement the local num_free */
> + vqs[1].num_free -= bufs_per_frame;
> +
> + for (j = 0; j < bufs_per_frame; ++j) {
> + /* get the last_used_idx descriptor */
> + struct vring_desc *desc = &vring_desc[1][vqs[1].next_free % VHOST_NDESCS];
> + /*
> + * the iov variable contains the iovecs for all frames we will send.
> + * access a single fragment of a frame (each fragment is one of tcp_iov_parts)
> + * denoted by iov at index i (index of the frame being processed) * bufs_per_frame
> + * plus j (the index of the fragment being processed)
> + */
> + const struct iovec *iov_i = &iov[i * bufs_per_frame + j];
> +
> + /*
> + * set that descriptor's address to the base of the iov and set the VRING_DESC_F_NEXT
> + * flag on the descriptor if its not the last frame fragment, so that the
> + * guest would recieve the entire frame in one go.
> + */
> + desc->addr = (uint64_t)iov_i->iov_base;
> + desc->len = iov_i->iov_len;
> + desc->flags = (j == bufs_per_frame - 1) ? 0 : htole16(VRING_DESC_F_NEXT);
> + vqs[1].next_free++;
> + }
> +
> + processed_frames++;
> + }
> +
> + /* we didn't process any frames, no need to notify the kernel */
> + if ((processed_frames == 0))
> + return 0;
> +
> + smp_wmb();
> + /* we will have used nframes descriptor chains */
> + AVAIL_Q(1).idx = htole16(le16toh(AVAIL_Q(1).idx)+processed_frames);
> + #undef AVAIL_Q
> +
> + vhost_kick(&vring_used_all[1].used, c->vq[1].kick_fd);
> +
> + return processed_frames;
> +}
> +
> +
> +/**
> + * tap_send_frames_pasta() - Send multiple frames to the pasta tap
> + * @c: Execution context
> + * @iov: Array of buffers
> + * @bufs_per_frame: Number of buffers (iovec entries) per frame
> + * @nframes: Number of frames to send
> + * @vhost: Use vhost-kernel or not
> + *
> + * @iov must have total length @bufs_per_frame * @nframes, with each set of
> + * @bufs_per_frame contiguous buffers representing a single frame.
> + *
> + * Return: number of frames successfully sent (or queued)
> *
> * #syscalls:pasta write
> */
> @@ -381,6 +484,9 @@ static size_t tap_send_frames_pasta(const struct ctx *c,
> size_t nbufs = bufs_per_frame * nframes;
> size_t i;
>
> + if (vhost)
> + return tap_send_frames_vhost(c, iov, bufs_per_frame, nframes);
> +
> for (i = 0; i < nbufs; i += bufs_per_frame) {
> ssize_t rc = writev(c->fd_tap, iov + i, bufs_per_frame);
> size_t framelen = iov_size(iov + i, bufs_per_frame);
> --
> 2.34.1
>
--
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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
prev parent reply other threads:[~2026-08-10 9:19 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-02 13:21 [RFC v3 0/8] Add vhost-net kernel support to pasta Ammar Yasser
2026-08-02 13:21 ` [RFC v3 1/8] tap: Move the tap_hdr file to a separate file Ammar Yasser
2026-08-07 5:40 ` David Gibson
2026-08-02 13:21 ` [RFC v3 2/8] udp,tcp: Make protocol specific buffers public Ammar Yasser
2026-08-07 5:56 ` David Gibson
2026-08-02 13:21 ` [RFC v3 3/8] conf: Add context fields, epoll types and the --vhost flag to pasta Ammar Yasser
2026-08-10 1:11 ` David Gibson
2026-08-02 13:21 ` [RFC v3 4/8] virtio: Define the pasta vhost interface Ammar Yasser
2026-08-10 2:06 ` David Gibson
2026-08-02 13:21 ` [RFC v3 5/8] virtio: Implement the pasta vhost functions Ammar Yasser
2026-08-10 6:34 ` David Gibson
2026-08-02 13:21 ` [RFC v3 6/8] virtio: Implement pasta vhost acceleration guest->pasta path Ammar Yasser
2026-08-10 7:34 ` David Gibson
2026-08-02 13:21 ` [RFC v3 7/8] pasta: Implement pasta vhost TX (pasta->guest) prerequisites Ammar Yasser
2026-08-10 9:01 ` David Gibson
2026-08-02 13:21 ` [RFC v3 8/8] tap: Implement pasta vhost TX Ammar Yasser
2026-08-10 9:18 ` David Gibson [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=anmXfIZgONLCtTxl@zatzit \
--to=david@gibson.dropbear.id.au \
--cc=aerosound161@gmail.com \
--cc=eperezma@redhat.com \
--cc=passt-dev@passt.top \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).