Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=46d0de4ed92650b95f27acae09914996bbe624e7
Commit:     46d0de4ed92650b95f27acae09914996bbe624e7
Parent:     7c9a4a5b67926dd186d427bc5b9fce6ccbde154c
Author:     Ilpo Järvinen <[EMAIL PROTECTED]>
AuthorDate: Wed Feb 21 23:10:39 2007 -0800
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Wed Apr 25 22:23:12 2007 -0700

    [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 <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 include/net/tcp.h    |    2 +-
 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 572a77b..7fd6b77 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 723cee6..a283fc1 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
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to