diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2025-01-02 10:55:19 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2025-01-02 10:55:19 +0000 |
commit | 448ba1fe1ed08062c5a97f8e13bc3889b9d01298 (patch) | |
tree | 11b4b05f24905ffd79cfc2eb1dc28157aa83c2bb | |
parent | 18b2927ab5d925375c2820376cd3fb813f446171 (diff) |
Reference count the listen inpcb in the TCP SYN cache.
To make progress in unlocking TCP input path, more reference counting
is needed. The SYN cache has a reference to the listen socket in
form of a struct tcpcb. Instead of adding a refcount to tcpcb, it
is easier to use a struct inpcb pointer which already has a refcount.
Acquire and hold the reference while running SYN cache timer.
OK mvs@
-rw-r--r-- | sys/netinet/tcp_input.c | 21 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 4 |
2 files changed, 15 insertions, 10 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 1f55d156fb6..cf557ef9f0d 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.416 2024/12/31 12:19:46 mvs Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.417 2025/01/02 10:55:18 bluhm Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -3173,7 +3173,8 @@ syn_cache_rm(struct syn_cache *sc) KASSERT(!ISSET(sc->sc_dynflags, SCF_DEAD)); SET(sc->sc_dynflags, SCF_DEAD); TAILQ_REMOVE(&sc->sc_buckethead->sch_bucket, sc, sc_bucketq); - sc->sc_tp = NULL; + in_pcbunref(sc->sc_inplisten); + sc->sc_inplisten = NULL; LIST_REMOVE(sc, sc_tpq); refcnt_rele(&sc->sc_refcnt); sc->sc_buckethead->sch_length--; @@ -3369,6 +3370,7 @@ void syn_cache_timer(void *arg) { struct syn_cache *sc = arg; + struct inpcb *inp; uint64_t now; int lastref; @@ -3397,6 +3399,9 @@ syn_cache_timer(void *arg) TCPTV_REXMTMAX); if (timeout_add_msec(&sc->sc_timer, sc->sc_rxtcur)) refcnt_take(&sc->sc_refcnt); + inp = in_pcbref(sc->sc_inplisten); + if (inp == NULL) + goto freeit; mtx_leave(&syn_cache_mtx); NET_LOCK(); @@ -3405,6 +3410,7 @@ syn_cache_timer(void *arg) tcpstat_inc(tcps_sc_retransmitted); NET_UNLOCK(); + in_pcbunref(inp); syn_cache_put(sc); return; @@ -3434,10 +3440,7 @@ syn_cache_cleanup(struct tcpcb *tp) mtx_enter(&syn_cache_mtx); LIST_FOREACH_SAFE(sc, &tp->t_sc, sc_tpq, nsc) { -#ifdef DIAGNOSTIC - if (sc->sc_tp != tp) - panic("invalid sc_tp in syn_cache_cleanup"); -#endif + KASSERT(sc->sc_inplisten == tp->t_inpcb); syn_cache_rm(sc); syn_cache_put(sc); } @@ -3949,7 +3952,7 @@ syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th, if (tb.t_flags & TF_SIGNATURE) SET(sc->sc_fixflags, SCF_SIGNATURE); #endif - sc->sc_tp = tp; + sc->sc_inplisten = in_pcbref(tp->t_inpcb); if (syn_cache_respond(sc, m, now) == 0) { mtx_enter(&syn_cache_mtx); /* @@ -3962,6 +3965,7 @@ syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th, tcpstat_inc(tcps_sndacks); tcpstat_inc(tcps_sndtotal); } else { + in_pcbunref(sc->sc_inplisten); syn_cache_put(sc); tcpstat_inc(tcps_sc_dropped); } @@ -4158,7 +4162,7 @@ syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint64_t now) /* use IPsec policy and ttl from listening socket, on SYN ACK */ mtx_enter(&syn_cache_mtx); - inp = sc->sc_tp ? sc->sc_tp->t_inpcb : NULL; + inp = in_pcbref(sc->sc_inplisten); mtx_leave(&syn_cache_mtx); /* @@ -4189,5 +4193,6 @@ syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint64_t now) break; #endif } + in_pcbunref(inp); return (error); } diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 5d6662172b3..4f78a3faf93 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_var.h,v 1.181 2024/12/28 22:17:09 bluhm Exp $ */ +/* $OpenBSD: tcp_var.h,v 1.182 2025/01/02 10:55:18 bluhm Exp $ */ /* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */ /* @@ -278,7 +278,7 @@ struct syn_cache { u_int sc_request_r_scale : 4, /* [I] */ sc_requested_s_scale : 4; /* [I] */ - struct tcpcb *sc_tp; /* [S] tcb for listening socket */ + struct inpcb *sc_inplisten; /* [S] inpcb for listening socket */ LIST_ENTRY(syn_cache) sc_tpq; /* [S] list of entries by same tp */ }; |