aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorYuchung Cheng <ycheng@google.com>2016-02-02 13:33:05 -0500
committerDavid S. Miller <davem@davemloft.net>2016-02-07 14:09:50 -0500
commit31ba0c10723e9eba378f96de1d1a9426129949e1 (patch)
tree98b0ed4aeb112803ccbb80ef18754acf58faa87d /net/ipv4/tcp_input.c
parente662ca40de846e0a2be6326a7c4668326ddb194c (diff)
tcp: move cwnd reduction after recovery state procesing
Currently the cwnd is reduced and increased in various different places. The reduction happens in various places in the recovery state processing (tcp_fastretrans_alert) while the increase happens afterward. A better sequence is to identify lost packets and update the congestion control state (icsk_ca_state) first. Then base on the new state, up/down the cwnd in one central place. It's more clear to reason cwnd changes. Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: Eric Dumazet <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.c60
1 files changed, 28 insertions, 32 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 84a4ab9c05d1..dc810df53e90 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2471,14 +2471,12 @@ static void tcp_init_cwnd_reduction(struct sock *sk)
2471 tcp_ecn_queue_cwr(tp); 2471 tcp_ecn_queue_cwr(tp);
2472} 2472}
2473 2473
2474static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked, 2474static void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked,
2475 int fast_rexmit, int flag) 2475 int flag)
2476{ 2476{
2477 struct tcp_sock *tp = tcp_sk(sk); 2477 struct tcp_sock *tp = tcp_sk(sk);
2478 int sndcnt = 0; 2478 int sndcnt = 0;
2479 int delta = tp->snd_ssthresh - tcp_packets_in_flight(tp); 2479 int delta = tp->snd_ssthresh - tcp_packets_in_flight(tp);
2480 int newly_acked_sacked = prior_unsacked -
2481 (tp->packets_out - tp->sacked_out);
2482 2480
2483 if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd)) 2481 if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd))
2484 return; 2482 return;
@@ -2496,7 +2494,8 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
2496 } else { 2494 } else {
2497 sndcnt = min(delta, newly_acked_sacked); 2495 sndcnt = min(delta, newly_acked_sacked);
2498 } 2496 }
2499 sndcnt = max(sndcnt, (fast_rexmit ? 1 : 0)); 2497 /* Force a fast retransmit upon entering fast recovery */
2498 sndcnt = max(sndcnt, (tp->prr_out ? 0 : 1));
2500 tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt; 2499 tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt;
2501} 2500}
2502 2501
@@ -2541,7 +2540,7 @@ static void tcp_try_keep_open(struct sock *sk)
2541 } 2540 }
2542} 2541}
2543 2542
2544static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked) 2543static void tcp_try_to_open(struct sock *sk, int flag)
2545{ 2544{
2546 struct tcp_sock *tp = tcp_sk(sk); 2545 struct tcp_sock *tp = tcp_sk(sk);
2547 2546
@@ -2555,8 +2554,6 @@ static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked)
2555 2554
2556 if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { 2555 if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
2557 tcp_try_keep_open(sk); 2556 tcp_try_keep_open(sk);
2558 } else {
2559 tcp_cwnd_reduction(sk, prior_unsacked, 0, flag);
2560 } 2557 }
2561} 2558}
2562 2559
@@ -2720,8 +2717,7 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack,
2720} 2717}
2721 2718
2722/* Undo during fast recovery after partial ACK. */ 2719/* Undo during fast recovery after partial ACK. */
2723static bool tcp_try_undo_partial(struct sock *sk, const int acked, 2720static bool tcp_try_undo_partial(struct sock *sk, const int acked)
2724 const int prior_unsacked, int flag)
2725{ 2721{
2726 struct tcp_sock *tp = tcp_sk(sk); 2722 struct tcp_sock *tp = tcp_sk(sk);
2727 2723
@@ -2736,10 +2732,8 @@ static bool tcp_try_undo_partial(struct sock *sk, const int acked,
2736 * can undo. Otherwise we clock out new packets but do not 2732 * can undo. Otherwise we clock out new packets but do not
2737 * mark more packets lost or retransmit more. 2733 * mark more packets lost or retransmit more.
2738 */ 2734 */
2739 if (tp->retrans_out) { 2735 if (tp->retrans_out)
2740 tcp_cwnd_reduction(sk, prior_unsacked, 0, flag);
2741 return true; 2736 return true;
2742 }
2743 2737
2744 if (!tcp_any_retrans_done(sk)) 2738 if (!tcp_any_retrans_done(sk))
2745 tp->retrans_stamp = 0; 2739 tp->retrans_stamp = 0;
@@ -2758,21 +2752,21 @@ static bool tcp_try_undo_partial(struct sock *sk, const int acked,
2758 * taking into account both packets sitting in receiver's buffer and 2752 * taking into account both packets sitting in receiver's buffer and
2759 * packets lost by network. 2753 * packets lost by network.
2760 * 2754 *
2761 * Besides that it does CWND reduction, when packet loss is detected 2755 * Besides that it updates the congestion state when packet loss or ECN
2762 * and changes state of machine. 2756 * is detected. But it does not reduce the cwnd, it is done by the
2757 * congestion control later.
2763 * 2758 *
2764 * It does _not_ decide what to send, it is made in function 2759 * It does _not_ decide what to send, it is made in function
2765 * tcp_xmit_retransmit_queue(). 2760 * tcp_xmit_retransmit_queue().
2766 */ 2761 */
2767static void tcp_fastretrans_alert(struct sock *sk, const int acked, 2762static void tcp_fastretrans_alert(struct sock *sk, const int acked,
2768 const int prior_unsacked, 2763 bool is_dupack, int *ack_flag, int *rexmit)
2769 bool is_dupack, int flag, int *rexmit)
2770{ 2764{
2771 struct inet_connection_sock *icsk = inet_csk(sk); 2765 struct inet_connection_sock *icsk = inet_csk(sk);
2772 struct tcp_sock *tp = tcp_sk(sk); 2766 struct tcp_sock *tp = tcp_sk(sk);
2767 int fast_rexmit = 0, flag = *ack_flag;
2773 bool do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && 2768 bool do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) &&
2774 (tcp_fackets_out(tp) > tp->reordering)); 2769 (tcp_fackets_out(tp) > tp->reordering));
2775 int fast_rexmit = 0;
2776 2770
2777 if (WARN_ON(!tp->packets_out && tp->sacked_out)) 2771 if (WARN_ON(!tp->packets_out && tp->sacked_out))
2778 tp->sacked_out = 0; 2772 tp->sacked_out = 0;
@@ -2819,8 +2813,10 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
2819 2813
2820 /* Use RACK to detect loss */ 2814 /* Use RACK to detect loss */
2821 if (sysctl_tcp_recovery & TCP_RACK_LOST_RETRANS && 2815 if (sysctl_tcp_recovery & TCP_RACK_LOST_RETRANS &&
2822 tcp_rack_mark_lost(sk)) 2816 tcp_rack_mark_lost(sk)) {
2823 flag |= FLAG_LOST_RETRANS; 2817 flag |= FLAG_LOST_RETRANS;
2818 *ack_flag |= FLAG_LOST_RETRANS;
2819 }
2824 2820
2825 /* E. Process state. */ 2821 /* E. Process state. */
2826 switch (icsk->icsk_ca_state) { 2822 switch (icsk->icsk_ca_state) {
@@ -2829,7 +2825,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
2829 if (tcp_is_reno(tp) && is_dupack) 2825 if (tcp_is_reno(tp) && is_dupack)
2830 tcp_add_reno_sack(sk); 2826 tcp_add_reno_sack(sk);
2831 } else { 2827 } else {
2832 if (tcp_try_undo_partial(sk, acked, prior_unsacked, flag)) 2828 if (tcp_try_undo_partial(sk, acked))
2833 return; 2829 return;
2834 /* Partial ACK arrived. Force fast retransmit. */ 2830 /* Partial ACK arrived. Force fast retransmit. */
2835 do_lost = tcp_is_reno(tp) || 2831 do_lost = tcp_is_reno(tp) ||
@@ -2858,7 +2854,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
2858 tcp_try_undo_dsack(sk); 2854 tcp_try_undo_dsack(sk);
2859 2855
2860 if (!tcp_time_to_recover(sk, flag)) { 2856 if (!tcp_time_to_recover(sk, flag)) {
2861 tcp_try_to_open(sk, flag, prior_unsacked); 2857 tcp_try_to_open(sk, flag);
2862 return; 2858 return;
2863 } 2859 }
2864 2860
@@ -2880,7 +2876,6 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
2880 2876
2881 if (do_lost) 2877 if (do_lost)
2882 tcp_update_scoreboard(sk, fast_rexmit); 2878 tcp_update_scoreboard(sk, fast_rexmit);
2883 tcp_cwnd_reduction(sk, prior_unsacked, fast_rexmit, flag);
2884 *rexmit = REXMIT_LOST; 2879 *rexmit = REXMIT_LOST;
2885} 2880}
2886 2881
@@ -3306,9 +3301,6 @@ static inline bool tcp_ack_is_dubious(const struct sock *sk, const int flag)
3306/* Decide wheather to run the increase function of congestion control. */ 3301/* Decide wheather to run the increase function of congestion control. */
3307static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag) 3302static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag)
3308{ 3303{
3309 if (tcp_in_cwnd_reduction(sk))
3310 return false;
3311
3312 /* If reordering is high then always grow cwnd whenever data is 3304 /* If reordering is high then always grow cwnd whenever data is
3313 * delivered regardless of its ordering. Otherwise stay conservative 3305 * delivered regardless of its ordering. Otherwise stay conservative
3314 * and only grow cwnd on in-order delivery (RFC5681). A stretched ACK w/ 3306 * and only grow cwnd on in-order delivery (RFC5681). A stretched ACK w/
@@ -3551,6 +3543,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3551 int prior_packets = tp->packets_out; 3543 int prior_packets = tp->packets_out;
3552 const int prior_unsacked = tp->packets_out - tp->sacked_out; 3544 const int prior_unsacked = tp->packets_out - tp->sacked_out;
3553 int acked = 0; /* Number of packets newly acked */ 3545 int acked = 0; /* Number of packets newly acked */
3546 int acked_sacked; /* Number of packets newly acked or sacked */
3554 int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */ 3547 int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */
3555 3548
3556 sack_state.first_sackt.v64 = 0; 3549 sack_state.first_sackt.v64 = 0;
@@ -3647,15 +3640,20 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3647 3640
3648 if (tcp_ack_is_dubious(sk, flag)) { 3641 if (tcp_ack_is_dubious(sk, flag)) {
3649 is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); 3642 is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
3650 tcp_fastretrans_alert(sk, acked, prior_unsacked, 3643 tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);
3651 is_dupack, flag, &rexmit);
3652 } 3644 }
3653 if (tp->tlp_high_seq) 3645 if (tp->tlp_high_seq)
3654 tcp_process_tlp_ack(sk, ack, flag); 3646 tcp_process_tlp_ack(sk, ack, flag);
3655 3647
3648 acked_sacked = prior_unsacked - (tp->packets_out - tp->sacked_out);
3656 /* Advance cwnd if state allows */ 3649 /* Advance cwnd if state allows */
3657 if (tcp_may_raise_cwnd(sk, flag)) 3650 if (tcp_in_cwnd_reduction(sk)) {
3651 /* Reduce cwnd if state mandates */
3652 tcp_cwnd_reduction(sk, acked_sacked, flag);
3653 } else if (tcp_may_raise_cwnd(sk, flag)) {
3654 /* Advance cwnd if state allows */
3658 tcp_cong_avoid(sk, ack, acked); 3655 tcp_cong_avoid(sk, ack, acked);
3656 }
3659 3657
3660 if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) { 3658 if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) {
3661 struct dst_entry *dst = __sk_dst_get(sk); 3659 struct dst_entry *dst = __sk_dst_get(sk);
@@ -3672,8 +3670,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3672no_queue: 3670no_queue:
3673 /* If data was DSACKed, see if we can undo a cwnd reduction. */ 3671 /* If data was DSACKed, see if we can undo a cwnd reduction. */
3674 if (flag & FLAG_DSACKING_ACK) 3672 if (flag & FLAG_DSACKING_ACK)
3675 tcp_fastretrans_alert(sk, acked, prior_unsacked, 3673 tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);
3676 is_dupack, flag, &rexmit);
3677 /* If this ack opens up a zero window, clear backoff. It was 3674 /* If this ack opens up a zero window, clear backoff. It was
3678 * being used to time the probes, and is probably far higher than 3675 * being used to time the probes, and is probably far higher than
3679 * it needs to be for normal retransmission. 3676 * it needs to be for normal retransmission.
@@ -3696,8 +3693,7 @@ old_ack:
3696 if (TCP_SKB_CB(skb)->sacked) { 3693 if (TCP_SKB_CB(skb)->sacked) {
3697 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, 3694 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
3698 &sack_state); 3695 &sack_state);
3699 tcp_fastretrans_alert(sk, acked, prior_unsacked, 3696 tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);
3700 is_dupack, flag, &rexmit);
3701 tcp_xmit_recovery(sk, rexmit); 3697 tcp_xmit_recovery(sk, rexmit);
3702 } 3698 }
3703 3699