FreeBSD bpf bug
Peter Van Epp
vanepp at sfu.ca
Mon Oct 16 12:48:54 EDT 2000
With advise on how things should work from Carter I've found
corrected (perhaps even properly :-)) a bug in FreeBSD's (and OpenBSD's)
kernel bpf code. For small packet bursts (9 packets in the case I was testing)
bpf isn't passing the data up to libpcap on timeout (Solaris for instance
does). OpenBSD fixed part of the problem (so I shamelessly stole their fix
an put it in FreeBSD) but the fix is flawed in that it only got the first of
the 8 packets up correctly. I have changed the timeout logic so that it will
flush the buffers on a timeout and tested it on the test code and with tcpdump
(both only once so you've been warned :-)). Now I'll submit this to the
FreeBSD hackers list and see if anyone sees a problem I haven't considered,
and then file a PR with both FreeBSD and OpenBSD to see if I can get the fix
committed. To reproduce this you need either tcpreplay (what I used) and a
small capture file or to do something that creates a small number of packets
(then no more) on a link. Before the patch argus (1.8.1 or 2.0) won't see
any packets. After the patch argus should see the packets (and hopefully
nothing else should break :-)).
You need to apply these two patches then rebuild and install a new
kernel.
Peter Van Epp / Operations and Technical Support
Simon Fraser University, Burnaby, B.C. Canada
*** /sys/net/bpfdesc.h.orig Sat Oct 14 19:16:07 2000
--- /sys/net/bpfdesc.h Sat Oct 14 19:21:54 2000
***************
*** 69,74 ****
--- 69,75 ----
struct bpf_if * bd_bif; /* interface descriptor */
u_long bd_rtout; /* Read timeout in 'ticks' */
+ u_long bd_rdStart; /* when the read started */
struct bpf_insn *bd_filter; /* filter code */
u_long bd_rcount; /* number of packets received */
u_long bd_dcount; /* number of packets dropped */
*** /sys/net/bpf.c.orig Sat Oct 14 19:00:59 2000
--- /sys/net/bpf.c Mon Oct 16 09:30:24 2000
***************
*** 1054,1061 ****
if (events & (POLLIN | POLLRDNORM)) {
if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0))
revents |= events & (POLLIN | POLLRDNORM);
! else
! selrecord(p, &d->bd_sel);
}
splx(s);
return (revents);
--- 1054,1076 ----
if (events & (POLLIN | POLLRDNORM)) {
if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0))
revents |= events & (POLLIN | POLLRDNORM);
! else {
! /*
! * If there is a timeout and no data in the hold buffer
! * see if there has been data in the capture buffer
! * for more than a timeout interval. If so rotate the
! * buffer to push the packets to the user.
! */
! if ((d->bd_slen != 0) && (d->bd_hlen == 0)) {
! if ((d->bd_rtout != -1) &&
! (d->bd_rdStart + d->bd_rtout) > ticks) {
! ROTATE_BUFFERS(d);
! revents |= events & (POLLIN | POLLRDNORM);
! }
! } else
! selrecord(p, &d->bd_sel);
!
! }
}
splx(s);
return (revents);
***************
*** 1219,1224 ****
--- 1234,1245 ----
*/
(*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen));
d->bd_slen = curlen + totlen;
+
+ /*
+ * Mark the time the last packet was seen for poll timeout processing.
+ */
+
+ d->bd_rdStart = ticks;
}
/*
More information about the argus
mailing list