bpf for subsystems, not just interfaces

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

bpf for subsystems, not just interfaces

David Gwynne-5
im sending this out more as a backup than a serious diff.

this tweaks bpf so it can be used by subsystems, not just interfaces.
this is done by making bpf store and use names (eg, "pf" and "em0")
instead of just interfaces. interfaces get some special handling
so you can't bpfwrite or enable ifpromisc unless bif_ifp is set.

an example use of this is attaching bpf to pf. you can see all the
packets handed to pf_test with this diff and tcpdump -ni pf.

Index: bpf.c
===================================================================
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.165
diff -u -p -r1.165 bpf.c
--- bpf.c 30 Dec 2017 23:08:29 -0000 1.165
+++ bpf.c 10 Jan 2018 07:27:45 -0000
@@ -93,7 +93,7 @@ struct bpf_if *bpf_iflist;
 LIST_HEAD(, bpf_d) bpf_d_list;
 
 int bpf_allocbufs(struct bpf_d *);
-void bpf_ifname(struct ifnet *, struct ifreq *);
+void bpf_ifname(struct bpf_if*, struct ifreq *);
 int _bpf_mtap(caddr_t, const struct mbuf *, u_int,
     void (*)(const void *, void *, size_t));
 void bpf_mcopy(const void *, void *, size_t);
@@ -320,6 +320,8 @@ bpf_detachd(struct bpf_d *d)
  if (d->bd_promisc) {
  int error;
 
+ KASSERT(bp->bif_ifp != NULL);
+
  d->bd_promisc = 0;
 
  bpf_get(d);
@@ -593,7 +595,7 @@ bpfwrite(dev_t dev, struct uio *uio, int
  bpf_get(d);
  ifp = d->bd_bif->bif_ifp;
 
- if ((ifp->if_flags & IFF_UP) == 0) {
+ if (ifp == NULL || (ifp->if_flags & IFF_UP) == 0) {
  error = ENETDOWN;
  goto out;
  }
@@ -789,7 +791,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
  * No interface attached yet.
  */
  error = EINVAL;
- } else {
+ } else if (d->bd_bif->bif_ifp != NULL) {
  if (d->bd_promisc == 0) {
  MUTEX_ASSERT_UNLOCKED(&d->bd_mtx);
  error = ifpromisc(d->bd_bif->bif_ifp, 1);
@@ -839,7 +841,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
  if (d->bd_bif == NULL)
  error = EINVAL;
  else
- bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
+ bpf_ifname(d->bd_bif, (struct ifreq *)addr);
  break;
 
  /*
@@ -1049,10 +1051,7 @@ bpf_setif(struct bpf_d *d, struct ifreq
  * Look through attached interfaces for the named one.
  */
  for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
- struct ifnet *ifp = bp->bif_ifp;
-
- if (ifp == NULL ||
-    strcmp(ifp->if_xname, ifr->ifr_name) != 0)
+ if (strcmp(bp->bif_name, ifr->ifr_name) != 0)
  continue;
 
  if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt)
@@ -1090,9 +1089,9 @@ out:
  * Copy the interface name to the ifreq.
  */
 void
-bpf_ifname(struct ifnet *ifp, struct ifreq *ifr)
+bpf_ifname(struct bpf_if *bif, struct ifreq *ifr)
 {
- bcopy(ifp->if_xname, ifr->ifr_name, IFNAMSIZ);
+ bcopy(bif->bif_name, ifr->ifr_name, sizeof(ifr->ifr_name));
 }
 
 /*
@@ -1538,21 +1537,17 @@ bpf_put(struct bpf_d *bd)
  free(bd, M_DEVBUF, sizeof(*bd));
 }
 
-/*
- * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
- * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
- * size of the link header (variable length headers not yet supported).
- */
-void
-bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
+void *
+bpfsattach(caddr_t *bpfp, const char *name, u_int dlt, u_int hdrlen)
 {
  struct bpf_if *bp;
 
  if ((bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT)) == NULL)
  panic("bpfattach");
  SRPL_INIT(&bp->bif_dlist);
- bp->bif_driverp = (struct bpf_if **)driverp;
- bp->bif_ifp = ifp;
+ bp->bif_driverp = (struct bpf_if **)bpfp;
+ bp->bif_name = name;
+ bp->bif_ifp = NULL;
  bp->bif_dlt = dlt;
 
  bp->bif_next = bpf_iflist;
@@ -1567,6 +1562,17 @@ bpfattach(caddr_t *driverp, struct ifnet
  * performance reasons and to alleviate alignment restrictions).
  */
  bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
+
+ return (bp);
+}
+
+void
+bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
+{
+ struct bpf_if *bp;
+
+ bp = bpfsattach(driverp, ifp->if_xname, dlt, hdrlen);
+ bp->bif_ifp = ifp;
 }
 
 /* Detach an interface from its attached bpf device.  */
@@ -1574,31 +1580,39 @@ void
 bpfdetach(struct ifnet *ifp)
 {
  struct bpf_if *bp, *nbp, **pbp = &bpf_iflist;
- struct bpf_d *bd;
- int maj;
 
  KERNEL_ASSERT_LOCKED();
 
  for (bp = bpf_iflist; bp; bp = nbp) {
- nbp= bp->bif_next;
+ nbp = bp->bif_next;
  if (bp->bif_ifp == ifp) {
  *pbp = nbp;
 
- /* Locate the major number. */
- for (maj = 0; maj < nchrdev; maj++)
- if (cdevsw[maj].d_open == bpfopen)
- break;
-
- while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
- vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
-
- free(bp, M_DEVBUF, sizeof *bp);
+ bpfsdetach(bp);
  } else
  pbp = &bp->bif_next;
  }
  ifp->if_bpf = NULL;
 }
 
+void
+bpfsdetach(void *p)
+{
+ struct bpf_if *bp = p;
+ struct bpf_d *bd;
+ int maj;
+
+ /* Locate the major number. */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == bpfopen)
+ break;
+
+ while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
+ vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
+
+ free(bp, M_DEVBUF, sizeof *bp);
+}
+
 int
 bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
     void *newp, size_t newlen)
