diff options
-rw-r--r-- | include/net/tcp.h | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 25 |
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, | |||
341 | extern int tcp_child_process(struct sock *parent, | 341 | extern 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); |
344 | extern int tcp_use_frto(const struct sock *sk); | 344 | extern int tcp_use_frto(struct sock *sk); |
345 | extern void tcp_enter_frto(struct sock *sk); | 345 | extern void tcp_enter_frto(struct sock *sk); |
346 | extern void tcp_enter_loss(struct sock *sk, int how); | 346 | extern void tcp_enter_loss(struct sock *sk, int how); |
347 | extern void tcp_clear_retrans(struct tcp_sock *tp); | 347 | 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_ | |||
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 | */ |
1243 | int tcp_use_frto(const struct sock *sk) | 1244 | int 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 |