summaryrefslogtreecommitdiffstats
path: root/sys/net/bpf.c
diff options
context:
space:
mode:
authorcsjp <csjp@FreeBSD.org>2005-07-24 17:21:17 +0000
committercsjp <csjp@FreeBSD.org>2005-07-24 17:21:17 +0000
commitb29c8f5d6430823b9692023da05b35945fbccb4e (patch)
tree05d4cf85788e8c758f3cdeec57f208c3601572dd /sys/net/bpf.c
parentd5948017e9381368f9b2c698d387c982af9b4ffe (diff)
downloadFreeBSD-src-b29c8f5d6430823b9692023da05b35945fbccb4e.zip
FreeBSD-src-b29c8f5d6430823b9692023da05b35945fbccb4e.tar.gz
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
Diffstat (limited to 'sys/net/bpf.c')
-rw-r--r--sys/net/bpf.c105
1 files changed, 91 insertions, 14 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index e917866..e513570 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -79,20 +79,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
* structures registered by different layers in the stack (i.e., 802.11
@@ -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 */
OpenPOWER on IntegriCloud