Skip to content

Commit

Permalink
Merge branch 'tcp-in-slow-start'
Browse files Browse the repository at this point in the history
Yuchung Cheng says:

====================
tcp: fixes some congestion control corner cases

This patch series fixes corner cases of TCP congestion control.
First issue is to avoid continuing slow start when cwnd reaches ssthresh.
Second issue is incorrectly processing order of congestion state and
cwnd update when entering fast recovery or undoing cwnd.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 9, 2015
2 parents 1007f59 + b20a3fa commit 986ca37
Show file tree
Hide file tree
Showing 14 changed files with 26 additions and 23 deletions.
7 changes: 6 additions & 1 deletion include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,11 @@ static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp)

#define TCP_INFINITE_SSTHRESH 0x7fffffff

static inline bool tcp_in_slow_start(const struct tcp_sock *tp)
{
return tp->snd_cwnd < tp->snd_ssthresh;
}

static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp)
{
return tp->snd_ssthresh >= TCP_INFINITE_SSTHRESH;
Expand Down Expand Up @@ -1065,7 +1070,7 @@ static inline bool tcp_is_cwnd_limited(const struct sock *sk)
const struct tcp_sock *tp = tcp_sk(sk);

/* If in slow start, ensure cwnd grows to twice what was ACKed. */
if (tp->snd_cwnd <= tp->snd_ssthresh)
if (tcp_in_slow_start(tp))
return tp->snd_cwnd < 2 * tp->max_packets_out;

return tp->is_cwnd_limited;
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_bic.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk))
return;

if (tp->snd_cwnd <= tp->snd_ssthresh)
if (tcp_in_slow_start(tp))
tcp_slow_start(tp, acked);
else {
bictcp_update(ca, tp->snd_cwnd);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_cdg.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ static void tcp_cdg_cong_avoid(struct sock *sk, u32 ack, u32 acked)
u32 prior_snd_cwnd;
u32 incr;

if (tp->snd_cwnd < tp->snd_ssthresh && hystart_detect)
if (tcp_in_slow_start(tp) && hystart_detect)
tcp_cdg_hystart_update(sk);

if (after(ack, ca->rtt_seq) && ca->rtt.v64) {
Expand Down
6 changes: 2 additions & 4 deletions net/ipv4/tcp_cong.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,8 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
*/
u32 tcp_slow_start(struct tcp_sock *tp, u32 acked)
{
u32 cwnd = tp->snd_cwnd + acked;
u32 cwnd = min(tp->snd_cwnd + acked, tp->snd_ssthresh);

if (cwnd > tp->snd_ssthresh)
cwnd = tp->snd_ssthresh + 1;
acked -= cwnd - tp->snd_cwnd;
tp->snd_cwnd = min(cwnd, tp->snd_cwnd_clamp);

Expand Down Expand Up @@ -413,7 +411,7 @@ void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
return;

/* In "safe" area, increase. */
if (tp->snd_cwnd <= tp->snd_ssthresh) {
if (tcp_in_slow_start(tp)) {
acked = tcp_slow_start(tp, acked);
if (!acked)
return;
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/tcp_cubic.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk))
return;

if (tp->snd_cwnd <= tp->snd_ssthresh) {
if (tcp_in_slow_start(tp)) {
if (hystart && after(ack, ca->end_seq))
bictcp_hystart_reset(sk);
acked = tcp_slow_start(tp, acked);
Expand Down Expand Up @@ -439,7 +439,7 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us)
ca->delay_min = delay;

/* hystart triggers when cwnd is larger than some threshold */
if (hystart && tp->snd_cwnd <= tp->snd_ssthresh &&
if (hystart && tcp_in_slow_start(tp) &&
tp->snd_cwnd >= hystart_low_window)
hystart_update(sk, delay);
}
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_highspeed.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ static void hstcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk))
return;

if (tp->snd_cwnd <= tp->snd_ssthresh)
if (tcp_in_slow_start(tp))
tcp_slow_start(tp, acked);
else {
/* Update AIMD parameters.
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_htcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk))
return;

if (tp->snd_cwnd <= tp->snd_ssthresh)
if (tcp_in_slow_start(tp))
tcp_slow_start(tp, acked);
else {
/* In dangerous area, increase slowly.
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_hybla.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked)

rho_fractions = ca->rho_3ls - (ca->rho << 3);

if (tp->snd_cwnd < tp->snd_ssthresh) {
if (tcp_in_slow_start(tp)) {
/*
* slow start
* INC = 2^RHO - 1
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_illinois.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked)
return;

/* In slow start */
if (tp->snd_cwnd <= tp->snd_ssthresh)
if (tcp_in_slow_start(tp))
tcp_slow_start(tp, acked);

else {
Expand Down
8 changes: 4 additions & 4 deletions net/ipv4/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -3568,10 +3568,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
&sack_state);
acked -= tp->packets_out;

/* Advance cwnd if state allows */
if (tcp_may_raise_cwnd(sk, flag))
tcp_cong_avoid(sk, ack, acked);

if (tcp_ack_is_dubious(sk, flag)) {
is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
tcp_fastretrans_alert(sk, acked, prior_unsacked,
Expand All @@ -3580,6 +3576,10 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
if (tp->tlp_high_seq)
tcp_process_tlp_ack(sk, ack, flag);

/* Advance cwnd if state allows */
if (tcp_may_raise_cwnd(sk, flag))
tcp_cong_avoid(sk, ack, acked);

if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) {
struct dst_entry *dst = __sk_dst_get(sk);
if (dst)
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ void tcp_update_metrics(struct sock *sk)
tcp_metric_set(tm, TCP_METRIC_CWND,
tp->snd_cwnd);
}
} else if (tp->snd_cwnd > tp->snd_ssthresh &&
} else if (!tcp_in_slow_start(tp) &&
icsk->icsk_ca_state == TCP_CA_Open) {
/* Cong. avoidance phase, cwnd is reliable. */
if (!tcp_metric_locked(tm, TCP_METRIC_SSTHRESH))
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_scalable.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked)
if (!tcp_is_cwnd_limited(sk))
return;

if (tp->snd_cwnd <= tp->snd_ssthresh)
if (tcp_in_slow_start(tp))
tcp_slow_start(tp, acked);
else
tcp_cong_avoid_ai(tp, min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT),
Expand Down
6 changes: 3 additions & 3 deletions net/ipv4/tcp_vegas.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
*/
diff = tp->snd_cwnd * (rtt-vegas->baseRTT) / vegas->baseRTT;

if (diff > gamma && tp->snd_cwnd <= tp->snd_ssthresh) {
if (diff > gamma && tcp_in_slow_start(tp)) {
/* Going too fast. Time to slow down
* and switch to congestion avoidance.
*/
Expand All @@ -240,7 +240,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1);
tp->snd_ssthresh = tcp_vegas_ssthresh(tp);

} else if (tp->snd_cwnd <= tp->snd_ssthresh) {
} else if (tcp_in_slow_start(tp)) {
/* Slow start. */
tcp_slow_start(tp, acked);
} else {
Expand Down Expand Up @@ -281,7 +281,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
vegas->minRTT = 0x7fffffff;
}
/* Use normal slow start */
else if (tp->snd_cwnd <= tp->snd_ssthresh)
else if (tcp_in_slow_start(tp))
tcp_slow_start(tp, acked);
}

Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_veno.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked)

veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd;

if (tp->snd_cwnd <= tp->snd_ssthresh) {
if (tcp_in_slow_start(tp)) {
/* Slow start. */
tcp_slow_start(tp, acked);
} else {
Expand Down

0 comments on commit 986ca37

Please sign in to comment.