The branch main has been updated by tuexen:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=5fb4b091e8352602894fc2b7284c8e1e3d8a8729

commit 5fb4b091e8352602894fc2b7284c8e1e3d8a8729
Author:     Michael Tuexen <tue...@freebsd.org>
AuthorDate: 2025-06-26 16:59:36 +0000
Commit:     Michael Tuexen <tue...@freebsd.org>
CommitDate: 2025-06-26 16:59:36 +0000

    tcp: allow specifying a MSL for local communications
    
    When setting the sysctl-variable net.inet.tcp.nolocaltimewait to 1,
    which is the default, a TCP endpoint does not enter the TIME-WAIT state,
    when the communication is local. This can result in sending
    RST-segments without any error situation. By setting the
    sysctl-variable net.inet.tcp.nolocaltimewait to 0, this does not
    occur, and the behavior is compliant with the TCP specification.
    But there is no reason to stay in the TIME-WAIT state for two times
    the value of the sysctl-variable net.inet.tcp.msl, if the
    communication is local. Therefore provide a separate sysctl-variable
    net.inet.tcp.msl_local, which controls how long an TCP end-point
    stays in the TIME-WAIT state, if the communication is local.
    The default value is 10 ms.
    
    Reviewed by:            glebius, Peter Lei
    Sponsored by:           Netflix, Inc.
    Differential Revision:  https://reviews.freebsd.org/D50637
---
 share/man/man4/tcp.4       |  7 +++++++
 sys/netinet/tcp_subr.c     |  1 +
 sys/netinet/tcp_timer.c    |  6 ++++++
 sys/netinet/tcp_timer.h    |  3 +++
 sys/netinet/tcp_timewait.c | 26 ++++++++++++++++++++++++--
 5 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4
index 536bd904d796..f19b6cb2ae14 100644
--- a/share/man/man4/tcp.4
+++ b/share/man/man4/tcp.4
@@ -780,6 +780,13 @@ Minimum TCP Maximum Segment Size; used to prevent a denial 
of service attack
 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
index 6b1907305fb9..bbcd20b715ba 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1455,6 +1455,7 @@ tcp_vnet_init(void *arg __unused)
        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.c b/sys/netinet/tcp_timer.c
index a9046e5725d5..32ce3001929c 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -109,6 +109,12 @@ SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl,
     &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,
     &tcp_rexmit_initial, 0, sysctl_msec_to_ticks, "I",
diff --git a/sys/netinet/tcp_timer.h b/sys/netinet/tcp_timer.h
index 394207bcb89b..34a0f1375463 100644
--- a/sys/netinet/tcp_timer.h
+++ b/sys/netinet/tcp_timer.h
@@ -74,6 +74,7 @@
  * Time constants.
  */
 #define        TCPTV_MSL       MSEC_2_TICKS(30000)     /* max seg lifetime 
(hah!) */
+#define        TCPTV_MSL_LOCAL MSEC_2_TICKS(10)        /* max seg lifetime for 
local comm */
 #define        TCPTV_SRTTBASE  0                       /* base roundtrip time;
                                                   if 0, no idea yet */
 #define        TCPTV_RTOBASE   MSEC_2_TICKS(1000)      /* assumed RTO if no 
info */
@@ -183,6 +184,8 @@ VNET_DECLARE(int, tcp_v6pmtud_blackhole_mss);
 #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_timewait.c b/sys/netinet/tcp_timewait.c
index 2b4ae462af89..9f2943725ef0 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -93,6 +93,28 @@ SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, nolocaltimewait,
     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 @@ tcp_twstart(struct tcpcb *tp)
                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 @@ tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct 
tcphdr *th,
        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));
        }
 
        /*

Reply via email to