Commit 01a6a62e authored by David S. Miller's avatar David S. Miller

Merge branch 'tcp-fix-stretch-ACK-bugs-in-congestion-control-modules'

Pengcheng Yang says:

====================
tcp: fix stretch ACK bugs in congestion control modules

"stretch ACKs" (caused by LRO, GRO, delayed ACKs or middleboxes)
can cause serious performance shortfalls in common congestion
control algorithms. Neal Cardwell submitted a series of patches
starting with commit e73ebb08 ("tcp: stretch ACK fixes prep")
to handle stretch ACKs and fixed stretch ACK bugs in Reno and
CUBIC congestion control algorithms.

This patch series continues to fix bic, scalable, veno and yeah
congestion control algorithms to handle stretch ACKs.

Changes in v2:
- Provide [PATCH 0/N] to describe the modifications of this patch series
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 86e85bf6 fa4cb9eb
...@@ -145,12 +145,13 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) ...@@ -145,12 +145,13 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk)) if (!tcp_is_cwnd_limited(sk))
return; return;
if (tcp_in_slow_start(tp)) if (tcp_in_slow_start(tp)) {
tcp_slow_start(tp, acked); acked = tcp_slow_start(tp, acked);
else { if (!acked)
bictcp_update(ca, tp->snd_cwnd); return;
tcp_cong_avoid_ai(tp, ca->cnt, 1);
} }
bictcp_update(ca, tp->snd_cwnd);
tcp_cong_avoid_ai(tp, ca->cnt, acked);
} }
/* /*
......
...@@ -10,10 +10,9 @@ ...@@ -10,10 +10,9 @@
#include <net/tcp.h> #include <net/tcp.h>
/* These factors derived from the recommended values in the aer: /* These factors derived from the recommended values in the aer:
* .01 and and 7/8. We use 50 instead of 100 to account for * .01 and and 7/8.
* delayed ack.
*/ */
#define TCP_SCALABLE_AI_CNT 50U #define TCP_SCALABLE_AI_CNT 100U
#define TCP_SCALABLE_MD_SCALE 3 #define TCP_SCALABLE_MD_SCALE 3
static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked) static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked)
...@@ -23,11 +22,13 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked) ...@@ -23,11 +22,13 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk)) if (!tcp_is_cwnd_limited(sk))
return; return;
if (tcp_in_slow_start(tp)) if (tcp_in_slow_start(tp)) {
tcp_slow_start(tp, acked); acked = tcp_slow_start(tp, acked);
else if (!acked)
tcp_cong_avoid_ai(tp, min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT), return;
1); }
tcp_cong_avoid_ai(tp, min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT),
acked);
} }
static u32 tcp_scalable_ssthresh(struct sock *sk) static u32 tcp_scalable_ssthresh(struct sock *sk)
......
...@@ -153,31 +153,34 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked) ...@@ -153,31 +153,34 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd; veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd;
if (tcp_in_slow_start(tp)) { if (tcp_in_slow_start(tp)) {
/* Slow start. */ /* Slow start. */
tcp_slow_start(tp, acked); acked = tcp_slow_start(tp, acked);
if (!acked)
goto done;
}
/* Congestion avoidance. */
if (veno->diff < beta) {
/* In the "non-congestive state", increase cwnd
* every rtt.
*/
tcp_cong_avoid_ai(tp, tp->snd_cwnd, acked);
} else { } else {
/* Congestion avoidance. */ /* In the "congestive state", increase cwnd
if (veno->diff < beta) { * every other rtt.
/* In the "non-congestive state", increase cwnd */
* every rtt. if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
*/ if (veno->inc &&
tcp_cong_avoid_ai(tp, tp->snd_cwnd, 1); tp->snd_cwnd < tp->snd_cwnd_clamp) {
} else { tp->snd_cwnd++;
/* In the "congestive state", increase cwnd veno->inc = 0;
* every other rtt.
*/
if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
if (veno->inc &&
tp->snd_cwnd < tp->snd_cwnd_clamp) {
tp->snd_cwnd++;
veno->inc = 0;
} else
veno->inc = 1;
tp->snd_cwnd_cnt = 0;
} else } else
tp->snd_cwnd_cnt++; veno->inc = 1;
} tp->snd_cwnd_cnt = 0;
} else
tp->snd_cwnd_cnt += acked;
} }
done:
if (tp->snd_cwnd < 2) if (tp->snd_cwnd < 2)
tp->snd_cwnd = 2; tp->snd_cwnd = 2;
else if (tp->snd_cwnd > tp->snd_cwnd_clamp) else if (tp->snd_cwnd > tp->snd_cwnd_clamp)
......
...@@ -36,8 +36,6 @@ struct yeah { ...@@ -36,8 +36,6 @@ struct yeah {
u32 reno_count; u32 reno_count;
u32 fast_count; u32 fast_count;
u32 pkts_acked;
}; };
static void tcp_yeah_init(struct sock *sk) static void tcp_yeah_init(struct sock *sk)
...@@ -57,18 +55,6 @@ static void tcp_yeah_init(struct sock *sk) ...@@ -57,18 +55,6 @@ static void tcp_yeah_init(struct sock *sk)
tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128); tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
} }
static void tcp_yeah_pkts_acked(struct sock *sk,
const struct ack_sample *sample)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct yeah *yeah = inet_csk_ca(sk);
if (icsk->icsk_ca_state == TCP_CA_Open)
yeah->pkts_acked = sample->pkts_acked;
tcp_vegas_pkts_acked(sk, sample);
}
static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked) static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
{ {
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
...@@ -77,24 +63,19 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked) ...@@ -77,24 +63,19 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk)) if (!tcp_is_cwnd_limited(sk))
return; return;
if (tcp_in_slow_start(tp)) if (tcp_in_slow_start(tp)) {
tcp_slow_start(tp, acked); acked = tcp_slow_start(tp, acked);
if (!acked)
goto do_vegas;
}
else if (!yeah->doing_reno_now) { if (!yeah->doing_reno_now) {
/* Scalable */ /* Scalable */
tcp_cong_avoid_ai(tp, min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT),
tp->snd_cwnd_cnt += yeah->pkts_acked; acked);
if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)) {
if (tp->snd_cwnd < tp->snd_cwnd_clamp)
tp->snd_cwnd++;
tp->snd_cwnd_cnt = 0;
}
yeah->pkts_acked = 1;
} else { } else {
/* Reno */ /* Reno */
tcp_cong_avoid_ai(tp, tp->snd_cwnd, 1); tcp_cong_avoid_ai(tp, tp->snd_cwnd, acked);
} }
/* The key players are v_vegas.beg_snd_una and v_beg_snd_nxt. /* The key players are v_vegas.beg_snd_una and v_beg_snd_nxt.
...@@ -118,7 +99,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked) ...@@ -118,7 +99,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
* of bytes we send in an RTT is often less than our cwnd will allow. * of bytes we send in an RTT is often less than our cwnd will allow.
* So we keep track of our cwnd separately, in v_beg_snd_cwnd. * So we keep track of our cwnd separately, in v_beg_snd_cwnd.
*/ */
do_vegas:
if (after(ack, yeah->vegas.beg_snd_nxt)) { if (after(ack, yeah->vegas.beg_snd_nxt)) {
/* We do the Vegas calculations only if we got enough RTT /* We do the Vegas calculations only if we got enough RTT
* samples that we can be reasonably sure that we got * samples that we can be reasonably sure that we got
...@@ -232,7 +213,7 @@ static struct tcp_congestion_ops tcp_yeah __read_mostly = { ...@@ -232,7 +213,7 @@ static struct tcp_congestion_ops tcp_yeah __read_mostly = {
.set_state = tcp_vegas_state, .set_state = tcp_vegas_state,
.cwnd_event = tcp_vegas_cwnd_event, .cwnd_event = tcp_vegas_cwnd_event,
.get_info = tcp_vegas_get_info, .get_info = tcp_vegas_get_info,
.pkts_acked = tcp_yeah_pkts_acked, .pkts_acked = tcp_vegas_pkts_acked,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "yeah", .name = "yeah",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment