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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user