diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4 --- a/share/man/man4/tcp.4 +++ b/share/man/man4/tcp.4 @@ -31,7 +31,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 10, 2025 +.Dd June 13, 2025 .Dt TCP 4 .Os .Sh NAME @@ -780,6 +780,13 @@ from an unreasonably low MSS. .It Va msl The Maximum Segment Lifetime, in milliseconds, for a packet. +.It Va msl_local +The Maximum Segment Lifetime, in milliseconds, for a packet when both endpoints +are local. +.Va msl_local +is only used if +.Va nolocaltimewait +is zero. .It Va mssdflt The default value used for the TCP Maximum Segment Size .Pq Dq MSS diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1454,6 +1454,7 @@ VNET_PCPUSTAT_ALLOC(tcpstat, M_WAITOK); V_tcp_msl = TCPTV_MSL; + V_tcp_msl_local = TCPTV_MSL_LOCAL; arc4rand(&V_ts_offset_secret, sizeof(V_ts_offset_secret), 0); } VNET_SYSINIT(tcp_vnet_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, diff --git a/sys/netinet/tcp_timer.h b/sys/netinet/tcp_timer.h --- a/sys/netinet/tcp_timer.h +++ b/sys/netinet/tcp_timer.h @@ -72,6 +72,7 @@ * Time constants. */ #define TCPTV_MSL ( 30*hz) /* max seg lifetime (hah!) */ +#define TCPTV_MSL_LOCAL ( hz/100) /* max seg lifetime for local comm */ #define TCPTV_SRTTBASE 0 /* base roundtrip time; if 0, no idea yet */ #define TCPTV_RTOBASE ( 1*hz) /* assumed RTO if no info */ @@ -184,6 +185,8 @@ #define V_tcp_v6pmtud_blackhole_mss VNET(tcp_v6pmtud_blackhole_mss) VNET_DECLARE(int, tcp_msl); #define V_tcp_msl VNET(tcp_msl) +VNET_DECLARE(int, tcp_msl_local); +#define V_tcp_msl_local VNET(tcp_msl_local) #endif /* _KERNEL */ diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -115,6 +115,12 @@ &VNET_NAME(tcp_msl), 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime"); +VNET_DEFINE(int, tcp_msl_local); +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl_local, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_VNET, + &VNET_NAME(tcp_msl_local), 0, sysctl_msec_to_ticks, "I", + "Maximum segment lifetime for local communication"); + int tcp_rexmit_initial; SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_initial, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -93,6 +93,28 @@ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(nolocaltimewait), true, "Do not create TCP TIME_WAIT state for local connections"); +static u_int +tcp_msl(struct tcpcb *tp) +{ + struct inpcb *inp = tptoinpcb(tp); +#ifdef INET6 + bool isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6; +#endif + + if ( +#ifdef INET6 + isipv6 ? in6_localip(&inp->in6p_faddr) : +#endif +#ifdef INET + in_localip(inp->inp_faddr)) +#else + false) +#endif + return (V_tcp_msl_local); + else + return (V_tcp_msl); +} + /* * Move a TCP connection into TIME_WAIT state. * inp is locked, and is unlocked before returning. @@ -140,7 +162,7 @@ return; } - tcp_timer_activate(tp, TT_2MSL, 2 * V_tcp_msl); + tcp_timer_activate(tp, TT_2MSL, 2 * tcp_msl(tp)); INP_WUNLOCK(inp); } @@ -283,7 +305,7 @@ if (thflags & TH_FIN) { seq = th->th_seq + tlen + (thflags & TH_SYN ? 1 : 0); if (seq + 1 == tp->rcv_nxt) - tcp_timer_activate(tp, TT_2MSL, 2 * V_tcp_msl); + tcp_timer_activate(tp, TT_2MSL, 2 * tcp_msl(tp)); } /*