Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
192 lines (177 sloc) 6.66 KB
diff --git a/include/net/tcp.h b/include/net/tcp.h
index c7f88f7..662e5e0 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -246,6 +246,7 @@ extern struct inet_timewait_death_row tcp_death_row;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
extern int sysctl_tcp_sack;
+extern int sysctl_tcp_timewait_len;
extern int sysctl_tcp_fin_timeout;
extern int sysctl_tcp_keepalive_time;
extern int sysctl_tcp_keepalive_probes;
diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
index e443695..ddc3d4c 100644
--- a/include/uapi/linux/sysctl.h
+++ b/include/uapi/linux/sysctl.h
@@ -426,6 +426,7 @@ enum
NET_TCP_ALLOWED_CONG_CONTROL=123,
NET_TCP_MAX_SSTHRESH=124,
NET_TCP_FRTO_RESPONSE=125,
+ NET_IPV4_TCP_TIMEWAIT_LEN=126,
};
enum {
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 0d73fd1..6eadc4f 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -356,6 +356,7 @@ static const struct bin_table bin_net_ipv4_table[] = {
{ CTL_INT, NET_IPV4_TCP_KEEPALIVE_INTVL, "tcp_keepalive_intvl" },
{ CTL_INT, NET_IPV4_TCP_RETRIES1, "tcp_retries1" },
{ CTL_INT, NET_IPV4_TCP_RETRIES2, "tcp_retries2" },
+ { CTL_INT, NET_IPV4_TCP_TIMEWAIT_LEN, "tcp_timewait_len" },
{ CTL_INT, NET_IPV4_TCP_FIN_TIMEOUT, "tcp_fin_timeout" },
{ CTL_INT, NET_TCP_SYNCOOKIES, "tcp_syncookies" },
{ CTL_INT, NET_TCP_TW_RECYCLE, "tcp_tw_recycle" },
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index b59465f..67d3485 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -404,6 +404,13 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec
},
{
+ .procname = "tcp_timewait_len",
+ .data = &sysctl_tcp_timewait_len,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
+ },
+ {
.procname = "tcp_fin_timeout",
.data = &sysctl_tcp_fin_timeout,
.maxlen = sizeof(int),
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 3e7062c..ff62c1b 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2091,9 +2091,9 @@ adjudge_to_death:
} else {
const int tmo = tcp_fin_time(sk);
- if (tmo > TCP_TIMEWAIT_LEN) {
+ if (tmo > sysctl_tcp_timewait_len) {
inet_csk_reset_keepalive_timer(sk,
- tmo - TCP_TIMEWAIT_LEN);
+ tmo - sysctl_tcp_timewait_len);
} else {
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
goto out;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 6896f0d..9ff5d66 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5763,8 +5763,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
}
tmo = tcp_fin_time(sk);
- if (tmo > TCP_TIMEWAIT_LEN) {
- inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN);
+ if (tmo > sysctl_tcp_timewait_len) {
+ inet_csk_reset_keepalive_timer(sk, tmo - sysctl_tcp_timewait_len);
} else if (th->fin || sock_owned_by_user(sk)) {
/* Bad case. We could lose such FIN otherwise.
* It is not a big problem, but it looks confusing
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index a325e25..92235f1 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -27,6 +27,8 @@
#include <net/inet_common.h>
#include <net/xfrm.h>
+int sysctl_tcp_timewait_len __read_mostly = TCP_TIMEWAIT_LEN;
+
int sysctl_tcp_syncookies __read_mostly = 1;
EXPORT_SYMBOL(sysctl_tcp_syncookies);
@@ -108,6 +110,9 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
}
}
+
+ tcp_death_row.period = sysctl_tcp_timewait_len / INET_TWDR_TWKILL_SLOTS;
+
if (tw->tw_substate == TCP_FIN_WAIT2) {
/* Just repeat all the checks of tcp_rcv_state_process() */
@@ -155,10 +160,10 @@ kill_with_rst:
tcptw->tw_ts_recent_stamp &&
tcp_tw_remember_stamp(tw))
inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout,
- TCP_TIMEWAIT_LEN);
+ sysctl_tcp_timewait_len);
else
- inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
- TCP_TIMEWAIT_LEN);
+ inet_twsk_schedule(tw, &tcp_death_row, sysctl_tcp_timewait_len,
+ sysctl_tcp_timewait_len);
return TCP_TW_ACK;
}
@@ -196,8 +201,8 @@ kill:
return TCP_TW_SUCCESS;
}
}
- inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
- TCP_TIMEWAIT_LEN);
+ inet_twsk_schedule(tw, &tcp_death_row, sysctl_tcp_timewait_len,
+ sysctl_tcp_timewait_len);
if (tmp_opt.saw_tstamp) {
tcptw->tw_ts_recent = tmp_opt.rcv_tsval;
@@ -247,8 +252,8 @@ kill:
* Do not reschedule in the last case.
*/
if (paws_reject || th->ack)
- inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
- TCP_TIMEWAIT_LEN);
+ inet_twsk_schedule(tw, &tcp_death_row, sysctl_tcp_timewait_len,
+ sysctl_tcp_timewait_len);
/* Send ACK. Note, we do not put the bucket,
* it will be released by caller.
@@ -269,6 +274,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
const struct inet_connection_sock *icsk = inet_csk(sk);
const struct tcp_sock *tp = tcp_sk(sk);
bool recycle_ok = false;
+ tcp_death_row.period = sysctl_tcp_timewait_len / INET_TWDR_TWKILL_SLOTS;
if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
recycle_ok = tcp_remember_stamp(sk);
@@ -330,13 +336,13 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
if (recycle_ok) {
tw->tw_timeout = rto;
} else {
- tw->tw_timeout = TCP_TIMEWAIT_LEN;
+ tw->tw_timeout = sysctl_tcp_timewait_len;
if (state == TCP_TIME_WAIT)
- timeo = TCP_TIMEWAIT_LEN;
+ timeo = sysctl_tcp_timewait_len;
}
inet_twsk_schedule(tw, &tcp_death_row, timeo,
- TCP_TIMEWAIT_LEN);
+ sysctl_tcp_timewait_len);
inet_twsk_put(tw);
} else {
/* Sorry, if we're out of memory, just CLOSE this
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index af07b5b..75a45b9 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -69,7 +69,7 @@ static int tcp_out_of_resources(struct sock *sk, int do_reset)
if (tcp_check_oom(sk, shift)) {
/* Catch exceptional cases, when connection requires reset.
* 1. Last segment was sent recently. */
- if ((s32)(tcp_time_stamp - tp->lsndtime) <= TCP_TIMEWAIT_LEN ||
+ if ((s32)(tcp_time_stamp - tp->lsndtime) <= sysctl_tcp_timewait_len ||
/* 2. Window is closed. */
(!tp->snd_wnd && !tp->packets_out))
do_reset = 1;
@@ -576,7 +576,7 @@ static void tcp_keepalive_timer (unsigned long data)
if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) {
if (tp->linger2 >= 0) {
- const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN;
+ const int tmo = tcp_fin_time(sk) - sysctl_tcp_timewait_len;
if (tmo > 0) {
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);