|
@@ -4199,6 +4199,17 @@ static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq)
|
|
tcp_sack_extend(tp->duplicate_sack, seq, end_seq);
|
|
tcp_sack_extend(tp->duplicate_sack, seq, end_seq);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void tcp_rcv_spurious_retrans(struct sock *sk, const struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ /* When the ACK path fails or drops most ACKs, the sender would
|
|
|
|
+ * timeout and spuriously retransmit the same segment repeatedly.
|
|
|
|
+ * The receiver remembers and reflects via DSACKs. Leverage the
|
|
|
|
+ * DSACK state and change the txhash to re-route speculatively.
|
|
|
|
+ */
|
|
|
|
+ if (TCP_SKB_CB(skb)->seq == tcp_sk(sk)->duplicate_sack[0].start_seq)
|
|
|
|
+ sk_rethink_txhash(sk);
|
|
|
|
+}
|
|
|
|
+
|
|
static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
|
|
static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
|
|
{
|
|
{
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
@@ -4211,6 +4222,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
|
|
if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) {
|
|
if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) {
|
|
u32 end_seq = TCP_SKB_CB(skb)->end_seq;
|
|
u32 end_seq = TCP_SKB_CB(skb)->end_seq;
|
|
|
|
|
|
|
|
+ tcp_rcv_spurious_retrans(sk, skb);
|
|
if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))
|
|
if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))
|
|
end_seq = tp->rcv_nxt;
|
|
end_seq = tp->rcv_nxt;
|
|
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq);
|
|
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq);
|
|
@@ -4755,6 +4767,7 @@ queue_and_out:
|
|
}
|
|
}
|
|
|
|
|
|
if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
|
|
if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
|
|
|
|
+ tcp_rcv_spurious_retrans(sk, skb);
|
|
/* A retransmit, 2nd most common case. Force an immediate ack. */
|
|
/* A retransmit, 2nd most common case. Force an immediate ack. */
|
|
NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);
|
|
NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);
|
|
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
|
|
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
|