add support for using kqueue to watch bpf sockets.

Submitted by:	Brian Buchanan of nCircle, Inc.
Tested on:	i386 and sparc64
This commit is contained in:
John-Mark Gurney 2003-08-05 07:12:49 +00:00
parent e04e4bacf6
commit 95aab9cc49
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=118471
3 changed files with 85 additions and 10 deletions

View File

@ -265,6 +265,13 @@ When the last writer disconnects, the filter will set EV_EOF in
This may be cleared by passing in EV_CLEAR, at which point the
filter will resume waiting for data to become available before
returning.
.It "BPF devices"
Returns when the BPF buffer is full, the BPF timeout has expired, or
when the BPF has
.Dq immediate mode
enabled and there is any data to read;
.Va data
contains the number of bytes available.
.El
.It EVFILT_WRITE
Takes a descriptor as the identifier, and returns whenever
@ -274,7 +281,7 @@ and fifos,
will contain the amount of space remaining in the write buffer.
The filter will set EV_EOF when the reader disconnects, and for
the fifo case, this may be cleared by use of EV_CLEAR.
Note that this filter is not supported for vnodes.
Note that this filter is not supported for vnodes or BPF devices.
.Pp
For sockets, the low water mark and socket error handling is
identical to the EVFILT_READ case.

View File

@ -44,6 +44,7 @@
#include "opt_mac.h"
#include "opt_netgraph.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
@ -58,7 +59,10 @@
#include <sys/ttycom.h>
#include <sys/filedesc.h>
#include <sys/event.h>
#include <sys/file.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/vnode.h>
@ -111,6 +115,8 @@ static void reset_d(struct bpf_d *);
static int bpf_setf(struct bpf_d *, struct bpf_program *);
static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *);
static int bpf_setdlt(struct bpf_d *, u_int);
static void filt_bpfdetach(struct knote *);
static int filt_bpfread(struct knote *, long);
static d_open_t bpfopen;
static d_close_t bpfclose;
@ -118,6 +124,7 @@ static d_read_t bpfread;
static d_write_t bpfwrite;
static d_ioctl_t bpfioctl;
static d_poll_t bpfpoll;
static d_kqfilter_t bpfkqfilter;
#define CDEV_MAJOR 23
static struct cdevsw bpf_cdevsw = {
@ -129,8 +136,11 @@ static struct cdevsw bpf_cdevsw = {
.d_poll = bpfpoll,
.d_name = "bpf",
.d_maj = CDEV_MAJOR,
.d_kqfilter = bpfkqfilter,
};
static struct filterops bpfread_filtops =
{ 1, NULL, filt_bpfdetach, filt_bpfread };
static int
bpf_movein(uio, linktype, mp, sockp, datlen)
@ -518,6 +528,7 @@ bpf_wakeup(d)
pgsigio(&d->bd_sigio, d->bd_sig, 0);
selwakeup(&d->bd_sel);
KNOTE(&d->bd_sel.si_note, 0);
}
static void
@ -1046,15 +1057,7 @@ bpfpoll(dev, events, td)
revents = events & (POLLOUT | POLLWRNORM);
BPFD_LOCK(d);
if (events & (POLLIN | POLLRDNORM)) {
/*
* An imitation of the FIONREAD ioctl code.
* XXX not quite. An exact imitation:
* if (d->b_slen != 0 ||
* (d->bd_hbuf != NULL && d->bd_hlen != 0)
*/
if (d->bd_hlen != 0 ||
((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) &&
d->bd_slen != 0))
if (bpf_ready(d))
revents |= events & (POLLIN | POLLRDNORM);
else {
selrecord(td, &d->bd_sel);
@ -1070,6 +1073,65 @@ bpfpoll(dev, events, td)
return (revents);
}
/*
* Support for kevent() system call. Register EVFILT_READ filters and
* reject all others.
*/
int
bpfkqfilter(dev, kn)
dev_t dev;
struct knote *kn;
{
struct bpf_d *d = (struct bpf_d *)dev->si_drv1;
if (kn->kn_filter != EVFILT_READ)
return (1);
kn->kn_fop = &bpfread_filtops;
kn->kn_hook = d;
BPFD_LOCK(d);
SLIST_INSERT_HEAD(&d->bd_sel.si_note, kn, kn_selnext);
BPFD_UNLOCK(d);
return (0);
}
static void
filt_bpfdetach(kn)
struct knote *kn;
{
struct bpf_d *d = (struct bpf_d *)kn->kn_hook;
BPFD_LOCK(d);
SLIST_REMOVE(&d->bd_sel.si_note, kn, knote, kn_selnext);
BPFD_UNLOCK(d);
}
static int
filt_bpfread(kn, hint)
struct knote *kn;
long hint;
{
struct bpf_d *d = (struct bpf_d *)kn->kn_hook;
int ready;
BPFD_LOCK(d);
ready = bpf_ready(d);
if (ready) {
kn->kn_data = d->bd_slen;
if (d->bd_hbuf)
kn->kn_data += d->bd_hlen;
}
else if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) {
callout_reset(&d->bd_callout, d->bd_rtout,
bpf_timed_out, d);
d->bd_state = BPF_WAITING;
}
BPFD_UNLOCK(d);
return (ready);
}
/*
* Incoming linkage from device drivers. Process the packet pkt, of length
* pktlen, which is stored in a contiguous buffer. The packet is parsed

View File

@ -104,6 +104,12 @@ struct bpf_d {
#define BPFD_LOCK(bd) mtx_lock(&(bd)->bd_mtx)
#define BPFD_UNLOCK(bd) mtx_unlock(&(bd)->bd_mtx)
/* Test whether a BPF is ready for read(). */
#define bpf_ready(bd) \
((bd)->bd_hlen != 0 || \
(((bd)->bd_immediate || (bd)->bd_state == BPF_TIMED_OUT) && \
(bd)->bd_slen != 0))
/*
* Descriptor associated with each attached hardware interface.
*/