diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4c2dd9f863f7..62508a2f9b21 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -4199,6 +4199,17 @@ static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq) | |||
4199 | tcp_sack_extend(tp->duplicate_sack, seq, end_seq); | 4199 | tcp_sack_extend(tp->duplicate_sack, seq, end_seq); |
4200 | } | 4200 | } |
4201 | 4201 | ||
4202 | static void tcp_rcv_spurious_retrans(struct sock *sk, const struct sk_buff *skb) | ||
4203 | { | ||
4204 | /* When the ACK path fails or drops most ACKs, the sender would | ||
4205 | * timeout and spuriously retransmit the same segment repeatedly. | ||
4206 | * The receiver remembers and reflects via DSACKs. Leverage the | ||
4207 | * DSACK state and change the txhash to re-route speculatively. | ||
4208 | */ | ||
4209 | if (TCP_SKB_CB(skb)->seq == tcp_sk(sk)->duplicate_sack[0].start_seq) | ||
4210 | sk_rethink_txhash(sk); | ||
4211 | } | ||
4212 | |||
4202 | static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) | 4213 | static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) |
4203 | { | 4214 | { |
4204 | struct tcp_sock *tp = tcp_sk(sk); | 4215 | struct tcp_sock *tp = tcp_sk(sk); |
@@ -4211,6 +4222,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) | |||
4211 | if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) { | 4222 | if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) { |
4212 | u32 end_seq = TCP_SKB_CB(skb)->end_seq; | 4223 | u32 end_seq = TCP_SKB_CB(skb)->end_seq; |
4213 | 4224 | ||
4225 | tcp_rcv_spurious_retrans(sk, skb); | ||
4214 | if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) | 4226 | if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) |
4215 | end_seq = tp->rcv_nxt; | 4227 | end_seq = tp->rcv_nxt; |
4216 | tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq); | 4228 | tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq); |
@@ -4755,6 +4767,7 @@ queue_and_out: | |||
4755 | } | 4767 | } |
4756 | 4768 | ||
4757 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { | 4769 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { |
4770 | tcp_rcv_spurious_retrans(sk, skb); | ||
4758 | /* A retransmit, 2nd most common case. Force an immediate ack. */ | 4771 | /* A retransmit, 2nd most common case. Force an immediate ack. */ |
4759 | NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); | 4772 | NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); |
4760 | tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); | 4773 | tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); |