aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2018-11-20 08:53:59 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-21 18:49:52 -0500
commit86de5921a3d5dd246df661e09bdd0a6131b39ae3 (patch)
treeefa8b73f929d9a2e136aaa0e0fa1605d6c12ed1e /net/ipv4/tcp_input.c
parentb5dd186d10ba59e6b5ba60e42b3b083df56df6f3 (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.c14
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;