diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_input.c | 29 | ||||
-rw-r--r-- | net/ipv4/tcp_timer.c | 4 |
2 files changed, 20 insertions, 13 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7832d941dbcd..6a2984507755 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1904,16 +1904,17 @@ void tcp_clear_retrans(struct tcp_sock *tp) | |||
1904 | tp->sacked_out = 0; | 1904 | tp->sacked_out = 0; |
1905 | } | 1905 | } |
1906 | 1906 | ||
1907 | /* Enter Loss state. If "how" is not zero, forget all SACK information | 1907 | /* Enter Loss state. If we detect SACK reneging, forget all SACK information |
1908 | * and reset tags completely, otherwise preserve SACKs. If receiver | 1908 | * and reset tags completely, otherwise preserve SACKs. If receiver |
1909 | * dropped its ofo queue, we will know this due to reneging detection. | 1909 | * dropped its ofo queue, we will know this due to reneging detection. |
1910 | */ | 1910 | */ |
1911 | void tcp_enter_loss(struct sock *sk, int how) | 1911 | void tcp_enter_loss(struct sock *sk) |
1912 | { | 1912 | { |
1913 | const struct inet_connection_sock *icsk = inet_csk(sk); | 1913 | const struct inet_connection_sock *icsk = inet_csk(sk); |
1914 | struct tcp_sock *tp = tcp_sk(sk); | 1914 | struct tcp_sock *tp = tcp_sk(sk); |
1915 | struct sk_buff *skb; | 1915 | struct sk_buff *skb; |
1916 | bool new_recovery = false; | 1916 | bool new_recovery = false; |
1917 | bool is_reneg; /* is receiver reneging on SACKs? */ | ||
1917 | 1918 | ||
1918 | /* Reduce ssthresh if it has not yet been made inside this window. */ | 1919 | /* Reduce ssthresh if it has not yet been made inside this window. */ |
1919 | if (icsk->icsk_ca_state <= TCP_CA_Disorder || | 1920 | if (icsk->icsk_ca_state <= TCP_CA_Disorder || |
@@ -1934,7 +1935,11 @@ void tcp_enter_loss(struct sock *sk, int how) | |||
1934 | tcp_reset_reno_sack(tp); | 1935 | tcp_reset_reno_sack(tp); |
1935 | 1936 | ||
1936 | tp->undo_marker = tp->snd_una; | 1937 | tp->undo_marker = tp->snd_una; |
1937 | if (how) { | 1938 | |
1939 | skb = tcp_write_queue_head(sk); | ||
1940 | is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED); | ||
1941 | if (is_reneg) { | ||
1942 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); | ||
1938 | tp->sacked_out = 0; | 1943 | tp->sacked_out = 0; |
1939 | tp->fackets_out = 0; | 1944 | tp->fackets_out = 0; |
1940 | } | 1945 | } |
@@ -1948,7 +1953,7 @@ void tcp_enter_loss(struct sock *sk, int how) | |||
1948 | tp->undo_marker = 0; | 1953 | tp->undo_marker = 0; |
1949 | 1954 | ||
1950 | TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; | 1955 | TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; |
1951 | if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) { | 1956 | if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || is_reneg) { |
1952 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; | 1957 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; |
1953 | TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; | 1958 | TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; |
1954 | tp->lost_out += tcp_skb_pcount(skb); | 1959 | tp->lost_out += tcp_skb_pcount(skb); |
@@ -1981,19 +1986,21 @@ void tcp_enter_loss(struct sock *sk, int how) | |||
1981 | * remembered SACKs do not reflect real state of receiver i.e. | 1986 | * remembered SACKs do not reflect real state of receiver i.e. |
1982 | * receiver _host_ is heavily congested (or buggy). | 1987 | * receiver _host_ is heavily congested (or buggy). |
1983 | * | 1988 | * |
1984 | * Do processing similar to RTO timeout. | 1989 | * To avoid big spurious retransmission bursts due to transient SACK |
1990 | * scoreboard oddities that look like reneging, we give the receiver a | ||
1991 | * little time (max(RTT/2, 10ms)) to send us some more ACKs that will | ||
1992 | * restore sanity to the SACK scoreboard. If the apparent reneging | ||
1993 | * persists until this RTO then we'll clear the SACK scoreboard. | ||
1985 | */ | 1994 | */ |
1986 | static bool tcp_check_sack_reneging(struct sock *sk, int flag) | 1995 | static bool tcp_check_sack_reneging(struct sock *sk, int flag) |
1987 | { | 1996 | { |
1988 | if (flag & FLAG_SACK_RENEGING) { | 1997 | if (flag & FLAG_SACK_RENEGING) { |
1989 | struct inet_connection_sock *icsk = inet_csk(sk); | 1998 | struct tcp_sock *tp = tcp_sk(sk); |
1990 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); | 1999 | unsigned long delay = max(usecs_to_jiffies(tp->srtt_us >> 4), |
2000 | msecs_to_jiffies(10)); | ||
1991 | 2001 | ||
1992 | tcp_enter_loss(sk, 1); | ||
1993 | icsk->icsk_retransmits++; | ||
1994 | tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); | ||
1995 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | 2002 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, |
1996 | icsk->icsk_rto, TCP_RTO_MAX); | 2003 | delay, TCP_RTO_MAX); |
1997 | return true; | 2004 | return true; |
1998 | } | 2005 | } |
1999 | return false; | 2006 | return false; |
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 286227abed10..df90cd1ce37f 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
@@ -391,7 +391,7 @@ void tcp_retransmit_timer(struct sock *sk) | |||
391 | tcp_write_err(sk); | 391 | tcp_write_err(sk); |
392 | goto out; | 392 | goto out; |
393 | } | 393 | } |
394 | tcp_enter_loss(sk, 0); | 394 | tcp_enter_loss(sk); |
395 | tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); | 395 | tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); |
396 | __sk_dst_reset(sk); | 396 | __sk_dst_reset(sk); |
397 | goto out_reset_timer; | 397 | goto out_reset_timer; |
@@ -422,7 +422,7 @@ void tcp_retransmit_timer(struct sock *sk) | |||
422 | NET_INC_STATS_BH(sock_net(sk), mib_idx); | 422 | NET_INC_STATS_BH(sock_net(sk), mib_idx); |
423 | } | 423 | } |
424 | 424 | ||
425 | tcp_enter_loss(sk, 0); | 425 | tcp_enter_loss(sk); |
426 | 426 | ||
427 | if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) > 0) { | 427 | if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) > 0) { |
428 | /* Retransmission failed because of local congestion, | 428 | /* Retransmission failed because of local congestion, |