tcp: new delivery accounting
[cascardo/linux.git] / net / ipv4 / tcp_input.c
index dc810df..2d690b3 100644 (file)
@@ -1214,6 +1214,7 @@ static u8 tcp_sacktag_one(struct sock *sk,
                sacked |= TCPCB_SACKED_ACKED;
                state->flag |= FLAG_DATA_SACKED;
                tp->sacked_out += pcount;
+               tp->delivered += pcount;  /* Out-of-order packets delivered */
 
                fack_count += pcount;
 
@@ -1825,8 +1826,12 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)
 static void tcp_add_reno_sack(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       u32 prior_sacked = tp->sacked_out;
+
        tp->sacked_out++;
        tcp_check_reno_reordering(sk, 0);
+       if (tp->sacked_out > prior_sacked)
+               tp->delivered++; /* Some out-of-order packet is delivered */
        tcp_verify_left_out(tp);
 }
 
@@ -1838,6 +1843,7 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked)
 
        if (acked > 0) {
                /* One ACK acked hole. The rest eat duplicate ACKs. */
+               tp->delivered += max_t(int, acked - tp->sacked_out, 1);
                if (acked - 1 >= tp->sacked_out)
                        tp->sacked_out = 0;
                else
@@ -3156,10 +3162,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                                flag |= FLAG_ORIG_SACK_ACKED;
                }
 
-               if (sacked & TCPCB_SACKED_ACKED)
+               if (sacked & TCPCB_SACKED_ACKED) {
                        tp->sacked_out -= acked_pcount;
-               else if (tcp_is_sack(tp) && !tcp_skb_spurious_retrans(tp, skb))
-                       tcp_rack_advance(tp, &skb->skb_mstamp, sacked);
+               } else if (tcp_is_sack(tp)) {
+                       tp->delivered += acked_pcount;
+                       if (!tcp_skb_spurious_retrans(tp, skb))
+                               tcp_rack_advance(tp, &skb->skb_mstamp, sacked);
+               }
                if (sacked & TCPCB_LOST)
                        tp->lost_out -= acked_pcount;
 
@@ -3541,9 +3550,9 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        bool is_dupack = false;
        u32 prior_fackets;
        int prior_packets = tp->packets_out;
-       const int prior_unsacked = tp->packets_out - tp->sacked_out;
+       u32 prior_delivered = tp->delivered;
        int acked = 0; /* Number of packets newly acked */
-       int acked_sacked; /* Number of packets newly acked or sacked */
+       u32 acked_sacked; /* Number of packets newly acked or sacked */
        int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */
 
        sack_state.first_sackt.v64 = 0;
@@ -3645,7 +3654,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        if (tp->tlp_high_seq)
                tcp_process_tlp_ack(sk, ack, flag);
 
-       acked_sacked = prior_unsacked - (tp->packets_out - tp->sacked_out);
+       acked_sacked = tp->delivered - prior_delivered;
        /* Advance cwnd if state allows */
        if (tcp_in_cwnd_reduction(sk)) {
                /* Reduce cwnd if state mandates */