Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 21 Jun 1996 09:50:50 +0200 (MET DST)
From:      grog@lemis.de (Greg Lehey)
To:        davidg@root.com
Cc:        hackers@freebsd.org (FreeBSD Hackers)
Subject:   Re: IP question: who should return ENOBUFS?
Message-ID:  <199606210750.JAA10691@allegro.lemis.de>
In-Reply-To: <199606202143.OAA01814@root.com> from "David Greenman" at Jun 20, 96 02:43:58 pm

next in thread | previous in thread | raw e-mail | index | archive | help
David Greenman writes:
>
>> === root@freebie (/dev/ttyp0) /sys/netinet 11 -> ping 192.109.197.38
>> PING 192.109.197.38 (192.109.197.38): 56 data bytes
>> ping: sendto: No buffer space available
>> ping: wrote 192.109.197.38 64 chars, ret=-1
>> ping: sendto: No buffer space available
>>
>> I found this strange, since in the interface code (b_isdnipi.c, line
>> 474) we have the code:
>>
>> 	if (IF_QFULL(&ifp->if_snd))
>> 	{
>> 		if (ifp->if_flags & IFF_RUNNING)
>> 			isdn_output(sc->sc_appl);
>> 		IF_DROP(&ifp->if_snd);
>> 		m_freem(m);
>> 		splx(x);
>> 		ifp->if_oerrors++;
>> 		return (ENOBUFS);
>> 	}
>>
>> This will drop the first packet *and* not enqueue the last if the
>> queue is full.  So I set a breakpoint on the IF_DROP, and hey! nothing
>> happened.  After a bit more investigation, I found this code in
>> ip_output.c:
>>
>> 	/*
>> 	 * Verify that we have any chance at all of being able to queue
>> 	 *      the packet or packet fragments
>> 	 */
>> 	if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
>> 		ifp->if_snd.ifq_maxlen) {
>> 			error = ENOBUFS;
>> 			goto bad;
>> 	}
>>
>> I think this is bogus.  It's not present in the BSD/OS version, so I
>> assume it was added in FreeBSD.  The problem is, it gives you no
>> possibility of recovery: the queue is full and stays that way.  Can
>> anybody give me an idea of why it's there, when the interface is
>> perfectly capable of looking after itself?
>
>    The interface has no knowledge of whether or not this is a fragment in a
> mulitple fragment datagram. FreeBSD is very good about keeping the output
> queue of an interface busy. Allowing any one of the fragments that make up
> an IP packet to be dropped makes the entire packet useless. The above piece
> of code fixes a bug where the output queue is kept completely full, and each
> time that the second fragment of a packet is queued it is dropped. This
> results eventually in the need to retransmit it and the same thing happens
> again. That in itself isn't so much of a problem except that in the process
> of doing this, you're flooding the network with useless fragments and getting
> nowhere in the process. The only way to fix this is to drop all of the
> fragments of a fragmented packet and the only place you can do this is before
> the packet is fragmented.
>    The above is only a problem for UDP. TCP's window prevents the queue limit
> from being reached in usual case.

Well, in fact these were ping messages, but I suppose the same thing
applies.  Admittedly, ISDN is unusual: it makes a bet that it can
establish a connection quickly, and thus accepts packets though the
link is down.  The same would apply to a dialup ppp, of course (I
don't know the FreeBSD implementation).  The problem arises when the
connection can't be established: the queue fills up, and since this
particular code doesn't drop any packets, it stays that way.
Deadlock.  The only thing you can do is to down the line and then up
it again.

It seems to me that the intention of this code is good, but the
implementation needs rethinking.  There's also the question of
interactive response time across an ISDN link, so maybe we should be
thinking of prioritizing packets somehow, and of being more selective
about which packets get dropped when the queue fills up.

Greg



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199606210750.JAA10691>