tcp: Don't defer hash table removal

When a TCP connection is closed, we mark it by setting events to CLOSED,
then some time later we do final cleanups: closing sockets, removing from
the hash table and so forth.

This does mean that when making a hash lookup we need to exclude any
apparent matches that are CLOSED, since they represent a stale connection.
This can happen in practice if one connection closes and a new one with the
same endpoints is started shortly afterward.

Checking for CLOSED is quite specific to TCP however, and won't work when
we extend the hash table to more general flows.  So, alter the code to
immediately remove the connection from the hash table when CLOSED, although
we still defer closing sockets and other cleanup.

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 2023-11-30 13:02:22 +11:00 committed by Stefano Brivio
parent e21b6d69b1
commit b86afe3559

10
tcp.c
View file

@ -781,6 +781,9 @@ static void conn_flag_do(const struct ctx *c, struct tcp_tap_conn *conn,
tcp_timer_ctl(c, conn); tcp_timer_ctl(c, conn);
} }
static void tcp_hash_remove(const struct ctx *c,
const struct tcp_tap_conn *conn);
/** /**
* conn_event_do() - Set and log connection events, update epoll state * conn_event_do() - Set and log connection events, update epoll state
* @c: Execution context * @c: Execution context
@ -825,7 +828,9 @@ static void conn_event_do(const struct ctx *c, struct tcp_tap_conn *conn,
flow_dbg(conn, "%s", flow_dbg(conn, "%s",
num == -1 ? "CLOSED" : tcp_event_str[num]); num == -1 ? "CLOSED" : tcp_event_str[num]);
if ((event == TAP_FIN_RCVD) && !(conn->events & SOCK_FIN_RCVD)) if (event == CLOSED)
tcp_hash_remove(c, conn);
else if ((event == TAP_FIN_RCVD) && !(conn->events & SOCK_FIN_RCVD))
conn_flag(c, conn, ACTIVE_CLOSE); conn_flag(c, conn, ACTIVE_CLOSE);
else else
tcp_epoll_ctl(c, conn); tcp_epoll_ctl(c, conn);
@ -1150,7 +1155,7 @@ static int tcp_hash_match(const struct tcp_tap_conn *conn,
const union inany_addr *faddr, const union inany_addr *faddr,
in_port_t eport, in_port_t fport) in_port_t eport, in_port_t fport)
{ {
if (conn->events != CLOSED && inany_equals(&conn->faddr, faddr) && if (inany_equals(&conn->faddr, faddr) &&
conn->eport == eport && conn->fport == fport) conn->eport == eport && conn->fport == fport)
return 1; return 1;
@ -1308,7 +1313,6 @@ static void tcp_conn_destroy(struct ctx *c, union flow *flow)
if (conn->timer != -1) if (conn->timer != -1)
close(conn->timer); close(conn->timer);
tcp_hash_remove(c, conn);
flow_table_compact(c, flow); flow_table_compact(c, flow);
} }