Skip to content

Commit 59c9af4

Browse files
yuchungchengdavem330
authored andcommitted
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>
1 parent 5b08e47 commit 59c9af4

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

net/ipv4/tcp_input.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,7 @@ struct tcp_sacktag_state {
10481048
int reord;
10491049
int fack_count;
10501050
int flag;
1051+
s32 rtt; /* RTT measured by SACKing never-retransmitted data */
10511052
};
10521053

10531054
/* 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,
11081109
static u8 tcp_sacktag_one(struct sock *sk,
11091110
struct tcp_sacktag_state *state, u8 sacked,
11101111
u32 start_seq, u32 end_seq,
1111-
bool dup_sack, int pcount)
1112+
int dup_sack, int pcount, u32 xmit_time)
11121113
{
11131114
struct tcp_sock *tp = tcp_sk(sk);
11141115
int fack_count = state->fack_count;
@@ -1148,6 +1149,9 @@ static u8 tcp_sacktag_one(struct sock *sk,
11481149
state->reord);
11491150
if (!after(end_seq, tp->high_seq))
11501151
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;
11511155
}
11521156

11531157
if (sacked & TCPCB_LOST) {
@@ -1205,7 +1209,8 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
12051209
* tcp_highest_sack_seq() when skb is highest_sack.
12061210
*/
12071211
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);
12091214

12101215
if (skb == tp->lost_skb_hint)
12111216
tp->lost_cnt_hint += pcount;
@@ -1479,7 +1484,8 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
14791484
TCP_SKB_CB(skb)->seq,
14801485
TCP_SKB_CB(skb)->end_seq,
14811486
dup_sack,
1482-
tcp_skb_pcount(skb));
1487+
tcp_skb_pcount(skb),
1488+
TCP_SKB_CB(skb)->when);
14831489

14841490
if (!before(TCP_SKB_CB(skb)->seq,
14851491
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
15361542

15371543
static int
15381544
tcp_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)
15401546
{
15411547
struct tcp_sock *tp = tcp_sk(sk);
15421548
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,
15541560

15551561
state.flag = 0;
15561562
state.reord = tp->packets_out;
1563+
state.rtt = -1;
15571564

15581565
if (!tp->sacked_out) {
15591566
if (WARN_ON(tp->fackets_out))
@@ -1737,6 +1744,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
17371744
WARN_ON((int)tp->retrans_out < 0);
17381745
WARN_ON((int)tcp_packets_in_flight(tp) < 0);
17391746
#endif
1747+
*sack_rtt = state.rtt;
17401748
return state.flag;
17411749
}
17421750

@@ -3254,6 +3262,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
32543262
int prior_packets = tp->packets_out;
32553263
const int prior_unsacked = tp->packets_out - tp->sacked_out;
32563264
int acked = 0; /* Number of packets newly acked */
3265+
s32 sack_rtt = -1;
32573266

32583267
/* If the ack is older than previous acks
32593268
* then we can probably ignore it.
@@ -3310,7 +3319,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
33103319
flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
33113320

33123321
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);
33143324

33153325
if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
33163326
flag |= FLAG_ECE;
@@ -3382,7 +3392,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
33823392
* If data was DSACKed, see if we can undo a cwnd reduction.
33833393
*/
33843394
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);
33863397
tcp_fastretrans_alert(sk, acked, prior_unsacked,
33873398
is_dupack, flag);
33883399
}

0 commit comments

Comments
 (0)