Skip to content

Commit 56f8c5d

Browse files
yuchungchengdavem330
authored andcommitted
tcp: don't mark recently sent packets lost on RTO
An RTO event indicates the head has not been acked for a long time after its last (re)transmission. But the other packets are not necessarily lost if they have been only sent recently (for example due to application limit). This patch would prohibit marking packets sent within an RTT to be lost on RTO event, using similar logic in TCP RACK detection. Normally the head (SND.UNA) would be marked lost since RTO should fire strictly after the head was sent. An exception is when the most recent RACK RTT measurement is larger than the (previous) RTO. To address this exception the head is always marked lost. Congestion control interaction: since we may not mark every packet lost, the congestion window may be more than 1 (inflight plus 1). But only one packet will be retransmitted after RTO, since tcp_retransmit_timer() calls tcp_retransmit_skb(...,segs=1). The connection still performs slow start from one packet (with Cubic congestion control). This commit was tested in an A/B test with Google web servers, and showed a reduction of 2% in (spurious) retransmits post timeout (SlowStartRetrans), and correspondingly reduced DSACKs (DSACKIgnoredOld) by 7%. Signed-off-by: Yuchung Cheng <[email protected]> Signed-off-by: Neal Cardwell <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Reviewed-by: Soheil Hassas Yeganeh <[email protected]> Reviewed-by: Priyaranjan Jha <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b8fef65 commit 56f8c5d

File tree

1 file changed

+8
-4
lines changed

1 file changed

+8
-4
lines changed

net/ipv4/tcp_input.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,11 +1929,11 @@ static bool tcp_is_rack(const struct sock *sk)
19291929
static void tcp_timeout_mark_lost(struct sock *sk)
19301930
{
19311931
struct tcp_sock *tp = tcp_sk(sk);
1932-
struct sk_buff *skb;
1932+
struct sk_buff *skb, *head;
19331933
bool is_reneg; /* is receiver reneging on SACKs? */
19341934

1935-
skb = tcp_rtx_queue_head(sk);
1936-
is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED);
1935+
head = tcp_rtx_queue_head(sk);
1936+
is_reneg = head && (TCP_SKB_CB(head)->sacked & TCPCB_SACKED_ACKED);
19371937
if (is_reneg) {
19381938
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSACKRENEGING);
19391939
tp->sacked_out = 0;
@@ -1943,9 +1943,13 @@ static void tcp_timeout_mark_lost(struct sock *sk)
19431943
tcp_reset_reno_sack(tp);
19441944
}
19451945

1946+
skb = head;
19461947
skb_rbtree_walk_from(skb) {
19471948
if (is_reneg)
19481949
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
1950+
else if (tcp_is_rack(sk) && skb != head &&
1951+
tcp_rack_skb_timeout(tp, skb, 0) > 0)
1952+
continue; /* Don't mark recently sent ones lost yet */
19491953
tcp_mark_skb_lost(sk, skb);
19501954
}
19511955
tcp_verify_left_out(tp);
@@ -1972,7 +1976,7 @@ void tcp_enter_loss(struct sock *sk)
19721976
tcp_ca_event(sk, CA_EVENT_LOSS);
19731977
tcp_init_undo(tp);
19741978
}
1975-
tp->snd_cwnd = 1;
1979+
tp->snd_cwnd = tcp_packets_in_flight(tp) + 1;
19761980
tp->snd_cwnd_cnt = 0;
19771981
tp->snd_cwnd_stamp = tcp_jiffies32;
19781982

0 commit comments

Comments
 (0)