simplify microsecond rtt sampling
Subsystems (3)
About commit 2d2abbab63f6726a147ae61ada39bf2c9ee0db9a:
It looks like this patch bypassed the enforcement of Karn's algorithm in tcp_ack_no_tstamp() for the purposes of usec RTT sampling used by congestion control modules. This will give them bad RTT data when there are retransmits. I haven't actually observed this, but it seems like it would be the case. ;) Please correct me if I'm wrong.
Here's a patch that should be a fix.
net/ipv4/tcp_input.c +2 -4
@@ -2306,8 +2306,6 @@ static int tcp_clean_rtx_queue(struct so seq_rtt =-1 ; }else if (seq_rtt <0 ) { seq_rtt = now - scb->when; -if (rtt_sample) - (*rtt_sample)(sk,tcp_usrtt (skb)); }if (sacked &TCPCB_SACKED_ACKED ) tp->sacked_out -=tcp_skb_pcount (skb);
@@ -2320,8 +2318,6 @@ static int tcp_clean_rtx_queue(struct so } }else if (seq_rtt <0 ) { seq_rtt = now - scb->when; -if (rtt_sample) - (*rtt_sample)(sk,tcp_usrtt (skb)); }tcp_dec_pcount_approx (&tp->fackets_out, skb);tcp_packets_out_dec (tp, skb);
@@ -2333,6 +2329,8 @@ static int tcp_clean_rtx_queue(struct soif (acked&FLAG_ACKED ) {tcp_ack_update_rtt (sk, acked, seq_rtt);tcp_ack_packets_out (sk, tp); +if (rtt_sample && !(acked &FLAG_RETRANS_DATA_ACKED )) + (*rtt_sample)(sk,tcp_usrtt (skb));if (icsk->icsk_ca_ops->pkts_acked) icsk->icsk_ca_ops->pkts_acked (sk, pkts_acked);
Okay, this patch is junk (never trust compile-tested code). Will send something better soon.
-John
Quoted 44 lines · John Heffner
About commit
2d2abbab63f6726a147ae61ada39bf2c9ee0db9a:It looks like this patch bypassed the enforcement of Karn's algorithm in
tcp_ack_no_tstamp()for the purposes of usec RTT sampling used by congestion control modules. This will give them bad RTT data when there are retransmits. I haven't actually observed this, but it seems like it would be the case. ;) Please correct me if I'm wrong.Here's a patch that should be a fix.
Signed-off-by John Heffner <[email protected]>------------------------------------------------------------------------
net/ipv4/tcp_input.c +2
-4@@ -2306,8 +2306,6 @@ static int tcp_clean_rtx_queue(struct so seq_rtt =-1 ; }else if (seq_rtt <0 ) { seq_rtt = now - scb->when; -if (rtt_sample) - (*rtt_sample)(sk,tcp_usrtt (skb)); }if (sacked &TCPCB_SACKED_ACKED ) tp->sacked_out -=tcp_skb_pcount (skb);@@ -2320,8 +2318,6 @@ static int tcp_clean_rtx_queue(struct so } }else if (seq_rtt <0 ) { seq_rtt = now - scb->when; -if (rtt_sample) - (*rtt_sample)(sk,tcp_usrtt (skb)); }tcp_dec_pcount_approx (&tp->fackets_out, skb);tcp_packets_out_dec (tp, skb);@@ -2333,6 +2329,8 @@ static int tcp_clean_rtx_queue(struct soif (acked&FLAG_ACKED ) {tcp_ack_update_rtt (sk, acked, seq_rtt);tcp_ack_packets_out (sk, tp); +if (rtt_sample && !(acked &FLAG_RETRANS_DATA_ACKED )) + (*rtt_sample)(sk,tcp_usrtt (skb));if (icsk->icsk_ca_ops->pkts_acked) icsk->icsk_ca_ops->pkts_acked (sk, pkts_acked);
Here is a corrected patch.
-static u32 tcp_usrtt(const struct sk_buff *skb)
+static u32 tcp_usrtt(struct timeval *tv)
{
- struct timeval tv, now;
+ struct timeval now;
do_gettimeofday(&now);
- skb_get_timestamp(skb, &tv);
- return (now.tv_sec - tv.tv_sec) * 1000000 + (now.tv_usec - tv.tv_usec);
+ return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - tv->tv_usec);
}
/* Remove acknowledged frames from the retransmission queue. */
@@ -2249,6 +2248,7 @@ static int tcp_clean_rtx_queue(struct so
u32 pkts_acked = 0;
void (*rtt_sample)(struct sock *sk, u32 usrtt)
= icsk->icsk_ca_ops->rtt_sample;
+ struct timeval tv;
while ((skb = skb_peek(&sk->sk_write_queue)) &&
skb != sk->sk_send_head) {
@@ -2297,8 +2297,7 @@ static int tcp_clean_rtx_queue(struct so
seq_rtt = -1;
} else if (seq_rtt < 0) {
seq_rtt = now - scb->when;
- if (rtt_sample)
- (*rtt_sample)(sk, tcp_usrtt(skb));
+ skb_get_timestamp(skb, &tv);
}
if (sacked & TCPCB_SACKED_ACKED)
tp->sacked_out -= tcp_skb_pcount(skb);
@@ -2311,8 +2310,7 @@ static int tcp_clean_rtx_queue(struct so
}
} else if (seq_rtt < 0) {
seq_rtt = now - scb->when;
- if (rtt_sample)
- (*rtt_sample)(sk, tcp_usrtt(skb));
+ skb_get_timestamp(skb, &tv);
}
tcp_dec_pcount_approx(&tp->fackets_out, skb); tcp_packets_out_dec(tp, skb);
@@ -2324,6 +2322,8 @@ static int tcp_clean_rtx_queue(struct so
if (acked&FLAG_ACKED) {
tcp_ack_update_rtt(sk, acked, seq_rtt); tcp_ack_packets_out(sk, tp);
+ if (rtt_sample && !(acked & FLAG_RETRANS_DATA_ACKED))
+ (*rtt_sample)(sk, tcp_usrtt(&tv));
if (icsk->icsk_ca_ops->pkts_acked)
icsk->icsk_ca_ops->pkts_acked(sk, pkts_acked);
Sigh. Here's one that's not corrupted. And for the record:
This changes the microsecond RTT sampling so that samples are taken in the same way that RTT samples are taken for the RTO calculator: on the last segment acknowledged, and only when the segment hasn't been retransmitted.
net/ipv4/tcp_input.c +8 -8
@@ -2228,13 +2228,12 @@ static int tcp_tso_acked(struct sock *skreturn acked; } -static u32 tcp_usrtt (const struct sk_buff *skb) +static u32 tcp_usrtt (struct timeval *tv) { -struct timeval tv, now; +struct timeval now;do_gettimeofday (&now); -skb_get_timestamp (skb, &tv); -return (now.tv_sec - tv.tv_sec) *1000000 + (now.tv_usec - tv.tv_usec); +return (now.tv_sec - tv->tv_sec) *1000000 + (now.tv_usec - tv->tv_usec); }/* Remove acknowledged frames from the retransmission queue. */
@@ -2249,6 +2248,7 @@ static int tcp_clean_rtx_queue(struct sou32 pkts_acked =0 ;void (*rtt_sample)(struct sock *sk,u32 usrtt) = icsk->icsk_ca_ops->rtt_sample; +struct timeval tv;while ((skb =skb_peek (&sk->sk_write_queue)) && skb != sk->sk_send_head) {
@@ -2297,8 +2297,7 @@ static int tcp_clean_rtx_queue(struct so seq_rtt =-1 ; }else if (seq_rtt <0 ) { seq_rtt = now - scb->when; -if (rtt_sample) - (*rtt_sample)(sk,tcp_usrtt (skb)); +skb_get_timestamp (skb, &tv); }if (sacked &TCPCB_SACKED_ACKED ) tp->sacked_out -=tcp_skb_pcount (skb);
@@ -2311,8 +2310,7 @@ static int tcp_clean_rtx_queue(struct so } }else if (seq_rtt <0 ) { seq_rtt = now - scb->when; -if (rtt_sample) - (*rtt_sample)(sk,tcp_usrtt (skb)); +skb_get_timestamp (skb, &tv); }tcp_dec_pcount_approx (&tp->fackets_out, skb);tcp_packets_out_dec (tp, skb);
@@ -2324,6 +2322,8 @@ static int tcp_clean_rtx_queue(struct soif (acked&FLAG_ACKED ) {tcp_ack_update_rtt (sk, acked, seq_rtt);tcp_ack_packets_out (sk, tp); +if (rtt_sample && !(acked &FLAG_RETRANS_DATA_ACKED )) + (*rtt_sample)(sk,tcp_usrtt (&tv));if (icsk->icsk_ca_ops->pkts_acked) icsk->icsk_ca_ops->pkts_acked (sk, pkts_acked);
Quoted 10 lines · On Thu, 28 Sep 2006 13:47:28 +0100 John Heffner <[email protected]> wrote:
Sigh. Here's one that's not corrupted. And for the record:
This changes the microsecond RTT sampling so that samples are taken in the same way that RTT samples are taken for the RTO calculator: on the last segment acknowledged, and only when the segment hasn't been retransmitted.
Signed-off-by John Heffner <[email protected]>
Looks ok. I wish skbuff timestamp was converted to ktime.
David Miller
maintainerFrom: Stephen Hemminger <[email protected]>
Date: Thu, 28 Sep 2006 09:36:50 -0700
Quoted 12 lines
Quoted 9 lines · On Thu, 28 Sep 2006 13:47:28 +0100 John Heffner <[email protected]> wrote:
Sigh. Here's one that's not corrupted. And for the record:
This changes the microsecond RTT sampling so that samples are taken in the same way that RTT samples are taken for the RTO calculator: on the last segment acknowledged, and only when the segment hasn't been retransmitted.
Quoted 3 lines
Quoted 1 line
Signed-off-by John Heffner <[email protected]>Looks ok. I wish skbuff timestamp was converted to ktime.
It looks good to me too, applied.
Since this is really a bug fix, I'm goint to push this into -stable as well.
Thanks a lot.