A tcp_do_segment() question

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Apr 2 10:26:28 UTC 2015


Hello,

I do currently some tests with a port of the FreeBSD 9.3 network stack 
to the RTEMS real-time operating system. I do an FTP transfer from my 
development machine to the target (curl -T /dev/zero 
ftp://anonymous@192.168.96.157/dev/null). So this is a one-sided TCP 
transfer.

In tcp_do_segment() there is one path as explained here:

     /*
      * Header prediction: check for the two common cases
      * of a uni-directional data xfer.  If the packet has
      * no control flags, is in-sequence, the window didn't
      * change and we're not retransmitting, it's a
      * candidate.  If the length is zero and the ack moved
      * forward, we're the sender side of the xfer.  Just
      * free the data acked & wake any higher level process
      * that was blocked waiting for space.  If the length
      * is non-zero and the ack didn't move, we're the
      * receiver side.  If we're getting packets in-order
      * (the reassembly queue is empty), add the data to
      * the socket buffer and note that we need a delayed ack.
      * Make sure that the hidden state-flags are also off.
      * Since we check for TCPS_ESTABLISHED first, it can only
      * be TH_NEEDSYN.
      */
     if (tp->t_state == TCPS_ESTABLISHED &&
         th->th_seq == tp->rcv_nxt &&
         (thflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
         tp->snd_nxt == tp->snd_max &&
         tiwin && tiwin == tp->snd_wnd &&
         ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) &&
         LIST_EMPTY(&tp->t_segq) &&
         ((to.to_flags & TOF_TS) == 0 ||
          TSTMP_GEQ(to.to_tsval, tp->ts_recent)) ) {

It seems that after some initial setup phase I end up always in this 
branch. The problem is now that the retransmit timer is ticking (TT_REXMT).

In this branch there are three alternatives:

1. if (tlen == 0) {

Since I transfer to the target, tlen != 0.

2.         } else if (th->th_ack == tp->snd_una &&
             tlen <= sbspace(&so->so_rcv)) {

It seems I always end up here.

3. Otherwise.

In the (1) alternative we end up in:

                 if (tp->snd_una == tp->snd_max)
                     tcp_timer_activate(tp, TT_REXMT, 0);
                 else if (!tcp_timer_active(tp, TT_PERSIST))
                     tcp_timer_activate(tp, TT_REXMT,
                               tp->t_rxtcur);
                 sowwakeup(so);
                 if (so->so_snd.sb_cc)
                     (void) tcp_output(tp);
                 goto check_delack;

So here we reset the retransmit timer if possible.

In the (2) alternative we don't reset the retransmit timer! All my 
connections stop after approx. 2:30min via tcp_timer_rexmt(). If I apply 
the following hack

@@ -1852,6 +1866,13 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, 
struct socket *so,
                         }
                         /* NB: sorwakeup_locked() does an implicit 
unlock. */
                         sorwakeup_locked(so);
+
+                       if (tp->snd_una == tp->snd_max)
+                               tcp_timer_activate(tp, TT_REXMT, 0);
+                       else if (!tcp_timer_active(tp, TT_PERSIST))
+                               tcp_timer_activate(tp, TT_REXMT,
+                                             tp->t_rxtcur);
+
                         if (DELAY_ACK(tp)) {
                                 tp->t_flags |= TF_DELACK;
                         } else {

in the (2) alternative, then I can transfer for hours.

Does anyone know why the retransmit timer is not reset in the (2) 
alternative?

-- 
Sebastian Huber, embedded brains GmbH

Address : Dornierstr. 4, D-82178 Puchheim, Germany
Phone   : +49 89 189 47 41-16
Fax     : +49 89 189 47 41-09
E-Mail  : sebastian.huber at embedded-brains.de
PGP     : Public key available on request.

Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG.



More information about the freebsd-hackers mailing list