diff options
author | David S. Miller <davem@davemloft.net> | 2016-07-23 19:31:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-07-24 00:53:32 -0400 |
commit | de0ba9a0d8909996f9e293d311c2cc459fa77d67 (patch) | |
tree | 199214afc477824bf431d11d08834ff7555c994b /net/ipv4/tcp_input.c | |
parent | d95a93a9b71677a43f967a1b7986decab84b7765 (diff) | |
parent | 107df03203bb66de56e2caec3bde6d22b55480c5 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Just several instances of overlapping changes.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 94d4aff97523..f9f9e375d7de 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -87,7 +87,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 1; | |||
87 | EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); | 87 | EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); |
88 | 88 | ||
89 | /* rfc5961 challenge ack rate limiting */ | 89 | /* rfc5961 challenge ack rate limiting */ |
90 | int sysctl_tcp_challenge_ack_limit = 100; | 90 | int sysctl_tcp_challenge_ack_limit = 1000; |
91 | 91 | ||
92 | int sysctl_tcp_stdurg __read_mostly; | 92 | int sysctl_tcp_stdurg __read_mostly; |
93 | int sysctl_tcp_rfc1337 __read_mostly; | 93 | int sysctl_tcp_rfc1337 __read_mostly; |
@@ -3424,6 +3424,23 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 | |||
3424 | return flag; | 3424 | return flag; |
3425 | } | 3425 | } |
3426 | 3426 | ||
3427 | static bool __tcp_oow_rate_limited(struct net *net, int mib_idx, | ||
3428 | u32 *last_oow_ack_time) | ||
3429 | { | ||
3430 | if (*last_oow_ack_time) { | ||
3431 | s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time); | ||
3432 | |||
3433 | if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) { | ||
3434 | NET_INC_STATS(net, mib_idx); | ||
3435 | return true; /* rate-limited: don't send yet! */ | ||
3436 | } | ||
3437 | } | ||
3438 | |||
3439 | *last_oow_ack_time = tcp_time_stamp; | ||
3440 | |||
3441 | return false; /* not rate-limited: go ahead, send dupack now! */ | ||
3442 | } | ||
3443 | |||
3427 | /* Return true if we're currently rate-limiting out-of-window ACKs and | 3444 | /* Return true if we're currently rate-limiting out-of-window ACKs and |
3428 | * thus shouldn't send a dupack right now. We rate-limit dupacks in | 3445 | * thus shouldn't send a dupack right now. We rate-limit dupacks in |
3429 | * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS | 3446 | * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS |
@@ -3437,21 +3454,9 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, | |||
3437 | /* Data packets without SYNs are not likely part of an ACK loop. */ | 3454 | /* Data packets without SYNs are not likely part of an ACK loop. */ |
3438 | if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) && | 3455 | if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) && |
3439 | !tcp_hdr(skb)->syn) | 3456 | !tcp_hdr(skb)->syn) |
3440 | goto not_rate_limited; | 3457 | return false; |
3441 | |||
3442 | if (*last_oow_ack_time) { | ||
3443 | s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time); | ||
3444 | |||
3445 | if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) { | ||
3446 | NET_INC_STATS(net, mib_idx); | ||
3447 | return true; /* rate-limited: don't send yet! */ | ||
3448 | } | ||
3449 | } | ||
3450 | |||
3451 | *last_oow_ack_time = tcp_time_stamp; | ||
3452 | 3458 | ||
3453 | not_rate_limited: | 3459 | return __tcp_oow_rate_limited(net, mib_idx, last_oow_ack_time); |
3454 | return false; /* not rate-limited: go ahead, send dupack now! */ | ||
3455 | } | 3460 | } |
3456 | 3461 | ||
3457 | /* RFC 5961 7 [ACK Throttling] */ | 3462 | /* RFC 5961 7 [ACK Throttling] */ |
@@ -3461,21 +3466,26 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) | |||
3461 | static u32 challenge_timestamp; | 3466 | static u32 challenge_timestamp; |
3462 | static unsigned int challenge_count; | 3467 | static unsigned int challenge_count; |
3463 | struct tcp_sock *tp = tcp_sk(sk); | 3468 | struct tcp_sock *tp = tcp_sk(sk); |
3464 | u32 now; | 3469 | u32 count, now; |
3465 | 3470 | ||
3466 | /* First check our per-socket dupack rate limit. */ | 3471 | /* First check our per-socket dupack rate limit. */ |
3467 | if (tcp_oow_rate_limited(sock_net(sk), skb, | 3472 | if (__tcp_oow_rate_limited(sock_net(sk), |
3468 | LINUX_MIB_TCPACKSKIPPEDCHALLENGE, | 3473 | LINUX_MIB_TCPACKSKIPPEDCHALLENGE, |
3469 | &tp->last_oow_ack_time)) | 3474 | &tp->last_oow_ack_time)) |
3470 | return; | 3475 | return; |
3471 | 3476 | ||
3472 | /* Then check the check host-wide RFC 5961 rate limit. */ | 3477 | /* Then check host-wide RFC 5961 rate limit. */ |
3473 | now = jiffies / HZ; | 3478 | now = jiffies / HZ; |
3474 | if (now != challenge_timestamp) { | 3479 | if (now != challenge_timestamp) { |
3480 | u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1; | ||
3481 | |||
3475 | challenge_timestamp = now; | 3482 | challenge_timestamp = now; |
3476 | challenge_count = 0; | 3483 | WRITE_ONCE(challenge_count, half + |
3484 | prandom_u32_max(sysctl_tcp_challenge_ack_limit)); | ||
3477 | } | 3485 | } |
3478 | if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { | 3486 | count = READ_ONCE(challenge_count); |
3487 | if (count > 0) { | ||
3488 | WRITE_ONCE(challenge_count, count - 1); | ||
3479 | NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); | 3489 | NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); |
3480 | tcp_send_ack(sk); | 3490 | tcp_send_ack(sk); |
3481 | } | 3491 | } |