aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
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