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

    [TCP] FRTO: Reverse RETRANS bit clearing logic
    
    Previously RETRANS bits were cleared on the entry to FRTO. We
    postpone that into tcp_enter_frto_loss, which is really the
    place were the clearing should be done anyway. This allows
    simplification of the logic from a clearing loop to the head skb
    clearing only.
    
    Besides, the other changes made in the previous patches to
    tcp_use_frto made it impossible for the non-SACKed FRTO to be
    entered if other than the head has been rexmitted.
    
    With SACK-enhanced FRTO (and Appendix B), however, there can be
    a number retransmissions in flight when RTO expires (same thing
    could happen before this patchset also with non-SACK FRTO). To
    not introduce any jumpiness into the packet counting during FRTO,
    instead of clearing RETRANS bits from skbs during entry, do it
    later on.
    
    Signed-off-by: Ilpo Järvinen <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 net/ipv4/tcp_input.c |   35 +++++++++++++++++++++++------------
 1 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a283fc1..3ef7e9e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1268,7 +1268,11 @@ int tcp_use_frto(struct sock *sk)
 
 /* RTO occurred, but do not yet enter Loss state. Instead, defer RTO
  * recovery a bit and use heuristics in tcp_process_frto() to detect if
- * the RTO was spurious.
+ * the RTO was spurious. Only clear SACKED_RETRANS of the head here to
+ * keep retrans_out counting accurate (with SACK F-RTO, other than head
+ * may still have that bit set); TCPCB_LOST and remaining SACKED_RETRANS
+ * bits are handled if the Loss state is really to be entered (in
+ * tcp_enter_frto_loss).
  *
  * Do like tcp_enter_loss() would; when RTO expires the second time it
  * does:
@@ -1289,17 +1293,13 @@ void tcp_enter_frto(struct sock *sk)
                tcp_ca_event(sk, CA_EVENT_FRTO);
        }
 
-       /* Have to clear retransmission markers here to keep the bookkeeping
-        * in shape, even though we are not yet in Loss state.
-        * If something was really lost, it is eventually caught up
-        * in tcp_enter_frto_loss.
-        */
-       tp->retrans_out = 0;
        tp->undo_marker = tp->snd_una;
        tp->undo_retrans = 0;
 
-       sk_stream_for_retrans_queue(skb, sk) {
+       skb = skb_peek(&sk->sk_write_queue);
+       if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
                TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
+               tp->retrans_out -= tcp_skb_pcount(skb);
        }
        tcp_sync_left_out(tp);
 
@@ -1313,7 +1313,7 @@ void tcp_enter_frto(struct sock *sk)
  * which indicates that we should follow the traditional RTO recovery,
  * i.e. mark everything lost and do go-back-N retransmission.
  */
-static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments)
+static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int 
flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
@@ -1322,10 +1322,21 @@ static void tcp_enter_frto_loss(struct sock *sk, int 
allowed_segments)
        tp->sacked_out = 0;
        tp->lost_out = 0;
        tp->fackets_out = 0;
+       tp->retrans_out = 0;
 
        sk_stream_for_retrans_queue(skb, sk) {
                cnt += tcp_skb_pcount(skb);
-               TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
+               /*
+                * Count the retransmission made on RTO correctly (only when
+                * waiting for the first ACK and did not get it)...
+                */
+               if ((tp->frto_counter == 1) && !(flag&FLAG_DATA_ACKED)) {
+                       tp->retrans_out += tcp_skb_pcount(skb);
+                       /* ...enter this if branch just for the first segment */
+                       flag |= FLAG_DATA_ACKED;
+               } else {
+                       TCP_SKB_CB(skb)->sacked &= 
~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
+               }
                if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) {
 
                        /* Do not mark those segments lost that were
@@ -2550,7 +2561,7 @@ static int tcp_process_frto(struct sock *sk, u32 
prior_snd_una, int flag)
                inet_csk(sk)->icsk_retransmits = 0;
 
        if (!before(tp->snd_una, tp->frto_highmark)) {
-               tcp_enter_frto_loss(sk, tp->frto_counter + 1);
+               tcp_enter_frto_loss(sk, tp->frto_counter + 1, flag);
                return 1;
        }
 
@@ -2562,7 +2573,7 @@ static int tcp_process_frto(struct sock *sk, u32 
prior_snd_una, int flag)
                return 1;
 
        if (!(flag&FLAG_DATA_ACKED)) {
-               tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3));
+               tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3), flag);
                return 1;
        }
 
-
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