From: David Gibson <david@gibson.dropbear.id.au>
To: Laurent Vivier <lvivier@redhat.com>
Cc: passt-dev@passt.top
Subject: Re: [PATCH v6 12/12] flow: Derive epoll fd from queue pair, removing epollid field
Date: Mon, 3 Aug 2026 13:46:20 +1000 [thread overview]
Message-ID: <anAPAb9QwWPa5Ed5@zatzit> (raw)
In-Reply-To: <20260731161617.3550626-13-lvivier@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 9733 bytes --]
On Fri, Jul 31, 2026 at 06:16:17PM +0200, Laurent Vivier wrote:
> Since each queue pair maps to exactly one epoll instance, the epoll
> file descriptor can be looked up directly from the flow's qpair
> field. This makes the separate epollid field and its indirection
> through epoll_id_to_fd[] redundant.
>
> Replace epoll_id_to_fd[] with qpair_to_fd[], derived from the qpair
> assigned at flow creation. Remove flow_epollid_set(),
> flow_epollid_register(), flow_qp()/FLOW_QP(), and the epollid field
> from flow_common. flow_epollfd() now simply returns
> qpair_to_fd[f->qpair].
>
> flow_init() now takes the execution context to initialise
> qpair_to_fd[] from c->epollfd.
>
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
A few minor comments, otherwise LGTM.
> ---
> flow.c | 55 +++++++++-------------------------------------------
> flow.h | 20 +++++--------------
> icmp.c | 1 -
> passt.c | 3 +--
> tcp.c | 3 ---
> tcp_splice.c | 1 -
> udp_flow.c | 1 -
> 7 files changed, 15 insertions(+), 69 deletions(-)
>
> diff --git a/flow.c b/flow.c
> index 40b2e68be0ab..1efa9b966991 100644
> --- a/flow.c
> +++ b/flow.c
> @@ -130,7 +130,7 @@ static_assert(ARRAY_SIZE(flow_epoll) == FLOW_NUM_TYPES,
> unsigned flow_first_free;
> union flow flowtab[FLOW_MAX];
> static const union flow *flow_new_entry; /* = NULL */
> -static int epoll_id_to_fd[EPOLLFD_ID_SIZE];
> +int qpair_to_fd[FLOW_QPAIR_SIZE];
Nit: I'd suggest qpair_to_epollfd[], since there could bve a bunch of
fds related to a qpair one way or another.
>
> /* Hash table to index it */
> #define FLOW_HASH_LOAD 70 /* % */
> @@ -364,19 +364,7 @@ static void flow_set_state(struct flow_common *f, enum flow_state state)
> */
> int flow_epollfd(const struct flow_common *f)
> {
> - return epoll_id_to_fd[f->epollid];
> -}
> -
> -/**
> - * flow_epollid_set() - Associate a flow with an epoll id
> - * @f: Flow to update
> - * @epollid: epoll id to associate with this flow
> - */
> -void flow_epollid_set(struct flow_common *f, int epollid)
> -{
> - assert(epollid < EPOLLFD_ID_SIZE);
> -
> - f->epollid = epollid;
> + return qpair_to_fd[f->qpair];
> }
>
> /**
> @@ -405,31 +393,6 @@ int flow_epoll_set(const struct flow_common *f, int command, uint32_t events,
> return epoll_ctl(flow_epollfd(f), command, fd, &ev);
> }
>
> -/**
> - * flow_epollid_register() - Initialize the epoll id -> fd mapping
> - * @epollid: epoll id to associate to
> - * @epollfd: epoll file descriptor for this epoll id
> - */
> -void flow_epollid_register(int epollid, int epollfd)
> -{
> - assert(epollid < EPOLLFD_ID_SIZE);
> -
> - epoll_id_to_fd[epollid] = epollfd;
> -}
> -
> -/**
> - * flow_qp() - Get the queue pair for a flow
> - * @f: Flow to query (may be NULL)
> - *
> - * Return: queue pair number for the flow, or 0 if flow is NULL or has no
> - * valid queue pair assignment
> - */
> -/* cppcheck-suppress unusedFunction */
> -unsigned int flow_qp(const struct flow_common *f)
> -{
> - return f->qpair;
> -}
> -
> /**
> * flow_setqp() - Set queue pair assignment for a flow
> * @f: Flow to update
> @@ -437,13 +400,9 @@ unsigned int flow_qp(const struct flow_common *f)
> */
> static void flow_setqp(struct flow_common *f, unsigned int qpair)
> {
> - assert(qpair < FLOW_QPAIR_MAX);
> -
> - if (f->qpair == qpair)
> - return;
> + assert(qpair < FLOW_QPAIR_SIZE);
>
> - flow_trace((union flow *)f, "updating queue pair from %d to %d",
> - f->qpair, qpair);
> + flow_trace((union flow *)f, "setting queue pair to %d", qpair);
>
> f->qpair = qpair;
> }
> @@ -1299,8 +1258,9 @@ int flow_migrate_target(struct ctx *c, const struct migrate_stage *stage,
>
> /**
> * flow_init() - Initialise flow related data structures
> + * @c: Execution context
> */
> -void flow_init(void)
> +void flow_init(const struct ctx *c)
> {
> unsigned b;
>
> @@ -1310,4 +1270,7 @@ void flow_init(void)
>
> for (b = 0; b < FLOW_HASH_SIZE; b++)
> flow_hashtab[b] = FLOW_SIDX_NONE;
> +
> + for (b = 0; b < FLOW_QPAIR_SIZE; b++)
> + qpair_to_fd[b] = c->epollfd;
> }
> diff --git a/flow.h b/flow.h
> index b6f980b4f826..028d42bccc0c 100644
> --- a/flow.h
> +++ b/flow.h
> @@ -157,6 +157,8 @@ struct flowside {
> in_port_t eport;
> };
>
> +extern int qpair_to_fd[];
Does this need to be extern? Looks like everything outside flow.h
accesses it indirectly via flow_epollfd()?
> +
> /**
> * flowside_eq() - Check if two flowsides are equal
> * @left, @right: Flowsides to compare
> @@ -203,19 +205,12 @@ struct flow_common {
>
> uint8_t tap_omac[6];
>
> -#define EPOLLFD_ID_BITS 8
> - unsigned int epollid:EPOLLFD_ID_BITS;
> #define FLOW_QPAIR_BITS 5
> unsigned int qpair:FLOW_QPAIR_BITS;
> };
>
> -#define EPOLLFD_ID_DEFAULT 0
> -#define EPOLLFD_ID_SIZE (1 << EPOLLFD_ID_BITS)
> -
> -#define FLOW_QPAIR_NUM (1 << FLOW_QPAIR_BITS)
> -#define FLOW_QPAIR_MAX (FLOW_QPAIR_NUM - 1)
> -
> -static_assert(VHOST_USER_MAX_VQS <= FLOW_QPAIR_MAX * 2);
> +#define FLOW_QPAIR_SIZE (1 << FLOW_QPAIR_BITS)
> +static_assert(VHOST_USER_MAX_VQS <= FLOW_QPAIR_SIZE * 2);
>
> #define FLOW_INDEX_BITS 17 /* 128k - 1 */
> #define FLOW_MAX MAX_FROM_BITS(FLOW_INDEX_BITS)
> @@ -271,15 +266,10 @@ flow_sidx_t flow_lookup_sa(const struct ctx *c, uint8_t proto, uint8_t pif,
>
> union flow;
>
> -void flow_init(void);
> +void flow_init(const struct ctx *c);
> int flow_epollfd(const struct flow_common *f);
> -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);
> -unsigned int flow_qp(const struct flow_common *f);
> -#define FLOW_QP(flow_) \
> - (flow_qp(&(flow_)->f))
>
> void flow_defer_handler(const struct ctx *c, const struct timespec *now,
> unsigned int qpair);
> diff --git a/icmp.c b/icmp.c
> index e75d66d168be..46c5d925600a 100644
> --- a/icmp.c
> +++ b/icmp.c
> @@ -219,7 +219,6 @@ static struct icmp_ping_flow *icmp_ping_new(const struct ctx *c,
> if (pingf->sock > FD_REF_MAX)
> goto cancel;
>
> - flow_epollid_set(&pingf->f, EPOLLFD_ID_DEFAULT);
> if (flow_epoll_set(&pingf->f, EPOLL_CTL_ADD, EPOLLIN, pingf->sock,
> TGTSIDE) < 0) {
> close(pingf->sock);
> diff --git a/passt.c b/passt.c
> index 55708d96fb06..bc9f1575ef8c 100644
> --- a/passt.c
> +++ b/passt.c
> @@ -382,7 +382,6 @@ int main(int argc, char **argv)
> c->epollfd = epoll_create1(EPOLL_CLOEXEC);
> if (c->epollfd == -1)
> die_perror("Failed to create epoll file descriptor");
> - flow_epollid_register(EPOLLFD_ID_DEFAULT, c->epollfd);
>
> if (getrlimit(RLIMIT_NOFILE, &limit))
> die_perror("Failed to get maximum value of open files limit");
> @@ -405,7 +404,7 @@ int main(int argc, char **argv)
> if (clock_gettime(CLOCK_MONOTONIC, &now))
> die_perror("Failed to get CLOCK_MONOTONIC time");
>
> - flow_init();
> + flow_init(c);
> fwd_scan_ports_init(c);
>
> if ((!c->no_udp && udp_init(c)) || (!c->no_tcp && tcp_init(c)))
> diff --git a/tcp.c b/tcp.c
> index 39f732f8bea3..e80a64e38f24 100644
> --- a/tcp.c
<> +++ b/tcp.c
> @@ -1764,7 +1764,6 @@ static void tcp_conn_from_tap(const struct ctx *c, unsigned int qpair,
>
> conn->sock = s;
> conn->timer = -1;
> - flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT);
> if (flow_epoll_set(&conn->f, EPOLL_CTL_ADD, 0, s, TGTSIDE) < 0) {
> flow_perror_ratelimit(flow, now, "Can't register with epoll");
> goto cancel;
> @@ -2578,7 +2577,6 @@ static void tcp_tap_conn_from_sock(const struct ctx *c, union flow *flow,
> conn->timer = -1;
> conn->ws_to_tap = conn->ws_from_tap = 0;
>
> - flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT);
> if (flow_epoll_set(&conn->f, EPOLL_CTL_ADD, 0, s, INISIDE) < 0) {
> flow_perror_ratelimit(flow, now, "Can't register with epoll");
> conn_flag(c, conn, CLOSING, now);
> @@ -3876,7 +3874,6 @@ int tcp_flow_migrate_target(struct ctx *c, int fd)
> goto out;
> }
>
> - flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT);
> if (flow_epoll_set(&conn->f, EPOLL_CTL_ADD, 0, conn->sock,
> !TAPSIDE(conn)))
> goto out; /* tcp_flow_migrate_target_ext() will clean this up */
> diff --git a/tcp_splice.c b/tcp_splice.c
> index 4b01f1aa3602..8617e62cea9a 100644
> --- a/tcp_splice.c
> +++ b/tcp_splice.c
> @@ -387,7 +387,6 @@ static int tcp_splice_connect(const struct ctx *c, struct tcp_splice_conn *conn,
>
> pif_sockaddr(c, &sa, tgtpif, &tgt->eaddr, tgt->eport);
>
> - flow_epollid_set(&conn->f, EPOLLFD_ID_DEFAULT);
> if (flow_epoll_set(&conn->f, EPOLL_CTL_ADD, 0, conn->s[0], 0) ||
> flow_epoll_set(&conn->f, EPOLL_CTL_ADD, 0, conn->s[1], 1)) {
> int ret = -errno;
> diff --git a/udp_flow.c b/udp_flow.c
> index 2578d640a3da..8e985df8398d 100644
> --- a/udp_flow.c
> +++ b/udp_flow.c
> @@ -154,7 +154,6 @@ static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow,
> uflow->ttl[INISIDE] = uflow->ttl[TGTSIDE] = 0;
> uflow->activity[INISIDE] = 1;
> uflow->activity[TGTSIDE] = 0;
> - flow_epollid_set(&uflow->f, EPOLLFD_ID_DEFAULT);
>
> flow_foreach_sidei(sidei) {
> if (pif_is_socket(uflow->f.pif[sidei]))
> --
> 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 --]
prev parent 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
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 [this message]
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=anAPAb9QwWPa5Ed5@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).