aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorYuchung Cheng <ycheng@google.com>2016-02-02 13:33:06 -0500
committerDavid S. Miller <davem@davemloft.net>2016-02-07 14:09:51 -0500
commitddf1af6fa00e772fdb67a7d22cb83fac2b8968a8 (patch)
tree0ef97572fcecf0c7e2d6a6c3b06102213a312b87 /net/ipv4/tcp_input.c
parent31ba0c10723e9eba378f96de1d1a9426129949e1 (diff)
tcp: new delivery accounting
This patch changes the accounting of how many packets are newly acked or sacked when the sender receives an ACK. The current approach basically computes newly_acked_sacked = (prior_packets - prior_sacked) - (tp->packets_out - tp->sacked_out) where prior_packets and prior_sacked out are snapshot at the beginning of the ACK processing. The new approach tracks the delivery information via a new TCP state variable "delivered" which monotically increases as new packets are delivered in order or out-of-order. The reason for this change is that the current approach is brittle that produces negative or inaccurate estimate. 1) For non-SACK connections, an ACK that advances the SND.UNA could reset the DUPACK counters (tp->sacked_out) in tcp_process_loss() or tcp_fastretrans_alert(). This inflates the inflight suddenly and causes under-estimate or even negative estimate. Here is a real example: before after (processing ACK) packets_out 75 73 sacked_out 23 0 ca state Loss Open The old approach computes (75-23) - (73 - 0) = -21 delivered while the new approach computes 1 delivered since it considers the 2nd-24th packets are delivered OOO. 2) MSS change would re-count packets_out and sacked_out so the estimate is in-accurate and can even become negative. E.g., the inflight is doubled when MSS is halved. 3) Spurious retransmission signaled by DSACK is not accounted The new approach is simpler and more robust. For SACK connections, tp->delivered increments as packets are being acked or sacked in SACK and ACK processing. For non-sack connections, it's done in tcp_remove_reno_sacks() and tcp_add_reno_sack(). When an ACK advances the SND.UNA, tp->delivered is incremented by the number of packets ACKed (less the current number of DUPACKs received plus one packet hole). Upon receiving a DUPACK, tp->delivered is incremented assuming one out-of-order packet is delivered. Upon receiving a DSACK, tp->delivered is incremtened assuming one retransmission is delivered in tcp_sacktag_write_queue(). 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.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index dc810df53e90..2d690b3f0a7b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1214,6 +1214,7 @@ static u8 tcp_sacktag_one(struct sock *sk,
1214 sacked |= TCPCB_SACKED_ACKED; 1214 sacked |= TCPCB_SACKED_ACKED;
1215 state->flag |= FLAG_DATA_SACKED; 1215 state->flag |= FLAG_DATA_SACKED;
1216 tp->sacked_out += pcount; 1216 tp->sacked_out += pcount;
1217 tp->delivered += pcount; /* Out-of-order packets delivered */
1217 1218
1218 fack_count += pcount; 1219 fack_count += pcount;
1219 1220
@@ -1825,8 +1826,12 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)
1825static void tcp_add_reno_sack(struct sock *sk) 1826static void tcp_add_reno_sack(struct sock *sk)
1826{ 1827{
1827 struct tcp_sock *tp = tcp_sk(sk); 1828 struct tcp_sock *tp = tcp_sk(sk);
1829 u32 prior_sacked = tp->sacked_out;
1830
1828 tp->sacked_out++; 1831 tp->sacked_out++;
1829 tcp_check_reno_reordering(sk, 0); 1832 tcp_check_reno_reordering(sk, 0);
1833 if (tp->sacked_out > prior_sacked)
1834 tp->delivered++; /* Some out-of-order packet is delivered */
1830 tcp_verify_left_out(tp); 1835 tcp_verify_left_out(tp);
1831} 1836}
1832 1837
@@ -1838,6 +1843,7 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked)
1838 1843
1839 if (acked > 0) { 1844 if (acked > 0) {
1840 /* One ACK acked hole. The rest eat duplicate ACKs. */ 1845 /* One ACK acked hole. The rest eat duplicate ACKs. */
1846 tp->delivered += max_t(int, acked - tp->sacked_out, 1);
1841 if (acked - 1 >= tp->sacked_out) 1847 if (acked - 1 >= tp->sacked_out)
1842 tp->sacked_out = 0; 1848 tp->sacked_out = 0;
1843 else 1849 else
@@ -3156,10 +3162,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
3156 flag |= FLAG_ORIG_SACK_ACKED; 3162 flag |= FLAG_ORIG_SACK_ACKED;
3157 } 3163 }
3158 3164
3159 if (sacked & TCPCB_SACKED_ACKED) 3165 if (sacked & TCPCB_SACKED_ACKED) {
3160 tp->sacked_out -= acked_pcount; 3166 tp->sacked_out -= acked_pcount;
3161 else if (tcp_is_sack(tp) && !tcp_skb_spurious_retrans(tp, skb)) 3167 } else if (tcp_is_sack(tp)) {
3162 tcp_rack_advance(tp, &skb->skb_mstamp, sacked); 3168 tp->delivered += acked_pcount;
3169 if (!tcp_skb_spurious_retrans(tp, skb))
3170 tcp_rack_advance(tp, &skb->skb_mstamp, sacked);
3171 }
3163 if (sacked & TCPCB_LOST) 3172 if (sacked & TCPCB_LOST)
3164 tp->lost_out -= acked_pcount; 3173 tp->lost_out -= acked_pcount;
3165 3174
@@ -3541,9 +3550,9 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3541 bool is_dupack = false; 3550 bool is_dupack = false;
3542 u32 prior_fackets; 3551 u32 prior_fackets;
3543 int prior_packets = tp->packets_out; 3552 int prior_packets = tp->packets_out;
3544 const int prior_unsacked = tp->packets_out - tp->sacked_out; 3553 u32 prior_delivered = tp->delivered;
3545 int acked = 0; /* Number of packets newly acked */ 3554 int acked = 0; /* Number of packets newly acked */
3546 int acked_sacked; /* Number of packets newly acked or sacked */ 3555 u32 acked_sacked; /* Number of packets newly acked or sacked */
3547 int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */ 3556 int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */
3548 3557
3549 sack_state.first_sackt.v64 = 0; 3558 sack_state.first_sackt.v64 = 0;
@@ -3645,7 +3654,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3645 if (tp->tlp_high_seq) 3654 if (tp->tlp_high_seq)
3646 tcp_process_tlp_ack(sk, ack, flag); 3655 tcp_process_tlp_ack(sk, ack, flag);
3647 3656
3648 acked_sacked = prior_unsacked - (tp->packets_out - tp->sacked_out); 3657 acked_sacked = tp->delivered - prior_delivered;
3649 /* Advance cwnd if state allows */ 3658 /* Advance cwnd if state allows */
3650 if (tcp_in_cwnd_reduction(sk)) { 3659 if (tcp_in_cwnd_reduction(sk)) {
3651 /* Reduce cwnd if state mandates */ 3660 /* Reduce cwnd if state mandates */