diff options
author | Yuchung Cheng <ycheng@google.com> | 2016-02-02 13:33:05 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-02-07 14:09:50 -0500 |
commit | 31ba0c10723e9eba378f96de1d1a9426129949e1 (patch) | |
tree | 98b0ed4aeb112803ccbb80ef18754acf58faa87d /net/ipv4/tcp_input.c | |
parent | e662ca40de846e0a2be6326a7c4668326ddb194c (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.c | 60 |
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 | ||
2474 | static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked, | 2474 | static 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 | ||
2544 | static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked) | 2543 | static 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. */ |
2723 | static bool tcp_try_undo_partial(struct sock *sk, const int acked, | 2720 | static 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 | */ |
2767 | static void tcp_fastretrans_alert(struct sock *sk, const int acked, | 2762 | static 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. */ |
3307 | static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag) | 3302 | static 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) | |||
3672 | no_queue: | 3670 | no_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 | ||