public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
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 6/8] virtio: Implement pasta vhost acceleration guest->pasta path
Date: Thu, 13 Aug 2026 11:35:07 +1000	[thread overview]
Message-ID: <an0fQPtgcDspFWpv@zatzit> (raw)
In-Reply-To: <DKN66PH6OXY8.2DF7FQ2VOG93@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 9135 bytes --]

On Wed, Aug 12, 2026 at 09:17:30PM +0300, Ammar Yasser wrote:
> On Mon Aug 10, 2026 at 10:34 AM EEST, David Gibson wrote:
> > On Sun, Aug 02, 2026 at 01:21:53PM +0000, Ammar Yasser wrote:
> >> Add a new function called tap_vhost_input that will be used to indicate
> >> that the guest is trying to send data to us through the rx queue and the
> >> kernel is informing us to handle this data.
> >> 
> >> We will however still recieve epoll events on the fd normally. We should
> >
> > "the fd" is not very clear here, there are a bunch of fds.  I'm
> > guessing you mean the character device fd?
> 
> Yeah. And tying it back to your comment about the fact that we
> shouldn't call epoll add with the device fd if the user requested vhost
> means that this comment will be redundant anyways, will delete it.
> 
> For the record, while debugging performance, the fact that we received a
> double kick on the device fd and the queue fd was a major slow down
> reason. I did remove epoll registration for the device in this
> experimental branch. Will include it in my next revision.

Oh, excellent :).

