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
Cc: eperezma@redhat.com
Subject: Re: [PATCH 3/7] virtio: Add the pasta vhost-net interface and implementation
Date: Wed, 9 Sep 2026 17:13:34 +0200	[thread overview]
Message-ID: <16b9f003-4144-4383-b837-a3ad09017bd3@redhat.com> (raw)
In-Reply-To: <20260904212826.41027-4-aerosound161@gmail.com>

On 9/4/26 23:28, aerosouund wrote:
> From: Ammar Yasser <aerosound161@gmail.com>
> 
> Add vhost.c and vhost.h which define the api and implementation for
> pasta vhost acceleration
> 
> - vq_state/vhost_vq_state[]: our own view of each virtqueue, which the
>    kernel doesn't track for us: descriptors ready to hand back, how far
>    we've read the used ring, and the next descriptor to allocate
> - vring_desc, vring_avail_all, vring_used_all, vhost_memory: the rings
>    and the region table shared with the kernel
> - vhost_setup_net: open /dev/vhost-net and negotiate VIRTIO_F_VERSION_1
>    and VHOST_NET_F_VIRTIO_NET_HDR. Failure is fatal only if
>    --vhost-kernel is set to 'on'.
> - vhost_setup_eventfds: create, register and watch the call, kick and
>    error eventfds for one queue
> - vhost_setup_memory_table: register the buffers the kernel may touch.
>    pasta has no guest, so each region maps guest_phys_addr onto the
>    identical userspace_addr, making GPA translation an identity mapping.
>    This function uses the *_register_memory_regions functions created per
>    protocol and for general purpose buffers.
> - vhost_set_vring: publish a vring's addresses, bind the tap fd as its
>    backend and lay out its descriptors
> - vhost_rx_descriptor_handoff, vhost_kick: hand consumed descriptors back
>    and notify the kernel unless it says it's already polling
> 
> Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Ammar Yasser <aerosound161@gmail.com>
> ---
>   Makefile  |   2 +-
>   tcp_buf.c |  16 ++-
>   tcp_buf.h |   4 +
>   udp.c     |  14 +++
>   udp.h     |   3 +
>   util.c    |  12 +++
>   util.h    |   2 +
>   vhost.c   | 295 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   vhost.h   |  79 +++++++++++++++
>   9 files changed, 425 insertions(+), 2 deletions(-)
>   create mode 100644 vhost.c
>   create mode 100644 vhost.h
> 
> diff --git a/Makefile b/Makefile
> index b315242..74d0f96 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -38,7 +38,7 @@ PASST_SRCS = arch.c arp.c bitmap.c checksum.c conf.c dhcp.c dhcpv6.c \
>   	isolation.c lineread.c log.c mld.c ndp.c netlink.c migrate.c packet.c \
>   	parse.c passt.c pasta.c pcap.c pif.c repair.c serialise.c tap.c tcp.c \
>   	tcp_buf.c tcp_splice.c tcp_vu.c udp.c udp_flow.c udp_vu.c util.c \
> -	vhost_user.c virtio.c vu_common.c
> +	vhost.c vhost_user.c virtio.c vu_common.c
>   PASST_REPAIR_SRCS = passt-repair.c
>   PESTO_SRCS = pesto.c bitmap.c fwd_rule.c inany.c ip.c lineread.c parse.c \
>   	serialise.c
> diff --git a/tcp_buf.c b/tcp_buf.c
> index 72c4541..1f28728 100644
> --- a/tcp_buf.c
> +++ b/tcp_buf.c
> @@ -31,7 +31,7 @@
>   #include "inany.h"
>   #include "tcp_conn.h"
>   #include "tcp_internal.h"
> -#include "tcp_buf.h"
> +#include "vhost.h"
>   
>   #define TCP_FRAMES_MEM			128
>   #define TCP_FRAMES							   \
> @@ -75,6 +75,20 @@ void tcp_update_l2_buf(const unsigned char *eth_d)
>   		eth_update_mac(&tcp_eth_hdr[i], eth_d, NULL);
>   }
>   
> +/**
> + * tcp_register_memory_region() - Register the TCP specific buffers into a memory
> + *                                struct so it can be shared with the kernel.
> + * @vhost_mem: The memory struct to register regions into
> + * @last_idx:  The last index at which memory region has been placed
> + */
> +void tcp_register_memory_regions(union vhost_memory_u *vhost_mem, size_t *last_idx) {
> +   	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(tcp_payload_tap_hdr);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(tcp4_payload_ip);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(tcp6_payload_ip);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(tcp_payload);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(tcp_eth_hdr);

You should check this doesn't oveflow vhost_mem->mem.regions[]

> +}
> +
>   /**
>    * tcp_sock_iov_init() - Initialise scatter-gather L2 buffers for IPv4 sockets
>    * @c:		Execution context
> diff --git a/tcp_buf.h b/tcp_buf.h
> index 5d31cea..5e341ed 100644
> --- a/tcp_buf.h
> +++ b/tcp_buf.h
> @@ -6,11 +6,15 @@
>   #ifndef TCP_BUF_H
>   #define TCP_BUF_H
>   
> +union vhost_memory_u;
> +struct tcp_tap_conn;
> +
>   void tcp_sock_iov_init(const struct ctx *c);
>   void tcp_payload_flush(const struct ctx *c, const struct timespec *now);
>   int tcp_buf_data_from_sock(const struct ctx *c, struct tcp_tap_conn *conn,
>   			   uint32_t already_sent, const struct timespec *now);
>   int tcp_buf_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags,
>   		      const struct timespec *now);
> +void tcp_register_memory_regions(union vhost_memory_u *vhost_mem, size_t *last_idx);
>   
>   #endif  /*TCP_BUF_H */
> diff --git a/udp.c b/udp.c
> index 505e554..5e3bd86 100644
> --- a/udp.c
> +++ b/udp.c
> @@ -118,6 +118,7 @@
>   #include "udp_internal.h"
>   #include "udp_vu.h"
>   #include "epoll_ctl.h"
> +#include "vhost.h"
>   
>   #define UDP_MAX_FRAMES		32  /* max # of frames to receive at once */
>   
> @@ -448,6 +449,19 @@ static void udp_send_tap_icmp4(const struct ctx *c,
>   	tap_icmp4_send(c, saddr, eaddr, &msg, tap_omac, msglen);
>   }
>   
> +/**
> + * udp_register_memory_region() - Register the UDP specific buffers into a memory
> + *                                struct so it can be shared with the kernel.
> + * @vhost_mem: The memory struct to register regions into
> + * @last_idx:  The last index at which memory region has been placed
> + */
> +void udp_register_memory_regions(union vhost_memory_u *vhost_mem, size_t *last_idx) {
> +   	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(udp_payload);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(udp_eth_hdr);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(udp_iov_recv);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(udp_mh_recv);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(udp_meta);

You should check this doesn't oveflow vhost_mem->mem.regions[]

> +}
>   
>   /**
>    * udp_send_tap_icmp6() - Construct and send ICMPv6 to local peer
> diff --git a/udp.h b/udp.h
> index b50283e..ebf1a4e 100644
> --- a/udp.h
> +++ b/udp.h
> @@ -11,6 +11,8 @@
>   
>   #include "fwd.h"
>   
> +union vhost_memory_u;
> +
>   void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
>   			     uint32_t events, const struct timespec *now);
>   void udp_sock_handler(const struct ctx *c, union epoll_ref ref,
> @@ -21,6 +23,7 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif,
>   		    const struct timespec *now);
>   int udp_init(struct ctx *c);
>   void udp_update_l2_buf(const unsigned char *eth_d);
> +void udp_register_memory_regions(union vhost_memory_u *vhost_mem, size_t *last_idx);
>   
>   /**
>    * struct udp_ctx - Execution context for UDP
> diff --git a/util.c b/util.c
> index 28c32e4..a994d88 100644
> --- a/util.c
> +++ b/util.c
> @@ -36,6 +36,7 @@
>   #include "epoll_ctl.h"
>   #include "pasta.h"
>   #include "serialise.h"
> +#include "vhost.h"
>   #ifdef HAS_GETRANDOM
>   #include <sys/random.h>
>   #endif
> @@ -456,6 +457,17 @@ int open_in_ns(const struct ctx *c, const char *path, int flags)
>   	return arg.fd;
>   }
>   
> +/**
> + * general_register_memory_region() - Register the general (non protocol specific) buffers
> + *                                    into a memory struct so it can be shared with the kernel.
> + * @vhost_mem: The memory struct to register regions into
> + * @last_idx:  The last index at which memory region has been placed
> + */
> +void general_register_memory_regions(union vhost_memory_u *vhost_mem, size_t *last_idx) {
> +   	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(pkt_buf);
> +	vhost_mem->mem.regions[(*last_idx)++] = VHOST_MEMORY_REGION(eth_pad);

You should check this doesn't oveflow vhost_mem->mem.regions[]

> +}
> +
>   /**
>    * pidfile_write() - Write PID to file, if requested to do so, and close it
>    * @fd:		Open PID file descriptor, closed on exit, -1 to skip writing it
> diff --git a/util.h b/util.h
> index 2435f53..27eac22 100644
> --- a/util.h
> +++ b/util.h
> @@ -145,6 +145,7 @@ int do_clone(int (*fn)(void *), char *stack_area, size_t stack_size, int flags,
>   
>   struct ctx;
>   union sockaddr_inany;
> +union vhost_memory_u;
>   
>   int sock_l4(const struct ctx *c, enum epoll_type type,
>   	    const union sockaddr_inany *sa, const char *ifname);
> @@ -170,6 +171,7 @@ int write_remainder(int fd, const struct iovec *iov, size_t iovcnt,
>   int read_remainder(int fd, const struct iovec *iov, size_t cnt, size_t skip);
>   bool snprintf_check(char *str, size_t size, const char *format, ...);
>   long clamped_scale(long x, long y, long lo, long hi, long f);
> +void general_register_memory_regions(union vhost_memory_u *vhost_mem, size_t *last_idx);
>   
>   /**
>    * af_name() - Return name of an address family
> diff --git a/vhost.c b/vhost.c
> new file mode 100644
> index 0000000..0c60c21
> --- /dev/null
> +++ b/vhost.c
> @@ -0,0 +1,295 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/* Copyright Red Hat
> + * Author: Ammar Yasser <aerosound161@gmail.com>
> + *
> + * vhost.c - vhost-net (vhost-kernel) acceleration for pasta mode
> + */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/eventfd.h>
> +#include <sys/ioctl.h>
> +
> +#include "util.h"
> +#include "passt.h"
> +#include "vhost.h"
> +#include "epoll_ctl.h"
> +#include "udp.h"
> +#include "tcp_buf.h"
> +
> +struct vq_state vhost_vq_state[2];
> +
> +struct vring_desc vring_desc[2][VHOST_NDESCS]
> +				__attribute__((aligned(PAGE_SIZE)));
> +
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wpedantic"
> +union vring_avail_u vring_avail_all[2] __attribute__((aligned(PAGE_SIZE)));
> +union vring_used_u vring_used_all[2] __attribute__((aligned(PAGE_SIZE)));
> +#pragma GCC diagnostic pop

