public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
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


  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).