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,
341extern int tcp_child_process(struct sock *parent, 341extern int tcp_child_process(struct sock *parent,
342 struct sock *child, 342 struct sock *child,
343 struct sk_buff *skb); 343 struct sk_buff *skb);
344extern int tcp_use_frto(const struct sock *sk); 344extern int tcp_use_frto(struct sock *sk);
345extern void tcp_enter_frto(struct sock *sk); 345extern void tcp_enter_frto(struct sock *sk);
346extern void tcp_enter_loss(struct sock *sk, int how); 346extern void tcp_enter_loss(struct sock *sk, int how);
347extern void tcp_clear_retrans(struct tcp_sock *tp); 347extern 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_
1239/* F-RTO can only be used if these conditions are satisfied: 1239/* F-RTO can only be used if these conditions are satisfied:
1240 * - there must be some unsent new data 1240 * - there must be some unsent new data
1241 * - the advertised window should allow sending it 1241 * - the advertised window should allow sending it
1242 * - TCP has never retransmitted anything other than head
1242 */ 1243 */
1243int tcp_use_frto(const struct sock *sk) 1244int tcp_use_frto(struct sock *sk)
1244{ 1245{
1245 const struct tcp_sock *tp = tcp_sk(sk); 1246 const struct tcp_sock *tp = tcp_sk(sk);
1247 struct sk_buff *skb;
1248
1249 if (!sysctl_tcp_frto || !sk->sk_send_head ||
1250 after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
1251 tp->snd_una + tp->snd_wnd))
1252 return 0;
1246 1253
1247 return (sysctl_tcp_frto && sk->sk_send_head && 1254 /* Avoid expensive walking of rexmit queue if possible */
1248 !after(TCP_SKB_CB(sk->sk_send_head)->end_seq, 1255 if (tp->retrans_out > 1)
1249 tp->snd_una + tp->snd_wnd)); 1256 return 0;
1257
1258 skb = skb_peek(&sk->sk_write_queue)->next; /* Skips head */
1259 sk_stream_for_retrans_queue_from(skb, sk) {
1260 if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS)
1261 return 0;
1262 /* Short-circuit when first non-SACKed skb has been checked */
1263 if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED))
1264 break;
1265 }
1266 return 1;
1250} 1267}
1251 1268
1252/* RTO occurred, but do not yet enter Loss state. Instead, defer RTO 1269/* RTO occurred, but do not yet enter Loss state. Instead, defer RTO