Date: Thu, 6 Nov 2003 00:38:48 -0800 From: Guy Harris <guy@alum.mit.edu> To: Bruce Evans <bde@zeta.org.au> Cc: fenner@freebsd.org Subject: Re: bpf/pcap are weird Message-ID: <20031106003848.F331@quadrajet.sonic.net>
next in thread | raw e-mail | index | archive | help
> bpfpoll() is reported to be broken; see PR 36219. Yes, that's the PR that indicated that "select()"/"poll()" don't, in fact, work correctly with timeouts. That was fixed in 4.5... > Rev.1.113 of bpf.c may have disturbed this. ...but might have been re-broken. > It removed the comment which said that > bpf_ready() doesn't acually imitate resultof(FIONREAD) != 0. ...and it also removed the check for "d->bd_state == BPF_TIMED_OUT" that made "select()"/"poll()" work with timeouts. And, unfortunately, it looks as if that's in 4.9 - revision 1.59.2.13 has it, and that's tagged with RELENG_4_9_0_RELEASE. If non-blocking reads *do* cause buffer rotation if necessary, this can, at least for "select()"/"poll()"-based applications that can control the timeout in their select loop, be worked around by making the timeout timer be a timeout in "select()" or "poll()", putting the BPF device in non-blocking mode (for which there is an API in recent versions of libpcap, and in older versions you can just set the flag on the descriptor you get from "pcap_fileno()"), and reading from the BPF device (or the pcap_t) either if "select()"/"poll()" says you can *or* the "select()"/"poll()" timer has expired. If they don't cause a buffer rotation, however, you're screwed unless there's some other way to force the buffer rotation. Turning BIOCIMMEDIATE mode on would take care of that - but it would also turn off packet buffering, which might cause too much CPU overhead when capturing on a busy network. (Or it might not; I don't know whether anybody's measured it.) However, in 4.9, a buffer rotation will be done in "bpf_read()" if a timeout has occurred, so it looks as if that workaround would work. In 4.x releases from 4.5 through 4.8, "select()"/"poll()" should, I thihnk, work with timeouts, and reads after a timeout has occurred should rotate the buffers even if the timeout occurred before the "read()" (such as in a "select()"/"poll()"). In releases prior to 4.4, "select()"/"poll()" won't work with timeouts - but non-blocking reads will force a buffer rotation; if the hold buffer is empty, and IO_NDELAY is set in "ioflag", "error" will be set to EWOULDBLOCK, and it'll eventually fall through to the "rotate buffers if EWOULDBLOCK is true, the hold buffer is empty, and the store buffer isn't" code. In 4.4, "bpf_read()" was changed (revision 1.59.2.5, MFC of 1.72) so that if the hold buffer is empty, and IO_NDELAY is set in "ioflag", it'll return EWOULDBLOCK. I.e., it was changed so that non-blocking reads *won't* force a buffer rotation; the comment for 1.72 is Fix bug: a read() on a bpf device which was in non-blocking mode and had no data available returned 0. Now it returns -1 with errno set to EWOULDBLOCK (== EAGAIN) as it should. This fix makes the bpf device usable in threaded programs. (It didn't make it usable, as far as I know, because the "select()"/"poll()" behavior also had to be fixed.) I don't know whether there's a PR for that bug or not. I have vague memories of seeing the problem reported, but it might've been in one of the mailing lists. I don't remember what the symptoms were, but it *might* mean that making non-blocking reads always rotate the buffers might cause a regression. Unfortunately, having non-blocking reads not force a buffer rotation means that the workaround for the BPF "select()"/"poll()" will, I think, not work - and it's not obvious how to make it work. (This means that if I make Ethereal register the pcap_t descriptor in the GTK+ main loop, and have the main loop wait both for UI events and packet arrival, that probably won't work on FreeBSD 4.4....)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20031106003848.F331>