From: David Gibson <david@gibson.dropbear.id.au>
To: passt-dev@passt.top, Stefano Brivio <sbrivio@redhat.com>
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH 2/4] udp: Simplify checking of epoll event bits
Date: Tue, 25 Mar 2025 14:00:08 +1100 [thread overview]
Message-ID: <20250325030010.970144-3-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20250325030010.970144-1-david@gibson.dropbear.id.au>
udp_{listen,reply}_sock_handler() can accept both EPOLLERR and EPOLLIN
events. However, unlike most epoll event handlers we don't check the
event bits right there. EPOLLERR is checked within udp_sock_errs() which
we call unconditionally. Checking EPOLLIN is still more buried: it is
checked within both udp_sock_recv() and udp_vu_sock_recv().
We can simplify the logic and pass less extraneous parameters around by
moving the checking of the event bits to the top level event handlers.
This makes udp_{buf,vu}_{listen,reply}_sock_handler() no longer general
event handlers, but specific to EPOLLIN events, meaning new data. So,
rename those functions to udp_{buf,vu}_{listen,reply}_sock_data() to better
reflect their function.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
udp.c | 78 ++++++++++++++++++++++++--------------------------------
udp_vu.c | 25 +++++++-----------
udp_vu.h | 8 +++---
3 files changed, 47 insertions(+), 64 deletions(-)
diff --git a/udp.c b/udp.c
index 4a06b162..26a91c9c 100644
--- a/udp.c
+++ b/udp.c
@@ -581,12 +581,10 @@ static int udp_sock_recverr(const struct ctx *c, union epoll_ref ref)
* udp_sock_errs() - Process errors on a socket
* @c: Execution context
* @ref: epoll reference
- * @events: epoll events bitmap
*
* Return: Number of errors handled, or < 0 if we have an unrecoverable error
*/
-static int udp_sock_errs(const struct ctx *c, union epoll_ref ref,
- uint32_t events)
+static int udp_sock_errs(const struct ctx *c, union epoll_ref ref)
{
unsigned n_err = 0;
socklen_t errlen;
@@ -595,9 +593,6 @@ static int udp_sock_errs(const struct ctx *c, union epoll_ref ref,
ASSERT(!c->no_udp);
- if (!(events & EPOLLERR))
- return 0; /* Nothing to do */
-
/* Empty the error queue */
while ((rc = udp_sock_recverr(c, ref)) > 0)
n_err += rc;
@@ -630,15 +625,13 @@ static int udp_sock_errs(const struct ctx *c, union epoll_ref ref,
* udp_sock_recv() - Receive datagrams from a socket
* @c: Execution context
* @s: Socket to receive from
- * @events: epoll events bitmap
* @mmh mmsghdr array to receive into
*
* Return: Number of datagrams received
*
* #syscalls recvmmsg arm:recvmmsg_time64 i686:recvmmsg_time64
*/
-static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
- struct mmsghdr *mmh)
+static int udp_sock_recv(const struct ctx *c, int s, struct mmsghdr *mmh)
{
/* For not entirely clear reasons (data locality?) pasta gets better
* throughput if we receive tap datagrams one at a atime. For small
@@ -651,9 +644,6 @@ static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
ASSERT(!c->no_udp);
- if (!(events & EPOLLIN))
- return 0;
-
n = recvmmsg(s, mmh, n, 0, NULL);
if (n < 0) {
err_perror("Error receiving datagrams");
@@ -664,22 +654,20 @@ static int udp_sock_recv(const struct ctx *c, int s, uint32_t events,
}
/**
- * udp_buf_listen_sock_handler() - Handle new data from socket
+ * udp_buf_listen_sock_data() - Handle new data from socket
* @c: Execution context
* @ref: epoll reference
- * @events: epoll events bitmap
* @now: Current timestamp
*
* #syscalls recvmmsg
*/
-static void udp_buf_listen_sock_handler(const struct ctx *c,
- union epoll_ref ref, uint32_t events,
- const struct timespec *now)
+static void udp_buf_listen_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now)
{
const socklen_t sasize = sizeof(udp_meta[0].s_in);
int n, i;
- if ((n = udp_sock_recv(c, ref.fd, events, udp_mh_recv)) <= 0)
+ if ((n = udp_sock_recv(c, ref.fd, udp_mh_recv)) <= 0)
return;
/* We divide datagrams into batches based on how we need to send them,
@@ -744,33 +732,33 @@ void udp_listen_sock_handler(const struct ctx *c,
union epoll_ref ref, uint32_t events,
const struct timespec *now)
{
- if (udp_sock_errs(c, ref, events) < 0) {
- err("UDP: Unrecoverable error on listening socket:"
- " (%s port %hu)", pif_name(ref.udp.pif), ref.udp.port);
- /* FIXME: what now? close/re-open socket? */
- return;
+ if (events & EPOLLERR) {
+ if (udp_sock_errs(c, ref) < 0) {
+ err("UDP: Unrecoverable error on listening socket:"
+ " (%s port %hu)", pif_name(ref.udp.pif), ref.udp.port);
+ /* FIXME: what now? close/re-open socket? */
+ return;
+ }
}
- if (c->mode == MODE_VU) {
- udp_vu_listen_sock_handler(c, ref, events, now);
- return;
+ if (events & EPOLLIN) {
+ if (c->mode == MODE_VU)
+ udp_vu_listen_sock_data(c, ref, now);
+ else
+ udp_buf_listen_sock_data(c, ref, now);
}
-
- udp_buf_listen_sock_handler(c, ref, events, now);
}
/**
- * udp_buf_reply_sock_handler() - Handle new data from flow specific socket
+ * udp_buf_reply_sock_data() - Handle new data from flow specific socket
* @c: Execution context
* @ref: epoll reference
- * @events: epoll events bitmap
* @now: Current timestamp
*
* #syscalls recvmmsg
*/
-static void udp_buf_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events,
- const struct timespec *now)
+static void udp_buf_reply_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now)
{
flow_sidx_t tosidx = flow_sidx_opposite(ref.flowside);
const struct flowside *toside = flowside_at_sidx(tosidx);
@@ -780,7 +768,7 @@ static void udp_buf_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
from_s = uflow->s[ref.flowside.sidei];
- if ((n = udp_sock_recv(c, from_s, events, udp_mh_recv)) <= 0)
+ if ((n = udp_sock_recv(c, from_s, udp_mh_recv)) <= 0)
return;
flow_trace(uflow, "Received %d datagrams on reply socket", n);
@@ -821,19 +809,21 @@ void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
ASSERT(!c->no_udp && uflow);
- if (udp_sock_errs(c, ref, events) < 0) {
- flow_err(uflow, "Unrecoverable error on reply socket");
- flow_err_details(uflow);
- udp_flow_close(c, uflow);
- return;
+ if (events & EPOLLERR) {
+ if (udp_sock_errs(c, ref) < 0) {
+ flow_err(uflow, "Unrecoverable error on reply socket");
+ flow_err_details(uflow);
+ udp_flow_close(c, uflow);
+ return;
+ }
}
- if (c->mode == MODE_VU) {
- udp_vu_reply_sock_handler(c, ref, events, now);
- return;
+ if (events & EPOLLIN) {
+ if (c->mode == MODE_VU)
+ udp_vu_reply_sock_data(c, ref, now);
+ else
+ udp_buf_reply_sock_data(c, ref, now);
}
-
- udp_buf_reply_sock_handler(c, ref, events, now);
}
/**
diff --git a/udp_vu.c b/udp_vu.c
index 84f52aff..698667f6 100644
--- a/udp_vu.c
+++ b/udp_vu.c
@@ -78,14 +78,12 @@ static int udp_vu_sock_info(int s, union sockaddr_inany *s_in)
* udp_vu_sock_recv() - Receive datagrams from socket into vhost-user buffers
* @c: Execution context
* @s: Socket to receive from
- * @events: epoll events bitmap
* @v6: Set for IPv6 connections
* @dlen: Size of received data (output)
*
* Return: Number of iov entries used to store the datagram
*/
-static int udp_vu_sock_recv(const struct ctx *c, int s, uint32_t events,
- bool v6, ssize_t *dlen)
+static int udp_vu_sock_recv(const struct ctx *c, int s, bool v6, ssize_t *dlen)
{
struct vu_dev *vdev = c->vdev;
struct vu_virtq *vq = &vdev->vq[VHOST_USER_RX_QUEUE];
@@ -95,9 +93,6 @@ static int udp_vu_sock_recv(const struct ctx *c, int s, uint32_t events,
ASSERT(!c->no_udp);
- if (!(events & EPOLLIN))
- return 0;
-
/* compute L2 header length */
hdrlen = udp_vu_hdrlen(v6);
@@ -214,14 +209,13 @@ static void udp_vu_csum(const struct flowside *toside, int iov_used)
}
/**
- * udp_vu_listen_sock_handler() - Handle new data from socket
+ * udp_vu_listen_sock_data() - Handle new data from socket
* @c: Execution context
* @ref: epoll reference
- * @events: epoll events bitmap
* @now: Current timestamp
*/
-void udp_vu_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now)
+void udp_vu_listen_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now)
{
struct vu_dev *vdev = c->vdev;
struct vu_virtq *vq = &vdev->vq[VHOST_USER_RX_QUEUE];
@@ -262,7 +256,7 @@ void udp_vu_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
v6 = !(inany_v4(&toside->eaddr) && inany_v4(&toside->oaddr));
- iov_used = udp_vu_sock_recv(c, ref.fd, events, v6, &dlen);
+ iov_used = udp_vu_sock_recv(c, ref.fd, v6, &dlen);
if (iov_used <= 0)
break;
@@ -277,14 +271,13 @@ void udp_vu_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
}
/**
- * udp_vu_reply_sock_handler() - Handle new data from flow specific socket
+ * udp_vu_reply_sock_data() - Handle new data from flow specific socket
* @c: Execution context
* @ref: epoll reference
- * @events: epoll events bitmap
* @now: Current timestamp
*/
-void udp_vu_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now)
+void udp_vu_reply_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now)
{
flow_sidx_t tosidx = flow_sidx_opposite(ref.flowside);
const struct flowside *toside = flowside_at_sidx(tosidx);
@@ -313,7 +306,7 @@ void udp_vu_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
v6 = !(inany_v4(&toside->eaddr) && inany_v4(&toside->oaddr));
- iov_used = udp_vu_sock_recv(c, from_s, events, v6, &dlen);
+ iov_used = udp_vu_sock_recv(c, from_s, v6, &dlen);
if (iov_used <= 0)
break;
flow_trace(uflow, "Received 1 datagram on reply socket");
diff --git a/udp_vu.h b/udp_vu.h
index ba7018d3..4f2262d0 100644
--- a/udp_vu.h
+++ b/udp_vu.h
@@ -6,8 +6,8 @@
#ifndef UDP_VU_H
#define UDP_VU_H
-void udp_vu_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now);
-void udp_vu_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now);
+void udp_vu_listen_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now);
+void udp_vu_reply_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now);
#endif /* UDP_VU_H */
--
@@ -6,8 +6,8 @@
#ifndef UDP_VU_H
#define UDP_VU_H
-void udp_vu_listen_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now);
-void udp_vu_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
- uint32_t events, const struct timespec *now);
+void udp_vu_listen_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now);
+void udp_vu_reply_sock_data(const struct ctx *c, union epoll_ref ref,
+ const struct timespec *now);
#endif /* UDP_VU_H */
--
2.49.0
next prev parent reply other threads:[~2025-03-25 3:00 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-25 3:00 [PATCH 0/4] UDP flow socket preliminaries David Gibson
2025-03-25 3:00 ` [PATCH 1/4] udp: Common invocation of udp_sock_errs() for vhost-user and "buf" paths David Gibson
2025-03-25 3:00 ` David Gibson [this message]
2025-03-25 3:00 ` [PATCH 3/4] udp_vu: Factor things out of udp_vu_reply_sock_data() loop David Gibson
2025-03-25 3:00 ` [PATCH 4/4] udp: Share more logic between vu and non-vu reply socket paths 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=20250325030010.970144-3-david@gibson.dropbear.id.au \
--to=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
--cc=sbrivio@redhat.com \
/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).