public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
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)


  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).