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:
parent
7ad9f9bd2b
commit
1166401c2f
3 changed files with 23 additions and 2 deletions
3
flow.c
3
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);
|
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:
|
||||||
|
|
18
udp_flow.c
18
udp_flow.c
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue