From: Laurent Vivier <lvivier@redhat.com>
To: aerosouund <aerosound161@gmail.com>, passt-dev@passt.top
Subject: Re: [PATCH v2 4/7] tap: Implement the pasta vhost-net from-guest path
Date: Mon, 9 Nov 2026 16:37:06 +0100 [thread overview]
Message-ID: <6530da0a-39ee-45e8-92f4-566304c35330@redhat.com> (raw)
In-Reply-To: <20261016204940.33190-5-aerosound161@gmail.com>
On 10/16/26 22:49, aerosouund wrote:
> From: Ammar Yasser <aerosound161@gmail.com>
>
> Add tap_vhost_input(), called when the kernel signals on a call eventfd
> that it has written guest frames into the from-guest queue. It consumes
> descriptors with consume_one_rx_descriptor(), skips the virtio_net header
> on each, builds an iov_tail from what's left and queues it for
> processing, then tells the kernel the descriptors are free to reuse.
>
> consume_one_rx_descriptor() pops one entry from the used ring, advances
> our read cursor and the count of descriptors awaiting handoff, and
> returns a pointer to that descriptor's data.
>
> Bootstrap vhost in tap_sock_tun_init(). If setup fails we leave
> c->vhost.fd at -1 and carry on unaccelerated.
>
> With vhost-net running the kernel reads the tap fd itself, so don't add
> that fd to our epoll set at all: tap_handler_pasta() would otherwise be
> woken for data it must not read.
>
> Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Ammar Yasser <aerosound161@gmail.com>
> ---
> passt.c | 6 +++
> tap.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> tap.h | 2 +
> 3 files changed, 119 insertions(+), 1 deletion(-)
>
> diff --git a/passt.c b/passt.c
> index 6002231..372b743 100644
> --- a/passt.c
> +++ b/passt.c
> @@ -305,6 +305,12 @@ static void passt_worker(void *opaque, int nfds, struct epoll_event *events)
> case EPOLL_TYPE_CONF:
> conf_handler(c, eventmask);
> break;
> + case EPOLL_TYPE_VHOST_CALL:
> + tap_vhost_input(c, ref, &now);
> + break;
> + case EPOLL_TYPE_VHOST_ERROR:
> + die("Error on vhost-kernel socket");
> + break;
> default:
> /* Can't happen */
> assert(0);
> diff --git a/tap.c b/tap.c
> index dfa66c7..a5fdee8 100644
> --- a/tap.c
> +++ b/tap.c
> @@ -38,6 +38,7 @@
> #include <netinet/udp.h>
> #include <netinet/ip_icmp.h>
> #include <netinet/if_ether.h>
> +#include <sys/eventfd.h>
>
> #include <linux/if_tun.h>
> #include <linux/icmpv6.h>
> @@ -61,6 +62,7 @@
> #include "vhost_user.h"
> #include "vu_common.h"
> #include "epoll_ctl.h"
> +#include "vhost.h"
>
> /* Maximum allowed frame lengths (including L2 header) */
>
> @@ -1446,7 +1448,11 @@ static void tap_start_connection(const struct ctx *c)
> break;
> }
>
> - epoll_add(c->epollfd, EPOLLIN | EPOLLRDHUP, ref);
> + /* With vhost-net running, the kernel reads the tap fd for us and
> + * notifies us on the call eventfd, so we mustn't watch it ourselves
> + */
> + if (c->vhost.fd == -1)
> + epoll_add(c->epollfd, EPOLLIN | EPOLLRDHUP, ref);
>
> if (!tap_is_ready(c))
> return;
> @@ -1514,6 +1520,89 @@ void tap_listen_handler(struct ctx *c, uint32_t events)
> tap_start_connection(c);
> }
>
> +/**
> + * consume_one_rx_descriptor() - Consume one used from-guest descriptor
> + * @len: Set to the length of data written by the kernel
> + *
> + * Pops a single entry from the used ring, advancing our read cursor and the
> + * count of descriptors awaiting refill announcement.
> + *
> + * NOTE: This function assumes the kernel is going to post single descriptors
> + * always, No chains. If that changes, we would need to increment num_free
> + * as we advertise back to the kernel the free descriptors by the length of the chain.
> + *
> + * Return: pointer to the packet buffer, or NULL if no data is available
> + */
> +static void *consume_one_rx_descriptor(size_t *len)
pass the queue_idx
> +{
> + struct vring_used_pasta *used = &vring_used_all[VHOST_AVAIL_Q_IDX];
use queue_idx rather than VHOST_AVAIL_Q_IDX
> + uint16_t used_idx, last_used;
> + uint32_t i;
> +
> + used_idx = le16toh(used->idx);
> +
> + smp_rmb();
> +
> + /* If the kernel's used index matches ours, we've consumed everything
> + * it has posted
> + */
> + if (used_idx == vhost_vq_state[VHOST_AVAIL_Q_IDX].last_used_idx) {
> + *len = 0;
> + return NULL;
> + }
> +
> + last_used = vhost_vq_state[VHOST_AVAIL_Q_IDX].last_used_idx % VHOST_NDESCS;
VHOST_NDESCS should be repaced by vhost_vq_state[queue_idx].num_free
> + i = le32toh(used->ring[last_used].id);
> + *len = le32toh(used->ring[last_used].len);
> +
> + if (i != last_used)
> + die("vhost: id %u at used position %u", i, last_used);
> +
> + /* The kernel has queued for us something we cannot receive */
> + if (*len > VHOST_DESC_BYTES)
> + die("vhost: id %u len %zu > %zu", i, *len,
> + (size_t)VHOST_DESC_BYTES);
> +
> + vhost_vq_state[VHOST_AVAIL_Q_IDX].last_used_idx++;
> + vhost_vq_state[VHOST_AVAIL_Q_IDX].num_free++;
> +
> + return pkt_buf + i * VHOST_DESC_BYTES;
> +}
> +
> +/**
> + * tap_vhost_input() - Handle frames the kernel wrote to the from-guest queue
> + * @c: Execution context
> + * @ref: epoll reference
> + * @now: Current timestamp
> + */
> +void tap_vhost_input(struct ctx *c, union epoll_ref ref,
> + const struct timespec *now)
> +{
> + struct virtio_net_hdr_mrg_rxbuf *hdr;
> + struct iov_tail data;
> + size_t len;
> +
> + eventfd_read(ref.fd, (eventfd_t[]){ 0 });
> +
> + tap_flush_pools();
> +
In ref.queue we should have queue_idx we can pass to consume_one_rx_descriptor()
> + while ((hdr = consume_one_rx_descriptor(&len))) {
> + /* a valid receive is one where there is a virtio net header followed by atleast sizeof(struct ethhdr) bytes */
> + if (len < (sizeof(*hdr) + sizeof(struct ethhdr))) {
> + warn("vhost: invalid len %lu", len);
> + continue;
> + }
> +
> + /* Skip over the vnet header, add the packet without it */
> + data = IOV_TAIL_FROM_BUF((void *)(hdr + 1),
> + len - sizeof(*hdr), 0);
> + tap_add_packet(c, &data, now);
> + }
> +
> + tap_handler(c, now);
> + vhost_rx_descriptor_handoff(c);
> +}
> +
> /**
> * tap_ns_tun() - Get tuntap fd in namespace
> * @c: Execution context
> @@ -1555,12 +1644,33 @@ static int tap_ns_tun(void *arg)
> */
> static void tap_sock_tun_init(struct ctx *c)
> {
> + int i;
> +
> if (!c->splice_only) {
> NS_CALL(tap_ns_tun, c);
> if (c->fd_tap == -1)
> die("Failed to set up tap device in namespace");
> }
>
> + /* Nothing else here runs if this fails: c->vhost.fd stays -1 and we
> + * carry on reading the tap fd ourselves, unless acceleration was
> + * explicitly asked for
> + */
> + if (c->vhost.mode != VHOST_MODE_OFF && vhost_setup_net(c) < 0 &&
> + c->vhost.mode == VHOST_MODE_ON)
> + die("vhost-net is not available");
> +
> + if (c->vhost.fd != -1) {
> + for (i = 0; i < ARRAY_SIZE(c->vhost.vq); i++)
> + vhost_setup_eventfds(c, i);
> +
> + if (vhost_setup_memory_table(c) < 0)
> + die_perror("VHOST_SET_MEM_TABLE ioctl failed");
> +
> + for (i = 0; i < ARRAY_SIZE(c->vhost.vq); i++)
> + vhost_set_vring(c, i, c->fd_tap);
> + }
> +
> pasta_ns_conf(c);
>
> if (!c->splice_only)
> diff --git a/tap.h b/tap.h
> index f8c30e2..0f1f7a3 100644
> --- a/tap.h
> +++ b/tap.h
> @@ -48,6 +48,8 @@ static inline void tap_hdr_update(struct tap_hdr *thdr, size_t l2len)
> thdr->vnet_len = htonl(l2len);
> }
>
> +void tap_vhost_input(struct ctx *c, union epoll_ref ref,
> + const struct timespec *now);
> unsigned long tap_l2_max_len(const struct ctx *c);
> void *tap_push_l2h(const struct ctx *c, void *buf,
> const void *src_mac, uint16_t proto);
> --
> 2.39.5 (Apple Git-154)
next prev parent reply other threads:[~2026-11-09 15:37 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 20:49 [PATCH v2 0/7] Add vhost-net kernel support to pasta aerosouund
2026-10-16 20:49 ` [PATCH v2 1/7] tap: Move the tap_hdr file to a separate file aerosouund
2026-11-06 10:47 ` Laurent Vivier
2026-10-16 20:49 ` [PATCH v2 2/7] conf: Add context fields, epoll types and --vhost-kernel flag to pasta aerosouund
2026-11-06 15:34 ` Laurent Vivier
2026-10-16 20:49 ` [PATCH v2 3/7] virtio: Add the pasta vhost-net interface and implementation aerosouund
2026-11-06 17:00 ` Laurent Vivier
2026-11-09 15:07 ` Laurent Vivier
2026-10-16 20:49 ` [PATCH v2 4/7] tap: Implement the pasta vhost-net from-guest path aerosouund
2026-11-09 15:37 ` Laurent Vivier [this message]
2026-10-16 20:49 ` [PATCH v2 5/7] tap, tcp, udp: Prepare the to-guest path for vhost-net aerosouund
2026-11-09 16:41 ` Laurent Vivier
2026-10-16 20:49 ` [PATCH v2 6/7] tap: Implement the pasta vhost-net to-guest path aerosouund
2026-10-16 20:49 ` [PATCH v2 7/7] tap/tcp: Replace tcp_payload_used with a ring buffer style index aerosouund
-- strict thread matches above, loose matches on Subject: below --
2026-10-16 20:37 [PATCH v2 4/7] tap: Implement the pasta vhost-net from-guest path Ammar Yasser
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=6530da0a-39ee-45e8-92f4-566304c35330@redhat.com \
--to=lvivier@redhat.com \
--cc=aerosound161@gmail.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).