diff --git a/sys/net/bpf.c b/sys/net/bpf.c index f1a106a58bf8..c647b12de9be 100644 --- a/sys/net/bpf.c +++ b/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 -__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 #include @@ -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); + } + } diff --git a/sys/net/bpf.h b/sys/net/bpf.h index ece4b65f5aa9..84012c4c7392 100644 --- a/sys/net/bpf.h +++ b/sys/net/bpf.h @@ -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 */ diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h index 7bd49be229b1..2374334d8a5b 100644 --- a/sys/net/bpfdesc.h +++ b/sys/net/bpfdesc.h @@ -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 #include /* for struct selinfo */ +#include /* 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. */