aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorYuchung Cheng <ycheng@google.com>2015-07-01 17:11:15 -0400
committerDavid S. Miller <davem@davemloft.net>2015-07-08 16:29:46 -0400
commit3759824da87b30ce7a35b4873b62b0ba38905ef5 (patch)
tree26542ae9bf43b3803e1f1bc6fc0eaff9067ba2e3 /net/ipv4/tcp_input.c
parent291a00d1a70f96b393da9ac90c58a82bc7949fc8 (diff)
tcp: PRR uses CRB mode by default and SS mode conditionally
PRR slow start is often too aggressive especially when drops are caused by traffic policers. The policers mainly use token bucket to enforce the rate so sending (twice) faster than the delivery rate causes excessive drops. This patch changes PRR to the conservative reduction bound (CRB) mode in RFC 6937 by default. CRB follows the packet conservation rule to send at most the delivery rate by default. But if many packets are lost and the pipe is empty, CRB may take N round trips to repair N losses. We conditionally turn on slow start mode if all these conditions are made to speed up the recovery: 1) on the second round or later in recovery 2) retransmission sent in the previous round is delivered on this ACK 3) no retransmission is marked lost on this ACK By using packet conservation by default, this change reduces the loss retransmits signicantly on networks that deploy traffic policers, up to 20% reduction of overall loss rate. Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Nandita Dukkipati <nanditad@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c29
1 files changed, 15 insertions, 14 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 923e0e568bfa..ad1482dd215e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2476,15 +2476,14 @@ static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo)
2476 return false; 2476 return false;
2477} 2477}
2478 2478
2479/* The cwnd reduction in CWR and Recovery use the PRR algorithm 2479/* The cwnd reduction in CWR and Recovery uses the PRR algorithm in RFC 6937.
2480 * https://datatracker.ietf.org/doc/draft-ietf-tcpm-proportional-rate-reduction/
2481 * It computes the number of packets to send (sndcnt) based on packets newly 2480 * It computes the number of packets to send (sndcnt) based on packets newly
2482 * delivered: 2481 * delivered:
2483 * 1) If the packets in flight is larger than ssthresh, PRR spreads the 2482 * 1) If the packets in flight is larger than ssthresh, PRR spreads the
2484 * cwnd reductions across a full RTT. 2483 * cwnd reductions across a full RTT.
2485 * 2) If packets in flight is lower than ssthresh (such as due to excess 2484 * 2) Otherwise PRR uses packet conservation to send as much as delivered.
2486 * losses and/or application stalls), do not perform any further cwnd 2485 * But when the retransmits are acked without further losses, PRR
2487 * reductions, but instead slow start up to ssthresh. 2486 * slow starts cwnd up to ssthresh to speed up the recovery.
2488 */ 2487 */
2489static void tcp_init_cwnd_reduction(struct sock *sk) 2488static void tcp_init_cwnd_reduction(struct sock *sk)
2490{ 2489{
@@ -2501,7 +2500,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk)
2501} 2500}
2502 2501
2503static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked, 2502static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
2504 int fast_rexmit) 2503 int fast_rexmit, int flag)
2505{ 2504{
2506 struct tcp_sock *tp = tcp_sk(sk); 2505 struct tcp_sock *tp = tcp_sk(sk);
2507 int sndcnt = 0; 2506 int sndcnt = 0;
@@ -2510,16 +2509,18 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
2510 (tp->packets_out - tp->sacked_out); 2509 (tp->packets_out - tp->sacked_out);
2511 2510
2512 tp->prr_delivered += newly_acked_sacked; 2511 tp->prr_delivered += newly_acked_sacked;
2513 if (tcp_packets_in_flight(tp) > tp->snd_ssthresh) { 2512 if (delta < 0) {
2514 u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered + 2513 u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
2515 tp->prior_cwnd - 1; 2514 tp->prior_cwnd - 1;
2516 sndcnt = div_u64(dividend, tp->prior_cwnd) - tp->prr_out; 2515 sndcnt = div_u64(dividend, tp->prior_cwnd) - tp->prr_out;
2517 } else { 2516 } else if ((flag & FLAG_RETRANS_DATA_ACKED) &&
2517 !(flag & FLAG_LOST_RETRANS)) {
2518 sndcnt = min_t(int, delta, 2518 sndcnt = min_t(int, delta,
2519 max_t(int, tp->prr_delivered - tp->prr_out, 2519 max_t(int, tp->prr_delivered - tp->prr_out,
2520 newly_acked_sacked) + 1); 2520 newly_acked_sacked) + 1);
2521 } else {
2522 sndcnt = min(delta, newly_acked_sacked);
2521 } 2523 }
2522
2523 sndcnt = max(sndcnt, (fast_rexmit ? 1 : 0)); 2524 sndcnt = max(sndcnt, (fast_rexmit ? 1 : 0));
2524 tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt; 2525 tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt;
2525} 2526}
@@ -2580,7 +2581,7 @@ static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked)
2580 if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { 2581 if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
2581 tcp_try_keep_open(sk); 2582 tcp_try_keep_open(sk);
2582 } else { 2583 } else {
2583 tcp_cwnd_reduction(sk, prior_unsacked, 0); 2584 tcp_cwnd_reduction(sk, prior_unsacked, 0, flag);
2584 } 2585 }
2585} 2586}
2586 2587
@@ -2737,7 +2738,7 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
2737 2738
2738/* Undo during fast recovery after partial ACK. */ 2739/* Undo during fast recovery after partial ACK. */
2739static bool tcp_try_undo_partial(struct sock *sk, const int acked, 2740static bool tcp_try_undo_partial(struct sock *sk, const int acked,
2740 const int prior_unsacked) 2741 const int prior_unsacked, int flag)
2741{ 2742{
2742 struct tcp_sock *tp = tcp_sk(sk); 2743 struct tcp_sock *tp = tcp_sk(sk);
2743 2744
@@ -2753,7 +2754,7 @@ static bool tcp_try_undo_partial(struct sock *sk, const int acked,
2753 * mark more packets lost or retransmit more. 2754 * mark more packets lost or retransmit more.
2754 */ 2755 */
2755 if (tp->retrans_out) { 2756 if (tp->retrans_out) {
2756 tcp_cwnd_reduction(sk, prior_unsacked, 0); 2757 tcp_cwnd_reduction(sk, prior_unsacked, 0, flag);
2757 return true; 2758 return true;
2758 } 2759 }
2759 2760
@@ -2840,7 +2841,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
2840 if (tcp_is_reno(tp) && is_dupack) 2841 if (tcp_is_reno(tp) && is_dupack)
2841 tcp_add_reno_sack(sk); 2842 tcp_add_reno_sack(sk);
2842 } else { 2843 } else {
2843 if (tcp_try_undo_partial(sk, acked, prior_unsacked)) 2844 if (tcp_try_undo_partial(sk, acked, prior_unsacked, flag))
2844 return; 2845 return;
2845 /* Partial ACK arrived. Force fast retransmit. */ 2846 /* Partial ACK arrived. Force fast retransmit. */
2846 do_lost = tcp_is_reno(tp) || 2847 do_lost = tcp_is_reno(tp) ||
@@ -2891,7 +2892,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
2891 2892
2892 if (do_lost) 2893 if (do_lost)
2893 tcp_update_scoreboard(sk, fast_rexmit); 2894 tcp_update_scoreboard(sk, fast_rexmit);
2894 tcp_cwnd_reduction(sk, prior_unsacked, fast_rexmit); 2895 tcp_cwnd_reduction(sk, prior_unsacked, fast_rexmit, flag);
2895 tcp_xmit_retransmit_queue(sk); 2896 tcp_xmit_retransmit_queue(sk);
2896} 2897}
2897 2898