Skip to content

Commit 3f80e08

Browse files
edumazetdavem330
authored andcommitted
tcp: add tcp_reset_xmit_timer() helper
With EDT model, SRTT no longer is inflated by pacing delays. This means that RTO and some other xmit timers might be setup incorrectly. This is particularly visible with either : - Very small enforced pacing rates (SO_MAX_PACING_RATE) - Reduced rto (from the default 200 ms) This can lead to TCP flows aborts in the worst case, or spurious retransmits in other cases. For example, this session gets far more throughput than the requested 80kbit : $ netperf -H 127.0.0.2 -l 100 -- -q 10000 MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 127.0.0.2 () port 0 AF_INET Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 540000 262144 262144 104.00 2.66 With the fix : $ netperf -H 127.0.0.2 -l 100 -- -q 10000 MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 127.0.0.2 () port 0 AF_INET Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 540000 262144 262144 104.00 0.12 EDT allows for better control of rtx timers, since TCP has a better idea of the earliest departure time of each skb in the rtx queue. We only have to eventually add to the timer the difference of the EDT time with current time. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 68203a6 commit 3f80e08

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

include/net/tcp.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,8 +1245,31 @@ static inline bool tcp_needs_internal_pacing(const struct sock *sk)
12451245
return smp_load_acquire(&sk->sk_pacing_status) == SK_PACING_NEEDED;
12461246
}
12471247

1248+
/* Return in jiffies the delay before one skb is sent.
1249+
* If @skb is NULL, we look at EDT for next packet being sent on the socket.
1250+
*/
1251+
static inline unsigned long tcp_pacing_delay(const struct sock *sk,
1252+
const struct sk_buff *skb)
1253+
{
1254+
s64 pacing_delay = skb ? skb->tstamp : tcp_sk(sk)->tcp_wstamp_ns;
1255+
1256+
pacing_delay -= tcp_sk(sk)->tcp_clock_cache;
1257+
1258+
return pacing_delay > 0 ? nsecs_to_jiffies(pacing_delay) : 0;
1259+
}
1260+
1261+
static inline void tcp_reset_xmit_timer(struct sock *sk,
1262+
const int what,
1263+
unsigned long when,
1264+
const unsigned long max_when,
1265+
const struct sk_buff *skb)
1266+
{
1267+
inet_csk_reset_xmit_timer(sk, what, when + tcp_pacing_delay(sk, skb),
1268+
max_when);
1269+
}
1270+
12481271
/* Something is really bad, we could not queue an additional packet,
1249-
* because qdisc is full or receiver sent a 0 window.
1272+
* because qdisc is full or receiver sent a 0 window, or we are paced.
12501273
* We do not want to add fuel to the fire, or abort too early,
12511274
* so make sure the timer we arm now is at least 200ms in the future,
12521275
* regardless of current icsk_rto value (as it could be ~2ms)
@@ -1268,8 +1291,9 @@ static inline unsigned long tcp_probe0_when(const struct sock *sk,
12681291
static inline void tcp_check_probe_timer(struct sock *sk)
12691292
{
12701293
if (!tcp_sk(sk)->packets_out && !inet_csk(sk)->icsk_pending)
1271-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
1272-
tcp_probe0_base(sk), TCP_RTO_MAX);
1294+
tcp_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
1295+
tcp_probe0_base(sk), TCP_RTO_MAX,
1296+
NULL);
12731297
}
12741298

12751299
static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq)

net/ipv4/tcp_input.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2979,8 +2979,8 @@ void tcp_rearm_rto(struct sock *sk)
29792979
*/
29802980
rto = usecs_to_jiffies(max_t(int, delta_us, 1));
29812981
}
2982-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,
2983-
TCP_RTO_MAX);
2982+
tcp_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,
2983+
TCP_RTO_MAX, tcp_rtx_queue_head(sk));
29842984
}
29852985
}
29862986

@@ -3255,8 +3255,8 @@ static void tcp_ack_probe(struct sock *sk)
32553255
} else {
32563256
unsigned long when = tcp_probe0_when(sk, TCP_RTO_MAX);
32573257

3258-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3259-
when, TCP_RTO_MAX);
3258+
tcp_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3259+
when, TCP_RTO_MAX, NULL);
32603260
}
32613261
}
32623262

net/ipv4/tcp_output.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2455,8 +2455,8 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto)
24552455
if (rto_delta_us > 0)
24562456
timeout = min_t(u32, timeout, usecs_to_jiffies(rto_delta_us));
24572457

2458-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_LOSS_PROBE, timeout,
2459-
TCP_RTO_MAX);
2458+
tcp_reset_xmit_timer(sk, ICSK_TIME_LOSS_PROBE, timeout,
2459+
TCP_RTO_MAX, NULL);
24602460
return true;
24612461
}
24622462

@@ -3020,9 +3020,10 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
30203020

30213021
if (skb == rtx_head &&
30223022
icsk->icsk_pending != ICSK_TIME_REO_TIMEOUT)
3023-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
3024-
inet_csk(sk)->icsk_rto,
3025-
TCP_RTO_MAX);
3023+
tcp_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
3024+
inet_csk(sk)->icsk_rto,
3025+
TCP_RTO_MAX,
3026+
skb);
30263027
}
30273028
}
30283029

@@ -3752,9 +3753,10 @@ void tcp_send_probe0(struct sock *sk)
37523753
icsk->icsk_probes_out = 1;
37533754
probe_max = TCP_RESOURCE_PROBE_INTERVAL;
37543755
}
3755-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3756-
tcp_probe0_when(sk, probe_max),
3757-
TCP_RTO_MAX);
3756+
tcp_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
3757+
tcp_probe0_when(sk, probe_max),
3758+
TCP_RTO_MAX,
3759+
NULL);
37583760
}
37593761

37603762
int tcp_rtx_synack(const struct sock *sk, struct request_sock *req)

0 commit comments

Comments
 (0)