tcp: use correct counters in CA_CWR state too
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>
Thu, 14 Oct 2010 01:52:09 +0000 (01:52 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sun, 17 Oct 2010 20:46:33 +0000 (13:46 -0700)
As CWR is stronger than CA_Disorder state, we can miscount
SACK/Reno failure into other timeouts. Not a bad problem as
it can happen only due to ECN, FRTO detecting spurious RTO
or xmit error which are the only callers of tcp_enter_cwr.
And even then losses and RTO must still follow thereafter
to actually end up into the relevant code paths.

Compile tested.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp_timer.c

index f3c8c6c019ae9790d0d1c79bb695d1cb5ac8ff25..74a6aa003657392d45d97f040ba6a987ee413004 100644 (file)
@@ -367,18 +367,19 @@ void tcp_retransmit_timer(struct sock *sk)
        if (icsk->icsk_retransmits == 0) {
                int mib_idx;
 
-               if (icsk->icsk_ca_state == TCP_CA_Disorder) {
-                       if (tcp_is_sack(tp))
-                               mib_idx = LINUX_MIB_TCPSACKFAILURES;
-                       else
-                               mib_idx = LINUX_MIB_TCPRENOFAILURES;
-               } else if (icsk->icsk_ca_state == TCP_CA_Recovery) {
+               if (icsk->icsk_ca_state == TCP_CA_Recovery) {
                        if (tcp_is_sack(tp))
                                mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL;
                        else
                                mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL;
                } else if (icsk->icsk_ca_state == TCP_CA_Loss) {
                        mib_idx = LINUX_MIB_TCPLOSSFAILURES;
+               } else if ((icsk->icsk_ca_state == TCP_CA_Disorder) ||
+                          tp->sacked_out) {
+                       if (tcp_is_sack(tp))
+                               mib_idx = LINUX_MIB_TCPSACKFAILURES;
+                       else
+                               mib_idx = LINUX_MIB_TCPRENOFAILURES;
                } else {
                        mib_idx = LINUX_MIB_TCPTIMEOUTS;
                }