I don't think we should ignore "-Wpedantic".
> +
> +union vhost_memory_u vhost_memory = {
> +	.mem = {
> +		.nregions = N_VHOST_REGIONS,
> +	},
> +};
> +
> +/**
> + * vhost_setup_net() - Open and negotiate features on /dev/vhost-net
> + * @c:		Execution context; c->vhost.fd and c->vhost.features are set
> + *		on success, and left untouched on failure
> + *
> + * Failure here means vhost-net isn't usable, not that pasta can't run: the
> + * caller falls back to plain tap operation unless acceleration was required.
> + * That's why nothing in here is fatal.
> + *
> + * Return: 0 on success, -1 if vhost-net is unavailable or unusable
> + */
> +int vhost_setup_net(struct ctx *c)
> +{
> +	const uint64_t req_features = (1ULL << VIRTIO_F_VERSION_1) |
> +				      (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
> +	uint64_t features;
> +	int vhost_fd;
> +
> +	vhost_fd = open("/dev/vhost-net", O_RDWR | O_NONBLOCK | O_CLOEXEC);
> +	if (vhost_fd < 0) {
> +		debug_perror("Couldn't open /dev/vhost-net");
> +		return -1;
> +	}
> +
> +	if (ioctl(vhost_fd, VHOST_SET_OWNER, NULL) < 0) {
> +		debug_perror("VHOST_SET_OWNER ioctl failed");
> +		goto close_fd;
> +	}
> +
> +	if (ioctl(vhost_fd, VHOST_GET_FEATURES, &features) < 0) {
> +		debug_perror("VHOST_GET_FEATURES ioctl failed");
> +		goto close_fd;
> +	}
> +
> +	if ((features & req_features) != req_features) {
> +		debug("vhost-net is missing features: 0x%016" PRIx64,
> +		      req_features & ~features);
> +		goto close_fd;
> +	}
> +
> +	features = req_features;
> +	if (ioctl(vhost_fd, VHOST_SET_FEATURES, &features) < 0) {
> +		debug_perror("VHOST_SET_FEATURES ioctl failed");
> +		goto close_fd;
> +	}
> +
> +	c->vhost.features = features;
> +	c->vhost.fd = vhost_fd;
> +
> +	return 0;
> +
> +close_fd:
> +	close(vhost_fd);
> +
> +	return -1;
> +}
> +
> +/**
> + * vhost_setup_eventfds() - Set up one queue's eventfds and ring size
> + * @c:		Execution context; c->vhost.fd must already be set
> + * @queue_idx:	Index of the queue (vring) to configure
> + *
> + */
> +void vhost_setup_eventfds(struct ctx *c, int queue_idx)
> +{
> +	struct vhost_vring_file call_file = { .index = queue_idx };
> +	struct vhost_vring_file kick_file = { .index = queue_idx };
> +	struct vhost_vring_file err_file = { .index = queue_idx };
> +	struct vhost_vring_state state = { .index = queue_idx };

Perhaps you can decale only one struct vhost_vring_file and reuse it for all (the 
queue_idx doesn't change).

> +	union epoll_ref ref = { .type = EPOLL_TYPE_VHOST_CALL };
> +	int vhost_fd = c->vhost.fd;
> +	struct epoll_event ev;
> +	int rc;
> +
> +	state.num = VHOST_NDESCS;
> +	ref.queue = queue_idx;
> +
> +	call_file.fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
> +	if (call_file.fd < 0)
> +		die_perror("Failed to create vhost call eventfd, queue %d",
> +			   queue_idx);

as you update ref later, perhaps add ref.type = EPOLL_TYPE_VHOST_CALL here and not set on 
declaration.

> +	ref.fd = call_file.fd;
> +
> +	rc = ioctl(vhost_fd, VHOST_SET_VRING_CALL, &call_file);
> +	if (rc < 0)
> +		die_perror("VHOST_SET_VRING_CALL ioctl failed, queue %d",
> +			   queue_idx);
> +
> +	ev = (struct epoll_event){ .data.u64 = ref.u64, .events = EPOLLIN };
> +	rc = epoll_ctl(c->epollfd, EPOLL_CTL_ADD, ref.fd, &ev);

we can use epoll_add() here


> +	if (rc < 0)
> +		die_perror("Failed to watch vhost call eventfd, queue %d",
> +			   queue_idx);
> +	c->vhost.vq[queue_idx].call_fd = call_file.fd;
> +
> +	err_file.fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
> +	if (err_file.fd < 0)
> +		die_perror("Failed to create vhost error eventfd, queue %d",
> +			   queue_idx);
> +
> +	rc = ioctl(vhost_fd, VHOST_SET_VRING_ERR, &err_file);
> +	if (rc < 0)
> +		die_perror("VHOST_SET_VRING_ERR ioctl failed, queue %d",
> +			   queue_idx);
> +
> +	ref.type = EPOLL_TYPE_VHOST_ERROR;
> +	ref.fd = err_file.fd;
> +	ev.data.u64 = ref.u64;
> +	rc = epoll_ctl(c->epollfd, EPOLL_CTL_ADD, ref.fd, &ev);

epoll_add()

> +	if (rc < 0)
> +		die_perror("Failed to watch vhost error eventfd, queue %d",
> +			   queue_idx);
> +	c->vhost.vq[queue_idx].err_fd = err_file.fd;
> +
> +	rc = ioctl(vhost_fd, VHOST_SET_VRING_NUM, &state);
> +	if (rc < 0)
> +		die_perror("VHOST_SET_VRING_NUM ioctl failed, queue %d",
> +			   queue_idx);
> +
> +	kick_file.fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
> +	if (kick_file.fd < 0)
> +		die_perror("Failed to create vhost kick eventfd, queue %d",
> +			   queue_idx);
> +
> +	rc = ioctl(vhost_fd, VHOST_SET_VRING_KICK, &kick_file);
> +	if (rc < 0)
> +		die_perror("VHOST_SET_VRING_KICK ioctl failed, queue %d",
> +			   queue_idx);
> +
> +	c->vhost.vq[queue_idx].kick_fd = kick_file.fd;
> +
> +	vhost_vq_state[queue_idx].num_free = VHOST_NDESCS;
> +}
> +
> +/**
> + * vhost_setup_memory_table() - Register the GPA/HVA translation table
> + * @c:		Execution context; c->vhost.fd must already be set
> + *
> + * vhost-net reads the addresses we put in descriptors as guest physical
> + * addresses, and translates them through this table before touching the
> + * memory they refer to. pasta has no guest and no second address space:
> + * the addresses we put there are our own virtual addresses. Every region
> + * below therefore sets guest_phys_addr equal to userspace_addr, so that
> + * GPA == HVA and the translation is an identity mapping.
> + *
> + * Return: 0 on success, -1 on error with errno set
> + */
> +int vhost_setup_memory_table(struct ctx *c) {
> +	size_t region_idx = 0;
> +
> +	/* general purpose buffers */
> +	general_register_memory_regions(&vhost_memory, &region_idx);
> +
> +	/* tcp specific buffers */
> +	tcp_register_memory_regions(&vhost_memory, &region_idx);
> +
> +	/* udp specific buffers */
> +	udp_register_memory_regions(&vhost_memory, &region_idx);
> +
> +	vhost_memory.mem.nregions = region_idx;
> +
> +	return ioctl(c->vhost.fd, VHOST_SET_MEM_TABLE, &vhost_memory.mem);
> +}
> +
> +/**
> + * vhost_set_vring() - Register a vring's addresses and bind its backend
> + * @c:		Execution context; c->vhost.fd must already be set
> + * @queue_idx:	Index of the queue (vring) to configure
> + * @tap_fd:	Tap fd to bind as this queue's backend
> + */
> +void vhost_set_vring(struct ctx *c, int queue_idx, int tap_fd)
> +{
> +	int vhost_fd = c->vhost.fd;
> +	struct vhost_vring_addr addr = {
> +		.index = queue_idx,
> +		.desc_user_addr = (unsigned long)vring_desc[queue_idx],
> +		.avail_user_addr = (unsigned long)&vring_avail_all[queue_idx],
> +		.used_user_addr = (unsigned long)&vring_used_all[queue_idx],
> +		.log_guest_addr = (unsigned long)&vring_used_all[queue_idx],
> +	};
> +	struct vhost_vring_file file = {
> +		.index = queue_idx,
> +		.fd = tap_fd,
> +	};
> +	unsigned int i;
> +	int rc;
> +
> +	rc = ioctl(vhost_fd, VHOST_SET_VRING_ADDR, &addr);
> +	if (rc < 0)
> +		die_perror("VHOST_SET_VRING_ADDR ioctl failed, queue %d",
> +			   queue_idx);
> +
> +	if (queue_idx == 0) {
> +		for (i = 0; i < VHOST_NDESCS; ++i) {
> +			vring_desc[0][i].addr = (uintptr_t)pkt_buf +
> +				i * VHOST_DESC_BYTES;
> +			vring_desc[0][i].len = VHOST_DESC_BYTES;
> +			vring_desc[0][i].flags = VRING_DESC_F_WRITE;
> +		}
> +
> +		for (i = 0; i < VHOST_NDESCS; ++i)
> +			vring_avail_all[0].avail.ring[i] = htole16(i);
> +
> +		vhost_rx_descriptor_handoff(c);
> +	}
> +
> +	if (queue_idx == 1) {
> +		for (i = 0; i < (VHOST_NDESCS - 1); ++i)
> +			vring_desc[1][i].next = i + 1;
> +	}

Perhaps you can use something like VHOST_USER_IS_QUEUE_TX()/VHOST_USER_IS_QUEUE_RX() 
rather then queue index?

> +
> +	rc = ioctl(vhost_fd, VHOST_NET_SET_BACKEND, &file);
> +	if (rc < 0)
> +		die_perror("VHOST_NET_SET_BACKEND ioctl failed, queue %d",
> +			   queue_idx);
> +}
> +
> +/**
> + * vhost_rx_descriptor_handoff() - Announce freed from-guest descriptors
> + * @c:		Execution context
> + *
> + * Bumps avail.idx by the number of descriptors accumulated in
> + * vhost_vq_state[0].num_free (from prior consume_one_rx_descriptor() calls),
> + * then resets the counter to zero. The kernel will see the new
> + * avail.idx and consume the freshly-available descriptors.
> + */
> +void vhost_rx_descriptor_handoff(struct ctx *c)
> +{
> +	smp_wmb();
> +
> +	if (!vhost_vq_state[0].num_free)
> +		return;
> +
> +	vring_avail_all[0].avail.idx += vhost_vq_state[0].num_free;
> +	vhost_vq_state[0].num_free = 0;
> +	vhost_kick(&vring_used_all[0].used, c->vhost.vq[0].kick_fd);
> +}
> +
> +/**
> + * vhost_kick() - Notify the kernel that new descriptors are available
> + * @used:	Used ring of the queue we're announcing on, checked to see
> + *		whether the kernel's virtio thread is already reading
> + *		descriptors and doesn't want to be notified
> + * @kick_fd:	Kick eventfd of that same queue
> + */
> +void vhost_kick(struct vring_used *used, int kick_fd)
> +{
> +	/* Ensure that the read of used->flags doesn't get reordered to be
> +	 * above the avail.idx update
> +	 */
> +	smp_mb();
> +
> +	if (!(used->flags & VRING_USED_F_NO_NOTIFY))
> +		eventfd_write(kick_fd, 1);
> +}
> diff --git a/vhost.h b/vhost.h
> new file mode 100644
> index 0000000..aaa937d
> --- /dev/null
> +++ b/vhost.h
> @@ -0,0 +1,79 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later
> + * Copyright Red Hat

If you wrote the code, I'm not sure it's copyrighted by Red Hat.

> + * Author: Ammar Yasser <aerosound161@gmail.com>
> + *
> + * vhost.h - vhost-net (vhost-kernel) acceleration for pasta mode
> + */
> +
> +#ifndef VHOST_H
> +#define VHOST_H
> +
> +#include <assert.h>
> +#include <stddef.h>
> +#include <stdint.h>
> +
> +#include <linux/vhost.h>
> +#include <linux/vhost_types.h>
> +#include <linux/virtio_config.h>
> +#include <linux/virtio_net.h>
> +#include <linux/virtio_ring.h>
> +
> +#include "passt.h"
> +
> +/**
> + * struct vq_state - Per-virtqueue local descriptor tracking
> + * @num_free:		Number of descriptors ready to be announced to the
> + *			kernel via vhost_rx_descriptor_handoff()
> + * @last_used_idx:	Number of used-ring entries consumed so far;
> + *			lagging read cursor vs. vring_used->idx (the
> + *			kernel's write cursor)
> + */
> +extern struct vq_state {
> +	uint16_t num_free;
> +	uint16_t last_used_idx;
> +	uint16_t next_free;
> +} vhost_vq_state[2];
> +
> +
> +extern struct vring_desc vring_desc[2][VHOST_NDESCS];
> +union vring_avail_u {
> +	struct vring_avail avail;
> +	char buf[offsetof(struct vring_avail, ring[VHOST_NDESCS])];
> +};

perhaps you can declare instead

struct vring_avail_passt {
	__virtio16 flags;
	__virtio16 idx;
	__virtio16 ring[VHOST_NDESCS];
};

This will be easier to read, and avoid to ignore the -Wpedantic

> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wpedantic"
> +extern union vring_avail_u vring_avail_all[2];
> +#pragma GCC diagnostic pop
> +
> +union vring_used_u {
> +	struct vring_used used;
> +	char buf[offsetof(struct vring_used, ring[VHOST_NDESCS])];
> +};

struct vring_used_pasta {
	__virtio16 flags;
	__virtio16 idx;
	vring_used_elem_t ring[VHOST_NDESCS];
};

> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wpedantic"
> +extern union vring_used_u vring_used_all[2];
> +#pragma GCC diagnostic pop
> +
> +#define N_VHOST_REGIONS 2

2 is not enough to store all the regions.

> +union vhost_memory_u {
> +	struct vhost_memory mem;
> +	char buf[offsetof(struct vhost_memory, regions[N_VHOST_REGIONS])];
> +};

struct vhost_memory_pasta {
	__u32 nregions;
	__u32 padding;
	struct vhost_memory_region regions[N_VHOST_REGIONS];
};

> +extern union vhost_memory_u vhost_memory;
> +
> +#define VHOST_MEMORY_REGION_PTR(addr, size) \
> +    (struct vhost_memory_region) { \
> +        .guest_phys_addr = (uintptr_t)addr, \
> +        .memory_size = size, \
> +        .userspace_addr  = (uintptr_t)addr, \
> +    }
> +#define VHOST_MEMORY_REGION(buf) VHOST_MEMORY_REGION_PTR(&buf, sizeof(buf))
> +
> +void vhost_set_vring(struct ctx *c, int queue_idx, int tap_fd);
> +int vhost_setup_memory_table(struct ctx *c);
> +int vhost_setup_net(struct ctx *c);
> +void vhost_setup_eventfds(struct ctx *c, int queue_idx);
> +void vhost_rx_descriptor_handoff(struct ctx *c);
> +void vhost_kick(struct vring_used *used, int kick_fd);
> +
> +#endif /* VHOST_H */


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

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-04 21:28 [PATCH 0/7] Add vhost-net kernel support to pasta aerosouund
2026-09-04 21:28 ` [PATCH 1/7] tap: Move the tap_hdr file to a separate file aerosouund
2026-09-05  1:52   ` David Gibson
2026-09-09  8:47   ` Laurent Vivier
2026-09-09  9:10     ` David Gibson
2026-09-09  9:42       ` Laurent Vivier
2026-09-04 21:28 ` [PATCH 2/7] conf: Add context fields, epoll types and --vhost-kernel flag to pasta aerosouund
2026-09-09 12:35   ` Laurent Vivier
2026-09-12 10:57     ` Ammar Yasser
2026-09-14  6:56       ` Laurent Vivier
2026-09-04 21:28 ` [PATCH 3/7] virtio: Add the pasta vhost-net interface and implementation aerosouund
2026-09-09 15:13   ` Laurent Vivier [this message]
2026-09-04 21:28 ` [PATCH 4/7] tap: Implement the pasta vhost-net from-guest path aerosouund
2026-09-04 21:28 ` [PATCH 5/7] tap, tcp, udp: Prepare the to-guest path for vhost-net aerosouund
2026-09-04 21:28 ` [PATCH 6/7] tap: Implement the pasta vhost-net to-guest path aerosouund
2026-09-16 14:00   ` Laurent Vivier
2026-09-04 21:28 ` [PATCH 7/7] tap/tcp: Replace tcp_payload_used with a ring buffer style index aerosouund
2026-09-16 14:29   ` Laurent Vivier
2026-09-05 16:25 ` [PATCH 2/7] conf: Add context fields, epoll types and --vhost-kernel flag to pasta aerosouund
2026-09-05 16:25   ` [PATCH 3/7] virtio: Add the pasta vhost-net interface and implementation aerosouund
2026-09-05 16:25   ` [PATCH 4/7] tap: Implement the pasta vhost-net from-guest path aerosouund
2026-09-05 16:25   ` [PATCH 7/7] tap/tcp: Replace tcp_payload_used with a ring buffer style index aerosouund

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=16b9f003-4144-4383-b837-a3ad09017bd3@redhat.com \
    --to=lvivier@redhat.com \
    --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).