aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal Cardwell <ncardwell@google.com>2015-02-06 16:04:41 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-08 04:03:13 -0500
commit4fb17a6091674f469e8ac85dc770fbf9a9ba7cc8 (patch)
treec01ae32365fd340ddec2a12682a43abd585aed97
parentf2b2c582e82429270d5818fbabe653f4359d7024 (diff)
tcp: mitigate ACK loops for connections as tcp_timewait_sock
Ensure that in state FIN_WAIT2 or TIME_WAIT, where the connection is represented by a tcp_timewait_sock, we rate limit dupacks in response to incoming packets (a) with TCP timestamps that fail PAWS checks, or (b) with sequence numbers that are out of the acceptable window. We do not send a dupack in response to out-of-window packets if it has been less than sysctl_tcp_invalid_ratelimit (default 500ms) since we last sent a dupack in response to an out-of-window packet. Reported-by: Avery Fay <avery@mixpanel.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/tcp.h4
-rw-r--r--net/ipv4/tcp_minisocks.c29
2 files changed, 28 insertions, 5 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 66d85a80a1ec..1a7adb411647 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -342,6 +342,10 @@ struct tcp_timewait_sock {
342 u32 tw_rcv_wnd; 342 u32 tw_rcv_wnd;
343 u32 tw_ts_offset; 343 u32 tw_ts_offset;
344 u32 tw_ts_recent; 344 u32 tw_ts_recent;
345
346 /* The time we sent the last out-of-window ACK: */
347 u32 tw_last_oow_ack_time;
348
345 long tw_ts_recent_stamp; 349 long tw_ts_recent_stamp;
346#ifdef CONFIG_TCP_MD5SIG 350#ifdef CONFIG_TCP_MD5SIG
347 struct tcp_md5sig_key *tw_md5_key; 351 struct tcp_md5sig_key *tw_md5_key;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 98a840561ec8..dd11ac7798c6 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -58,6 +58,25 @@ static bool tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
58 return seq == e_win && seq == end_seq; 58 return seq == e_win && seq == end_seq;
59} 59}
60 60
61static enum tcp_tw_status
62tcp_timewait_check_oow_rate_limit(struct inet_timewait_sock *tw,
63 const struct sk_buff *skb, int mib_idx)
64{
65 struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
66
67 if (!tcp_oow_rate_limited(twsk_net(tw), skb, mib_idx,
68 &tcptw->tw_last_oow_ack_time)) {
69 /* Send ACK. Note, we do not put the bucket,
70 * it will be released by caller.
71 */
72 return TCP_TW_ACK;
73 }
74
75 /* We are rate-limiting, so just release the tw sock and drop skb. */
76 inet_twsk_put(tw);
77 return TCP_TW_SUCCESS;
78}
79
61/* 80/*
62 * * Main purpose of TIME-WAIT state is to close connection gracefully, 81 * * Main purpose of TIME-WAIT state is to close connection gracefully,
63 * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN 82 * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN
@@ -116,7 +135,8 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
116 !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, 135 !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
117 tcptw->tw_rcv_nxt, 136 tcptw->tw_rcv_nxt,
118 tcptw->tw_rcv_nxt + tcptw->tw_rcv_wnd)) 137 tcptw->tw_rcv_nxt + tcptw->tw_rcv_wnd))
119 return TCP_TW_ACK; 138 return tcp_timewait_check_oow_rate_limit(
139 tw, skb, LINUX_MIB_TCPACKSKIPPEDFINWAIT2);
120 140
121 if (th->rst) 141 if (th->rst)
122 goto kill; 142 goto kill;
@@ -250,10 +270,8 @@ kill:
250 inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN, 270 inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
251 TCP_TIMEWAIT_LEN); 271 TCP_TIMEWAIT_LEN);
252 272
253 /* Send ACK. Note, we do not put the bucket, 273 return tcp_timewait_check_oow_rate_limit(
254 * it will be released by caller. 274 tw, skb, LINUX_MIB_TCPACKSKIPPEDTIMEWAIT);
255 */
256 return TCP_TW_ACK;
257 } 275 }
258 inet_twsk_put(tw); 276 inet_twsk_put(tw);
259 return TCP_TW_SUCCESS; 277 return TCP_TW_SUCCESS;
@@ -289,6 +307,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
289 tcptw->tw_ts_recent = tp->rx_opt.ts_recent; 307 tcptw->tw_ts_recent = tp->rx_opt.ts_recent;
290 tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; 308 tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp;
291 tcptw->tw_ts_offset = tp->tsoffset; 309 tcptw->tw_ts_offset = tp->tsoffset;
310 tcptw->tw_last_oow_ack_time = 0;
292 311
293#if IS_ENABLED(CONFIG_IPV6) 312#if IS_ENABLED(CONFIG_IPV6)
294 if (tw->tw_family == PF_INET6) { 313 if (tw->tw_family == PF_INET6) {