1
0
mirror of https://passt.top/passt synced 2024-12-22 05:35:23 +00:00

udp: Allow UDP flows to be prematurely closed

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>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-09-06 15:17:06 +10:00 committed by Stefano Brivio
parent 7ad9f9bd2b
commit 1166401c2f
3 changed files with 23 additions and 2 deletions

3
flow.c
View File

@ -832,7 +832,8 @@ void flow_defer_handler(const struct ctx *c, const struct timespec *now)
closed = icmp_ping_timer(c, &flow->ping, now); closed = icmp_ping_timer(c, &flow->ping, now);
break; break;
case FLOW_UDP: case FLOW_UDP:
if (timer) closed = udp_flow_defer(&flow->udp);
if (!closed && timer)
closed = udp_flow_timer(c, &flow->udp, now); closed = udp_flow_timer(c, &flow->udp, now);
break; break;
default: default:

View File

@ -39,8 +39,11 @@ struct udp_flow *udp_at_sidx(flow_sidx_t sidx)
* @c: Execution context * @c: Execution context
* @uflow: UDP flow * @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) { if (uflow->s[INISIDE] >= 0) {
/* The listening socket needs to stay in epoll */ /* The listening socket needs to stay in epoll */
close(uflow->s[INISIDE]); 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)); flow_hash_remove(c, FLOW_SIDX(uflow, INISIDE));
if (!pif_is_socket(uflow->f.pif[TGTSIDE])) if (!pif_is_socket(uflow->f.pif[TGTSIDE]))
flow_hash_remove(c, FLOW_SIDX(uflow, 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); 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 * udp_flow_timer() - Handler for timed events related to a given flow
* @c: Execution context * @c: Execution context

View File

@ -10,6 +10,7 @@
/** /**
* struct udp - Descriptor for a flow of UDP packets * struct udp - Descriptor for a flow of UDP packets
* @f: Generic flow information * @f: Generic flow information
* @closed: Flow is already closed
* @ts: Activity timestamp * @ts: Activity timestamp
* @s: Socket fd (or -1) for each side of the flow * @s: Socket fd (or -1) for each side of the flow
*/ */
@ -17,6 +18,7 @@ struct udp_flow {
/* Must be first element */ /* Must be first element */
struct flow_common f; struct flow_common f;
bool closed :1;
time_t ts; time_t ts;
int s[SIDES]; int s[SIDES];
}; };
@ -30,6 +32,8 @@ flow_sidx_t udp_flow_from_tap(const struct ctx *c,
const void *saddr, const void *daddr, const void *saddr, const void *daddr,
in_port_t srcport, in_port_t dstport, in_port_t srcport, in_port_t dstport,
const struct timespec *now); 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, bool udp_flow_timer(const struct ctx *c, struct udp_flow *uflow,
const struct timespec *now); const struct timespec *now);