Previously the prior_ssthresh was only used in the undo functions
that were called by fastretrans_alert. FRTO processing, however,
happens before that and one of the responses is doing undo too.

I think that after this patch, FRTO should be ECN-safe; only the
undo_cwr response is a suspect anyway. The possible cases:

    1)  Pre-RTO ECE: FRTO is not setting prior_ssthresh in
        CA_CWR at all, therefore it correctly remains cleared
        and ssthresh is the already reduced one

    2a) Post-RTO ECE, before deciding ACK: prior_ssthresh is
        cleared, so no undoing for ssthresh will occur

    2b) Post-RTO ECE, deciding ACK: this patch changes this case
        equal to 2a

    3)  Between two RTOs: prior_ssthresh is cleared like in 2a
        or the reduced value is used like in 1

Deciding ACK is the one after which FRTO declared RTO as
spurious.

Signed-off-by: Ilpo Järvinen <[EMAIL PROTECTED]>
---

This problem could be solved locally in the undo_cwr response of
FRTO by falling back to ratehalving response when FLAG_ECE is
enabled. If it's more preferrable way, just ping me to get a
patch. I'm not absolutely sure that this does not break anything
even though I couldn't find any using prior_ssthresh between
the new and the old place (seen more than once already within
years that things are not always as simple as they seem).


 net/ipv4/tcp_input.c |   19 +++++++++----------
 1 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index dc221a3..b0c9dfb 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2080,15 +2080,11 @@ tcp_fastretrans_alert(struct sock *sk, u
                tp->fackets_out = 0;
 
        /* Now state machine starts.
-        * A. ECE, hence prohibit cwnd undoing, the reduction is required. */
-       if (flag&FLAG_ECE)
-               tp->prior_ssthresh = 0;
-
-       /* B. In all the states check for reneging SACKs. */
+        * A. In all the states check for reneging SACKs. */
        if (tp->sacked_out && tcp_check_sack_reneging(sk))
                return;
 
-       /* C. Process data loss notification, provided it is valid. */
+       /* B. Process data loss notification, provided it is valid. */
        if ((flag&FLAG_DATA_LOST) &&
            before(tp->snd_una, tp->high_seq) &&
            icsk->icsk_ca_state != TCP_CA_Open &&
@@ -2097,10 +2093,10 @@ tcp_fastretrans_alert(struct sock *sk, u
                NET_INC_STATS_BH(LINUX_MIB_TCPLOSS);
        }
 
-       /* D. Synchronize left_out to current state. */
+       /* C. Synchronize left_out to current state. */
        tcp_sync_left_out(tp);
 
-       /* E. Check state exit conditions. State can be terminated
+       /* D. Check state exit conditions. State can be terminated
         *    when high_seq is ACKed. */
        if (icsk->icsk_ca_state == TCP_CA_Open) {
                BUG_TRAP(tp->retrans_out == 0);
@@ -2143,7 +2139,7 @@ tcp_fastretrans_alert(struct sock *sk, u
                }
        }
 
-       /* F. Process state. */
+       /* E. Process state. */
        switch (icsk->icsk_ca_state) {
        case TCP_CA_Recovery:
                if (prior_snd_una == tp->snd_una) {
@@ -2742,8 +2738,11 @@ static int tcp_ack(struct sock *sk, stru
                if (TCP_SKB_CB(skb)->sacked)
                        flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
 
-               if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th))
+               if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th)) {
                        flag |= FLAG_ECE;
+                       /* ECE, prohibit cwnd undoing, reduction is required */
+                       tp->prior_ssthresh = 0;
+               }
 
                tcp_ca_event(sk, CA_EVENT_SLOW_ACK);
        }
-- 
1.4.2

Reply via email to