Introduce new sysctl variable: net.bpf.stats. This sysctl variable can
be used to pass statistics regarding dropped, matched and received packet counts from the kernel to user-space. While we are here introduce a new counter for filtered or matched packets. We currently keep track of packets received or dropped by the bpf device, but not how many packets actually matched the bpf filter. -Introduce net.bpf.stats sysctl OID -Move sysctl variables after the function prototypes so we can reference bpf_stats_sysctl(9) without build errors. -Introduce bpf descriptor counter which is used mainly for sizing of the xbpf_d array. -Introduce a xbpf_d structure which will act as an external representation of the bpf_d structure. -Add a the following members to the bpfd structure: bd_fcount - Number of packets which matched bpf filter bd_pid - PID which opened the bpf device bd_pcomm - Process name which opened the device. It should be noted that it's possible that the process which opened the device could be long gone at the time of stats collection. An example might be a process that opens the bpf device forks then exits leaving the child process with the bpf fd. Reviewed by: mdodd
This commit is contained in:
parent
d48c77b534
commit
69f7644bc9
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=148366
105
sys/net/bpf.c
105
sys/net/bpf.c
@ -78,20 +78,6 @@ static MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
|
||||
|
||||
#define PRINET 26 /* interruptible */
|
||||
|
||||
/*
|
||||
* The default read buffer size is patchable.
|
||||
*/
|
||||
SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl");
|
||||
static int bpf_bufsize = 4096;
|
||||
SYSCTL_INT(_net_bpf, OID_AUTO, bufsize, CTLFLAG_RW,
|
||||
&bpf_bufsize, 0, "");
|
||||
static int bpf_maxbufsize = BPF_MAXBUFSIZE;
|
||||
SYSCTL_INT(_net_bpf, OID_AUTO, maxbufsize, CTLFLAG_RW,
|
||||
&bpf_maxbufsize, 0, "");
|
||||
static int bpf_maxinsns = BPF_MAXINSNS;
|
||||
SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW,
|
||||
&bpf_maxinsns, 0, "Maximum bpf program instructions");
|
||||
|
||||
/*
|
||||
* bpf_iflist is a list of BPF interface structures, each corresponding to a
|
||||
* specific DLT. The same network interface might have several BPF interface
|
||||
@ -100,6 +86,7 @@ SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW,
|
||||
*/
|
||||
static LIST_HEAD(, bpf_if) bpf_iflist;
|
||||
static struct mtx bpf_mtx; /* bpf global lock */
|
||||
static int bpf_bpfd_cnt;
|
||||
|
||||
static int bpf_allocbufs(struct bpf_d *);
|
||||
static void bpf_attachd(struct bpf_d *d, struct bpf_if *bp);
|
||||
@ -122,6 +109,23 @@ static void filt_bpfdetach(struct knote *);
|
||||
static int filt_bpfread(struct knote *, long);
|
||||
static void bpf_drvinit(void *);
|
||||
static void bpf_clone(void *, char *, int, struct cdev **);
|
||||
static int bpf_stats_sysctl(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
/*
|
||||
* The default read buffer size is patchable.
|
||||
*/
|
||||
SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl");
|
||||
static int bpf_bufsize = 4096;
|
||||
SYSCTL_INT(_net_bpf, OID_AUTO, bufsize, CTLFLAG_RW,
|
||||
&bpf_bufsize, 0, "");
|
||||
static int bpf_maxbufsize = BPF_MAXBUFSIZE;
|
||||
SYSCTL_INT(_net_bpf, OID_AUTO, maxbufsize, CTLFLAG_RW,
|
||||
&bpf_maxbufsize, 0, "");
|
||||
static int bpf_maxinsns = BPF_MAXINSNS;
|
||||
SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW,
|
||||
&bpf_maxinsns, 0, "Maximum bpf program instructions");
|
||||
SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_RW,
|
||||
bpf_stats_sysctl, "bpf statistics portal");
|
||||
|
||||
static d_open_t bpfopen;
|
||||
static d_close_t bpfclose;
|
||||
@ -279,6 +283,7 @@ bpf_attachd(d, bp)
|
||||
d->bd_bif = bp;
|
||||
LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next);
|
||||
|
||||
bpf_bpfd_cnt++;
|
||||
*bp->bif_driverp = bp;
|
||||
BPFIF_UNLOCK(bp);
|
||||
}
|
||||
@ -304,6 +309,7 @@ bpf_detachd(d)
|
||||
*/
|
||||
LIST_REMOVE(d, bd_next);
|
||||
|
||||
bpf_bpfd_cnt--;
|
||||
/*
|
||||
* Let the driver know that there are no more listeners.
|
||||
*/
|
||||
@ -369,6 +375,8 @@ bpfopen(dev, flags, fmt, td)
|
||||
d->bd_bufsize = bpf_bufsize;
|
||||
d->bd_sig = SIGIO;
|
||||
d->bd_seesent = 1;
|
||||
d->bd_pid = td->td_proc->p_pid;
|
||||
strlcpy(d->bd_pcomm, td->td_proc->p_comm, MAXCOMLEN);
|
||||
#ifdef MAC
|
||||
mac_init_bpfdesc(d);
|
||||
mac_create_bpfdesc(td->td_ucred, d);
|
||||
@ -634,6 +642,7 @@ reset_d(d)
|
||||
d->bd_hlen = 0;
|
||||
d->bd_rcount = 0;
|
||||
d->bd_dcount = 0;
|
||||
d->bd_fcount = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1178,6 +1187,7 @@ bpf_tap(bp, pkt, pktlen)
|
||||
++d->bd_rcount;
|
||||
slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen);
|
||||
if (slen != 0) {
|
||||
d->bd_fcount++;
|
||||
#ifdef MAC
|
||||
if (mac_check_bpfdesc_receive(d, bp->bif_ifp) == 0)
|
||||
#endif
|
||||
@ -1247,6 +1257,7 @@ bpf_mtap(bp, m)
|
||||
++d->bd_rcount;
|
||||
slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0);
|
||||
if (slen != 0)
|
||||
d->bd_fcount++;
|
||||
#ifdef MAC
|
||||
if (mac_check_bpfdesc_receive(d, bp->bif_ifp) == 0)
|
||||
#endif
|
||||
@ -1298,6 +1309,7 @@ bpf_mtap2(bp, data, dlen, m)
|
||||
++d->bd_rcount;
|
||||
slen = bpf_filter(d->bd_filter, (u_char *)&mb, pktlen, 0);
|
||||
if (slen != 0)
|
||||
d->bd_fcount++;
|
||||
#ifdef MAC
|
||||
if (mac_check_bpfdesc_receive(d, bp->bif_ifp) == 0)
|
||||
#endif
|
||||
@ -1631,6 +1643,71 @@ bpf_drvinit(unused)
|
||||
EVENTHANDLER_REGISTER(dev_clone, bpf_clone, 0, 1000);
|
||||
}
|
||||
|
||||
static void
|
||||
bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd)
|
||||
{
|
||||
|
||||
bzero(d, sizeof(*d));
|
||||
BPFD_LOCK_ASSERT(bd);
|
||||
d->bd_immediate = bd->bd_immediate;
|
||||
d->bd_promisc = bd->bd_promisc;
|
||||
d->bd_hdrcmplt = bd->bd_hdrcmplt;
|
||||
d->bd_seesent = bd->bd_seesent;
|
||||
d->bd_async = bd->bd_async;
|
||||
d->bd_rcount = bd->bd_rcount;
|
||||
d->bd_dcount = bd->bd_dcount;
|
||||
d->bd_fcount = bd->bd_fcount;
|
||||
d->bd_sig = bd->bd_sig;
|
||||
d->bd_slen = bd->bd_slen;
|
||||
d->bd_hlen = bd->bd_hlen;
|
||||
d->bd_bufsize = bd->bd_bufsize;
|
||||
d->bd_pid = bd->bd_pid;
|
||||
strlcpy(d->bd_ifname,
|
||||
bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ);
|
||||
strlcpy(d->bd_pcomm, bd->bd_pcomm, MAXCOMLEN);
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_stats_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct xbpf_d xbd;
|
||||
int error;
|
||||
struct bpf_if *bp;
|
||||
struct bpf_d *bd;
|
||||
|
||||
/*
|
||||
* XXX This is not technically correct. It is possible for non
|
||||
* privileged users to open bpf devices. It would make sense
|
||||
* if the users who opened the devices were able to retrieve
|
||||
* the statistics for them, too.
|
||||
*/
|
||||
error = suser(req->td);
|
||||
if (error)
|
||||
return (error);
|
||||
if (req->oldptr == NULL)
|
||||
return (SYSCTL_OUT(req, 0, bpf_bpfd_cnt * sizeof(xbd)));
|
||||
if (req->oldlen < bpf_bpfd_cnt * sizeof(xbd))
|
||||
return (ENOMEM);
|
||||
if (bpf_bpfd_cnt == 0)
|
||||
return (SYSCTL_OUT(req, 0, 0));
|
||||
mtx_lock(&bpf_mtx);
|
||||
KASSERT(bpf_bpfd_cnt != 0, ("zero bpf descriptors present"));
|
||||
LIST_FOREACH(bp, &bpf_iflist, bif_next) {
|
||||
LIST_FOREACH(bd, &bp->bif_dlist, bd_next) {
|
||||
BPFD_LOCK(bd);
|
||||
bpfstats_fill_xbpf(&xbd, bd);
|
||||
BPFD_UNLOCK(bd);
|
||||
error = SYSCTL_OUT(req, &xbd, sizeof(xbd));
|
||||
if (error != 0) {
|
||||
mtx_unlock(&bpf_mtx);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
mtx_unlock(&bpf_mtx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,bpf_drvinit,NULL)
|
||||
|
||||
#else /* !DEV_BPF && !NETGRAPH_BPF */
|
||||
|
@ -42,6 +42,8 @@
|
||||
#include <sys/callout.h>
|
||||
#include <sys/selinfo.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/conf.h>
|
||||
#include <net/if.h>
|
||||
|
||||
/*
|
||||
* Descriptor associated with each open bpf file.
|
||||
@ -90,6 +92,9 @@ struct bpf_d {
|
||||
struct mtx bd_mtx; /* mutex for this descriptor */
|
||||
struct callout bd_callout; /* for BPF timeouts with select */
|
||||
struct label *bd_label; /* MAC label for descriptor */
|
||||
u_long bd_fcount; /* number of packets which matched filter */
|
||||
pid_t bd_pid; /* PID which created descriptor */
|
||||
char bd_pcomm[MAXCOMLEN + 1];
|
||||
};
|
||||
|
||||
/* Values for bd_state */
|
||||
@ -123,6 +128,27 @@ struct bpf_if {
|
||||
struct mtx bif_mtx; /* mutex for interface */
|
||||
};
|
||||
|
||||
/*
|
||||
* External representation of the bpf descriptor
|
||||
*/
|
||||
struct xbpf_d {
|
||||
u_char bd_promisc;
|
||||
u_char bd_immediate;
|
||||
int bd_hdrcmplt;
|
||||
int bd_seesent;
|
||||
int bd_async;
|
||||
u_long bd_rcount;
|
||||
u_long bd_dcount;
|
||||
u_long bd_fcount;
|
||||
int bd_sig;
|
||||
int bd_slen;
|
||||
int bd_hlen;
|
||||
int bd_bufsize;
|
||||
pid_t bd_pid;
|
||||
char bd_ifname[IFNAMSIZ];
|
||||
char bd_pcomm[MAXCOMLEN + 1];
|
||||
};
|
||||
|
||||
#define BPFIF_LOCK(bif) mtx_lock(&(bif)->bif_mtx)
|
||||
#define BPFIF_UNLOCK(bif) mtx_unlock(&(bif)->bif_mtx)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user