public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: Laurent Vivier <lvivier@redhat.com>
Cc: passt-dev@passt.top
Subject: Re: [PATCH v6 07/12] udp: Pass queue pair explicitly through UDP send path
Date: Mon, 3 Aug 2026 13:22:21 +1000	[thread overview]
Message-ID: <anAJXvKBImWdfgNq@zatzit> (raw)
In-Reply-To: <20260731161617.3550626-8-lvivier@redhat.com>

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

On Fri, Jul 31, 2026 at 06:16:12PM +0200, Laurent Vivier wrote:
> Thread the queue pair parameter through the UDP socket handler and send
> path, replacing hardcoded QPAIR_DEFAULT values.  This is the UDP
> counterpart to the equivalent TCP and ARP changes.
> 
> Add a qpair parameter to udp_listen_sock_handler(), udp_sock_handler(),
> udp_sock_fwd(), udp_sock_recverr(), udp_sock_errs(), udp_tap_handler(),
> udp_send_tap_icmp4(), and udp_send_tap_icmp6().
> 
> The queue pair is passed from passt_worker() through
> udp_listen_sock_handler() and udp_sock_handler(), into udp_sock_fwd()
> and down into udp_sock_errs()/udp_sock_recverr() for ICMP error
> generation, as well as udp_vu_sock_to_tap() for vhost-user delivery.
> 
> On the tap side, udp_tap_handler() receives the queue pair and passes it
> to udp_flow_from_tap(), which takes the parameter for completeness but
> does not yet use it: new flows are not associated with a specific queue
> pair at creation time.
> 
> On the flow handling side, flow_defer_handler() receives the queue pair
> and passes it to udp_flow_defer() and udp_flush_flow(), so that deferred
> UDP datagrams are forwarded on the correct queue.
> 
> udp_vu_sock_to_tap() now uses the passed qpair to select the RX
> virtqueue instead of always using QPAIR_DEFAULT.
> 
> No functional change.
> 
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

With a couple of nits about the description of the @qpair parameter in
some places.

> ---
>  flow.c         |  6 ++++--
>  flow.h         |  3 ++-
>  passt.c        |  8 +++++---
>  tap.c          |  4 ++--
>  udp.c          | 48 +++++++++++++++++++++++++++---------------------
>  udp.h          |  9 +++++----
>  udp_flow.c     | 23 ++++++++++++++---------
>  udp_flow.h     | 13 +++++++------
>  udp_internal.h |  3 ++-
>  udp_vu.c       |  6 ++++--
>  udp_vu.h       |  3 ++-
>  11 files changed, 74 insertions(+), 52 deletions(-)
> 
> diff --git a/flow.c b/flow.c
> index 71918b773738..c63491804709 100644
> --- a/flow.c
> +++ b/flow.c
> @@ -884,8 +884,10 @@ flow_sidx_t flow_lookup_sa(const struct ctx *c, uint8_t proto, uint8_t pif,
>   * flow_defer_handler() - Handler for per-flow deferred and timed tasks
>   * @c:		Execution context
>   * @now:	Current timestamp
> + * @qpair:	Queue pair to process
>   */
> -void flow_defer_handler(const struct ctx *c, const struct timespec *now)
> +void flow_defer_handler(const struct ctx *c, const struct timespec *now,
> +			unsigned int qpair)
>  {
>  	struct flow_free_cluster *free_head = NULL;
>  	unsigned *last_next = &flow_first_free;
> @@ -924,7 +926,7 @@ void flow_defer_handler(const struct ctx *c, const struct timespec *now)
>  				closed = icmp_ping_timer(c, &flow->ping, now);
>  			break;
>  		case FLOW_UDP:
> -			closed = udp_flow_defer(c, &flow->udp, now);
> +			closed = udp_flow_defer(c, &flow->udp, now, qpair);
>  			if (!closed && timer)
>  				closed = udp_flow_timer(c, &flow->udp, now);
>  			break;
> diff --git a/flow.h b/flow.h
> index db028455a7a4..8d85e27427db 100644
> --- a/flow.h
> +++ b/flow.h
> @@ -270,7 +270,8 @@ void flow_epollid_set(struct flow_common *f, int epollid);
>  int flow_epoll_set(const struct flow_common *f, int command, uint32_t events,
>  		   int fd, unsigned int sidei);
>  void flow_epollid_register(int epollid, int epollfd);
> -void flow_defer_handler(const struct ctx *c, const struct timespec *now);
> +void flow_defer_handler(const struct ctx *c, const struct timespec *now,
> +			unsigned int qpair);
>  int flow_migrate_source_early(struct ctx *c, const struct migrate_stage *stage,
>  			      int fd);
>  int flow_migrate_source_pre(struct ctx *c, const struct migrate_stage *stage,
> diff --git a/passt.c b/passt.c
> index 86ed339ff67f..a26653db7763 100644
> --- a/passt.c
> +++ b/passt.c
> @@ -116,7 +116,7 @@ static void post_handler(struct ctx *c, const struct timespec *now,
>  	if (!c->no_tcp)
>  		tcp_defer_handler(c, now, qpair);
>  
> -	flow_defer_handler(c, now);
> +	flow_defer_handler(c, now, qpair);
>  	fwd_scan_ports_timer(c, now);
>  
>  	if (!c->no_ndp)
> @@ -275,10 +275,12 @@ static void passt_worker(void *opaque, int nfds, struct epoll_event *events)
>  			tcp_timer_handler(c, ref, &now, QPAIR_DEFAULT);
>  			break;
>  		case EPOLL_TYPE_UDP_LISTEN:
> -			udp_listen_sock_handler(c, ref, eventmask, &now);
> +			udp_listen_sock_handler(c, ref, eventmask, &now,
> +						QPAIR_DEFAULT);
>  			break;
>  		case EPOLL_TYPE_UDP:
> -			udp_sock_handler(c, ref, eventmask, &now);
> +			udp_sock_handler(c, ref, eventmask, &now,
> +					 QPAIR_DEFAULT);
>  			break;
>  		case EPOLL_TYPE_PING:
>  			icmp_sock_handler(c, ref, &now);
> diff --git a/tap.c b/tap.c
> index 9ce32d36f1d7..61d18ee161b1 100644
> --- a/tap.c
> +++ b/tap.c
> @@ -872,7 +872,7 @@ append:
>  			if (c->no_udp)
>  				continue;
>  			for (k = 0; k < p->count; )
> -				k += udp_tap_handler(c, PIF_TAP, AF_INET,
> +				k += udp_tap_handler(c, qpair, PIF_TAP, AF_INET,
>  						     &seq->saddr, &seq->daddr,
>  						     seq->ttl, p, k, now);
>  		}
> @@ -1123,7 +1123,7 @@ append:
>  			if (c->no_udp)
>  				continue;
>  			for (k = 0; k < p->count; )
> -				k += udp_tap_handler(c, PIF_TAP, AF_INET6,
> +				k += udp_tap_handler(c, qpair, PIF_TAP, AF_INET6,
>  						     &seq->saddr, &seq->daddr,
>  						     seq->hop_limit, p, k, now);
>  		}
> diff --git a/udp.c b/udp.c
> index 589d48a17613..a3321289bb53 100644
> --- a/udp.c
> +++ b/udp.c
> @@ -403,13 +403,14 @@ static void udp_tap_prepare(const struct mmsghdr *mmh,
>  /**
>   * udp_send_tap_icmp4() - Construct and send ICMPv4 to local peer
>   * @c:		Execution context
> + * @qpair:	Queue pair on which to send the ICMPv4 packet
>   * @ee:	Extended error descriptor
>   * @toside:	Destination side of flow
>   * @saddr:	Address of ICMP generating node
>   * @in:	First bytes (max 8) of original UDP message body
>   * @dlen:	Length of the read part of original UDP message body
>   */
> -static void udp_send_tap_icmp4(const struct ctx *c,
> +static void udp_send_tap_icmp4(const struct ctx *c, unsigned int qpair,
>  			       const struct sock_extended_err *ee,
>  			       const struct flowside *toside,
>  			       struct in_addr saddr,
> @@ -445,13 +446,14 @@ static void udp_send_tap_icmp4(const struct ctx *c,
>  	/* Try to obtain the MAC address of the generating node */
>  	saddr_any = inany_from_v4(saddr);
>  	fwd_neigh_mac_get(c, &saddr_any, tap_omac);
> -	tap_icmp4_send(c, QPAIR_DEFAULT, saddr, eaddr, &msg, tap_omac, msglen);
> +	tap_icmp4_send(c, qpair, saddr, eaddr, &msg, tap_omac, msglen);
>  }
>  
>  
>  /**
>   * udp_send_tap_icmp6() - Construct and send ICMPv6 to local peer
>   * @c:		Execution context
> + * @qpair:	Queue pair on which to send the ICMPv6 packet
>   * @ee:	Extended error descriptor
>   * @toside:	Destination side of flow
>   * @saddr:	Address of ICMP generating node
> @@ -459,7 +461,7 @@ static void udp_send_tap_icmp4(const struct ctx *c,
>   * @dlen:	Length of the read part of original UDP message body
>   * @flow:	IPv6 flow identifier
>   */
> -static void udp_send_tap_icmp6(const struct ctx *c,
> +static void udp_send_tap_icmp6(const struct ctx *c, unsigned int qpair,
>  			       const struct sock_extended_err *ee,
>  			       const struct flowside *toside,
>  			       const struct in6_addr *saddr,
> @@ -493,7 +495,7 @@ static void udp_send_tap_icmp6(const struct ctx *c,
>  
>  	/* Try to obtain the MAC address of the generating node */
>  	fwd_neigh_mac_get(c, (union inany_addr *) saddr, tap_omac);
> -	tap_icmp6_send(c, QPAIR_DEFAULT, saddr, eaddr, &msg, tap_omac, msglen);
> +	tap_icmp6_send(c, qpair, saddr, eaddr, &msg, tap_omac, msglen);
>  }
>  
>  /**
> @@ -548,7 +550,7 @@ static int udp_pktinfo(struct msghdr *msg, union inany_addr *dst)
>   */
>  static int udp_sock_recverr(const struct ctx *c, int s, flow_sidx_t sidx,
>  			    uint8_t pif, in_port_t port,
> -			    const struct timespec *now)
> +			    const struct timespec *now, unsigned int qpair)
>  {
>  	char buf[PKTINFO_SPACE + RECVERR_SPACE];
>  	const struct sock_extended_err *ee;
> @@ -655,12 +657,12 @@ static int udp_sock_recverr(const struct ctx *c, int s, flow_sidx_t sidx,
>  	if (hdr->cmsg_level == IPPROTO_IP &&
>  	    (o4 = inany_v4(&otap)) && inany_v4(&toside->eaddr)) {
>  		dlen = MIN(dlen, ICMP4_MAX_DLEN);
> -		udp_send_tap_icmp4(c, ee, toside, *o4, data, dlen);
> +		udp_send_tap_icmp4(c, qpair, ee, toside, *o4, data, dlen);
>  		return 1;
>  	}
>  
>  	if (hdr->cmsg_level == IPPROTO_IPV6 && !inany_v4(&toside->eaddr)) {
> -		udp_send_tap_icmp6(c, ee, toside, &otap.a6, data, dlen,
> +		udp_send_tap_icmp6(c, qpair, ee, toside, &otap.a6, data, dlen,
>  				   FLOW_IDX(uflow));
>  		return 1;
>  	}
> @@ -691,7 +693,7 @@ fail:
>   */
>  static int udp_sock_errs(const struct ctx *c, int s, flow_sidx_t sidx,
>  			 uint8_t pif, in_port_t port,
> -			 const struct timespec *now)
> +			 const struct timespec *now, unsigned int qpair)

Does this need to be added to the function comments as well?

>  {
>  	struct udp_flow *uflow = udp_at_sidx(sidx);
>  	unsigned n_err = 0;
> @@ -701,7 +703,7 @@ static int udp_sock_errs(const struct ctx *c, int s, flow_sidx_t sidx,
>  	assert(!c->no_udp);
>  
>  	/* Empty the error queue */
> -	while ((rc = udp_sock_recverr(c, s, sidx, pif, port, now)) > 0)
> +	while ((rc = udp_sock_recverr(c, s, sidx, pif, port, now, qpair)) > 0)
>  		n_err += rc;
>  
>  	if (rc < 0)
> @@ -862,7 +864,8 @@ static void udp_buf_sock_to_tap(const struct ctx *c, int s, int n,
>   * @now:	Current timestamp
>   */
>  void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
> -		  uint8_t frompif, in_port_t port, const struct timespec *now)
> +		  uint8_t frompif, in_port_t port, const struct timespec *now,
> +		  unsigned int qpair)
>  {
>  	union sockaddr_inany src;
>  	union inany_addr dst;
> @@ -878,7 +881,7 @@ void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
>  			      strerror_(-rc));
>  			/* Clear errors & carry on */
>  			if (udp_sock_errs(c, s, FLOW_SIDX_NONE,
> -					  frompif, port, now) < 0) {
> +					  frompif, port, now, qpair) < 0) {
>  				err_ratelimit(now,
>  "UDP: Unrecoverable error on listening socket: (%s port %hu)",
>  				    pif_name(frompif), port);
> @@ -887,7 +890,7 @@ void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
>  			continue;
>  		}
>  
> -		tosidx = udp_flow_from_sock(c, frompif, &dst, port, &src,
> +		tosidx = udp_flow_from_sock(c, qpair, frompif, &dst, port, &src,
>  					    rule_hint, now);
>  		topif = pif_at_sidx(tosidx);
>  
> @@ -895,7 +898,7 @@ void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
>  			udp_sock_to_sock(c, s, 1, tosidx);
>  		} else if (topif == PIF_TAP) {
>  			if (c->mode == MODE_VU)
> -				udp_vu_sock_to_tap(c, s, 1, tosidx);
> +				udp_vu_sock_to_tap(c, s, 1, tosidx, qpair);
>  			else
>  				udp_buf_sock_to_tap(c, s, 1, tosidx);
>  		} else if (flow_sidx_valid(tosidx)) {
> @@ -926,14 +929,15 @@ void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
>   * @ref:	epoll reference
>   * @events:	epoll events bitmap
>   * @now:	Current timestamp
> + * @qpair:	Queue pair to process

As with TCP, I'm not sure that "Queue pair to process" really conveys
what this means.  AIUI, this will be the qpair associated with the
epoll set on which we received the event.

>   */
>  void udp_listen_sock_handler(const struct ctx *c,
>  			     union epoll_ref ref, uint32_t events,
> -			     const struct timespec *now)
> +			     const struct timespec *now, unsigned int qpair)
>  {
>  	if (events & (EPOLLERR | EPOLLIN)) {
>  		udp_sock_fwd(c, ref.fd, ref.listen.rule,
> -			     ref.listen.pif, ref.listen.port, now);
> +			     ref.listen.pif, ref.listen.port, now, qpair);
>  	}
>  }
>  
> @@ -943,9 +947,10 @@ void udp_listen_sock_handler(const struct ctx *c,
>   * @ref:	epoll reference
>   * @events:	epoll events bitmap
>   * @now:	Current timestamp
> + * @qpair:	Queue pair to process
>   */
> -void udp_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, uint32_t events,
> +		      const struct timespec *now, unsigned int qpair)
>  {
>  	struct udp_flow *uflow = udp_at_sidx(ref.flowside);
>  
> @@ -953,7 +958,7 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref,
>  
>  	if (events & EPOLLERR) {
>  		if (udp_sock_errs(c, ref.fd, ref.flowside,
> -				  PIF_NONE, 0, now) < 0) {
> +				  PIF_NONE, 0, now, qpair) < 0) {
>  			flow_err_ratelimit(
>  				uflow, now,
>  				"Unrecoverable error on flow socket");
> @@ -982,7 +987,7 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref,
>  		} else if (topif == PIF_TAP) {
>  			if (c->mode == MODE_VU) {
>  				udp_vu_sock_to_tap(c, s, UDP_MAX_FRAMES,
> -						   tosidx);
> +						   tosidx, qpair);
>  			} else {
>  				udp_buf_sock_to_tap(c, s, n, tosidx);
>  			}
> @@ -1003,6 +1008,7 @@ fail:
>  /**
>   * udp_tap_handler() - Handle packets from tap
>   * @c:		Execution context
> + * @qpair:	Queue pair to process
>   * @pif:	pif on which the packet is arriving
>   * @af:		Address family, AF_INET or AF_INET6
>   * @saddr:	Source address
> @@ -1016,7 +1022,7 @@ fail:
>   *
>   * #syscalls sendmmsg
>   */
> -int udp_tap_handler(const struct ctx *c, uint8_t pif,
> +int udp_tap_handler(const struct ctx *c, unsigned int qpair, uint8_t pif,
>  		    sa_family_t af, const void *saddr, const void *daddr,
>  		    uint8_t ttl, const struct pool *p, int idx,
>  		    const struct timespec *now)
> @@ -1049,7 +1055,7 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif,
>  	src = ntohs(uh->source);
>  	dst = ntohs(uh->dest);
>  
> -	tosidx = udp_flow_from_tap(c, pif, af, saddr, daddr, src, dst, now);
> +	tosidx = udp_flow_from_tap(c, qpair, pif, af, saddr, daddr, src, dst, now);
>  	if (!(uflow = udp_at_sidx(tosidx))) {
>  		char sstr[INET6_ADDRSTRLEN], dstr[INET6_ADDRSTRLEN];
>  
> diff --git a/udp.h b/udp.h
> index b50283eab198..abd651f2fab6 100644
> --- a/udp.h
> +++ b/udp.h
> @@ -12,10 +12,11 @@
>  #include "fwd.h"
>  
>  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,
> -		      uint32_t events, const struct timespec *now);
> -int udp_tap_handler(const struct ctx *c, uint8_t pif,
> +			     uint32_t events, const struct timespec *now,
> +			     unsigned int qpair);
> +void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events,
> +		      const struct timespec *now, unsigned int qpair);
> +int udp_tap_handler(const struct ctx *c, unsigned int qpair, uint8_t pif,
>  		    sa_family_t af, const void *saddr, const void *daddr,
>  		    uint8_t ttl, const struct pool *p, int idx,
>  		    const struct timespec *now);
> diff --git a/udp_flow.c b/udp_flow.c
> index f59649f6f2fc..ff6abcb8eba0 100644
> --- a/udp_flow.c
> +++ b/udp_flow.c
> @@ -207,6 +207,7 @@ cancel:
>  /**
>   * udp_flow_from_sock() - Find or create UDP flow for incoming datagram
>   * @c:		Execution context
> + * @qpair:	Queue pair for the flow
>   * @pif:	Interface the datagram is arriving from
>   * @dst:	Our (local) address to which the datagram is arriving
>   * @port:	Our (local) port number to which the datagram is arriving
> @@ -219,9 +220,9 @@ cancel:
>   * Return: sidx for the destination side of the flow for this packet, or
>   *         FLOW_SIDX_NONE if we couldn't find or create a flow.
>   */
> -flow_sidx_t udp_flow_from_sock(const struct ctx *c, uint8_t pif,
> -			       const union inany_addr *dst, in_port_t port,
> -			       const union sockaddr_inany *s_in,
> +flow_sidx_t udp_flow_from_sock(const struct ctx *c, unsigned int qpair,
> +			       uint8_t pif, const union inany_addr *dst,
> +			       in_port_t port, const union sockaddr_inany *s_in,
>  			       int rule_hint, const struct timespec *now)
>  {
>  	const struct flowside *ini;
> @@ -235,6 +236,7 @@ flow_sidx_t udp_flow_from_sock(const struct ctx *c, uint8_t pif,
>  		return flow_sidx_opposite(sidx);
>  	}
>  
> +	(void)qpair;
>  	if (!(flow = flow_alloc())) {
>  		char sastr[SOCKADDR_STRLEN];
>  
> @@ -264,6 +266,7 @@ flow_sidx_t udp_flow_from_sock(const struct ctx *c, uint8_t pif,
>  /**
>   * udp_flow_from_tap() - Find or create UDP flow for tap packets
>   * @c:		Execution context
> + * @qpair:	Queue pair for the flow
>   * @pif:	pif on which the packet is arriving
>   * @af:		Address family, AF_INET or AF_INET6
>   * @saddr:	Source address on guest side
> @@ -274,7 +277,7 @@ flow_sidx_t udp_flow_from_sock(const struct ctx *c, uint8_t pif,
>   * Return: sidx for the destination side of the flow for this packet, or
>   *         FLOW_SIDX_NONE if we couldn't find or create a flow.
>   */
> -flow_sidx_t udp_flow_from_tap(const struct ctx *c,
> +flow_sidx_t udp_flow_from_tap(const struct ctx *c, unsigned int qpair,
>  			      uint8_t pif, sa_family_t af,
>  			      const void *saddr, const void *daddr,
>  			      in_port_t srcport, in_port_t dstport,
> @@ -294,6 +297,7 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c,
>  		return flow_sidx_opposite(sidx);
>  	}
>  
> +	(void)qpair;
>  	if (!(flow = flow_alloc())) {
>  		char sstr[INET6_ADDRSTRLEN], dstr[INET6_ADDRSTRLEN];
>  
> @@ -323,15 +327,16 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c,
>   * @uflow:	Flow to handle
>   * @sidei:	Side of the flow to flush
>   * @now:	Current timestamp
> + * @qpair:	Queue pair for the flow
>   */
>  static void udp_flush_flow(const struct ctx *c,
>  			   const struct udp_flow *uflow, unsigned sidei,
> -			   const struct timespec *now)
> +			   const struct timespec *now, unsigned int qpair)
>  {
>  	/* We don't know exactly where the datagrams will come from, but we know
>  	 * they'll have an interface and oport matching this flow */
>  	udp_sock_fwd(c, uflow->s[sidei], -1, uflow->f.pif[sidei],
> -		     uflow->f.side[sidei].oport, now);
> +		     uflow->f.side[sidei].oport, now, qpair);
>  }
>  
>  /**
> @@ -343,14 +348,14 @@ static void udp_flush_flow(const struct ctx *c,
>   * Return: true if the connection is ready to free, false otherwise
>   */
>  bool udp_flow_defer(const struct ctx *c, struct udp_flow *uflow,
> -		    const struct timespec *now)
> +		    const struct timespec *now, unsigned int qpair)
>  {
>  	if (uflow->flush0) {
> -		udp_flush_flow(c, uflow, INISIDE, now);
> +		udp_flush_flow(c, uflow, INISIDE, now, qpair);
>  		uflow->flush0 = false;
>  	}
>  	if (uflow->flush1) {
> -		udp_flush_flow(c, uflow, TGTSIDE, now);
> +		udp_flush_flow(c, uflow, TGTSIDE, now, qpair);
>  		uflow->flush1 = false;
>  	}
>  	return uflow->closed;
> diff --git a/udp_flow.h b/udp_flow.h
> index 62cc9b3aae1f..f82a9a7c8923 100644
> --- a/udp_flow.h
> +++ b/udp_flow.h
> @@ -40,18 +40,19 @@ struct udp_flow {
>  };
>  
>  struct udp_flow *udp_at_sidx(flow_sidx_t sidx);
> -flow_sidx_t udp_flow_from_sock(const struct ctx *c, uint8_t pif,
> -			       const union inany_addr *dst, in_port_t port,
> -			       const union sockaddr_inany *s_in,
> -			       int rule_hint, const struct timespec *now);
> -flow_sidx_t udp_flow_from_tap(const struct ctx *c,
> +flow_sidx_t udp_flow_from_sock(const struct ctx *c, unsigned int qpair,
> +			       uint8_t pif, const union inany_addr *dst,
> +			       in_port_t port,
> +			       const union sockaddr_inany *s_in, int rule_hint,
> +			       const struct timespec *now);
> +flow_sidx_t udp_flow_from_tap(const struct ctx *c, unsigned int qpair,
>  			      uint8_t pif, sa_family_t af,
>  			      const void *saddr, const void *daddr,
>  			      in_port_t srcport, in_port_t dstport,
>  			      const struct timespec *now);
>  void udp_flow_close(const struct ctx *c, struct udp_flow *uflow);
>  bool udp_flow_defer(const struct ctx *c, struct udp_flow *uflow,
> -		    const struct timespec *now);
> +		    const struct timespec *now, unsigned int qpair);
>  bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
>  		    const struct timespec *now);
>  void udp_flow_activity(struct udp_flow *uflow, unsigned int sidei,
> diff --git a/udp_internal.h b/udp_internal.h
> index 361cc7495a01..0cd6da49fc05 100644
> --- a/udp_internal.h
> +++ b/udp_internal.h
> @@ -34,6 +34,7 @@ size_t udp_update_hdr6(struct ipv6hdr *ip6h, struct udphdr *uh,
>  		       const struct flowside *toside, size_t dlen,
<>  		       bool no_udp_csum);
>  void udp_sock_fwd(const struct ctx *c, int s, int rule_hint,
> -		  uint8_t frompif, in_port_t port, const struct timespec *now);
> +		  uint8_t frompif, in_port_t port, const struct timespec *now,
> +		  unsigned int qpair);
>  
>  #endif /* UDP_INTERNAL_H */
> diff --git a/udp_vu.c b/udp_vu.c
> index 4003f5b42b56..21fa891b3b51 100644
> --- a/udp_vu.c
> +++ b/udp_vu.c
> @@ -144,13 +144,15 @@ static void udp_vu_prepare(const struct ctx *c, struct iov_tail *data,
>   * @s:		Socket to read data from
>   * @n:		Maximum number of datagrams to forward
>   * @tosidx:	Flow & side to forward data from @s to
> + * @qpair:	Queue pair to process
>   */
> -void udp_vu_sock_to_tap(const struct ctx *c, int s, int n, flow_sidx_t tosidx)
> +void udp_vu_sock_to_tap(const struct ctx *c, int s, int n, flow_sidx_t tosidx,
> +			 unsigned int qpair)
>  {
>  	const struct flowside *toside = flowside_at_sidx(tosidx);
>  	bool v6 = !(inany_v4(&toside->eaddr) && inany_v4(&toside->oaddr));
>  	static struct vu_virtq_element elem[VIRTQUEUE_MAX_SIZE];
> -	int toguest = QPAIR_TOGUEST_QUEUE(QPAIR_DEFAULT);
> +	int toguest = QPAIR_TOGUEST_QUEUE(qpair);
>  	static struct iovec iov_vu[VIRTQUEUE_MAX_SIZE];
>  	struct vu_dev *vdev = c->vdev;
>  	struct vu_virtq *vq = &vdev->vq[toguest];
> diff --git a/udp_vu.h b/udp_vu.h
> index 1e38af35ad4e..40ab28119b10 100644
> --- a/udp_vu.h
> +++ b/udp_vu.h
> @@ -10,6 +10,7 @@
>  
>  void udp_vu_listen_sock_data(const struct ctx *c, union epoll_ref ref,
>  			     const struct timespec *now);
> -void udp_vu_sock_to_tap(const struct ctx *c, int s, int n, flow_sidx_t tosidx);
> +void udp_vu_sock_to_tap(const struct ctx *c, int s, int n, flow_sidx_t tosidx,
> +			unsigned int qpair);
>  
>  #endif /* UDP_VU_H */
> -- 
> 2.54.0
> 

-- 
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-03  3:46 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-31 16:16 [PATCH v6 00/12] vhost-user: Add multiqueue support Laurent Vivier
2026-07-31 16:16 ` [PATCH v6 01/12] tap: Remove pool parameter from tap4_handler() and tap6_handler() Laurent Vivier
2026-07-31 16:16 ` [PATCH v6 02/12] vhost-user: Advertise multiqueue support Laurent Vivier
2026-08-03  2:03   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 03/12] test: Add multiqueue support to vhost-user test infrastructure Laurent Vivier
2026-07-31 16:16 ` [PATCH v6 04/12] tap: Thread queue pair through all remaining tap paths Laurent Vivier
2026-08-03  3:10   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 05/12] arp: Pass queue pair explicitly through ARP send path Laurent Vivier
2026-08-03  3:10   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 06/12] tcp: Pass queue pair explicitly through TCP " Laurent Vivier
2026-08-03  3:17   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 07/12] udp: Pass queue pair explicitly through UDP " Laurent Vivier
2026-08-03  3:22   ` David Gibson [this message]
2026-07-31 16:16 ` [PATCH v6 08/12] dhcp/dhcpv6: Pass queue pair explicitly through DHCP " Laurent Vivier
2026-08-03  3:24   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 09/12] icmp: Pass queue pair explicitly through ICMP " Laurent Vivier
2026-08-03  3:26   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 10/12] ndp: Pass queue pair explicitly through NDP " Laurent Vivier
2026-08-03  3:27   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 11/12] flow: Add queue pair tracking to flow management Laurent Vivier
2026-08-03  3:40   ` David Gibson
2026-07-31 16:16 ` [PATCH v6 12/12] flow: Derive epoll fd from queue pair, removing epollid field Laurent Vivier
2026-08-03  3:46   ` 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=anAJXvKBImWdfgNq@zatzit \
    --to=david@gibson.dropbear.id.au \
    --cc=lvivier@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).