From owner-freebsd-hackers Fri Jun 21 05:47:09 1996 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.7.5/8.7.3) id FAA13188 for hackers-outgoing; Fri, 21 Jun 1996 05:47:09 -0700 (PDT) Received: from diablo.ppp.de (diablo.ppp.de [193.141.101.34]) by freefall.freebsd.org (8.7.5/8.7.3) with SMTP id FAA13164 for ; Fri, 21 Jun 1996 05:46:54 -0700 (PDT) Received: from allegro.lemis.de by diablo.ppp.de with smtp (Smail3.1.28.1 #1) id m0uX5bL-000QcBC; Fri, 21 Jun 96 14:46 MET DST From: grog@lemis.de (Greg Lehey) Organisation: LEMIS, Schellnhausen 2, 36325 Feldatal, Germany Phone: +49-6637-919123 Fax: +49-6637-919122 Received: (grog@localhost) by allegro.lemis.de (8.6.9/8.6.9) id JAA10691; Fri, 21 Jun 1996 09:50:50 +0200 Message-Id: <199606210750.JAA10691@allegro.lemis.de> Subject: Re: IP question: who should return ENOBUFS? To: davidg@root.com Date: Fri, 21 Jun 1996 09:50:50 +0200 (MET DST) Cc: hackers@freebsd.org (FreeBSD Hackers) In-Reply-To: <199606202143.OAA01814@root.com> from "David Greenman" at Jun 20, 96 02:43:58 pm X-Mailer: ELM [version 2.4 PL23] MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk 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