summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authormohans <mohans@FreeBSD.org>2007-02-26 22:25:21 +0000
committermohans <mohans@FreeBSD.org>2007-02-26 22:25:21 +0000
commit384aeb29f6100b5e13581c56efdea6d423675769 (patch)
tree21cfa3a2368a7f712458dfdd8d3485b03c0c6fa7 /sys/netinet
parent2bd7382fdc16aa04088cebb691546535c56c484b (diff)
downloadFreeBSD-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.c6
-rw-r--r--sys/netinet/tcp_reass.c6
-rw-r--r--sys/netinet/tcp_subr.c1
-rw-r--r--sys/netinet/tcp_timer.c32
-rw-r--r--sys/netinet/tcp_timer.h5
-rw-r--r--sys/netinet/tcp_timewait.c1
-rw-r--r--sys/netinet/tcp_usrreq.c9
-rw-r--r--sys/netinet/tcp_var.h3
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 }, \
OpenPOWER on IntegriCloud