[Bug 199287] Missing TCP retransmit timer reset
bugzilla-noreply at freebsd.org
bugzilla-noreply at freebsd.org
Wed Apr 8 08:17:17 UTC 2015
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 at FreeBSD.org
Reporter: sebastian.huber at 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.
More information about the freebsd-bugs
mailing list