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