|
@@ -1904,16 +1904,17 @@ void tcp_clear_retrans(struct tcp_sock *tp)
|
|
tp->sacked_out = 0;
|
|
tp->sacked_out = 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/* Enter Loss state. If "how" is not zero, forget all SACK information
|
|
|
|
|
|
+/* Enter Loss state. If we detect SACK reneging, forget all SACK information
|
|
* and reset tags completely, otherwise preserve SACKs. If receiver
|
|
* and reset tags completely, otherwise preserve SACKs. If receiver
|
|
* dropped its ofo queue, we will know this due to reneging detection.
|
|
* dropped its ofo queue, we will know this due to reneging detection.
|
|
*/
|
|
*/
|
|
-void tcp_enter_loss(struct sock *sk, int how)
|
|
|
|
|
|
+void tcp_enter_loss(struct sock *sk)
|
|
{
|
|
{
|
|
const struct inet_connection_sock *icsk = inet_csk(sk);
|
|
const struct inet_connection_sock *icsk = inet_csk(sk);
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
struct sk_buff *skb;
|
|
struct sk_buff *skb;
|
|
bool new_recovery = false;
|
|
bool new_recovery = false;
|
|
|
|
+ bool is_reneg; /* is receiver reneging on SACKs? */
|
|
|
|
|
|
/* Reduce ssthresh if it has not yet been made inside this window. */
|
|
/* Reduce ssthresh if it has not yet been made inside this window. */
|
|
if (icsk->icsk_ca_state <= TCP_CA_Disorder ||
|
|
if (icsk->icsk_ca_state <= TCP_CA_Disorder ||
|
|
@@ -1934,7 +1935,11 @@ void tcp_enter_loss(struct sock *sk, int how)
|
|
tcp_reset_reno_sack(tp);
|
|
tcp_reset_reno_sack(tp);
|
|
|
|
|
|
tp->undo_marker = tp->snd_una;
|
|
tp->undo_marker = tp->snd_una;
|
|
- if (how) {
|
|
|
|
|
|
+
|
|
|
|
+ skb = tcp_write_queue_head(sk);
|
|
|
|
+ is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED);
|
|
|
|
+ if (is_reneg) {
|
|
|
|
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING);
|
|
tp->sacked_out = 0;
|
|
tp->sacked_out = 0;
|
|
tp->fackets_out = 0;
|
|
tp->fackets_out = 0;
|
|
}
|
|
}
|
|
@@ -1948,7 +1953,7 @@ void tcp_enter_loss(struct sock *sk, int how)
|
|
tp->undo_marker = 0;
|
|
tp->undo_marker = 0;
|
|
|
|
|
|
TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
|
|
TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
|
|
- if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) {
|
|
|
|
|
|
+ if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || is_reneg) {
|
|
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
|
|
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
|
|
TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
|
|
TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
|
|
tp->lost_out += tcp_skb_pcount(skb);
|
|
tp->lost_out += tcp_skb_pcount(skb);
|
|
@@ -1981,19 +1986,21 @@ void tcp_enter_loss(struct sock *sk, int how)
|
|
* remembered SACKs do not reflect real state of receiver i.e.
|
|
* remembered SACKs do not reflect real state of receiver i.e.
|
|
* receiver _host_ is heavily congested (or buggy).
|
|
* receiver _host_ is heavily congested (or buggy).
|
|
*
|
|
*
|
|
- * Do processing similar to RTO timeout.
|
|
|
|
|
|
+ * To avoid big spurious retransmission bursts due to transient SACK
|
|
|
|
+ * scoreboard oddities that look like reneging, we give the receiver a
|
|
|
|
+ * little time (max(RTT/2, 10ms)) to send us some more ACKs that will
|
|
|
|
+ * restore sanity to the SACK scoreboard. If the apparent reneging
|
|
|
|
+ * persists until this RTO then we'll clear the SACK scoreboard.
|
|
*/
|
|
*/
|
|
static bool tcp_check_sack_reneging(struct sock *sk, int flag)
|
|
static bool tcp_check_sack_reneging(struct sock *sk, int flag)
|
|
{
|
|
{
|
|
if (flag & FLAG_SACK_RENEGING) {
|
|
if (flag & FLAG_SACK_RENEGING) {
|
|
- struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING);
|
|
|
|
|
|
+ struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
+ unsigned long delay = max(usecs_to_jiffies(tp->srtt_us >> 4),
|
|
|
|
+ msecs_to_jiffies(10));
|
|
|
|
|
|
- tcp_enter_loss(sk, 1);
|
|
|
|
- icsk->icsk_retransmits++;
|
|
|
|
- tcp_retransmit_skb(sk, tcp_write_queue_head(sk));
|
|
|
|
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
|
|
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
|
|
- icsk->icsk_rto, TCP_RTO_MAX);
|
|
|
|
|
|
+ delay, TCP_RTO_MAX);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
return false;
|