d0b2d44
From 8272c58d085e5611a7f839fa32e148ae62446375 Mon Sep 17 00:00:00 2001
d0b2d44
From: Jason Baron <jbaron@akamai.com>
d0b2d44
Date: Thu, 14 Jul 2016 11:38:40 -0400
d0b2d44
Subject: [PATCH] tcp: enable per-socket rate limiting of all 'challenge acks'
d0b2d44
d0b2d44
The per-socket rate limit for 'challenge acks' was introduced in the
d0b2d44
context of limiting ack loops:
d0b2d44
d0b2d44
commit f2b2c582e824 ("tcp: mitigate ACK loops for connections as tcp_sock")
d0b2d44
d0b2d44
And I think it can be extended to rate limit all 'challenge acks' on a
d0b2d44
per-socket basis.
d0b2d44
d0b2d44
Since we have the global tcp_challenge_ack_limit, this patch allows for
d0b2d44
tcp_challenge_ack_limit to be set to a large value and effectively rely on
d0b2d44
the per-socket limit, or set tcp_challenge_ack_limit to a lower value and
d0b2d44
still prevents a single connections from consuming the entire challenge ack
d0b2d44
quota.
d0b2d44
d0b2d44
It further moves in the direction of eliminating the global limit at some
d0b2d44
point, as Eric Dumazet has suggested. This a follow-up to:
d0b2d44
Subject: tcp: make challenge acks less predictable
d0b2d44
d0b2d44
Cc: Eric Dumazet <edumazet@google.com>
d0b2d44
Cc: David S. Miller <davem@davemloft.net>
d0b2d44
Cc: Neal Cardwell <ncardwell@google.com>
d0b2d44
Cc: Yuchung Cheng <ycheng@google.com>
d0b2d44
Cc: Yue Cao <ycao009@ucr.edu>
d0b2d44
Signed-off-by: Jason Baron <jbaron@akamai.com>
d0b2d44
Signed-off-by: David S. Miller <davem@davemloft.net>
d0b2d44
---
d0b2d44
 net/ipv4/tcp_input.c | 39 ++++++++++++++++++++++-----------------
d0b2d44
 1 file changed, 22 insertions(+), 17 deletions(-)
d0b2d44
d0b2d44
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
d0b2d44
index 8c011359646b..796315104ad7 100644
d0b2d44
--- a/net/ipv4/tcp_input.c
d0b2d44
+++ b/net/ipv4/tcp_input.c
d0b2d44
@@ -3423,6 +3423,23 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32
d0b2d44
 	return flag;
d0b2d44
 }
d0b2d44
 
d0b2d44
+static bool __tcp_oow_rate_limited(struct net *net, int mib_idx,
d0b2d44
+				   u32 *last_oow_ack_time)
d0b2d44
+{
d0b2d44
+	if (*last_oow_ack_time) {
d0b2d44
+		s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time);
d0b2d44
+
d0b2d44
+		if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) {
d0b2d44
+			NET_INC_STATS(net, mib_idx);
d0b2d44
+			return true;	/* rate-limited: don't send yet! */
d0b2d44
+		}
d0b2d44
+	}
d0b2d44
+
d0b2d44
+	*last_oow_ack_time = tcp_time_stamp;
d0b2d44
+
d0b2d44
+	return false;	/* not rate-limited: go ahead, send dupack now! */
d0b2d44
+}
d0b2d44
+
d0b2d44
 /* Return true if we're currently rate-limiting out-of-window ACKs and
d0b2d44
  * thus shouldn't send a dupack right now. We rate-limit dupacks in
d0b2d44
  * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS
d0b2d44
@@ -3436,21 +3453,9 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb,
d0b2d44
 	/* Data packets without SYNs are not likely part of an ACK loop. */
d0b2d44
 	if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) &&
d0b2d44
 	    !tcp_hdr(skb)->syn)
d0b2d44
-		goto not_rate_limited;
d0b2d44
-
d0b2d44
-	if (*last_oow_ack_time) {
d0b2d44
-		s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time);
d0b2d44
-
d0b2d44
-		if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) {
d0b2d44
-			NET_INC_STATS_BH(net, mib_idx);
d0b2d44
-			return true;	/* rate-limited: don't send yet! */
d0b2d44
-		}
d0b2d44
-	}
d0b2d44
-
d0b2d44
-	*last_oow_ack_time = tcp_time_stamp;
d0b2d44
+		return false;
d0b2d44
 
d0b2d44
-not_rate_limited:
d0b2d44
-	return false;	/* not rate-limited: go ahead, send dupack now! */
d0b2d44
+	return __tcp_oow_rate_limited(net, mib_idx, last_oow_ack_time);
d0b2d44
 }
d0b2d44
 
d0b2d44
 /* RFC 5961 7 [ACK Throttling] */
d0b2d44
@@ -3463,9 +3468,9 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb)
d0b2d44
 	u32 count, now;
d0b2d44
 
d0b2d44
 	/* First check our per-socket dupack rate limit. */
d0b2d44
-	if (tcp_oow_rate_limited(sock_net(sk), skb,
d0b2d44
-				 LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
d0b2d44
-				 &tp->last_oow_ack_time))
d0b2d44
+	if (__tcp_oow_rate_limited(sock_net(sk),
d0b2d44
+				   LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
d0b2d44
+				   &tp->last_oow_ack_time))
d0b2d44
 		return;
d0b2d44
 
d0b2d44
 	/* Then check host-wide RFC 5961 rate limit. */
d0b2d44
-- 
d0b2d44
2.7.4
d0b2d44