@@ -1674,14 +1688,14 @@ int
 bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
 {
  int n, error;
- struct ifnet *ifp;
  struct bpf_if *bp;
+ const char *name;
 
- ifp = d->bd_bif->bif_ifp;
+ name = d->bd_bif->bif_name;
  n = 0;
  error = 0;
  for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
- if (bp->bif_ifp != ifp)
+ if (strcmp(name, bp->bif_name) != 0)
  continue;
  if (bfl->bfl_list != NULL) {
  if (n >= bfl->bfl_len)
@@ -1704,15 +1718,17 @@ bpf_getdltlist(struct bpf_d *d, struct b
 int
 bpf_setdlt(struct bpf_d *d, u_int dlt)
 {
- struct ifnet *ifp;
+ const char *name;
  struct bpf_if *bp;
 
  MUTEX_ASSERT_LOCKED(&d->bd_mtx);
  if (d->bd_bif->bif_dlt == dlt)
  return (0);
- ifp = d->bd_bif->bif_ifp;
+ name = d->bd_bif->bif_name;
  for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
- if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
+ if (strcmp(name, bp->bif_name) != 0)
+ continue;
+ if (bp->bif_dlt == dlt)
  break;
  }
  if (bp == NULL)
Index: bpf.h
===================================================================
RCS file: /cvs/src/sys/net/bpf.h,v
retrieving revision 1.62
diff -u -p -r1.62 bpf.h
--- bpf.h 22 Feb 2017 09:56:03 -0000 1.62
+++ bpf.h 10 Jan 2018 07:27:45 -0000
@@ -313,6 +313,8 @@ int bpf_mtap_af(caddr_t, u_int32_t, con
 int bpf_mtap_ether(caddr_t, const struct mbuf *, u_int);
 void bpfattach(caddr_t *, struct ifnet *, u_int, u_int);
 void bpfdetach(struct ifnet *);
+void *bpfsattach(caddr_t *, const char *, u_int, u_int);
+void bpfsdetach(void *);
 void bpfilterattach(int);
 
 u_int bpf_mfilter(const struct bpf_insn *, const struct mbuf *, u_int);
Index: bpfdesc.h
===================================================================
RCS file: /cvs/src/sys/net/bpfdesc.h,v
retrieving revision 1.35
diff -u -p -r1.35 bpfdesc.h
--- bpfdesc.h 24 Jan 2017 10:08:30 -0000 1.35
+++ bpfdesc.h 10 Jan 2018 07:27:45 -0000
@@ -103,6 +103,7 @@ struct bpf_if {
  struct bpf_if **bif_driverp; /* pointer into softc */
  u_int bif_dlt; /* link layer type */
  u_int bif_hdrlen; /* length of header (with padding) */
+ const char *bif_name; /* name of "subsystem" */
  struct ifnet *bif_ifp; /* corresponding interface */
 };
 
Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1054
diff -u -p -r1.1054 pf.c
--- pf.c 29 Dec 2017 23:55:22 -0000 1.1054
+++ pf.c 10 Jan 2018 07:27:45 -0000
@@ -104,6 +104,11 @@
 #include <ddb/db_interface.h>
 #endif
 
+#if NBPFILTER > 0
+#include <net/bpf.h>
+caddr_t pf_bpf;
+#endif
+
 /*
  * Global variables
  */
@@ -6719,6 +6724,11 @@ pf_test(sa_family_t af, int fwdir, struc
 
  if (!pf_status.running)
  return (PF_PASS);
+
+#if NBPFILTER > 0
+ if (pf_bpf)
+ bpf_mtap_af(pf_bpf, af, *m0, BPF_DIRECTION_IN);
+#endif
 
 #if NCARP > 0
  if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
Index: pf_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net/pf_ioctl.c,v
retrieving revision 1.326
diff -u -p -r1.326 pf_ioctl.c
--- pf_ioctl.c 28 Nov 2017 16:05:46 -0000 1.326
+++ pf_ioctl.c 10 Jan 2018 07:27:45 -0000
@@ -35,6 +35,7 @@
  *
  */
 
+#include "bpfilter.h"
 #include "pfsync.h"
 #include "pflog.h"
 
@@ -84,6 +85,11 @@
 #include <net/if_pfsync.h>
 #endif /* NPFSYNC > 0 */
 
+#if NBPFILTER > 0
+#include <net/bpf.h>
+extern caddr_t pf_bpf;
+#endif
+
 struct pool pf_tag_pl;
 
 void pfattach(int);
@@ -231,6 +237,10 @@ pfattach(int num)
 
  /* XXX do our best to avoid a conflict */
  pf_status.hostid = arc4random();
+
+#if NBPFILTER > 0
+ bpfsattach(&pf_bpf, "pf", DLT_LOOP, sizeof(u_int32_t));
+#endif
 }
 
 int

Reply | Threaded
Open this post in threaded view
|

Re: bpf for subsystems, not just interfaces

Martin Pieuchot
On 11/01/18(Thu) 11:58, David Gwynne wrote:
> im sending this out more as a backup than a serious diff.

I love this.  It's one of the steps to be able to use bpf(4) for USB.

Is there an easy way to also remove the mbuf requirement?  For example
I'd like to call bpf_mtap() or similar in usb_transfer_complete().

> this tweaks bpf so it can be used by subsystems, not just interfaces.
> this is done by making bpf store and use names (eg, "pf" and "em0")
> instead of just interfaces. interfaces get some special handling
> so you can't bpfwrite or enable ifpromisc unless bif_ifp is set.
>
> an example use of this is attaching bpf to pf. you can see all the
> packets handed to pf_test with this diff and tcpdump -ni pf.
>
> Index: bpf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/bpf.c,v
> retrieving revision 1.165
> diff -u -p -r1.165 bpf.c
> --- bpf.c 30 Dec 2017 23:08:29 -0000 1.165
> +++ bpf.c 10 Jan 2018 07:27:45 -0000
> @@ -93,7 +93,7 @@ struct bpf_if *bpf_iflist;
>  LIST_HEAD(, bpf_d) bpf_d_list;
>  
>  int bpf_allocbufs(struct bpf_d *);
> -void bpf_ifname(struct ifnet *, struct ifreq *);
> +void bpf_ifname(struct bpf_if*, struct ifreq *);
>  int _bpf_mtap(caddr_t, const struct mbuf *, u_int,
>      void (*)(const void *, void *, size_t));
>  void bpf_mcopy(const void *, void *, size_t);
> @@ -320,6 +320,8 @@ bpf_detachd(struct bpf_d *d)
>   if (d->bd_promisc) {
>   int error;
>  
> + KASSERT(bp->bif_ifp != NULL);
> +
>   d->bd_promisc = 0;
>  
>   bpf_get(d);
> @@ -593,7 +595,7 @@ bpfwrite(dev_t dev, struct uio *uio, int
>   bpf_get(d);
>   ifp = d->bd_bif->bif_ifp;
>  
> - if ((ifp->if_flags & IFF_UP) == 0) {
> + if (ifp == NULL || (ifp->if_flags & IFF_UP) == 0) {
>   error = ENETDOWN;
>   goto out;
>   }
> @@ -789,7 +791,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>   * No interface attached yet.
>   */
>   error = EINVAL;
> - } else {
> + } else if (d->bd_bif->bif_ifp != NULL) {
>   if (d->bd_promisc == 0) {
>   MUTEX_ASSERT_UNLOCKED(&d->bd_mtx);
>   error = ifpromisc(d->bd_bif->bif_ifp, 1);
> @@ -839,7 +841,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>   if (d->bd_bif == NULL)
>   error = EINVAL;
>   else
> - bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
> + bpf_ifname(d->bd_bif, (struct ifreq *)addr);
>   break;
>  
>   /*
> @@ -1049,10 +1051,7 @@ bpf_setif(struct bpf_d *d, struct ifreq
>   * Look through attached interfaces for the named one.
>   */
>   for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> - struct ifnet *ifp = bp->bif_ifp;
> -
> - if (ifp == NULL ||
> -    strcmp(ifp->if_xname, ifr->ifr_name) != 0)
> + if (strcmp(bp->bif_name, ifr->ifr_name) != 0)
>   continue;
>  
>   if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt)
> @@ -1090,9 +1089,9 @@ out:
>   * Copy the interface name to the ifreq.
>   */
>  void
> -bpf_ifname(struct ifnet *ifp, struct ifreq *ifr)
> +bpf_ifname(struct bpf_if *bif, struct ifreq *ifr)
>  {
> - bcopy(ifp->if_xname, ifr->ifr_name, IFNAMSIZ);
> + bcopy(bif->bif_name, ifr->ifr_name, sizeof(ifr->ifr_name));
>  }
>  
>  /*
> @@ -1538,21 +1537,17 @@ bpf_put(struct bpf_d *bd)
>   free(bd, M_DEVBUF, sizeof(*bd));
>  }
>  
> -/*
> - * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
> - * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
> - * size of the link header (variable length headers not yet supported).
> - */
> -void
> -bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
> +void *
> +bpfsattach(caddr_t *bpfp, const char *name, u_int dlt, u_int hdrlen)
>  {
>   struct bpf_if *bp;
>  
>   if ((bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT)) == NULL)
>   panic("bpfattach");
>   SRPL_INIT(&bp->bif_dlist);
> - bp->bif_driverp = (struct bpf_if **)driverp;
> - bp->bif_ifp = ifp;
> + bp->bif_driverp = (struct bpf_if **)bpfp;
> + bp->bif_name = name;
> + bp->bif_ifp = NULL;
>   bp->bif_dlt = dlt;
>  
>   bp->bif_next = bpf_iflist;
> @@ -1567,6 +1562,17 @@ bpfattach(caddr_t *driverp, struct ifnet
>   * performance reasons and to alleviate alignment restrictions).
>   */
>   bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
> +
> + return (bp);
> +}
> +
> +void
> +bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
> +{
> + struct bpf_if *bp;
> +
> + bp = bpfsattach(driverp, ifp->if_xname, dlt, hdrlen);
> + bp->bif_ifp = ifp;
>  }
>  
>  /* Detach an interface from its attached bpf device.  */
> @@ -1574,31 +1580,39 @@ void
>  bpfdetach(struct ifnet *ifp)
>  {
>   struct bpf_if *bp, *nbp, **pbp = &bpf_iflist;
> - struct bpf_d *bd;
> - int maj;
>  
>   KERNEL_ASSERT_LOCKED();
>  
>   for (bp = bpf_iflist; bp; bp = nbp) {
> - nbp= bp->bif_next;
> + nbp = bp->bif_next;
>   if (bp->bif_ifp == ifp) {
>   *pbp = nbp;
>  
> - /* Locate the major number. */
> - for (maj = 0; maj < nchrdev; maj++)
> - if (cdevsw[maj].d_open == bpfopen)
> - break;
> -
> - while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
> - vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
> -
> - free(bp, M_DEVBUF, sizeof *bp);
> + bpfsdetach(bp);
>   } else
>   pbp = &bp->bif_next;
>   }
>   ifp->if_bpf = NULL;
>  }
>  
> +void
> +bpfsdetach(void *p)
> +{
> + struct bpf_if *bp = p;
> + struct bpf_d *bd;
> + int maj;
> +
> + /* Locate the major number. */
> + for (maj = 0; maj < nchrdev; maj++)
> + if (cdevsw[maj].d_open == bpfopen)
> + break;
> +
> + while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
> + vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
> +
> + free(bp, M_DEVBUF, sizeof *bp);
> +}
> +
>  int
>  bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
>      void *newp, size_t newlen)
> @@ -1674,14 +1688,14 @@ int
>  bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
>  {
>   int n, error;
> - struct ifnet *ifp;
>   struct bpf_if *bp;
> + const char *name;
>  
> - ifp = d->bd_bif->bif_ifp;
> + name = d->bd_bif->bif_name;
>   n = 0;
>   error = 0;
>   for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> - if (bp->bif_ifp != ifp)
> + if (strcmp(name, bp->bif_name) != 0)
>   continue;
>   if (bfl->bfl_list != NULL) {
>   if (n >= bfl->bfl_len)
> @@ -1704,15 +1718,17 @@ bpf_getdltlist(struct bpf_d *d, struct b
>  int
>  bpf_setdlt(struct bpf_d *d, u_int dlt)
>  {
> - struct ifnet *ifp;
> + const char *name;
>   struct bpf_if *bp;
>  
>   MUTEX_ASSERT_LOCKED(&d->bd_mtx);
>   if (d->bd_bif->bif_dlt == dlt)
>   return (0);
> - ifp = d->bd_bif->bif_ifp;
> + name = d->bd_bif->bif_name;
>   for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> - if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
> + if (strcmp(name, bp->bif_name) != 0)
> + continue;
> + if (bp->bif_dlt == dlt)
>   break;
>   }
>   if (bp == NULL)
> Index: bpf.h
> ===================================================================
> RCS file: /cvs/src/sys/net/bpf.h,v
> retrieving revision 1.62
> diff -u -p -r1.62 bpf.h
> --- bpf.h 22 Feb 2017 09:56:03 -0000 1.62
> +++ bpf.h 10 Jan 2018 07:27:45 -0000
> @@ -313,6 +313,8 @@ int bpf_mtap_af(caddr_t, u_int32_t, con
>  int bpf_mtap_ether(caddr_t, const struct mbuf *, u_int);
>  void bpfattach(caddr_t *, struct ifnet *, u_int, u_int);
>  void bpfdetach(struct ifnet *);
> +void *bpfsattach(caddr_t *, const char *, u_int, u_int);
> +void bpfsdetach(void *);
>  void bpfilterattach(int);
>  
>  u_int bpf_mfilter(const struct bpf_insn *, const struct mbuf *, u_int);
> Index: bpfdesc.h
> ===================================================================
> RCS file: /cvs/src/sys/net/bpfdesc.h,v
> retrieving revision 1.35
> diff -u -p -r1.35 bpfdesc.h
> --- bpfdesc.h 24 Jan 2017 10:08:30 -0000 1.35
> +++ bpfdesc.h 10 Jan 2018 07:27:45 -0000
> @@ -103,6 +103,7 @@ struct bpf_if {
>   struct bpf_if **bif_driverp; /* pointer into softc */
>   u_int bif_dlt; /* link layer type */
>   u_int bif_hdrlen; /* length of header (with padding) */
> + const char *bif_name; /* name of "subsystem" */
>   struct ifnet *bif_ifp; /* corresponding interface */
>  };
>  
> Index: pf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf.c,v
> retrieving revision 1.1054
> diff -u -p -r1.1054 pf.c
> --- pf.c 29 Dec 2017 23:55:22 -0000 1.1054
> +++ pf.c 10 Jan 2018 07:27:45 -0000
> @@ -104,6 +104,11 @@
>  #include <ddb/db_interface.h>
>  #endif
>  
> +#if NBPFILTER > 0
> +#include <net/bpf.h>
> +caddr_t pf_bpf;
> +#endif
> +
>  /*
>   * Global variables
>   */
> @@ -6719,6 +6724,11 @@ pf_test(sa_family_t af, int fwdir, struc
>  
>   if (!pf_status.running)
>   return (PF_PASS);
> +
> +#if NBPFILTER > 0
> + if (pf_bpf)
> + bpf_mtap_af(pf_bpf, af, *m0, BPF_DIRECTION_IN);
> +#endif
>  
>  #if NCARP > 0
>   if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
> Index: pf_ioctl.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf_ioctl.c,v
> retrieving revision 1.326
> diff -u -p -r1.326 pf_ioctl.c
> --- pf_ioctl.c 28 Nov 2017 16:05:46 -0000 1.326
> +++ pf_ioctl.c 10 Jan 2018 07:27:45 -0000
> @@ -35,6 +35,7 @@
>   *
>   */
>  
> +#include "bpfilter.h"
>  #include "pfsync.h"
>  #include "pflog.h"
>  
> @@ -84,6 +85,11 @@
>  #include <net/if_pfsync.h>
>  #endif /* NPFSYNC > 0 */
>  
> +#if NBPFILTER > 0
> +#include <net/bpf.h>
> +extern caddr_t pf_bpf;
> +#endif
> +
>  struct pool pf_tag_pl;
>  
>  void pfattach(int);
> @@ -231,6 +237,10 @@ pfattach(int num)
>  
>   /* XXX do our best to avoid a conflict */
>   pf_status.hostid = arc4random();
> +
> +#if NBPFILTER > 0
> + bpfsattach(&pf_bpf, "pf", DLT_LOOP, sizeof(u_int32_t));
> +#endif
>  }
>  
>  int
>

Reply | Threaded
Open this post in threaded view
|

Re: bpf for subsystems, not just interfaces

David Gwynne-5


> On 11 Jan 2018, at 9:11 pm, Martin Pieuchot <[hidden email]> wrote:
>
> On 11/01/18(Thu) 11:58, David Gwynne wrote:
>> im sending this out more as a backup than a serious diff.
>
> I love this.  It's one of the steps to be able to use bpf(4) for USB.

oh yeah.

>
> Is there an easy way to also remove the mbuf requirement?  For example
> I'd like to call bpf_mtap() or similar in usb_transfer_complete().

is the usb payload in one or two contig buffers? we could just fake it.

>
>> this tweaks bpf so it can be used by subsystems, not just interfaces.
>> this is done by making bpf store and use names (eg, "pf" and "em0")
>> instead of just interfaces. interfaces get some special handling
>> so you can't bpfwrite or enable ifpromisc unless bif_ifp is set.
>>
>> an example use of this is attaching bpf to pf. you can see all the
>> packets handed to pf_test with this diff and tcpdump -ni pf.
>>
>> Index: bpf.c
>> ===================================================================
>> RCS file: /cvs/src/sys/net/bpf.c,v
>> retrieving revision 1.165
>> diff -u -p -r1.165 bpf.c
>> --- bpf.c 30 Dec 2017 23:08:29 -0000 1.165
>> +++ bpf.c 10 Jan 2018 07:27:45 -0000
>> @@ -93,7 +93,7 @@ struct bpf_if *bpf_iflist;
>> LIST_HEAD(, bpf_d) bpf_d_list;
>>
>> int bpf_allocbufs(struct bpf_d *);
>> -void bpf_ifname(struct ifnet *, struct ifreq *);
>> +void bpf_ifname(struct bpf_if*, struct ifreq *);
>> int _bpf_mtap(caddr_t, const struct mbuf *, u_int,
>>    void (*)(const void *, void *, size_t));
>> void bpf_mcopy(const void *, void *, size_t);
>> @@ -320,6 +320,8 @@ bpf_detachd(struct bpf_d *d)
>> if (d->bd_promisc) {
>> int error;
>>
>> + KASSERT(bp->bif_ifp != NULL);
>> +
>> d->bd_promisc = 0;
>>
>> bpf_get(d);
>> @@ -593,7 +595,7 @@ bpfwrite(dev_t dev, struct uio *uio, int
>> bpf_get(d);
>> ifp = d->bd_bif->bif_ifp;
>>
>> - if ((ifp->if_flags & IFF_UP) == 0) {
>> + if (ifp == NULL || (ifp->if_flags & IFF_UP) == 0) {
>> error = ENETDOWN;
>> goto out;
>> }
>> @@ -789,7 +791,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>> * No interface attached yet.
>> */
>> error = EINVAL;
>> - } else {
>> + } else if (d->bd_bif->bif_ifp != NULL) {
>> if (d->bd_promisc == 0) {
>> MUTEX_ASSERT_UNLOCKED(&d->bd_mtx);
>> error = ifpromisc(d->bd_bif->bif_ifp, 1);
>> @@ -839,7 +841,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>> if (d->bd_bif == NULL)
>> error = EINVAL;
>> else
>> - bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
>> + bpf_ifname(d->bd_bif, (struct ifreq *)addr);
>> break;
>>
>> /*
>> @@ -1049,10 +1051,7 @@ bpf_setif(struct bpf_d *d, struct ifreq
>> * Look through attached interfaces for the named one.
>> */
>> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
>> - struct ifnet *ifp = bp->bif_ifp;
>> -
>> - if (ifp == NULL ||
>> -    strcmp(ifp->if_xname, ifr->ifr_name) != 0)
>> + if (strcmp(bp->bif_name, ifr->ifr_name) != 0)
>> continue;
>>
>> if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt)
>> @@ -1090,9 +1089,9 @@ out:
>>  * Copy the interface name to the ifreq.
>>  */
>> void
>> -bpf_ifname(struct ifnet *ifp, struct ifreq *ifr)
>> +bpf_ifname(struct bpf_if *bif, struct ifreq *ifr)
>> {
>> - bcopy(ifp->if_xname, ifr->ifr_name, IFNAMSIZ);
>> + bcopy(bif->bif_name, ifr->ifr_name, sizeof(ifr->ifr_name));
>> }
>>
>> /*
>> @@ -1538,21 +1537,17 @@ bpf_put(struct bpf_d *bd)
>> free(bd, M_DEVBUF, sizeof(*bd));
>> }
>>
>> -/*
>> - * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
>> - * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
>> - * size of the link header (variable length headers not yet supported).
>> - */
>> -void
>> -bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
>> +void *
>> +bpfsattach(caddr_t *bpfp, const char *name, u_int dlt, u_int hdrlen)
>> {
>> struct bpf_if *bp;
>>
>> if ((bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT)) == NULL)
>> panic("bpfattach");
>> SRPL_INIT(&bp->bif_dlist);
>> - bp->bif_driverp = (struct bpf_if **)driverp;
>> - bp->bif_ifp = ifp;
>> + bp->bif_driverp = (struct bpf_if **)bpfp;
>> + bp->bif_name = name;
>> + bp->bif_ifp = NULL;
>> bp->bif_dlt = dlt;
>>
>> bp->bif_next = bpf_iflist;
>> @@ -1567,6 +1562,17 @@ bpfattach(caddr_t *driverp, struct ifnet
>> * performance reasons and to alleviate alignment restrictions).
>> */
>> bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
>> +
>> + return (bp);
>> +}
>> +
>> +void
>> +bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
>> +{
>> + struct bpf_if *bp;
>> +
>> + bp = bpfsattach(driverp, ifp->if_xname, dlt, hdrlen);
>> + bp->bif_ifp = ifp;
>> }
>>
>> /* Detach an interface from its attached bpf device.  */
>> @@ -1574,31 +1580,39 @@ void
>> bpfdetach(struct ifnet *ifp)
>> {
>> struct bpf_if *bp, *nbp, **pbp = &bpf_iflist;
>> - struct bpf_d *bd;
>> - int maj;
>>
>> KERNEL_ASSERT_LOCKED();
>>
>> for (bp = bpf_iflist; bp; bp = nbp) {
>> - nbp= bp->bif_next;
>> + nbp = bp->bif_next;
>> if (bp->bif_ifp == ifp) {
>> *pbp = nbp;
>>
>> - /* Locate the major number. */
>> - for (maj = 0; maj < nchrdev; maj++)
>> - if (cdevsw[maj].d_open == bpfopen)
>> - break;
>> -
>> - while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
>> - vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
>> -
>> - free(bp, M_DEVBUF, sizeof *bp);
>> + bpfsdetach(bp);
>> } else
>> pbp = &bp->bif_next;
>> }
>> ifp->if_bpf = NULL;
>> }
>>
>> +void
>> +bpfsdetach(void *p)
>> +{
>> + struct bpf_if *bp = p;
>> + struct bpf_d *bd;
>> + int maj;
>> +
>> + /* Locate the major number. */
>> + for (maj = 0; maj < nchrdev; maj++)
>> + if (cdevsw[maj].d_open == bpfopen)
>> + break;
>> +
>> + while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
>> + vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
>> +
>> + free(bp, M_DEVBUF, sizeof *bp);
>> +}
>> +
>> int
>> bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
>>     void *newp, size_t newlen)
>> @@ -1674,14 +1688,14 @@ int
>> bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
>> {
>> int n, error;
>> - struct ifnet *ifp;
>> struct bpf_if *bp;
>> + const char *name;
>>
>> - ifp = d->bd_bif->bif_ifp;
>> + name = d->bd_bif->bif_name;
>> n = 0;
>> error = 0;
>> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
>> - if (bp->bif_ifp != ifp)
>> + if (strcmp(name, bp->bif_name) != 0)
>> continue;
>> if (bfl->bfl_list != NULL) {
>> if (n >= bfl->bfl_len)
>> @@ -1704,15 +1718,17 @@ bpf_getdltlist(struct bpf_d *d, struct b
>> int
>> bpf_setdlt(struct bpf_d *d, u_int dlt)
>> {
>> - struct ifnet *ifp;
>> + const char *name;
>> struct bpf_if *bp;
>>
>> MUTEX_ASSERT_LOCKED(&d->bd_mtx);
>> if (d->bd_bif->bif_dlt == dlt)
>> return (0);
>> - ifp = d->bd_bif->bif_ifp;
>> + name = d->bd_bif->bif_name;
>> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
>> - if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
>> + if (strcmp(name, bp->bif_name) != 0)
>> + continue;
>> + if (bp->bif_dlt == dlt)
>> break;
>> }
>> if (bp == NULL)
>> Index: bpf.h
>> ===================================================================
>> RCS file: /cvs/src/sys/net/bpf.h,v
>> retrieving revision 1.62
>> diff -u -p -r1.62 bpf.h
>> --- bpf.h 22 Feb 2017 09:56:03 -0000 1.62
>> +++ bpf.h 10 Jan 2018 07:27:45 -0000
>> @@ -313,6 +313,8 @@ int bpf_mtap_af(caddr_t, u_int32_t, con
>> int bpf_mtap_ether(caddr_t, const struct mbuf *, u_int);
>> void bpfattach(caddr_t *, struct ifnet *, u_int, u_int);
>> void bpfdetach(struct ifnet *);
>> +void *bpfsattach(caddr_t *, const char *, u_int, u_int);
>> +void bpfsdetach(void *);
>> void bpfilterattach(int);
>>
>> u_int bpf_mfilter(const struct bpf_insn *, const struct mbuf *, u_int);
>> Index: bpfdesc.h
>> ===================================================================
>> RCS file: /cvs/src/sys/net/bpfdesc.h,v
>> retrieving revision 1.35
>> diff -u -p -r1.35 bpfdesc.h
>> --- bpfdesc.h 24 Jan 2017 10:08:30 -0000 1.35
>> +++ bpfdesc.h 10 Jan 2018 07:27:45 -0000
>> @@ -103,6 +103,7 @@ struct bpf_if {
>> struct bpf_if **bif_driverp; /* pointer into softc */
>> u_int bif_dlt; /* link layer type */
>> u_int bif_hdrlen; /* length of header (with padding) */
>> + const char *bif_name; /* name of "subsystem" */
>> struct ifnet *bif_ifp; /* corresponding interface */
>> };
>>
>> Index: pf.c
>> ===================================================================
>> RCS file: /cvs/src/sys/net/pf.c,v
>> retrieving revision 1.1054
>> diff -u -p -r1.1054 pf.c
>> --- pf.c 29 Dec 2017 23:55:22 -0000 1.1054
>> +++ pf.c 10 Jan 2018 07:27:45 -0000
>> @@ -104,6 +104,11 @@
>> #include <ddb/db_interface.h>
>> #endif
>>
>> +#if NBPFILTER > 0
>> +#include <net/bpf.h>
>> +caddr_t pf_bpf;
>> +#endif
>> +
>> /*
>>  * Global variables
>>  */
>> @@ -6719,6 +6724,11 @@ pf_test(sa_family_t af, int fwdir, struc
>>
>> if (!pf_status.running)
>> return (PF_PASS);
>> +
>> +#if NBPFILTER > 0
>> + if (pf_bpf)
>> + bpf_mtap_af(pf_bpf, af, *m0, BPF_DIRECTION_IN);
>> +#endif
>>
>> #if NCARP > 0
>> if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
>> Index: pf_ioctl.c
>> ===================================================================
>> RCS file: /cvs/src/sys/net/pf_ioctl.c,v
>> retrieving revision 1.326
>> diff -u -p -r1.326 pf_ioctl.c
>> --- pf_ioctl.c 28 Nov 2017 16:05:46 -0000 1.326
>> +++ pf_ioctl.c 10 Jan 2018 07:27:45 -0000
>> @@ -35,6 +35,7 @@
>>  *
>>  */
>>
>> +#include "bpfilter.h"
>> #include "pfsync.h"
>> #include "pflog.h"
>>
>> @@ -84,6 +85,11 @@
>> #include <net/if_pfsync.h>
>> #endif /* NPFSYNC > 0 */
>>
>> +#if NBPFILTER > 0
>> +#include <net/bpf.h>
>> +extern caddr_t pf_bpf;
>> +#endif
>> +
>> struct pool pf_tag_pl;
>>
>> void pfattach(int);
>> @@ -231,6 +237,10 @@ pfattach(int num)
>>
>> /* XXX do our best to avoid a conflict */
>> pf_status.hostid = arc4random();
>> +
>> +#if NBPFILTER > 0
>> + bpfsattach(&pf_bpf, "pf", DLT_LOOP, sizeof(u_int32_t));
>> +#endif
>> }
>>
>> int
>>

Reply | Threaded
Open this post in threaded view
|

Re: bpf for subsystems, not just interfaces

Martin Pieuchot
On 11/01/18(Thu) 23:10, David Gwynne wrote:

>
>
> > On 11 Jan 2018, at 9:11 pm, Martin Pieuchot <[hidden email]> wrote:
> >
> > On 11/01/18(Thu) 11:58, David Gwynne wrote:
> >> im sending this out more as a backup than a serious diff.
> >
> > I love this.  It's one of the steps to be able to use bpf(4) for USB.
>
> oh yeah.
>
> >
> > Is there an easy way to also remove the mbuf requirement?  For example
> > I'd like to call bpf_mtap() or similar in usb_transfer_complete().
>
> is the usb payload in one or two contig buffers? we could just fake it.

Yes, it's  KERNADDR(&xfer->dmabuf, 0) of size `xfer->actlen'.

> >> this tweaks bpf so it can be used by subsystems, not just interfaces.
> >> this is done by making bpf store and use names (eg, "pf" and "em0")
> >> instead of just interfaces. interfaces get some special handling
> >> so you can't bpfwrite or enable ifpromisc unless bif_ifp is set.
> >>
> >> an example use of this is attaching bpf to pf. you can see all the
> >> packets handed to pf_test with this diff and tcpdump -ni pf.
> >>
> >> Index: bpf.c
> >> ===================================================================
> >> RCS file: /cvs/src/sys/net/bpf.c,v
> >> retrieving revision 1.165
> >> diff -u -p -r1.165 bpf.c
> >> --- bpf.c 30 Dec 2017 23:08:29 -0000 1.165
> >> +++ bpf.c 10 Jan 2018 07:27:45 -0000
> >> @@ -93,7 +93,7 @@ struct bpf_if *bpf_iflist;
> >> LIST_HEAD(, bpf_d) bpf_d_list;
> >>
> >> int bpf_allocbufs(struct bpf_d *);
> >> -void bpf_ifname(struct ifnet *, struct ifreq *);
> >> +void bpf_ifname(struct bpf_if*, struct ifreq *);
> >> int _bpf_mtap(caddr_t, const struct mbuf *, u_int,
> >>    void (*)(const void *, void *, size_t));
> >> void bpf_mcopy(const void *, void *, size_t);
> >> @@ -320,6 +320,8 @@ bpf_detachd(struct bpf_d *d)
> >> if (d->bd_promisc) {
> >> int error;
> >>
> >> + KASSERT(bp->bif_ifp != NULL);
> >> +
> >> d->bd_promisc = 0;
> >>
> >> bpf_get(d);
> >> @@ -593,7 +595,7 @@ bpfwrite(dev_t dev, struct uio *uio, int
> >> bpf_get(d);
> >> ifp = d->bd_bif->bif_ifp;
> >>
> >> - if ((ifp->if_flags & IFF_UP) == 0) {
> >> + if (ifp == NULL || (ifp->if_flags & IFF_UP) == 0) {
> >> error = ENETDOWN;
> >> goto out;
> >> }
> >> @@ -789,7 +791,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
> >> * No interface attached yet.
> >> */
> >> error = EINVAL;
> >> - } else {
> >> + } else if (d->bd_bif->bif_ifp != NULL) {
> >> if (d->bd_promisc == 0) {
> >> MUTEX_ASSERT_UNLOCKED(&d->bd_mtx);
> >> error = ifpromisc(d->bd_bif->bif_ifp, 1);
> >> @@ -839,7 +841,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
> >> if (d->bd_bif == NULL)
> >> error = EINVAL;
> >> else
> >> - bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
> >> + bpf_ifname(d->bd_bif, (struct ifreq *)addr);
> >> break;
> >>
> >> /*
> >> @@ -1049,10 +1051,7 @@ bpf_setif(struct bpf_d *d, struct ifreq
> >> * Look through attached interfaces for the named one.
> >> */
> >> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> >> - struct ifnet *ifp = bp->bif_ifp;
> >> -
> >> - if (ifp == NULL ||
> >> -    strcmp(ifp->if_xname, ifr->ifr_name) != 0)
> >> + if (strcmp(bp->bif_name, ifr->ifr_name) != 0)
> >> continue;
> >>
> >> if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt)
> >> @@ -1090,9 +1089,9 @@ out:
> >>  * Copy the interface name to the ifreq.
> >>  */
> >> void
> >> -bpf_ifname(struct ifnet *ifp, struct ifreq *ifr)
> >> +bpf_ifname(struct bpf_if *bif, struct ifreq *ifr)
> >> {
> >> - bcopy(ifp->if_xname, ifr->ifr_name, IFNAMSIZ);
> >> + bcopy(bif->bif_name, ifr->ifr_name, sizeof(ifr->ifr_name));
> >> }
> >>
> >> /*
> >> @@ -1538,21 +1537,17 @@ bpf_put(struct bpf_d *bd)
> >> free(bd, M_DEVBUF, sizeof(*bd));
> >> }
> >>
> >> -/*
> >> - * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
> >> - * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
> >> - * size of the link header (variable length headers not yet supported).
> >> - */
> >> -void
> >> -bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
> >> +void *
> >> +bpfsattach(caddr_t *bpfp, const char *name, u_int dlt, u_int hdrlen)
> >> {
> >> struct bpf_if *bp;
> >>
> >> if ((bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT)) == NULL)
> >> panic("bpfattach");
> >> SRPL_INIT(&bp->bif_dlist);
> >> - bp->bif_driverp = (struct bpf_if **)driverp;
> >> - bp->bif_ifp = ifp;
> >> + bp->bif_driverp = (struct bpf_if **)bpfp;
> >> + bp->bif_name = name;
> >> + bp->bif_ifp = NULL;
> >> bp->bif_dlt = dlt;
> >>
> >> bp->bif_next = bpf_iflist;
> >> @@ -1567,6 +1562,17 @@ bpfattach(caddr_t *driverp, struct ifnet
> >> * performance reasons and to alleviate alignment restrictions).
> >> */
> >> bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
> >> +
> >> + return (bp);
> >> +}
> >> +
> >> +void
> >> +bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
> >> +{
> >> + struct bpf_if *bp;
> >> +
> >> + bp = bpfsattach(driverp, ifp->if_xname, dlt, hdrlen);
> >> + bp->bif_ifp = ifp;
> >> }
> >>
> >> /* Detach an interface from its attached bpf device.  */
> >> @@ -1574,31 +1580,39 @@ void
> >> bpfdetach(struct ifnet *ifp)
> >> {
> >> struct bpf_if *bp, *nbp, **pbp = &bpf_iflist;
> >> - struct bpf_d *bd;
> >> - int maj;
> >>
> >> KERNEL_ASSERT_LOCKED();
> >>
> >> for (bp = bpf_iflist; bp; bp = nbp) {
> >> - nbp= bp->bif_next;
> >> + nbp = bp->bif_next;
> >> if (bp->bif_ifp == ifp) {
> >> *pbp = nbp;
> >>
> >> - /* Locate the major number. */
> >> - for (maj = 0; maj < nchrdev; maj++)
> >> - if (cdevsw[maj].d_open == bpfopen)
> >> - break;
> >> -
> >> - while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
> >> - vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
> >> -
> >> - free(bp, M_DEVBUF, sizeof *bp);
> >> + bpfsdetach(bp);
> >> } else
> >> pbp = &bp->bif_next;
> >> }
> >> ifp->if_bpf = NULL;
> >> }
> >>
> >> +void
> >> +bpfsdetach(void *p)
> >> +{
> >> + struct bpf_if *bp = p;
> >> + struct bpf_d *bd;
> >> + int maj;
> >> +
> >> + /* Locate the major number. */
> >> + for (maj = 0; maj < nchrdev; maj++)
> >> + if (cdevsw[maj].d_open == bpfopen)
> >> + break;
> >> +
> >> + while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
> >> + vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
> >> +
> >> + free(bp, M_DEVBUF, sizeof *bp);
> >> +}
> >> +
> >> int
> >> bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
> >>     void *newp, size_t newlen)
> >> @@ -1674,14 +1688,14 @@ int
> >> bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
> >> {
> >> int n, error;
> >> - struct ifnet *ifp;
> >> struct bpf_if *bp;
> >> + const char *name;
> >>
> >> - ifp = d->bd_bif->bif_ifp;
> >> + name = d->bd_bif->bif_name;
> >> n = 0;
> >> error = 0;
> >> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> >> - if (bp->bif_ifp != ifp)
> >> + if (strcmp(name, bp->bif_name) != 0)
> >> continue;
> >> if (bfl->bfl_list != NULL) {
> >> if (n >= bfl->bfl_len)
> >> @@ -1704,15 +1718,17 @@ bpf_getdltlist(struct bpf_d *d, struct b
> >> int
> >> bpf_setdlt(struct bpf_d *d, u_int dlt)
> >> {
> >> - struct ifnet *ifp;
> >> + const char *name;
> >> struct bpf_if *bp;
> >>
> >> MUTEX_ASSERT_LOCKED(&d->bd_mtx);
> >> if (d->bd_bif->bif_dlt == dlt)
> >> return (0);
> >> - ifp = d->bd_bif->bif_ifp;
> >> + name = d->bd_bif->bif_name;
> >> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> >> - if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
> >> + if (strcmp(name, bp->bif_name) != 0)
> >> + continue;
> >> + if (bp->bif_dlt == dlt)
> >> break;
> >> }
> >> if (bp == NULL)
> >> Index: bpf.h
> >> ===================================================================
> >> RCS file: /cvs/src/sys/net/bpf.h,v
> >> retrieving revision 1.62
> >> diff -u -p -r1.62 bpf.h
> >> --- bpf.h 22 Feb 2017 09:56:03 -0000 1.62
> >> +++ bpf.h 10 Jan 2018 07:27:45 -0000
> >> @@ -313,6 +313,8 @@ int bpf_mtap_af(caddr_t, u_int32_t, con
> >> int bpf_mtap_ether(caddr_t, const struct mbuf *, u_int);
> >> void bpfattach(caddr_t *, struct ifnet *, u_int, u_int);
> >> void bpfdetach(struct ifnet *);
> >> +void *bpfsattach(caddr_t *, const char *, u_int, u_int);
> >> +void bpfsdetach(void *);
> >> void bpfilterattach(int);
> >>
> >> u_int bpf_mfilter(const struct bpf_insn *, const struct mbuf *, u_int);
> >> Index: bpfdesc.h
> >> ===================================================================
> >> RCS file: /cvs/src/sys/net/bpfdesc.h,v
> >> retrieving revision 1.35
> >> diff -u -p -r1.35 bpfdesc.h
> >> --- bpfdesc.h 24 Jan 2017 10:08:30 -0000 1.35
> >> +++ bpfdesc.h 10 Jan 2018 07:27:45 -0000
> >> @@ -103,6 +103,7 @@ struct bpf_if {
> >> struct bpf_if **bif_driverp; /* pointer into softc */
> >> u_int bif_dlt; /* link layer type */
> >> u_int bif_hdrlen; /* length of header (with padding) */
> >> + const char *bif_name; /* name of "subsystem" */
> >> struct ifnet *bif_ifp; /* corresponding interface */
> >> };
> >>
> >> Index: pf.c
> >> ===================================================================
> >> RCS file: /cvs/src/sys/net/pf.c,v
> >> retrieving revision 1.1054
> >> diff -u -p -r1.1054 pf.c
> >> --- pf.c 29 Dec 2017 23:55:22 -0000 1.1054
> >> +++ pf.c 10 Jan 2018 07:27:45 -0000
> >> @@ -104,6 +104,11 @@
> >> #include <ddb/db_interface.h>
> >> #endif
> >>
> >> +#if NBPFILTER > 0
> >> +#include <net/bpf.h>
> >> +caddr_t pf_bpf;
> >> +#endif
> >> +
> >> /*
> >>  * Global variables
> >>  */
> >> @@ -6719,6 +6724,11 @@ pf_test(sa_family_t af, int fwdir, struc
> >>
> >> if (!pf_status.running)
> >> return (PF_PASS);
> >> +
> >> +#if NBPFILTER > 0
> >> + if (pf_bpf)
> >> + bpf_mtap_af(pf_bpf, af, *m0, BPF_DIRECTION_IN);
> >> +#endif
> >>
> >> #if NCARP > 0
> >> if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
> >> Index: pf_ioctl.c
> >> ===================================================================
> >> RCS file: /cvs/src/sys/net/pf_ioctl.c,v
> >> retrieving revision 1.326
> >> diff -u -p -r1.326 pf_ioctl.c
> >> --- pf_ioctl.c 28 Nov 2017 16:05:46 -0000 1.326
> >> +++ pf_ioctl.c 10 Jan 2018 07:27:45 -0000
> >> @@ -35,6 +35,7 @@
> >>  *
> >>  */
> >>
> >> +#include "bpfilter.h"
> >> #include "pfsync.h"
> >> #include "pflog.h"
> >>
> >> @@ -84,6 +85,11 @@
> >> #include <net/if_pfsync.h>
> >> #endif /* NPFSYNC > 0 */
> >>
> >> +#if NBPFILTER > 0
> >> +#include <net/bpf.h>
> >> +extern caddr_t pf_bpf;
> >> +#endif
> >> +
> >> struct pool pf_tag_pl;
> >>
> >> void pfattach(int);
> >> @@ -231,6 +237,10 @@ pfattach(int num)
> >>
> >> /* XXX do our best to avoid a conflict */
> >> pf_status.hostid = arc4random();
> >> +
> >> +#if NBPFILTER > 0
> >> + bpfsattach(&pf_bpf, "pf", DLT_LOOP, sizeof(u_int32_t));
> >> +#endif
> >> }
> >>
> >> int
> >>
>

Reply | Threaded
Open this post in threaded view
|

Re: bpf for subsystems, not just interfaces

David Gwynne-5

> On 11 Jan 2018, at 23:54, Martin Pieuchot <[hidden email]> wrote:
>
> On 11/01/18(Thu) 23:10, David Gwynne wrote:
>>
>>
>>> On 11 Jan 2018, at 9:11 pm, Martin Pieuchot <[hidden email]> wrote:
>>>
>>> On 11/01/18(Thu) 11:58, David Gwynne wrote:
>>>> im sending this out more as a backup than a serious diff.
>>>
>>> I love this.  It's one of the steps to be able to use bpf(4) for USB.
>>
>> oh yeah.
>>
>>>
>>> Is there an easy way to also remove the mbuf requirement?  For example
>>> I'd like to call bpf_mtap() or similar in usb_transfer_complete().
>>
>> is the usb payload in one or two contig buffers? we could just fake it.
>
> Yes, it's  KERNADDR(&xfer->dmabuf, 0) of size `xfer->actlen'.

if it's a single buffer, just use https://man.openbsd.org/bpf_filter.

if you want to put a header on it too, we'll need to a bit of extra code, but it's fairly trivial.

jono reminded me that i wanted bpf on sd(4) at one point too. or ttys. i dont think ttys was my idea though.

dlg

>
>>>> this tweaks bpf so it can be used by subsystems, not just interfaces.
>>>> this is done by making bpf store and use names (eg, "pf" and "em0")
>>>> instead of just interfaces. interfaces get some special handling
>>>> so you can't bpfwrite or enable ifpromisc unless bif_ifp is set.
>>>>
>>>> an example use of this is attaching bpf to pf. you can see all the
>>>> packets handed to pf_test with this diff and tcpdump -ni pf.
>>>>
>>>> Index: bpf.c
>>>> ===================================================================
>>>> RCS file: /cvs/src/sys/net/bpf.c,v
>>>> retrieving revision 1.165
>>>> diff -u -p -r1.165 bpf.c
>>>> --- bpf.c 30 Dec 2017 23:08:29 -0000 1.165
>>>> +++ bpf.c 10 Jan 2018 07:27:45 -0000
>>>> @@ -93,7 +93,7 @@ struct bpf_if *bpf_iflist;
>>>> LIST_HEAD(, bpf_d) bpf_d_list;
>>>>
>>>> int bpf_allocbufs(struct bpf_d *);
>>>> -void bpf_ifname(struct ifnet *, struct ifreq *);
>>>> +void bpf_ifname(struct bpf_if*, struct ifreq *);
>>>> int _bpf_mtap(caddr_t, const struct mbuf *, u_int,
>>>>    void (*)(const void *, void *, size_t));
>>>> void bpf_mcopy(const void *, void *, size_t);
>>>> @@ -320,6 +320,8 @@ bpf_detachd(struct bpf_d *d)
>>>> if (d->bd_promisc) {
>>>> int error;
>>>>
>>>> + KASSERT(bp->bif_ifp != NULL);
>>>> +
>>>> d->bd_promisc = 0;
>>>>
>>>> bpf_get(d);
>>>> @@ -593,7 +595,7 @@ bpfwrite(dev_t dev, struct uio *uio, int
>>>> bpf_get(d);
>>>> ifp = d->bd_bif->bif_ifp;
>>>>
>>>> - if ((ifp->if_flags & IFF_UP) == 0) {
>>>> + if (ifp == NULL || (ifp->if_flags & IFF_UP) == 0) {
>>>> error = ENETDOWN;
>>>> goto out;
>>>> }
>>>> @@ -789,7 +791,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>>>> * No interface attached yet.
>>>> */
>>>> error = EINVAL;
>>>> - } else {
>>>> + } else if (d->bd_bif->bif_ifp != NULL) {
>>>> if (d->bd_promisc == 0) {
>>>> MUTEX_ASSERT_UNLOCKED(&d->bd_mtx);
>>>> error = ifpromisc(d->bd_bif->bif_ifp, 1);
>>>> @@ -839,7 +841,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>>>> if (d->bd_bif == NULL)
>>>> error = EINVAL;
>>>> else
>>>> - bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
>>>> + bpf_ifname(d->bd_bif, (struct ifreq *)addr);
>>>> break;
>>>>
>>>> /*
>>>> @@ -1049,10 +1051,7 @@ bpf_setif(struct bpf_d *d, struct ifreq
>>>> * Look through attached interfaces for the named one.
>>>> */
>>>> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
>>>> - struct ifnet *ifp = bp->bif_ifp;
>>>> -
>>>> - if (ifp == NULL ||
>>>> -    strcmp(ifp->if_xname, ifr->ifr_name) != 0)
>>>> + if (strcmp(bp->bif_name, ifr->ifr_name) != 0)
>>>> continue;
>>>>
>>>> if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt)
>>>> @@ -1090,9 +1089,9 @@ out:
>>>> * Copy the interface name to the ifreq.
>>>> */
>>>> void
>>>> -bpf_ifname(struct ifnet *ifp, struct ifreq *ifr)
>>>> +bpf_ifname(struct bpf_if *bif, struct ifreq *ifr)
>>>> {
>>>> - bcopy(ifp->if_xname, ifr->ifr_name, IFNAMSIZ);
>>>> + bcopy(bif->bif_name, ifr->ifr_name, sizeof(ifr->ifr_name));
>>>> }
>>>>
>>>> /*
>>>> @@ -1538,21 +1537,17 @@ bpf_put(struct bpf_d *bd)
>>>> free(bd, M_DEVBUF, sizeof(*bd));
>>>> }
>>>>
>>>> -/*
>>>> - * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
>>>> - * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
>>>> - * size of the link header (variable length headers not yet supported).
>>>> - */
>>>> -void
>>>> -bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
>>>> +void *
>>>> +bpfsattach(caddr_t *bpfp, const char *name, u_int dlt, u_int hdrlen)
>>>> {
>>>> struct bpf_if *bp;
>>>>
>>>> if ((bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT)) == NULL)
>>>> panic("bpfattach");
>>>> SRPL_INIT(&bp->bif_dlist);
>>>> - bp->bif_driverp = (struct bpf_if **)driverp;
>>>> - bp->bif_ifp = ifp;
>>>> + bp->bif_driverp = (struct bpf_if **)bpfp;
>>>> + bp->bif_name = name;
>>>> + bp->bif_ifp = NULL;
>>>> bp->bif_dlt = dlt;
>>>>
>>>> bp->bif_next = bpf_iflist;
>>>> @@ -1567,6 +1562,17 @@ bpfattach(caddr_t *driverp, struct ifnet
>>>> * performance reasons and to alleviate alignment restrictions).
>>>> */
>>>> bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
>>>> +
>>>> + return (bp);
>>>> +}
>>>> +
>>>> +void
>>>> +bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
>>>> +{
>>>> + struct bpf_if *bp;
>>>> +
>>>> + bp = bpfsattach(driverp, ifp->if_xname, dlt, hdrlen);
>>>> + bp->bif_ifp = ifp;
>>>> }
>>>>
>>>> /* Detach an interface from its attached bpf device.  */
>>>> @@ -1574,31 +1580,39 @@ void
>>>> bpfdetach(struct ifnet *ifp)
>>>> {
>>>> struct bpf_if *bp, *nbp, **pbp = &bpf_iflist;
>>>> - struct bpf_d *bd;
>>>> - int maj;
>>>>
>>>> KERNEL_ASSERT_LOCKED();
>>>>
>>>> for (bp = bpf_iflist; bp; bp = nbp) {
>>>> - nbp= bp->bif_next;
>>>> + nbp = bp->bif_next;
>>>> if (bp->bif_ifp == ifp) {
>>>> *pbp = nbp;
>>>>
>>>> - /* Locate the major number. */
>>>> - for (maj = 0; maj < nchrdev; maj++)
>>>> - if (cdevsw[maj].d_open == bpfopen)
>>>> - break;
>>>> -
>>>> - while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
>>>> - vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
>>>> -
>>>> - free(bp, M_DEVBUF, sizeof *bp);
>>>> + bpfsdetach(bp);
>>>> } else
>>>> pbp = &bp->bif_next;
>>>> }
>>>> ifp->if_bpf = NULL;
>>>> }
>>>>
>>>> +void
>>>> +bpfsdetach(void *p)
>>>> +{
>>>> + struct bpf_if *bp = p;
>>>> + struct bpf_d *bd;
>>>> + int maj;
>>>> +
>>>> + /* Locate the major number. */
>>>> + for (maj = 0; maj < nchrdev; maj++)
>>>> + if (cdevsw[maj].d_open == bpfopen)
>>>> + break;
>>>> +
>>>> + while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
>>>> + vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
>>>> +
>>>> + free(bp, M_DEVBUF, sizeof *bp);
>>>> +}
>>>> +
>>>> int
>>>> bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
>>>>    void *newp, size_t newlen)
>>>> @@ -1674,14 +1688,14 @@ int
>>>> bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
>>>> {
>>>> int n, error;
>>>> - struct ifnet *ifp;
>>>> struct bpf_if *bp;
>>>> + const char *name;
>>>>
>>>> - ifp = d->bd_bif->bif_ifp;
>>>> + name = d->bd_bif->bif_name;
>>>> n = 0;
>>>> error = 0;
>>>> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
>>>> - if (bp->bif_ifp != ifp)
>>>> + if (strcmp(name, bp->bif_name) != 0)
>>>> continue;
>>>> if (bfl->bfl_list != NULL) {
>>>> if (n >= bfl->bfl_len)
>>>> @@ -1704,15 +1718,17 @@ bpf_getdltlist(struct bpf_d *d, struct b
>>>> int
>>>> bpf_setdlt(struct bpf_d *d, u_int dlt)
>>>> {
>>>> - struct ifnet *ifp;
>>>> + const char *name;
>>>> struct bpf_if *bp;
>>>>
>>>> MUTEX_ASSERT_LOCKED(&d->bd_mtx);
>>>> if (d->bd_bif->bif_dlt == dlt)
>>>> return (0);
>>>> - ifp = d->bd_bif->bif_ifp;
>>>> + name = d->bd_bif->bif_name;
>>>> for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
>>>> - if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
>>>> + if (strcmp(name, bp->bif_name) != 0)
>>>> + continue;
>>>> + if (bp->bif_dlt == dlt)
>>>> break;
>>>> }
>>>> if (bp == NULL)
>>>> Index: bpf.h
>>>> ===================================================================
>>>> RCS file: /cvs/src/sys/net/bpf.h,v
>>>> retrieving revision 1.62
>>>> diff -u -p -r1.62 bpf.h
>>>> --- bpf.h 22 Feb 2017 09:56:03 -0000 1.62
>>>> +++ bpf.h 10 Jan 2018 07:27:45 -0000
>>>> @@ -313,6 +313,8 @@ int bpf_mtap_af(caddr_t, u_int32_t, con
>>>> int bpf_mtap_ether(caddr_t, const struct mbuf *, u_int);
>>>> void bpfattach(caddr_t *, struct ifnet *, u_int, u_int);
>>>> void bpfdetach(struct ifnet *);
>>>> +void *bpfsattach(caddr_t *, const char *, u_int, u_int);
>>>> +void bpfsdetach(void *);
>>>> void bpfilterattach(int);
>>>>
>>>> u_int bpf_mfilter(const struct bpf_insn *, const struct mbuf *, u_int);
>>>> Index: bpfdesc.h
>>>> ===================================================================
>>>> RCS file: /cvs/src/sys/net/bpfdesc.h,v
>>>> retrieving revision 1.35
>>>> diff -u -p -r1.35 bpfdesc.h
>>>> --- bpfdesc.h 24 Jan 2017 10:08:30 -0000 1.35
>>>> +++ bpfdesc.h 10 Jan 2018 07:27:45 -0000
>>>> @@ -103,6 +103,7 @@ struct bpf_if {
>>>> struct bpf_if **bif_driverp; /* pointer into softc */
>>>> u_int bif_dlt; /* link layer type */
>>>> u_int bif_hdrlen; /* length of header (with padding) */
>>>> + const char *bif_name; /* name of "subsystem" */
>>>> struct ifnet *bif_ifp; /* corresponding interface */
>>>> };
>>>>
>>>> Index: pf.c
>>>> ===================================================================
>>>> RCS file: /cvs/src/sys/net/pf.c,v
>>>> retrieving revision 1.1054
>>>> diff -u -p -r1.1054 pf.c
>>>> --- pf.c 29 Dec 2017 23:55:22 -0000 1.1054
>>>> +++ pf.c 10 Jan 2018 07:27:45 -0000
>>>> @@ -104,6 +104,11 @@
>>>> #include <ddb/db_interface.h>
>>>> #endif
>>>>
>>>> +#if NBPFILTER > 0
>>>> +#include <net/bpf.h>
>>>> +caddr_t pf_bpf;
>>>> +#endif
>>>> +
>>>> /*
>>>> * Global variables
>>>> */
>>>> @@ -6719,6 +6724,11 @@ pf_test(sa_family_t af, int fwdir, struc
>>>>
>>>> if (!pf_status.running)
>>>> return (PF_PASS);
>>>> +
>>>> +#if NBPFILTER > 0
>>>> + if (pf_bpf)
>>>> + bpf_mtap_af(pf_bpf, af, *m0, BPF_DIRECTION_IN);
>>>> +#endif
>>>>
>>>> #if NCARP > 0
>>>> if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
>>>> Index: pf_ioctl.c
>>>> ===================================================================
>>>> RCS file: /cvs/src/sys/net/pf_ioctl.c,v
>>>> retrieving revision 1.326
>>>> diff -u -p -r1.326 pf_ioctl.c
>>>> --- pf_ioctl.c 28 Nov 2017 16:05:46 -0000 1.326
>>>> +++ pf_ioctl.c 10 Jan 2018 07:27:45 -0000
>>>> @@ -35,6 +35,7 @@
>>>> *
>>>> */
>>>>
>>>> +#include "bpfilter.h"
>>>> #include "pfsync.h"
>>>> #include "pflog.h"
>>>>
>>>> @@ -84,6 +85,11 @@
>>>> #include <net/if_pfsync.h>
>>>> #endif /* NPFSYNC > 0 */
>>>>
>>>> +#if NBPFILTER > 0
>>>> +#include <net/bpf.h>
>>>> +extern caddr_t pf_bpf;
>>>> +#endif
>>>> +
>>>> struct pool pf_tag_pl;
>>>>
>>>> void pfattach(int);
>>>> @@ -231,6 +237,10 @@ pfattach(int num)
>>>>
>>>> /* XXX do our best to avoid a conflict */
>>>> pf_status.hostid = arc4random();
>>>> +
>>>> +#if NBPFILTER > 0
>>>> + bpfsattach(&pf_bpf, "pf", DLT_LOOP, sizeof(u_int32_t));
>>>> +#endif
>>>> }
>>>>
>>>> int

Reply | Threaded
Open this post in threaded view
|

Re: bpf for subsystems, not just interfaces

Martin Pieuchot
In reply to this post by David Gwynne-5
On 11/01/18(Thu) 11:58, David Gwynne wrote:
> im sending this out more as a backup than a serious diff.
>
> this tweaks bpf so it can be used by subsystems, not just interfaces.
> this is done by making bpf store and use names (eg, "pf" and "em0")
> instead of just interfaces. interfaces get some special handling
> so you can't bpfwrite or enable ifpromisc unless bif_ifp is set.
>
> an example use of this is attaching bpf to pf. you can see all the
> packets handed to pf_test with this diff and tcpdump -ni pf.

I'm successfully using this for USB.  So I'm ok for the API bits but
please add the corresponding documentation ;)

> Index: bpf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/bpf.c,v
> retrieving revision 1.165
> diff -u -p -r1.165 bpf.c
> --- bpf.c 30 Dec 2017 23:08:29 -0000 1.165
> +++ bpf.c 10 Jan 2018 07:27:45 -0000
> @@ -93,7 +93,7 @@ struct bpf_if *bpf_iflist;
>  LIST_HEAD(, bpf_d) bpf_d_list;
>  
>  int bpf_allocbufs(struct bpf_d *);
> -void bpf_ifname(struct ifnet *, struct ifreq *);
> +void bpf_ifname(struct bpf_if*, struct ifreq *);
>  int _bpf_mtap(caddr_t, const struct mbuf *, u_int,
>      void (*)(const void *, void *, size_t));
>  void bpf_mcopy(const void *, void *, size_t);
> @@ -320,6 +320,8 @@ bpf_detachd(struct bpf_d *d)
>   if (d->bd_promisc) {
>   int error;
>  
> + KASSERT(bp->bif_ifp != NULL);
> +
>   d->bd_promisc = 0;
>  
>   bpf_get(d);
> @@ -593,7 +595,7 @@ bpfwrite(dev_t dev, struct uio *uio, int
>   bpf_get(d);
>   ifp = d->bd_bif->bif_ifp;
>  
> - if ((ifp->if_flags & IFF_UP) == 0) {
> + if (ifp == NULL || (ifp->if_flags & IFF_UP) == 0) {
>   error = ENETDOWN;
>   goto out;
>   }
> @@ -789,7 +791,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>   * No interface attached yet.
>   */
>   error = EINVAL;
> - } else {
> + } else if (d->bd_bif->bif_ifp != NULL) {
>   if (d->bd_promisc == 0) {
>   MUTEX_ASSERT_UNLOCKED(&d->bd_mtx);
>   error = ifpromisc(d->bd_bif->bif_ifp, 1);
> @@ -839,7 +841,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t
>   if (d->bd_bif == NULL)
>   error = EINVAL;
>   else
> - bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
> + bpf_ifname(d->bd_bif, (struct ifreq *)addr);
>   break;
>  
>   /*
> @@ -1049,10 +1051,7 @@ bpf_setif(struct bpf_d *d, struct ifreq
>   * Look through attached interfaces for the named one.
>   */
>   for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> - struct ifnet *ifp = bp->bif_ifp;
> -
> - if (ifp == NULL ||
> -    strcmp(ifp->if_xname, ifr->ifr_name) != 0)
> + if (strcmp(bp->bif_name, ifr->ifr_name) != 0)
>   continue;
>  
>   if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt)
> @@ -1090,9 +1089,9 @@ out:
>   * Copy the interface name to the ifreq.
>   */
>  void
> -bpf_ifname(struct ifnet *ifp, struct ifreq *ifr)
> +bpf_ifname(struct bpf_if *bif, struct ifreq *ifr)
>  {
> - bcopy(ifp->if_xname, ifr->ifr_name, IFNAMSIZ);
> + bcopy(bif->bif_name, ifr->ifr_name, sizeof(ifr->ifr_name));
>  }
>  
>  /*
> @@ -1538,21 +1537,17 @@ bpf_put(struct bpf_d *bd)
>   free(bd, M_DEVBUF, sizeof(*bd));
>  }
>  
> -/*
> - * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
> - * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
> - * size of the link header (variable length headers not yet supported).
> - */
> -void
> -bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
> +void *
> +bpfsattach(caddr_t *bpfp, const char *name, u_int dlt, u_int hdrlen)
>  {
>   struct bpf_if *bp;
>  
>   if ((bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT)) == NULL)
>   panic("bpfattach");
>   SRPL_INIT(&bp->bif_dlist);
> - bp->bif_driverp = (struct bpf_if **)driverp;
> - bp->bif_ifp = ifp;
> + bp->bif_driverp = (struct bpf_if **)bpfp;
> + bp->bif_name = name;
> + bp->bif_ifp = NULL;
>   bp->bif_dlt = dlt;
>  
>   bp->bif_next = bpf_iflist;
> @@ -1567,6 +1562,17 @@ bpfattach(caddr_t *driverp, struct ifnet
>   * performance reasons and to alleviate alignment restrictions).
>   */
>   bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
> +
> + return (bp);
> +}
> +
> +void
> +bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
> +{
> + struct bpf_if *bp;
> +
> + bp = bpfsattach(driverp, ifp->if_xname, dlt, hdrlen);
> + bp->bif_ifp = ifp;
>  }
>  
>  /* Detach an interface from its attached bpf device.  */
> @@ -1574,31 +1580,39 @@ void
>  bpfdetach(struct ifnet *ifp)
>  {
>   struct bpf_if *bp, *nbp, **pbp = &bpf_iflist;
> - struct bpf_d *bd;
> - int maj;
>  
>   KERNEL_ASSERT_LOCKED();
>  
>   for (bp = bpf_iflist; bp; bp = nbp) {
> - nbp= bp->bif_next;
> + nbp = bp->bif_next;
>   if (bp->bif_ifp == ifp) {
>   *pbp = nbp;
>  
> - /* Locate the major number. */
> - for (maj = 0; maj < nchrdev; maj++)
> - if (cdevsw[maj].d_open == bpfopen)
> - break;
> -
> - while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
> - vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
> -
> - free(bp, M_DEVBUF, sizeof *bp);
> + bpfsdetach(bp);
>   } else
>   pbp = &bp->bif_next;
>   }
>   ifp->if_bpf = NULL;
>  }
>  
> +void
> +bpfsdetach(void *p)
> +{
> + struct bpf_if *bp = p;
> + struct bpf_d *bd;
> + int maj;
> +
> + /* Locate the major number. */
> + for (maj = 0; maj < nchrdev; maj++)
> + if (cdevsw[maj].d_open == bpfopen)
> + break;
> +
> + while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
> + vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
> +
> + free(bp, M_DEVBUF, sizeof *bp);
> +}
> +
>  int
>  bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
>      void *newp, size_t newlen)
> @@ -1674,14 +1688,14 @@ int
>  bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
>  {
>   int n, error;
> - struct ifnet *ifp;
>   struct bpf_if *bp;
> + const char *name;
>  
> - ifp = d->bd_bif->bif_ifp;
> + name = d->bd_bif->bif_name;
>   n = 0;
>   error = 0;
>   for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> - if (bp->bif_ifp != ifp)
> + if (strcmp(name, bp->bif_name) != 0)
>   continue;
>   if (bfl->bfl_list != NULL) {
>   if (n >= bfl->bfl_len)
> @@ -1704,15 +1718,17 @@ bpf_getdltlist(struct bpf_d *d, struct b
>  int
>  bpf_setdlt(struct bpf_d *d, u_int dlt)
>  {
> - struct ifnet *ifp;
> + const char *name;
>   struct bpf_if *bp;
>  
>   MUTEX_ASSERT_LOCKED(&d->bd_mtx);
>   if (d->bd_bif->bif_dlt == dlt)
>   return (0);
> - ifp = d->bd_bif->bif_ifp;
> + name = d->bd_bif->bif_name;
>   for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
> - if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
> + if (strcmp(name, bp->bif_name) != 0)
> + continue;
> + if (bp->bif_dlt == dlt)
>   break;
>   }
>   if (bp == NULL)
> Index: bpf.h
> ===================================================================
> RCS file: /cvs/src/sys/net/bpf.h,v
> retrieving revision 1.62
> diff -u -p -r1.62 bpf.h
> --- bpf.h 22 Feb 2017 09:56:03 -0000 1.62
> +++ bpf.h 10 Jan 2018 07:27:45 -0000
> @@ -313,6 +313,8 @@ int bpf_mtap_af(caddr_t, u_int32_t, con
>  int bpf_mtap_ether(caddr_t, const struct mbuf *, u_int);
>  void bpfattach(caddr_t *, struct ifnet *, u_int, u_int);
>  void bpfdetach(struct ifnet *);
> +void *bpfsattach(caddr_t *, const char *, u_int, u_int);
> +void bpfsdetach(void *);
>  void bpfilterattach(int);
>  
>  u_int bpf_mfilter(const struct bpf_insn *, const struct mbuf *, u_int);
> Index: bpfdesc.h
> ===================================================================
> RCS file: /cvs/src/sys/net/bpfdesc.h,v
> retrieving revision 1.35
> diff -u -p -r1.35 bpfdesc.h
> --- bpfdesc.h 24 Jan 2017 10:08:30 -0000 1.35
> +++ bpfdesc.h 10 Jan 2018 07:27:45 -0000
> @@ -103,6 +103,7 @@ struct bpf_if {
>   struct bpf_if **bif_driverp; /* pointer into softc */
>   u_int bif_dlt; /* link layer type */
>   u_int bif_hdrlen; /* length of header (with padding) */
> + const char *bif_name; /* name of "subsystem" */
>   struct ifnet *bif_ifp; /* corresponding interface */
>  };
>  
> Index: pf.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf.c,v
> retrieving revision 1.1054
> diff -u -p -r1.1054 pf.c
> --- pf.c 29 Dec 2017 23:55:22 -0000 1.1054
> +++ pf.c 10 Jan 2018 07:27:45 -0000
> @@ -104,6 +104,11 @@
>  #include <ddb/db_interface.h>
>  #endif
>  
> +#if NBPFILTER > 0
> +#include <net/bpf.h>
> +caddr_t pf_bpf;
> +#endif
> +
>  /*
>   * Global variables
>   */
> @@ -6719,6 +6724,11 @@ pf_test(sa_family_t af, int fwdir, struc
>  
>   if (!pf_status.running)
>   return (PF_PASS);
> +
> +#if NBPFILTER > 0
> + if (pf_bpf)
> + bpf_mtap_af(pf_bpf, af, *m0, BPF_DIRECTION_IN);
> +#endif
>  
>  #if NCARP > 0
>   if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
> Index: pf_ioctl.c
> ===================================================================
> RCS file: /cvs/src/sys/net/pf_ioctl.c,v
> retrieving revision 1.326
> diff -u -p -r1.326 pf_ioctl.c
> --- pf_ioctl.c 28 Nov 2017 16:05:46 -0000 1.326
> +++ pf_ioctl.c 10 Jan 2018 07:27:45 -0000
> @@ -35,6 +35,7 @@
>   *
>   */
>  
> +#include "bpfilter.h"
>  #include "pfsync.h"
>  #include "pflog.h"
>  
> @@ -84,6 +85,11 @@
>  #include <net/if_pfsync.h>
>  #endif /* NPFSYNC > 0 */
>  
> +#if NBPFILTER > 0
> +#include <net/bpf.h>
> +extern caddr_t pf_bpf;
> +#endif
> +
>  struct pool pf_tag_pl;
>  
>  void pfattach(int);
> @@ -231,6 +237,10 @@ pfattach(int num)
>  
>   /* XXX do our best to avoid a conflict */
>   pf_status.hostid = arc4random();
> +
> +#if NBPFILTER > 0
> + bpfsattach(&pf_bpf, "pf", DLT_LOOP, sizeof(u_int32_t));
> +#endif
>  }
>  
>  int
>