aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c25
1 files changed, 21 insertions, 4 deletions
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