Implemented the kernel part of BPF statistics and BPF peers, net.bpf.stats
and net.bpf.peers sysctls respectively. A new structure was added to describe the external (user viewable) representation of a BPF file; a new entry was added to the bpf_d structure to store the PID of the calling process; a simple_lock was added to protect the insert/removal from the net.bpf.peers sysctl handler. This idea came from FreeBSD (Christian S.J. Peron) but while it is implemented with sysctl's it differs a bit. Reviewed by: christos@ and atatat@ (who gave me the tip for the net.bpf.peers sysctl helper function).
This commit is contained in:
parent
ff4290fdee
commit
2fcfc4c276
136
sys/net/bpf.c
136
sys/net/bpf.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: bpf.c,v 1.109 2005/06/22 10:36:16 peter Exp $ */
|
||||
/* $NetBSD: bpf.c,v 1.110 2005/08/04 19:30:47 rpaulo Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1991, 1993
|
||||
|
@ -39,7 +39,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.109 2005/06/22 10:36:16 peter Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.110 2005/08/04 19:30:47 rpaulo Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -101,6 +101,18 @@ __KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.109 2005/06/22 10:36:16 peter Exp $");
|
|||
int bpf_bufsize = BPF_BUFSIZE;
|
||||
int bpf_maxbufsize = BPF_DFLTBUFSIZE; /* XXX set dynamically, see above */
|
||||
|
||||
|
||||
/*
|
||||
* Global BPF statistics returned by net.bpf.stats sysctl.
|
||||
*/
|
||||
struct bpf_stat bpf_gstats;
|
||||
|
||||
/*
|
||||
* Use a mutex to avoid a race condition between gathering the stats/peers
|
||||
* and opening/closing the device.
|
||||
*/
|
||||
struct simplelock bpf_slock;
|
||||
|
||||
/*
|
||||
* bpf_iflist is the list of interfaces; each corresponds to an ifnet
|
||||
* bpf_dtab holds the descriptors, indexed by minor device #
|
||||
|
@ -362,7 +374,15 @@ void
|
|||
bpfilterattach(n)
|
||||
int n;
|
||||
{
|
||||
simple_lock_init(&bpf_slock);
|
||||
|
||||
simple_lock(&bpf_slock);
|
||||
LIST_INIT(&bpf_list);
|
||||
simple_unlock(&bpf_slock);
|
||||
|
||||
bpf_gstats.bs_recv = 0;
|
||||
bpf_gstats.bs_drop = 0;
|
||||
bpf_gstats.bs_capt = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -388,9 +408,12 @@ bpfopen(dev, flag, mode, p)
|
|||
(void)memset(d, 0, sizeof(*d));
|
||||
d->bd_bufsize = bpf_bufsize;
|
||||
d->bd_seesent = 1;
|
||||
d->bd_pid = p->p_pid;
|
||||
callout_init(&d->bd_callout);
|
||||
|
||||
simple_lock(&bpf_slock);
|
||||
LIST_INSERT_HEAD(&bpf_list, d, bd_list);
|
||||
simple_unlock(&bpf_slock);
|
||||
|
||||
return fdclone(p, fp, fd, flag, &bpf_fileops, d);
|
||||
}
|
||||
|
@ -406,6 +429,11 @@ bpf_close(struct file *fp, struct proc *p)
|
|||
struct bpf_d *d = fp->f_data;
|
||||
int s;
|
||||
|
||||
/*
|
||||
* Refresh the PID associated with this bpf file.
|
||||
*/
|
||||
d->bd_pid = p->p_pid;
|
||||
|
||||
s = splnet();
|
||||
if (d->bd_state == BPF_WAITING)
|
||||
callout_stop(&d->bd_callout);
|
||||
|
@ -414,7 +442,9 @@ bpf_close(struct file *fp, struct proc *p)
|
|||
bpf_detachd(d);
|
||||
splx(s);
|
||||
bpf_freed(d);
|
||||
simple_lock(&bpf_slock);
|
||||
LIST_REMOVE(d, bd_list);
|
||||
simple_unlock(&bpf_slock);
|
||||
free(d, M_DEVBUF);
|
||||
fp->f_data = NULL;
|
||||
|
||||
|
@ -658,6 +688,11 @@ bpf_ioctl(struct file *fp, u_long cmd, void *addr, struct proc *p)
|
|||
struct bpf_insn **p;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Refresh the PID associated with this bpf file.
|
||||
*/
|
||||
d->bd_pid = p->p_pid;
|
||||
|
||||
s = splnet();
|
||||
if (d->bd_state == BPF_WAITING)
|
||||
callout_stop(&d->bd_callout);
|
||||
|
@ -1079,6 +1114,11 @@ bpf_poll(struct file *fp, int events, struct proc *p)
|
|||
int s = splnet();
|
||||
int revents;
|
||||
|
||||
/*
|
||||
* Refresh the PID associated with this bpf file.
|
||||
*/
|
||||
d->bd_pid = p->p_pid;
|
||||
|
||||
revents = events & (POLLOUT | POLLWRNORM);
|
||||
if (events & (POLLIN | POLLRDNORM)) {
|
||||
/*
|
||||
|
@ -1178,6 +1218,7 @@ bpf_tap(void *arg, u_char *pkt, u_int pktlen)
|
|||
bp = arg;
|
||||
for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
|
||||
++d->bd_rcount;
|
||||
++bpf_gstats.bs_recv;
|
||||
slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen);
|
||||
if (slen != 0)
|
||||
catchpacket(d, pkt, pktlen, slen, memcpy);
|
||||
|
@ -1229,6 +1270,7 @@ bpf_deliver(struct bpf_if *bp, void *(*cpfn)(void *, const void *, size_t),
|
|||
if (!d->bd_seesent && (rcvif == NULL))
|
||||
continue;
|
||||
++d->bd_rcount;
|
||||
++bpf_gstats.bs_recv;
|
||||
slen = bpf_filter(d->bd_filter, marg, pktlen, buflen);
|
||||
if (slen != 0)
|
||||
catchpacket(d, marg, pktlen, slen, cpfn);
|
||||
|
@ -1399,6 +1441,7 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
|
|||
int hdrlen = d->bd_bif->bif_hdrlen;
|
||||
|
||||
++d->bd_ccount;
|
||||
++bpf_gstats.bs_capt;
|
||||
/*
|
||||
* Figure out how many bytes to move. If the packet is
|
||||
* greater or equal to the snapshot length, transfer that
|
||||
|
@ -1425,6 +1468,7 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
|
|||
* so drop the packet.
|
||||
*/
|
||||
++d->bd_dcount;
|
||||
++bpf_gstats.bs_drop;
|
||||
return;
|
||||
}
|
||||
ROTATE_BUFFERS(d);
|
||||
|
@ -1694,7 +1738,77 @@ sysctl_net_bpf_maxbufsize(SYSCTLFN_ARGS)
|
|||
return (0);
|
||||
}
|
||||
|
||||
SYSCTL_SETUP(sysctl_net_bfp_setup, "sysctl net.bpf subtree setup")
|
||||
static int
|
||||
sysctl_net_bpf_peers(SYSCTLFN_ARGS)
|
||||
{
|
||||
int error, elem_count;
|
||||
struct bpf_d *dp;
|
||||
struct bpf_d_ext dpe;
|
||||
size_t len, needed, elem_size, out_size;
|
||||
char *sp;
|
||||
|
||||
if (namelen == 1 && name[0] == CTL_QUERY)
|
||||
return (sysctl_query(SYSCTLFN_CALL(rnode)));
|
||||
|
||||
if (namelen != 2)
|
||||
return (EINVAL);
|
||||
|
||||
if ((error = suser(l->l_proc->p_ucred, &l->l_proc->p_acflag)))
|
||||
return (error);
|
||||
|
||||
len = (oldp != NULL) ? *oldlenp : 0;
|
||||
sp = oldp;
|
||||
elem_size = name[0];
|
||||
elem_count = name[1];
|
||||
out_size = MIN(sizeof(dpe), elem_size);
|
||||
needed = 0;
|
||||
|
||||
if (elem_size < 1 || elem_count < 0)
|
||||
return (EINVAL);
|
||||
|
||||
simple_lock(&bpf_slock);
|
||||
LIST_FOREACH(dp, &bpf_list, bd_list) {
|
||||
if (len >= elem_size && elem_count > 0) {
|
||||
#define BPF_EXT(field) dpe.bde_ ## field = dp->bd_ ## field
|
||||
BPF_EXT(bufsize);
|
||||
BPF_EXT(promisc);
|
||||
BPF_EXT(promisc);
|
||||
BPF_EXT(state);
|
||||
BPF_EXT(immediate);
|
||||
BPF_EXT(hdrcmplt);
|
||||
BPF_EXT(seesent);
|
||||
BPF_EXT(pid);
|
||||
BPF_EXT(rcount);
|
||||
BPF_EXT(dcount);
|
||||
BPF_EXT(ccount);
|
||||
#undef BPF_EXT
|
||||
if (dp->bd_bif)
|
||||
(void)strlcpy(dpe.bde_ifname,
|
||||
dp->bd_bif->bif_ifp->if_xname,
|
||||
IFNAMSIZ - 1);
|
||||
else
|
||||
dpe.bde_ifname[0] = '\0';
|
||||
|
||||
error = copyout(&dpe, sp, out_size);
|
||||
if (error)
|
||||
break;
|
||||
sp += elem_size;
|
||||
len -= elem_size;
|
||||
}
|
||||
if (elem_count > 0) {
|
||||
needed += elem_size;
|
||||
if (elem_count != INT_MAX)
|
||||
elem_count--;
|
||||
}
|
||||
}
|
||||
simple_unlock(&bpf_slock);
|
||||
|
||||
*oldlenp = needed;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSCTL_SETUP(sysctl_net_bpf_setup, "sysctl net.bpf subtree setup")
|
||||
{
|
||||
const struct sysctlnode *node;
|
||||
|
||||
|
@ -1711,11 +1825,25 @@ SYSCTL_SETUP(sysctl_net_bfp_setup, "sysctl net.bpf subtree setup")
|
|||
SYSCTL_DESCR("BPF options"),
|
||||
NULL, 0, NULL, 0,
|
||||
CTL_NET, CTL_CREATE, CTL_EOL);
|
||||
if (node != NULL)
|
||||
if (node != NULL) {
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "maxbufsize",
|
||||
SYSCTL_DESCR("Maximum size for data capture buffer"),
|
||||
sysctl_net_bpf_maxbufsize, 0, &bpf_maxbufsize, 0,
|
||||
CTL_NET, node->sysctl_num, CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_STRUCT, "stats",
|
||||
SYSCTL_DESCR("BPF stats"),
|
||||
NULL, 0, &bpf_gstats, sizeof(bpf_gstats),
|
||||
CTL_NET, node->sysctl_num, CTL_CREATE, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
CTLTYPE_STRUCT, "peers",
|
||||
SYSCTL_DESCR("BPF peers"),
|
||||
sysctl_net_bpf_peers, 0, NULL, 0,
|
||||
CTL_NET, node->sysctl_num, CTL_CREATE, CTL_EOL);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: bpf.h,v 1.42 2005/02/26 22:45:09 perry Exp $ */
|
||||
/* $NetBSD: bpf.h,v 1.43 2005/08/04 19:30:47 rpaulo Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1991, 1993
|
||||
|
@ -69,7 +69,7 @@ struct bpf_program {
|
|||
};
|
||||
|
||||
/*
|
||||
* Struct returned by BIOCGSTATS.
|
||||
* Struct returned by BIOCGSTATS and net.bpf.stats sysctl.
|
||||
*/
|
||||
struct bpf_stat {
|
||||
u_int64_t bs_recv; /* number of packets received */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: bpfdesc.h,v 1.22 2005/03/17 20:39:17 kleink Exp $ */
|
||||
/* $NetBSD: bpfdesc.h,v 1.23 2005/08/04 19:30:47 rpaulo Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1991, 1993
|
||||
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include <sys/callout.h>
|
||||
#include <sys/selinfo.h> /* for struct selinfo */
|
||||
#include <net/if.h> /* for IFNAMSIZ */
|
||||
|
||||
/*
|
||||
* Descriptor associated with each open bpf file.
|
||||
|
@ -89,6 +90,7 @@ struct bpf_d {
|
|||
struct selinfo bd_sel; /* bsd select info */
|
||||
#endif
|
||||
struct callout bd_callout; /* for BPF timeouts with select */
|
||||
pid_t bd_pid; /* corresponding PID */
|
||||
LIST_ENTRY(bpf_d) bd_list; /* list of all BPF's */
|
||||
};
|
||||
|
||||
|
@ -98,6 +100,25 @@ struct bpf_d {
|
|||
#define BPF_WAITING 1 /* waiting for read timeout in select */
|
||||
#define BPF_TIMED_OUT 2 /* read timeout has expired in select */
|
||||
|
||||
/*
|
||||
* Description associated with the external representation of each
|
||||
* open bpf file.
|
||||
*/
|
||||
struct bpf_d_ext {
|
||||
int32_t bde_bufsize;
|
||||
u_int8_t bde_promisc;
|
||||
u_int8_t bde_state;
|
||||
u_int8_t bde_immediate;
|
||||
int32_t bde_hdrcmplt;
|
||||
int32_t bde_seesent;
|
||||
pid_t bde_pid;
|
||||
u_int64_t bde_rcount; /* number of packets received */
|
||||
u_int64_t bde_dcount; /* number of packets dropped */
|
||||
u_int64_t bde_ccount; /* number of packets captured */
|
||||
char bde_ifname[IFNAMSIZ];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Descriptor associated with each attached hardware interface.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue