diff options
author | Jason Baron <jbaron@akamai.com> | 2016-07-14 11:38:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-07-15 17:18:29 -0400 |
commit | 083ae308280d13d187512b9babe3454342a7987e (patch) | |
tree | d5540d3c373a2267191ed7bcfc9c43b2a917367b | |
parent | 005db31d5f5f7c31cfdc43505d77eb3ca5cf8ec6 (diff) |
tcp: enable per-socket rate limiting of all 'challenge acks'
The per-socket rate limit for 'challenge acks' was introduced in the
context of limiting ack loops:
commit f2b2c582e824 ("tcp: mitigate ACK loops for connections as tcp_sock")
And I think it can be extended to rate limit all 'challenge acks' on a
per-socket basis.
Since we have the global tcp_challenge_ack_limit, this patch allows for
tcp_challenge_ack_limit to be set to a large value and effectively rely on
the per-socket limit, or set tcp_challenge_ack_limit to a lower value and
still prevents a single connections from consuming the entire challenge ack
quota.
It further moves in the direction of eliminating the global limit at some
point, as Eric Dumazet has suggested. This a follow-up to:
Subject: tcp: make challenge acks less predictable
Cc: Eric Dumazet <edumazet@google.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Yue Cao <ycao009@ucr.edu>
Signed-off-by: Jason Baron <jbaron@akamai.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/tcp_input.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 91868bb17818..42bf89aaf6a5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -3421,6 +3421,23 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 | |||
3421 | return flag; | 3421 | return flag; |
3422 | } | 3422 | } |
3423 | 3423 | ||
3424 | static bool __tcp_oow_rate_limited(struct net *net, int mib_idx, | ||
3425 | u32 *last_oow_ack_time) | ||
3426 | { | ||
3427 | if (*last_oow_ack_time) { | ||
3428 | s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time); | ||
3429 | |||
3430 | if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) { | ||
3431 | NET_INC_STATS(net, mib_idx); | ||
3432 | return true; /* rate-limited: don't send yet! */ | ||
3433 | } | ||
3434 | } | ||
3435 | |||
3436 | *last_oow_ack_time = tcp_time_stamp; | ||
3437 | |||
3438 | return false; /* not rate-limited: go ahead, send dupack now! */ | ||
3439 | } | ||
3440 | |||
3424 | /* Return true if we're currently rate-limiting out-of-window ACKs and | 3441 | /* Return true if we're currently rate-limiting out-of-window ACKs and |
3425 | * thus shouldn't send a dupack right now. We rate-limit dupacks in | 3442 | * thus shouldn't send a dupack right now. We rate-limit dupacks in |
3426 | * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS | 3443 | * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS |
@@ -3434,21 +3451,9 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, | |||
3434 | /* Data packets without SYNs are not likely part of an ACK loop. */ | 3451 | /* Data packets without SYNs are not likely part of an ACK loop. */ |
3435 | if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) && | 3452 | if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) && |
3436 | !tcp_hdr(skb)->syn) | 3453 | !tcp_hdr(skb)->syn) |
3437 | goto not_rate_limited; | 3454 | return false; |
3438 | |||
3439 | if (*last_oow_ack_time) { | ||
3440 | s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time); | ||
3441 | |||
3442 | if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) { | ||
3443 | NET_INC_STATS(net, mib_idx); | ||
3444 | return true; /* rate-limited: don't send yet! */ | ||
3445 | } | ||
3446 | } | ||
3447 | |||
3448 | *last_oow_ack_time = tcp_time_stamp; | ||
3449 | 3455 | ||
3450 | not_rate_limited: | 3456 | return __tcp_oow_rate_limited(net, mib_idx, last_oow_ack_time); |
3451 | return false; /* not rate-limited: go ahead, send dupack now! */ | ||
3452 | } | 3457 | } |
3453 | 3458 | ||
3454 | /* RFC 5961 7 [ACK Throttling] */ | 3459 | /* RFC 5961 7 [ACK Throttling] */ |
@@ -3461,9 +3466,9 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) | |||
3461 | u32 count, now; | 3466 | u32 count, now; |
3462 | 3467 | ||
3463 | /* First check our per-socket dupack rate limit. */ | 3468 | /* First check our per-socket dupack rate limit. */ |
3464 | if (tcp_oow_rate_limited(sock_net(sk), skb, | 3469 | if (__tcp_oow_rate_limited(sock_net(sk), |
3465 | LINUX_MIB_TCPACKSKIPPEDCHALLENGE, | 3470 | LINUX_MIB_TCPACKSKIPPEDCHALLENGE, |
3466 | &tp->last_oow_ack_time)) | 3471 | &tp->last_oow_ack_time)) |
3467 | return; | 3472 | return; |
3468 | 3473 | ||
3469 | /* Then check host-wide RFC 5961 rate limit. */ | 3474 | /* Then check host-wide RFC 5961 rate limit. */ |