aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2007-02-22 02:10:39 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:23:12 -0400
commit46d0de4ed92650b95f27acae09914996bbe624e7 (patch)
tree455e6a9772294ef16a88800709685797e1779b75
parent7c9a4a5b67926dd186d427bc5b9fce6ccbde154c (diff)
[TCP] FRTO: Entry is allowed only during (New)Reno like recovery
This interpretation comes from RFC4138: "If the sender implements some loss recovery algorithm other than Reno or NewReno [FHG04], the F-RTO algorithm SHOULD NOT be entered when earlier fast recovery is underway." I think the RFC means to say (especially in the light of Appendix B) that ...recovery is underway (not just fast recovery) or was underway when it was interrupted by an earlier (F-)RTO that hasn't yet been resolved (snd_una has not advanced enough). Thus, my interpretation is that whenever TCP has ever retransmitted other than head, basic version cannot be used because then the order assumptions which are used as FRTO basis do not hold. NewReno has only the head segment retransmitted at a time. Therefore, walk up to the segment that has not been SACKed, if that segment is not retransmitted nor anything before it, we know for sure, that nothing after the non-SACKed segment should be either. This assumption is valid because TCPCB_EVER_RETRANS does not leave holes but each non-SACKed segment is rexmitted in-order. Check for retrans_out > 1 avoids more expensive walk through the skb list, as we can know the result beforehand: F-RTO will not be allowed. SACKed skb can turn into non-SACked only in the extremely rare case of SACK reneging, in this case we might fail to detect retransmissions if there were them for any other than head. To get rid of that feature, whole rexmit queue would have to be walked (always) or FRTO should be prevented when SACK reneging happens. Of course RTO should still trigger after reneging which makes this issue even less likely to show up. And as long as the response is as conservative as it's now, nothing bad happens even then. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
-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