Skip to content

Commit 76be93f

Browse files
yuchungchengdavem330
authored andcommitted
tcp: allow at most one TLP probe per flight
Previously TLP may send multiple probes of new data in one flight. This happens when the sender is cwnd limited. After the initial TLP containing new data is sent, the sender receives another ACK that acks partial inflight. It may re-arm another TLP timer to send more, if no further ACK returns before the next TLP timeout (PTO) expires. The sender may send in theory a large amount of TLP until send queue is depleted. This only happens if the sender sees such irregular uncommon ACK pattern. But it is generally undesirable behavior during congestion especially. The original TLP design restrict only one TLP probe per inflight as published in "Reducing Web Latency: the Virtue of Gentle Aggression", SIGCOMM 2013. This patch changes TLP to send at most one probe per inflight. Note that if the sender is app-limited, TLP retransmits old data and did not have this issue. Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 17ad73e commit 76be93f

File tree

3 files changed

+18
-12
lines changed

3 files changed

+18
-12
lines changed

include/linux/tcp.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,9 @@ struct tcp_sock {
220220
} rack;
221221
u16 advmss; /* Advertised MSS */
222222
u8 compressed_ack;
223-
u8 dup_ack_counter;
223+
u8 dup_ack_counter:2,
224+
tlp_retrans:1, /* TLP is a retransmission */
225+
unused:5;
224226
u32 chrono_start; /* Start time in jiffies of a TCP chrono */
225227
u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */
226228
u8 chrono_type:2, /* current chronograph type */
@@ -243,7 +245,7 @@ struct tcp_sock {
243245
save_syn:1, /* Save headers of SYN packet */
244246
is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */
245247
syn_smc:1; /* SYN includes SMC */
246-
u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */
248+
u32 tlp_high_seq; /* snd_nxt at the time of TLP */
247249

248250
u32 tcp_tx_delay; /* delay (in usec) added to TX packets */
249251
u64 tcp_wstamp_ns; /* departure time for next sent data packet */

net/ipv4/tcp_input.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3488,10 +3488,8 @@ static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
34883488
}
34893489
}
34903490

3491-
/* This routine deals with acks during a TLP episode.
3492-
* We mark the end of a TLP episode on receiving TLP dupack or when
3493-
* ack is after tlp_high_seq.
3494-
* Ref: loss detection algorithm in draft-dukkipati-tcpm-tcp-loss-probe.
3491+
/* This routine deals with acks during a TLP episode and ends an episode by
3492+
* resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack
34953493
*/
34963494
static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
34973495
{
@@ -3500,7 +3498,10 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
35003498
if (before(ack, tp->tlp_high_seq))
35013499
return;
35023500

3503-
if (flag & FLAG_DSACKING_ACK) {
3501+
if (!tp->tlp_retrans) {
3502+
/* TLP of new data has been acknowledged */
3503+
tp->tlp_high_seq = 0;
3504+
} else if (flag & FLAG_DSACKING_ACK) {
35043505
/* This DSACK means original and TLP probe arrived; no loss */
35053506
tp->tlp_high_seq = 0;
35063507
} else if (after(ack, tp->tlp_high_seq)) {

net/ipv4/tcp_output.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,6 +2624,11 @@ void tcp_send_loss_probe(struct sock *sk)
26242624
int pcount;
26252625
int mss = tcp_current_mss(sk);
26262626

2627+
/* At most one outstanding TLP */
2628+
if (tp->tlp_high_seq)
2629+
goto rearm_timer;
2630+
2631+
tp->tlp_retrans = 0;
26272632
skb = tcp_send_head(sk);
26282633
if (skb && tcp_snd_wnd_test(tp, skb, mss)) {
26292634
pcount = tp->packets_out;
@@ -2641,10 +2646,6 @@ void tcp_send_loss_probe(struct sock *sk)
26412646
return;
26422647
}
26432648

2644-
/* At most one outstanding TLP retransmission. */
2645-
if (tp->tlp_high_seq)
2646-
goto rearm_timer;
2647-
26482649
if (skb_still_in_host_queue(sk, skb))
26492650
goto rearm_timer;
26502651

@@ -2666,10 +2667,12 @@ void tcp_send_loss_probe(struct sock *sk)
26662667
if (__tcp_retransmit_skb(sk, skb, 1))
26672668
goto rearm_timer;
26682669

2670+
tp->tlp_retrans = 1;
2671+
2672+
probe_sent:
26692673
/* Record snd_nxt for loss detection. */
26702674
tp->tlp_high_seq = tp->snd_nxt;
26712675

2672-
probe_sent:
26732676
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPLOSSPROBES);
26742677
/* Reset s.t. tcp_rearm_rto will restart timer from now */
26752678
inet_csk(sk)->icsk_pending = 0;

0 commit comments

Comments
 (0)