Date: Wed, 08 Apr 2015 08:17:17 +0000 From: bugzilla-noreply@freebsd.org To: freebsd-bugs@FreeBSD.org Subject: [Bug 199287] Missing TCP retransmit timer reset Message-ID: <bug-199287-8@https.bugs.freebsd.org/bugzilla/>
next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=199287 Bug ID: 199287 Summary: Missing TCP retransmit timer reset Product: Base System Version: 9.3-RELEASE Hardware: Any OS: Any Status: New Severity: Affects Only Me Priority: --- Component: kern Assignee: freebsd-bugs@FreeBSD.org Reporter: sebastian.huber@embedded-brains.de There is a potential problem in the TCP implementation. I don't use FreeBSD directly, instead I use a port of the FreeBSD 9.3 network stack to the RTEMS real-time operating system. Nonetheless, this problem might exist in the real FreeBSD system. During tests under heavy load conditions the following situation occurred. I transfer data from my development hosts /dev/zero to the targets (RTEMS running the FreeBSD network stack) /dev/null via TCP. Thus the target sends only ACKs after the TCP connection setup. The interface driver uses an equal count for the rx and tx DMA descriptors. I use a small value to provoke packet loss at the rx side. This packet loss is dealt via SACK, so the transfer rate is nearly constant and at a high level for the target. In this setup the tx queue overflows occasionally, thus in ip_output() we end up at /* * Verify that we have any chance at all of being able to queue the * packet or packet fragments, unless ALTQ is enabled on the given * interface in which case packetdrop should be done by queueing. */ n = ip->ip_len / mtu + 1; /* how many fragments ? */ if ( #ifdef ALTQ (!ALTQ_IS_ENABLED(&ifp->if_snd)) && #endif /* ALTQ */ (ifp->if_snd.ifq_len + n) >= ifp->if_snd.ifq_maxlen ) { error = ENOBUFS; IPSTAT_INC(ips_odropped); ifp->if_snd.ifq_drops += n; goto bad; } and return ENOBUFS. This leads to tcp_ouput() out: SOCKBUF_UNLOCK_ASSERT(&so->so_snd); /* Check gotos. */ switch (error) { case EPERM: tp->t_softerror = error; return (error); case ENOBUFS: if (!tcp_timer_active(tp, TT_REXMT) && !tcp_timer_active(tp, TT_PERSIST)) tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); tp->snd_cwnd = tp->t_maxseg; return (0); So here we start the retransmit timer. An occasional drop of ACK-only packets doesn't hurt in this scenario so we don't observe any problems and on the rx side we nearly always end up in tcp_do_segment() with tlen != 0 /* * 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)) ) { In this path the retransmit timer is never reset, so in the end the connection is dropped by tcp_timer_rexmt() even though there is no real connection problem. -- You are receiving this mail because: You are the assignee for the bug.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-199287-8>