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:
parent
e04e4bacf6
commit
95aab9cc49
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=118471
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user