>   
> >> @@ -1359,7 +1362,8 @@ void tap_handler_pasta(struct ctx *c, uint32_t events,
> >>  	if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR))
> >>  		die("Disconnect event on /dev/net/tun device, exiting");
> >>  
> >> -	if (events & EPOLLIN)
> >> +	/* don't proceed with the normal tap processing in case vhost acceleration was required */
> >> +	if (events & EPOLLIN && !c->vhost)
> >
> > Seems like it would be more elegant to remove the character device fd
> > from the epoll set (or at least remove EPOLLIN) when vhost is
> > activated, rather than take it's events then ignore the.
> 
> Yeah, agreed as per my comment above.
> 
> >
> >>  		tap_pasta_input(c, now);
> >>  }
> >>  
> >> @@ -1514,6 +1518,90 @@ void tap_listen_handler(struct ctx *c, uint32_t events)
> >>  	tap_start_connection(c);
> >>  }
> >>  
> >> +/**
> >> + * consume_one_rx_descriptor() - Consume one used RX descriptor from the kernel
> >
> > I'd suggest avoiding "Rx" or "Tx" terminology throughout, using
> > "toguest" or "fromguest" instead.  Note that for extra confusion Rx
> > here is meaning "fromguest", but for vhost-user it means "toguest".
> 
> Noted
> 
> >
> >> + * @len:	Set to the length of data written by the kernel
> >> + *
> >> + * Pops a single entry from the used ring. Advances vqs[0].last_used_idx
> >> + * (the number of entries we have consumed) and vqs[0].num_free (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(unsigned *len)
> >
> > For a length of data, we'd typically use a size_t rather than a bare
> > unsigned.
> 
> Noted
> 
> >> +	/* read the last index we consumed */
> >> +	last_used = vqs[0].last_used_idx % VHOST_NDESCS;
> >> +	/* read the index of what the */
> >> +	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 != %u", i, last_used, i);
> >> +	}
> >
> > Braces not necessary for single line if blocks.
> 
> Ok
> 
> >
> >> +
> >> +	/* the kernel has queued for us something we cannot receive */
> >> +	if (*len > PKT_BUF_BYTES/VHOST_NDESCS) {
> >
> > This seems oddly circular: deriving the maximum frame size from the
> > buffer and number of descriptors, when the number of descriptors was
> > derived from the buffer size and maximum frame size.  Better to use
> > (or add) an L2_MAX_LEN_XX constant.
> 
> Will do
> 
> >
> >> +		die("vhost: id %d len %u > %zu", i, *len, PKT_BUF_BYTES/VHOST_NDESCS);
> >> +	}
> >> +
> >> +	vqs[0].last_used_idx++;
> >> +	vqs[0].num_free++;
> >> +	return pkt_buf + i * (PKT_BUF_BYTES/VHOST_NDESCS);
> >> +}
> >> +
> >> +
> >> +/**
> >> + * tap_vhost_input() - Handler for new data on the tun socket to hypervisor vq
> >> + * @c:		Execution context
> >> + * @ref:	epoll reference
> >> + * @now:	Current timestamp
> >> + */
> >> +void tap_vhost_input(struct ctx *c, union epoll_ref ref, const struct timespec *now)
> >> +{
> >> +	eventfd_read(ref.fd, (eventfd_t[]){ 0 });
> >> +
> >> +	tap_flush_pools();
> >> +
> >> +	struct virtio_net_hdr_mrg_rxbuf *hdr;
> >> +	struct iov_tail data;
> >> +	unsigned len;
> >
> > My convention, we don't use inline declarations, even though we could
> > in C11 - move these up to the top.
> >
> >> +
> >> +	while ((hdr = consume_one_rx_descriptor(&len))) {
> >> +		if (len < sizeof(*hdr)) {
> >
> > I think you want to check that at least an ethernet (L2) header is
> > there as well as the virtio_net_hdr_mrg_rxbuf: both tap_pasta_input()
> > and tap_passt_input() appear to check for this.
> 
> Sure, i can add that. But just for my knowledge is there any case where
> there can be a virtio_net header without an ethernet header ?

Maybe.  It might be possible to pass in tap device in with --fd, but
have it misconfigured as a "tun" device (raw IP) instead of "tap"
(virtual ethernet).  Not sure if that's currently possible to combine
with vhost-kernel, but it's close enough to possible that it makes
sense to be cautious.  I'm also not sure what would happen if the
guest used an AF_PACKET socket to send malformed Ethernet frames.
There's a good chance it would get filtered before reaching us, but
still, better to check.

> 
> >
> >> +			warn("vhost: invalid len %u", len);
> >> +			continue;
> >> +		}
> >> +		
> >> +		/* skip over the vnet header, we wanna 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);
> >> +	rx_descriptor_handoff(c);
> >> +}
> >> +
> >>  /**
> >>   * tap_ns_tun() - Get tuntap fd in namespace
> >>   * @c:		Execution context
> >> @@ -1524,16 +1612,15 @@ void tap_listen_handler(struct ctx *c, uint32_t events)
> >>   */
> >>  static int tap_ns_tun(void *arg)
> >>  {
> >> -	struct ifreq ifr = { .ifr_flags = IFF_TAP | IFF_NO_PI };
> >> -	int flags = O_RDWR | O_NONBLOCK | O_CLOEXEC;
> >>  	struct ctx *c = (struct ctx *)arg;
> >> +	struct ifreq ifr = { .ifr_flags = IFF_TAP | IFF_NO_PI };
> >>  	int fd, rc;
> >>  
> >>  	c->fd_tap = -1;
> >>  	memcpy(ifr.ifr_name, c->pasta_ifn, IFNAMSIZ);
> >>  	ns_enter(c);
> >>  
> >> -	fd = open("/dev/net/tun", flags);
> >> +	fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
> >
> > This change seems unrelated to the actual aim of this patch.
> 
> Woops, removing
> 
> >
> >>  	if (fd < 0)
> >>  		die_perror("Failed to open() /dev/net/tun");
> >>  
> >> @@ -1561,6 +1648,20 @@ static void tap_sock_tun_init(struct ctx *c)
> >>  			die("Failed to set up tap device in namespace");
> >>  	}
> >>  
> >> +	/* initialize the vhost-net dev file descriptor */
> >> +	if (c->vhost) {
> >> +		setup_vhost_net(c);
> >> +
> >> +		for (int i = 0; i < ARRAY_SIZE(c->vq); i++)
> >> +			setup_eventfds(c, i);
> >> +
> >> +		if (setup_memory_table(c) < 0)
> >> +			die_perror("VHOST_SET_MEM_TABLE ioctl on /dev/vhost-net failed");
> >> +
> >> +		for (int i = 0; i < ARRAY_SIZE(c->vq); i++)
> >> +			set_vring_for_queue(c, i, c->fd_tap);
> >> +	}
> >
> > It's not clear to me if this code block needs to execute within the
> > guest namespace.  If not, it should probably be in tap_sock_tun_init()
> > rather than tap_ns_tun().  If it _does_ have to be in tap_ns_tun(),
> > then tap_ns_tun() probably needs a rename, since it's now doing rather
> > more in the vhost case that just getting a device fd.
> 
> Not sure i follow. its already in tap_sock_tun_init not tap_ns_tun.
> But generally speaking it needs to be after tap_ns_tun. because it
> relies on the device fd that tap_ns_tun has created in the namespace

Oh, sorry, I misread the diff.

> >> +
> >>  	pasta_ns_conf(c);
> >>  
> >>  	if (!c->splice_only)
> >> diff --git a/tap.h b/tap.h
> >> index 1625975..eb02da8 100644
> >> --- a/tap.h
> >> +++ b/tap.h
> >> @@ -66,6 +66,7 @@ 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.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 --]

  reply	other threads:[~2026-08-13  2:09 UTC|newest]

Thread overview: 29+ 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-12 16:29     ` Ammar Yasser
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-12 16:36     ` Ammar Yasser
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-12 17:17     ` Ammar Yasser
2026-08-13  1:16       ` 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-12 17:57     ` Ammar Yasser
2026-08-13  1:26       ` 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-12 18:17     ` Ammar Yasser
2026-08-13  1:35       ` David Gibson [this message]
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-12 18:39     ` Ammar Yasser
2026-08-13  2: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
2026-08-12 18:45     ` Ammar Yasser
2026-08-13  2:09       ` David Gibson

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=an0fQPtgcDspFWpv@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).