]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv4/tcp_input.c
tcp: increase throughput when reordering is high
[karo-tx-linux.git] / net / ipv4 / tcp_input.c
index e965cc7b87ffdd02c6260ab86c3febea6971a60b..ec492eae0cd75684cc83d0bce697eb39fb37fdd5 100644 (file)
@@ -2485,8 +2485,6 @@ static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked)
 
        if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
                tcp_try_keep_open(sk);
-               if (inet_csk(sk)->icsk_ca_state != TCP_CA_Open)
-                       tcp_moderate_cwnd(tp);
        } else {
                tcp_cwnd_reduction(sk, prior_unsacked, 0);
        }
@@ -3128,11 +3126,24 @@ static inline bool tcp_ack_is_dubious(const struct sock *sk, const int flag)
                inet_csk(sk)->icsk_ca_state != TCP_CA_Open;
 }
 
+/* Decide wheather to run the increase function of congestion control. */
 static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag)
 {
-       const struct tcp_sock *tp = tcp_sk(sk);
-       return (!(flag & FLAG_ECE) || tp->snd_cwnd < tp->snd_ssthresh) &&
-               !tcp_in_cwnd_reduction(sk);
+       if (tcp_in_cwnd_reduction(sk))
+               return false;
+
+       /* If reordering is high then always grow cwnd whenever data is
+        * delivered regardless of its ordering. Otherwise stay conservative
+        * and only grow cwnd on in-order delivery in Open state, and retain
+        * cwnd in Disordered state (RFC5681). A stretched ACK with
+        * new SACK or ECE mark may first advance cwnd here and later reduce
+        * cwnd in tcp_fastretrans_alert() based on more states.
+        */
+       if (tcp_sk(sk)->reordering > sysctl_tcp_reordering)
+               return flag & FLAG_FORWARD_PROGRESS;
+
+       return inet_csk(sk)->icsk_ca_state == TCP_CA_Open &&
+              flag & FLAG_DATA_ACKED;
 }
 
 /* Check that window update is acceptable.
@@ -3352,18 +3363,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, sack_rtt);
        acked -= tp->packets_out;
 
+       /* Advance cwnd if state allows */
+       if (tcp_may_raise_cwnd(sk, flag))
+               tcp_cong_avoid(sk, ack, prior_in_flight);
+
        if (tcp_ack_is_dubious(sk, flag)) {
-               /* Advance CWND, if state allows this. */
-               if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(sk, flag))
-                       tcp_cong_avoid(sk, ack, prior_in_flight);
                is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
                tcp_fastretrans_alert(sk, acked, prior_unsacked,
                                      is_dupack, flag);
-       } else {
-               if (flag & FLAG_DATA_ACKED)
-                       tcp_cong_avoid(sk, ack, prior_in_flight);
        }
-
        if (tp->tlp_high_seq)
                tcp_process_tlp_ack(sk, ack, flag);