Skip to content

Commit 7788174

Browse files
yuchungchengdavem330
authored andcommitted
tcp: change IPv6 flow-label upon receiving spurious retransmission
Currently a Linux IPv6 TCP sender will change the flow label upon timeouts to potentially steer away from a data path that has gone bad. However this does not help if the problem is on the ACK path and the data path is healthy. In this case the receiver is likely to receive repeated spurious retransmission because the sender couldn't get the ACKs in time and has recurring timeouts. This patch adds another feature to mitigate this problem. It leverages the DSACK states in the receiver to change the flow label of the ACKs to speculatively re-route the ACK packets. In order to allow triggering on the second consecutive spurious RTO, the receiver changes the flow label upon sending a second consecutive DSACK for a sequence number below RCV.NXT. Signed-off-by: Yuchung Cheng <[email protected]> Signed-off-by: Neal Cardwell <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 506a03a commit 7788174

File tree

2 files changed

+15
-0
lines changed

2 files changed

+15
-0
lines changed

net/ipv4/tcp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,6 +2595,8 @@ int tcp_disconnect(struct sock *sk, int flags)
25952595
tp->compressed_ack = 0;
25962596
tp->bytes_sent = 0;
25972597
tp->bytes_retrans = 0;
2598+
tp->duplicate_sack[0].start_seq = 0;
2599+
tp->duplicate_sack[0].end_seq = 0;
25982600
tp->dsack_dups = 0;
25992601
tp->reord_seen = 0;
26002602

net/ipv4/tcp_input.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4199,6 +4199,17 @@ static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq)
41994199
tcp_sack_extend(tp->duplicate_sack, seq, end_seq);
42004200
}
42014201

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+
42024213
static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
42034214
{
42044215
struct tcp_sock *tp = tcp_sk(sk);
@@ -4211,6 +4222,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
42114222
if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) {
42124223
u32 end_seq = TCP_SKB_CB(skb)->end_seq;
42134224

4225+
tcp_rcv_spurious_retrans(sk, skb);
42144226
if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))
42154227
end_seq = tp->rcv_nxt;
42164228
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq);
@@ -4755,6 +4767,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
47554767
}
47564768

47574769
if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
4770+
tcp_rcv_spurious_retrans(sk, skb);
47584771
/* A retransmit, 2nd most common case. Force an immediate ack. */
47594772
NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);
47604773
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);

0 commit comments

Comments
 (0)