diff options
author | Eric Dumazet <edumazet@google.com> | 2018-11-20 08:53:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-11-21 18:49:52 -0500 |
commit | 86de5921a3d5dd246df661e09bdd0a6131b39ae3 (patch) | |
tree | efa8b73f929d9a2e136aaa0e0fa1605d6c12ed1e /net/ipv4/tcp_input.c | |
parent | b5dd186d10ba59e6b5ba60e42b3b083df56df6f3 (diff) |
tcp: defer SACK compression after DupThresh
Jean-Louis reported a TCP regression and bisected to recent SACK
compression.
After a loss episode (receiver not able to keep up and dropping
packets because its backlog is full), linux TCP stack is sending
a single SACK (DUPACK).
Sender waits a full RTO timer before recovering losses.
While RFC 6675 says in section 5, "Algorithm Details",
(2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true --
indicating at least three segments have arrived above the current
cumulative acknowledgment point, which is taken to indicate loss
-- go to step (4).
...
(4) Invoke fast retransmit and enter loss recovery as follows:
there are old TCP stacks not implementing this strategy, and
still counting the dupacks before starting fast retransmit.
While these stacks probably perform poorly when receivers implement
LRO/GRO, we should be a little more gentle to them.
This patch makes sure we do not enable SACK compression unless
3 dupacks have been sent since last rcv_nxt update.
Ideally we should even rearm the timer to send one or two
more DUPACK if no more packets are coming, but that will
be work aiming for linux-4.21.
Many thanks to Jean-Louis for bisecting the issue, providing
packet captures and testing this patch.
Fixes: 5d9f4262b7ea ("tcp: add SACK compression")
Reported-by: Jean-Louis Dupond <jean-louis@dupond.be>
Tested-by: Jean-Louis Dupond <jean-louis@dupond.be>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e695584bb33f..1e37c1388189 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -4268,7 +4268,7 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, u32 seq, u32 end_seq) | |||
4268 | * If the sack array is full, forget about the last one. | 4268 | * If the sack array is full, forget about the last one. |
4269 | */ | 4269 | */ |
4270 | if (this_sack >= TCP_NUM_SACKS) { | 4270 | if (this_sack >= TCP_NUM_SACKS) { |
4271 | if (tp->compressed_ack) | 4271 | if (tp->compressed_ack > TCP_FASTRETRANS_THRESH) |
4272 | tcp_send_ack(sk); | 4272 | tcp_send_ack(sk); |
4273 | this_sack--; | 4273 | this_sack--; |
4274 | tp->rx_opt.num_sacks--; | 4274 | tp->rx_opt.num_sacks--; |
@@ -5189,7 +5189,17 @@ send_now: | |||
5189 | if (!tcp_is_sack(tp) || | 5189 | if (!tcp_is_sack(tp) || |
5190 | tp->compressed_ack >= sock_net(sk)->ipv4.sysctl_tcp_comp_sack_nr) | 5190 | tp->compressed_ack >= sock_net(sk)->ipv4.sysctl_tcp_comp_sack_nr) |
5191 | goto send_now; | 5191 | goto send_now; |
5192 | tp->compressed_ack++; | 5192 | |
5193 | if (tp->compressed_ack_rcv_nxt != tp->rcv_nxt) { | ||
5194 | tp->compressed_ack_rcv_nxt = tp->rcv_nxt; | ||
5195 | if (tp->compressed_ack > TCP_FASTRETRANS_THRESH) | ||
5196 | NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPACKCOMPRESSED, | ||
5197 | tp->compressed_ack - TCP_FASTRETRANS_THRESH); | ||
5198 | tp->compressed_ack = 0; | ||
5199 | } | ||
5200 | |||
5201 | if (++tp->compressed_ack <= TCP_FASTRETRANS_THRESH) | ||
5202 | goto send_now; | ||
5193 | 5203 | ||
5194 | if (hrtimer_is_queued(&tp->compressed_ack_timer)) | 5204 | if (hrtimer_is_queued(&tp->compressed_ack_timer)) |
5195 | return; | 5205 | return; |