Reap FIN_WAIT_2 connections marked SOCANTRCVMORE faster. This mitigate
potential issues where the peer does not close, potentially leaving thousands of connections in FIN_WAIT_2. This is controlled by a new sysctl fast_finwait2_recycle, which is disabled by default. Reviewed by: gnn, silby.
This commit is contained in:
parent
2bd7382fdc
commit
384aeb29f6
@ -2301,8 +2301,12 @@ tcp_input(m, off0)
|
||||
* compressed state.
|
||||
*/
|
||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
|
||||
int timeout;
|
||||
|
||||
soisdisconnected(so);
|
||||
callout_reset(tp->tt_2msl, tcp_maxidle,
|
||||
timeout = (tcp_fast_finwait2_recycle) ?
|
||||
tcp_finwait2_timeout : tcp_maxidle;
|
||||
callout_reset(tp->tt_2msl, timeout,
|
||||
tcp_timer_2msl, tp);
|
||||
}
|
||||
tp->t_state = TCPS_FIN_WAIT_2;
|
||||
|
@ -2301,8 +2301,12 @@ tcp_input(m, off0)
|
||||
* compressed state.
|
||||
*/
|
||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
|
||||
int timeout;
|
||||
|
||||
soisdisconnected(so);
|
||||
callout_reset(tp->tt_2msl, tcp_maxidle,
|
||||
timeout = (tcp_fast_finwait2_recycle) ?
|
||||
tcp_finwait2_timeout : tcp_maxidle;
|
||||
callout_reset(tp->tt_2msl, timeout,
|
||||
tcp_timer_2msl, tp);
|
||||
}
|
||||
tp->t_state = TCPS_FIN_WAIT_2;
|
||||
|
@ -329,6 +329,7 @@ tcp_init(void)
|
||||
tcp_rexmit_min = TCPTV_MIN;
|
||||
tcp_rexmit_slop = TCPTV_CPU_VAR;
|
||||
tcp_inflight_rttthresh = TCPTV_INFLIGHT_RTTTHRESH;
|
||||
tcp_finwait2_timeout = TCPTV_FINWAIT2_TIMEOUT;
|
||||
|
||||
INP_INFO_LOCK_INIT(&tcbinfo, "tcp");
|
||||
LIST_INIT(&tcb);
|
||||
|
@ -96,6 +96,15 @@ static int always_keepalive = 1;
|
||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW,
|
||||
&always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections");
|
||||
|
||||
int tcp_fast_finwait2_recycle = 0;
|
||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW,
|
||||
&tcp_fast_finwait2_recycle, 0, "Recycle closed FIN_WAIT_2 connections faster");
|
||||
|
||||
int tcp_finwait2_timeout;
|
||||
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW,
|
||||
&tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "");
|
||||
|
||||
|
||||
static int tcp_keepcnt = TCPTV_KEEPCNT;
|
||||
/* max idle probes */
|
||||
int tcp_maxpersistidle;
|
||||
@ -211,13 +220,24 @@ tcp_timer_2msl(xtp)
|
||||
* still waiting for peer to close and connection has been idle
|
||||
* too long, or if 2MSL time is up from TIME_WAIT, delete connection
|
||||
* control block. Otherwise, check again in a bit.
|
||||
*
|
||||
* If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed,
|
||||
* there's no point in hanging onto FIN_WAIT_2 socket. Just close it.
|
||||
* Ignore fact that there were recent incoming segments.
|
||||
*/
|
||||
if (tp->t_state != TCPS_TIME_WAIT &&
|
||||
(ticks - tp->t_rcvtime) <= tcp_maxidle)
|
||||
callout_reset(tp->tt_2msl, tcp_keepintvl,
|
||||
tcp_timer_2msl, tp);
|
||||
else
|
||||
tp = tcp_close(tp);
|
||||
if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 &&
|
||||
tp->t_inpcb && tp->t_inpcb->inp_socket &&
|
||||
(tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) {
|
||||
tcpstat.tcps_finwait2_drops++;
|
||||
tp = tcp_close(tp);
|
||||
} else {
|
||||
if (tp->t_state != TCPS_TIME_WAIT &&
|
||||
(ticks - tp->t_rcvtime) <= tcp_maxidle)
|
||||
callout_reset(tp->tt_2msl, tcp_keepintvl,
|
||||
tcp_timer_2msl, tp);
|
||||
else
|
||||
tp = tcp_close(tp);
|
||||
}
|
||||
|
||||
#ifdef TCPDEBUG
|
||||
if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
|
||||
|
@ -89,6 +89,8 @@
|
||||
#define TCPTV_INFLIGHT_RTTTHRESH (10*hz/1000) /* below which inflight
|
||||
disengages, in msec */
|
||||
|
||||
#define TCPTV_FINWAIT2_TIMEOUT (60*hz) /* FIN_WAIT_2 timeout if no receiver */
|
||||
|
||||
/*
|
||||
* Minimum retransmit timer is 3 ticks, for algorithmic stability.
|
||||
* TCPT_RANGESET() will add another TCPTV_CPU_VAR to deal with
|
||||
@ -152,6 +154,9 @@ extern int tcp_backoff[];
|
||||
|
||||
struct tcptw;
|
||||
|
||||
extern int tcp_finwait2_timeout;
|
||||
extern int tcp_fast_finwait2_recycle;
|
||||
|
||||
void tcp_timer_init(void);
|
||||
void tcp_timer_2msl(void *xtp);
|
||||
struct tcptw *
|
||||
|
@ -329,6 +329,7 @@ tcp_init(void)
|
||||
tcp_rexmit_min = TCPTV_MIN;
|
||||
tcp_rexmit_slop = TCPTV_CPU_VAR;
|
||||
tcp_inflight_rttthresh = TCPTV_INFLIGHT_RTTTHRESH;
|
||||
tcp_finwait2_timeout = TCPTV_FINWAIT2_TIMEOUT;
|
||||
|
||||
INP_INFO_LOCK_INIT(&tcbinfo, "tcp");
|
||||
LIST_INIT(&tcb);
|
||||
|
@ -1581,9 +1581,14 @@ tcp_usrclosed(tp)
|
||||
if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
|
||||
soisdisconnected(tp->t_inpcb->inp_socket);
|
||||
/* To prevent the connection hanging in FIN_WAIT_2 forever. */
|
||||
if (tp->t_state == TCPS_FIN_WAIT_2)
|
||||
callout_reset(tp->tt_2msl, tcp_maxidle,
|
||||
if (tp->t_state == TCPS_FIN_WAIT_2) {
|
||||
int timeout;
|
||||
|
||||
timeout = (tcp_fast_finwait2_recycle) ?
|
||||
tcp_finwait2_timeout : tcp_maxidle;
|
||||
callout_reset(tp->tt_2msl, timeout,
|
||||
tcp_timer_2msl, tp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,6 +413,8 @@ struct tcpstat {
|
||||
u_long tcps_hc_added; /* entry added to hostcache */
|
||||
u_long tcps_hc_bucketoverflow; /* hostcache per bucket limit hit */
|
||||
|
||||
u_long tcps_finwait2_drops; /* Drop FIN_WAIT_2 connection after time limit */
|
||||
|
||||
/* SACK related stats */
|
||||
u_long tcps_sack_recovery_episode; /* SACK recovery episodes */
|
||||
u_long tcps_sack_rexmits; /* SACK rexmit segments */
|
||||
@ -455,6 +457,7 @@ struct xtcpcb {
|
||||
#define TCPCTL_SACK 14 /* Selective Acknowledgement,rfc 2018 */
|
||||
#define TCPCTL_DROP 15 /* drop tcp connection */
|
||||
#define TCPCTL_MAXID 16
|
||||
#define TCPCTL_FINWAIT2_TIMEOUT 17
|
||||
|
||||
#define TCPCTL_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
|
@ -436,6 +436,7 @@ tcp_stats(u_long off __unused, const char *name, int af1 __unused)
|
||||
p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
|
||||
p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
|
||||
p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
|
||||
p(tcps_finwait2_drops, "\t%lu Connection%s (fin_wait_2) dropped because of timeout\n");
|
||||
p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
|
||||
p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
|
||||
p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
|
||||
|
Loading…
Reference in New Issue
Block a user