diff options
author | mohans <mohans@FreeBSD.org> | 2007-02-26 22:25:21 +0000 |
---|---|---|
committer | mohans <mohans@FreeBSD.org> | 2007-02-26 22:25:21 +0000 |
commit | 384aeb29f6100b5e13581c56efdea6d423675769 (patch) | |
tree | 21cfa3a2368a7f712458dfdd8d3485b03c0c6fa7 /sys/netinet | |
parent | 2bd7382fdc16aa04088cebb691546535c56c484b (diff) | |
download | FreeBSD-src-384aeb29f6100b5e13581c56efdea6d423675769.zip FreeBSD-src-384aeb29f6100b5e13581c56efdea6d423675769.tar.gz |
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.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/tcp_input.c | 6 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 6 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 1 | ||||
-rw-r--r-- | sys/netinet/tcp_timer.c | 32 | ||||
-rw-r--r-- | sys/netinet/tcp_timer.h | 5 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 1 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 9 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 3 |
8 files changed, 53 insertions, 10 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 298dec1..01f2316 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -2301,8 +2301,12 @@ process_ACK: * 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; diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 298dec1..01f2316 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -2301,8 +2301,12 @@ process_ACK: * 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; diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 4257603..14287b2 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -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); diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 86d9c6a..33e4806 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -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)) diff --git a/sys/netinet/tcp_timer.h b/sys/netinet/tcp_timer.h index 1e1c239..8d8742de 100644 --- a/sys/netinet/tcp_timer.h +++ b/sys/netinet/tcp_timer.h @@ -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 * diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 4257603..14287b2 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -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); diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index c4362cf..57195a4 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -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); + } } } diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 4c50a82..46d396d 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -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 }, \ |