aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorYuchung Cheng <ycheng@google.com>2013-07-22 19:20:47 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-22 20:53:42 -0400
commit59c9af4234b0c21a1ed05cf65bf014d0c1a67bfd (patch)
tree04c219fec569b465394cd4c9497f74e74e4f802a /net/ipv4
parent5b08e47caf1f2034a3a5b566bbccc8b0be3961ca (diff)
tcp: measure RTT from new SACK
Take RTT sample if an ACK selectively acks some sequences that have never been retransmitted. The Karn's algorithm does not apply even if that ACK (s)acks other retransmitted sequences, because it must been generated by an original but perhaps out-of-order packet. There is no ambiguity. In case when multiple blocks are newly sacked because of ACK losses the earliest block is used to measure RTT, similar to cummulative ACKs. Such RTT samples allow the sender to estimate the RTO during loss recovery and packet reordering events. It is still useful even with TCP timestamps. That's because during these events the SND.UNA may not advance preventing RTT samples from TS ECR (thus the FLAG_ACKED check before calling tcp_ack_update_rtt()). Therefore this new RTT source is complementary to existing ACK and TS RTT mechanisms. This patch does not update the RTO. It is done in the next patch. Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tcp_input.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c7398f05d12b..b85bc7c3736a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1048,6 +1048,7 @@ struct tcp_sacktag_state {
1048 int reord; 1048 int reord;
1049 int fack_count; 1049 int fack_count;
1050 int flag; 1050 int flag;
1051 s32 rtt; /* RTT measured by SACKing never-retransmitted data */
1051}; 1052};
1052 1053
1053/* Check if skb is fully within the SACK block. In presence of GSO skbs, 1054/* Check if skb is fully within the SACK block. In presence of GSO skbs,
@@ -1108,7 +1109,7 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
1108static u8 tcp_sacktag_one(struct sock *sk, 1109static u8 tcp_sacktag_one(struct sock *sk,
1109 struct tcp_sacktag_state *state, u8 sacked, 1110 struct tcp_sacktag_state *state, u8 sacked,
1110 u32 start_seq, u32 end_seq, 1111 u32 start_seq, u32 end_seq,
1111 bool dup_sack, int pcount) 1112 int dup_sack, int pcount, u32 xmit_time)
1112{ 1113{
1113 struct tcp_sock *tp = tcp_sk(sk); 1114 struct tcp_sock *tp = tcp_sk(sk);
1114 int fack_count = state->fack_count; 1115 int fack_count = state->fack_count;
@@ -1148,6 +1149,9 @@ static u8 tcp_sacktag_one(struct sock *sk,
1148 state->reord); 1149 state->reord);
1149 if (!after(end_seq, tp->high_seq)) 1150 if (!after(end_seq, tp->high_seq))
1150 state->flag |= FLAG_ORIG_SACK_ACKED; 1151 state->flag |= FLAG_ORIG_SACK_ACKED;
1152 /* Pick the earliest sequence sacked for RTT */
1153 if (state->rtt < 0)
1154 state->rtt = tcp_time_stamp - xmit_time;
1151 } 1155 }
1152 1156
1153 if (sacked & TCPCB_LOST) { 1157 if (sacked & TCPCB_LOST) {
@@ -1205,7 +1209,8 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
1205 * tcp_highest_sack_seq() when skb is highest_sack. 1209 * tcp_highest_sack_seq() when skb is highest_sack.
1206 */ 1210 */
1207 tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked, 1211 tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
1208 start_seq, end_seq, dup_sack, pcount); 1212 start_seq, end_seq, dup_sack, pcount,
1213 TCP_SKB_CB(skb)->when);
1209 1214
1210 if (skb == tp->lost_skb_hint) 1215 if (skb == tp->lost_skb_hint)
1211 tp->lost_cnt_hint += pcount; 1216 tp->lost_cnt_hint += pcount;
@@ -1479,7 +1484,8 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
1479 TCP_SKB_CB(skb)->seq, 1484 TCP_SKB_CB(skb)->seq,
1480 TCP_SKB_CB(skb)->end_seq, 1485 TCP_SKB_CB(skb)->end_seq,
1481 dup_sack, 1486 dup_sack,
1482 tcp_skb_pcount(skb)); 1487 tcp_skb_pcount(skb),
1488 TCP_SKB_CB(skb)->when);
1483 1489
1484 if (!before(TCP_SKB_CB(skb)->seq, 1490 if (!before(TCP_SKB_CB(skb)->seq,
1485 tcp_highest_sack_seq(tp))) 1491 tcp_highest_sack_seq(tp)))
@@ -1536,7 +1542,7 @@ static int tcp_sack_cache_ok(const struct tcp_sock *tp, const struct tcp_sack_bl
1536 1542
1537static int 1543static int
1538tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, 1544tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
1539 u32 prior_snd_una) 1545 u32 prior_snd_una, s32 *sack_rtt)
1540{ 1546{
1541 struct tcp_sock *tp = tcp_sk(sk); 1547 struct tcp_sock *tp = tcp_sk(sk);
1542 const unsigned char *ptr = (skb_transport_header(ack_skb) + 1548 const unsigned char *ptr = (skb_transport_header(ack_skb) +
@@ -1554,6 +1560,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
1554 1560
1555 state.flag = 0; 1561 state.flag = 0;
1556 state.reord = tp->packets_out; 1562 state.reord = tp->packets_out;
1563 state.rtt = -1;
1557 1564
1558 if (!tp->sacked_out) { 1565 if (!tp->sacked_out) {
1559 if (WARN_ON(tp->fackets_out)) 1566 if (WARN_ON(tp->fackets_out))
@@ -1737,6 +1744,7 @@ out:
1737 WARN_ON((int)tp->retrans_out < 0); 1744 WARN_ON((int)tp->retrans_out < 0);
1738 WARN_ON((int)tcp_packets_in_flight(tp) < 0); 1745 WARN_ON((int)tcp_packets_in_flight(tp) < 0);
1739#endif 1746#endif
1747 *sack_rtt = state.rtt;
1740 return state.flag; 1748 return state.flag;
1741} 1749}
1742 1750
@@ -3254,6 +3262,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3254 int prior_packets = tp->packets_out; 3262 int prior_packets = tp->packets_out;
3255 const int prior_unsacked = tp->packets_out - tp->sacked_out; 3263 const int prior_unsacked = tp->packets_out - tp->sacked_out;
3256 int acked = 0; /* Number of packets newly acked */ 3264 int acked = 0; /* Number of packets newly acked */
3265 s32 sack_rtt = -1;
3257 3266
3258 /* If the ack is older than previous acks 3267 /* If the ack is older than previous acks
3259 * then we can probably ignore it. 3268 * then we can probably ignore it.
@@ -3310,7 +3319,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3310 flag |= tcp_ack_update_window(sk, skb, ack, ack_seq); 3319 flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
3311 3320
3312 if (TCP_SKB_CB(skb)->sacked) 3321 if (TCP_SKB_CB(skb)->sacked)
3313 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); 3322 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
3323 &sack_rtt);
3314 3324
3315 if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb))) 3325 if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
3316 flag |= FLAG_ECE; 3326 flag |= FLAG_ECE;
@@ -3382,7 +3392,8 @@ old_ack:
3382 * If data was DSACKed, see if we can undo a cwnd reduction. 3392 * If data was DSACKed, see if we can undo a cwnd reduction.
3383 */ 3393 */
3384 if (TCP_SKB_CB(skb)->sacked) { 3394 if (TCP_SKB_CB(skb)->sacked) {
3385 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); 3395 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
3396 &sack_rtt);
3386 tcp_fastretrans_alert(sk, acked, prior_unsacked, 3397 tcp_fastretrans_alert(sk, acked, prior_unsacked,
3387 is_dupack, flag); 3398 is_dupack, flag);
3388 } 3399 }