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/6] udp: Allow UDP flows to be prematurely closed
Date: Fri, 6 Sep 2024 15:17:06 +1000 [thread overview]
Message-ID: <20240906051710.3863211-3-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20240906051710.3863211-1-david@gibson.dropbear.id.au>
Unlike TCP, UDP has no in-band signalling for the end of a flow. So the
only way we remove flows is on a timer if they have no activity for 180s.
However, we've started to investigate some error conditions in which we
want to prematurely abort / abandon a UDP flow. We can call
udp_flow_close(), which will make the flow inert (sockets closed, no epoll
events, can't be looked up in hash). However it will still wait 3 minutes
to clear away the stale entry.
Clean this up by adding an explicit 'closed' flag which will cause a flow
to be more promptly cleaned up. We also publish udp_flow_close() so it
can be called from other places to abort UDP flows().
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
flow.c | 3 ++-
udp_flow.c | 18 +++++++++++++++++-
udp_flow.h | 4 ++++
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/flow.c b/flow.c
index a00e01d1..f2de0414 100644
--- a/flow.c
+++ b/flow.c
@@ -832,7 +832,8 @@ void flow_defer_handler(const struct ctx *c, const struct timespec *now)
closed = icmp_ping_timer(c, &flow->ping, now);
break;
case FLOW_UDP:
- if (timer)
+ closed = udp_flow_defer(&flow->udp);
+ if (!closed && timer)
closed = udp_flow_timer(c, &flow->udp, now);
break;
default:
diff --git a/udp_flow.c b/udp_flow.c
index 1ff59a9b..b81be2cf 100644
--- a/udp_flow.c
+++ b/udp_flow.c
@@ -39,8 +39,11 @@ struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
* @c: Execution context
* @uflow: UDP flow
*/
-static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow)
+void udp_flow_close(const struct ctx *c, struct udp_flow *uflow)
{
+ if (uflow->closed)
+ return; /* Nothing to do */
+
if (uflow->s[INISIDE] >= 0) {
/* The listening socket needs to stay in epoll */
close(uflow->s[INISIDE]);
@@ -56,6 +59,8 @@ static void udp_flow_close(const struct ctx *c, struct udp_flow *uflow)
flow_hash_remove(c, FLOW_SIDX(uflow, INISIDE));
if (!pif_is_socket(uflow->f.pif[TGTSIDE]))
flow_hash_remove(c, FLOW_SIDX(uflow, TGTSIDE));
+
+ uflow->closed = true;
}
/**
@@ -256,6 +261,17 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c,
return udp_flow_new(c, flow, -1, now);
}
+/**
+ * udp_flow_defer() - Deferred per-flow handling (clean up aborted flows)
+ * @uflow: Flow to handle
+ *
+ * Return: true if the connection is ready to free, false otherwise
+ */
+bool udp_flow_defer(const struct udp_flow *uflow)
+{
+ return uflow->closed;
+}
+
/**
* udp_flow_timer() - Handler for timed events related to a given flow
* @c: Execution context
diff --git a/udp_flow.h b/udp_flow.h
index 12ddf039..9a1b059c 100644
--- a/udp_flow.h
+++ b/udp_flow.h
@@ -10,6 +10,7 @@
/**
* struct udp - Descriptor for a flow of UDP packets
* @f: Generic flow information
+ * @closed: Flow is already closed
* @ts: Activity timestamp
* @s: Socket fd (or -1) for each side of the flow
*/
@@ -17,6 +18,7 @@ struct udp_flow {
/* Must be first element */
struct flow_common f;
+ bool closed :1;
time_t ts;
int s[SIDES];
};
@@ -30,6 +32,8 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c,
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 udp_flow *uflow);
bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
const struct timespec *now);
--
@@ -10,6 +10,7 @@
/**
* struct udp - Descriptor for a flow of UDP packets
* @f: Generic flow information
+ * @closed: Flow is already closed
* @ts: Activity timestamp
* @s: Socket fd (or -1) for each side of the flow
*/
@@ -17,6 +18,7 @@ struct udp_flow {
/* Must be first element */
struct flow_common f;
+ bool closed :1;
time_t ts;
int s[SIDES];
};
@@ -30,6 +32,8 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c,
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 udp_flow *uflow);
bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
const struct timespec *now);
--
2.46.0
next prev parent reply other threads:[~2024-09-06 5:17 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-06 5:17 [PATCH 0/6] RFC: Possible fixes for bug 94 and bug 95 David Gibson
2024-09-06 5:17 ` [PATCH 1/6] flow: Fix incorrect hash probe in flowside_lookup() David Gibson
2024-09-06 5:17 ` David Gibson [this message]
2024-09-06 5:17 ` [PATCH 3/6] flow: Helpers to log details of a flow David Gibson
2024-09-06 5:17 ` [PATCH 4/6] udp: Split socket error handling out from udp_sock_recv() David Gibson
2024-09-06 5:17 ` [PATCH 5/6] udp: Treat errors getting errors as unrecoverable David Gibson
2024-09-06 5:17 ` [PATCH 6/6] udp: Handle more error conditions in udp_sock_errs() David Gibson
2024-09-06 11:29 ` [PATCH 0/6] RFC: Possible fixes for bug 94 and bug 95 Stefano Brivio
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=20240906051710.3863211-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).