aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/tcp.h2
-rw-r--r--net/ipv4/tcp_input.c25
2 files changed, 22 insertions, 5 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 572a77bb6907..7fd6b77519c3 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -341,7 +341,7 @@ extern struct sock * tcp_check_req(struct sock *sk,struct sk_buff *skb,
extern int tcp_child_process(struct sock *parent,
struct sock *child,
struct sk_buff *skb);
-extern int tcp_use_frto(const struct sock *sk);
+extern int tcp_use_frto(struct sock *sk);
extern void tcp_enter_frto(struct sock *sk);
extern void tcp_enter_loss(struct sock *sk, int how);
extern void tcp_clear_retrans(struct tcp_sock *tp);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 723cee63791f..a283fc12186e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1239,14 +1239,31 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
/* F-RTO can only be used if these conditions are satisfied:
* - there must be some unsent new data
* - the advertised window should allow sending it
+ * - TCP has never retransmitted anything other than head
*/
-int tcp_use_frto(const struct sock *sk)
+int tcp_use_frto(struct sock *sk)
{
const struct tcp_sock *tp = tcp_sk(sk);
+ struct sk_buff *skb;
+
+ if (!sysctl_tcp_frto || !sk->sk_send_head ||
+ after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
+ tp->snd_una + tp->snd_wnd))
+ return 0;
- return (sysctl_tcp_frto && sk->sk_send_head &&
- !after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
- tp->snd_una + tp->snd_wnd));
+ /* Avoid expensive walking of rexmit queue if possible */
+ if (tp->retrans_out > 1)
+ return 0;
+
+ skb = skb_peek(&sk->sk_write_queue)->next; /* Skips head */
+ sk_stream_for_retrans_queue_from(skb, sk) {
+ if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS)
+ return 0;
+ /* Short-circuit when first non-SACKed skb has been checked */
+ if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED))
+ break;
+ }
+ return 1;
}
/* RTO occurred, but do not yet enter Loss state. Instead, defer RTO