Commit 56f8c5d7 authored by Yuchung Cheng's avatar Yuchung Cheng Committed by David S. Miller

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: default avatarYuchung Cheng <ycheng@google.com>
Signed-off-by: default avatarNeal Cardwell <ncardwell@google.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarSoheil Hassas Yeganeh <soheil@google.com>
Reviewed-by: default avatarPriyaranjan Jha <priyarjha@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b8fef65a
...@@ -1929,11 +1929,11 @@ static bool tcp_is_rack(const struct sock *sk) ...@@ -1929,11 +1929,11 @@ static bool tcp_is_rack(const struct sock *sk)
static void tcp_timeout_mark_lost(struct sock *sk) static void tcp_timeout_mark_lost(struct sock *sk)
{ {
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb, *head;
bool is_reneg; /* is receiver reneging on SACKs? */ bool is_reneg; /* is receiver reneging on SACKs? */
skb = tcp_rtx_queue_head(sk); head = tcp_rtx_queue_head(sk);
is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED); is_reneg = head && (TCP_SKB_CB(head)->sacked & TCPCB_SACKED_ACKED);
if (is_reneg) { if (is_reneg) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSACKRENEGING);
tp->sacked_out = 0; tp->sacked_out = 0;
...@@ -1943,9 +1943,13 @@ static void tcp_timeout_mark_lost(struct sock *sk) ...@@ -1943,9 +1943,13 @@ static void tcp_timeout_mark_lost(struct sock *sk)
tcp_reset_reno_sack(tp); tcp_reset_reno_sack(tp);
} }
skb = head;
skb_rbtree_walk_from(skb) { skb_rbtree_walk_from(skb) {
if (is_reneg) if (is_reneg)
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
else if (tcp_is_rack(sk) && skb != head &&
tcp_rack_skb_timeout(tp, skb, 0) > 0)
continue; /* Don't mark recently sent ones lost yet */
tcp_mark_skb_lost(sk, skb); tcp_mark_skb_lost(sk, skb);
} }
tcp_verify_left_out(tp); tcp_verify_left_out(tp);
...@@ -1972,7 +1976,7 @@ void tcp_enter_loss(struct sock *sk) ...@@ -1972,7 +1976,7 @@ void tcp_enter_loss(struct sock *sk)
tcp_ca_event(sk, CA_EVENT_LOSS); tcp_ca_event(sk, CA_EVENT_LOSS);
tcp_init_undo(tp); tcp_init_undo(tp);
} }
tp->snd_cwnd = 1; tp->snd_cwnd = tcp_packets_in_flight(tp) + 1;
tp->snd_cwnd_cnt = 0; tp->snd_cwnd_cnt = 0;
tp->snd_cwnd_stamp = tcp_jiffies32; tp->snd_cwnd_stamp = tcp_jiffies32;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment