Hi

I took a look at the number of TCP retransmissions
and error reporting after giving up to the application
and currently Linux retransmit one packet more than
specified through sys control interface.
Additionally it reports the timeout (giving up) to the
application immediately after it retransmits the last
time - so this retransmission is useless. Small patch
I am sending tries to correct this behavior -

1. sending the right number of retransmissions

2. report the error to the application after last
    retransmission plus next retransmit time.

regards
Pavel


--- linux-2.3.18/net/ipv4/tcp_timer.c.bak       Fri Sep 17 11:25:20 1999
+++ linux-2.3.18/net/ipv4/tcp_timer.c   Fri Sep 17 14:26:58 1999
@@ -152,14 +152,14 @@
 }
 
 /* A write timeout has occurred. Process the after effects. */
-static void tcp_write_timeout(struct sock *sk)
+static int tcp_write_timeout(struct sock *sk)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
        /* Look for a 'soft' timeout. */
        if ((sk->state == TCP_ESTABLISHED &&
             tp->retransmits && (tp->retransmits % TCP_QUICK_TRIES) == 0) ||
-           (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) {
+           (sk->state != TCP_ESTABLISHED && tp->retransmits >= sysctl_tcp_retries1)) {
                /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black
                   hole detection. :-(
 
@@ -185,14 +185,17 @@
        
        /* Have we tried to SYN too many times (repent repent 8)) */
        if (sk->state == TCP_SYN_SENT && 
-           ((!tp->syn_retries && tp->retransmits > sysctl_tcp_syn_retries) ||
-             (tp->syn_retries && tp->retransmits > tp->syn_retries))) {
+           ((!tp->syn_retries && tp->retransmits >= sysctl_tcp_syn_retries) ||
+             (tp->syn_retries && tp->retransmits >= tp->syn_retries))) {
                tcp_write_err(sk, 1);
+               return 1;
                /* Don't FIN, we got nothing back */
-       } else if (tp->retransmits > sysctl_tcp_retries2) {
+       } else if (tp->retransmits >= sysctl_tcp_retries2) {
                /* Has it gone just too far? */
                tcp_write_err(sk, 0);
+               return 1;
        }
+       return 0;
 }
 
 void tcp_delack_timer(unsigned long data)
@@ -391,6 +394,9 @@
 
        /* Clear delay ack timer. */
        tcp_clear_xmit_timer(sk, TIME_DACK);
+       
+       if (tcp_write_timeout(sk))
+               goto out_unlock;
 
        /* RFC 2018, clear all 'sacked' flags in retransmission queue,
         * the sender may have dropped out of order frames and we must
@@ -451,7 +457,6 @@
        tp->rto = min(tp->rto << 1, 120*HZ);
        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 
-       tcp_write_timeout(sk);
 
 out_unlock:
        bh_unlock_sock(sk);

Reply via email to