diff options
author | Yuchung Cheng <ycheng@google.com> | 2014-02-28 19:42:26 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-03 15:33:02 -0500 |
commit | c84a57113f59486e6688be1cd443b96e3118efa0 (patch) | |
tree | 5177aed13e8ff6c94ceed13239d824a92e672f71 | |
parent | de39d7a4f3693c4247135cbce42716bf2a113577 (diff) |
tcp: fix bogus RTT on special retransmission
RTT may be bogus with tall loss probe (TLP) when a packet
is retransmitted and latter (s)acked without TCPCB_SACKED_RETRANS flag.
For example, TLP calls __tcp_retransmit_skb() instead of
tcp_retransmit_skb(). The skb timestamps are updated but the sacked
flag is not marked with TCPCB_SACKED_RETRANS. As a result we'll
get bogus RTT in tcp_clean_rtx_queue() or in tcp_sacktag_one() on
spurious retransmission.
The fix is to apply the sticky flag TCP_EVER_RETRANS to enforce Karn's
check on RTT sampling. However this will disable F-RTO if timeout occurs
after TLP, by resetting undo_marker in tcp_enter_loss(). We relax this
check to only if any pending retransmists are still in-flight.
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Acked-by: Nandita Dukkipati <nanditad@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/tcp_input.c | 3 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 11 |
2 files changed, 10 insertions, 4 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 227cba79fa6b..eeaac399420d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1945,8 +1945,9 @@ void tcp_enter_loss(struct sock *sk, int how) | |||
1945 | if (skb == tcp_send_head(sk)) | 1945 | if (skb == tcp_send_head(sk)) |
1946 | break; | 1946 | break; |
1947 | 1947 | ||
1948 | if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS) | 1948 | if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) |
1949 | tp->undo_marker = 0; | 1949 | tp->undo_marker = 0; |
1950 | |||
1950 | TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; | 1951 | TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; |
1951 | if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) { | 1952 | if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) { |
1952 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; | 1953 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index d718482fd11c..f0eb4e337ec8 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -2337,6 +2337,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | |||
2337 | struct tcp_sock *tp = tcp_sk(sk); | 2337 | struct tcp_sock *tp = tcp_sk(sk); |
2338 | struct inet_connection_sock *icsk = inet_csk(sk); | 2338 | struct inet_connection_sock *icsk = inet_csk(sk); |
2339 | unsigned int cur_mss; | 2339 | unsigned int cur_mss; |
2340 | int err; | ||
2340 | 2341 | ||
2341 | /* Inconslusive MTU probe */ | 2342 | /* Inconslusive MTU probe */ |
2342 | if (icsk->icsk_mtup.probe_size) { | 2343 | if (icsk->icsk_mtup.probe_size) { |
@@ -2400,11 +2401,15 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | |||
2400 | skb_headroom(skb) >= 0xFFFF)) { | 2401 | skb_headroom(skb) >= 0xFFFF)) { |
2401 | struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER, | 2402 | struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER, |
2402 | GFP_ATOMIC); | 2403 | GFP_ATOMIC); |
2403 | return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : | 2404 | err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : |
2404 | -ENOBUFS; | 2405 | -ENOBUFS; |
2405 | } else { | 2406 | } else { |
2406 | return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); | 2407 | err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); |
2407 | } | 2408 | } |
2409 | |||
2410 | if (likely(!err)) | ||
2411 | TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS; | ||
2412 | return err; | ||
2408 | } | 2413 | } |
2409 | 2414 | ||
2410 | int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | 2415 | int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) |