From 05fc416403ece16a5409c39f01a4ccce2643ef69 Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Mon, 11 Apr 2016 10:00:38 +0000 Subject: [PATCH] During if_vmove() we call if_detach_internal() which in turn calls the event handler notifying about interface departure and one of the consumers will detach if_bpf. There is no way for us to re-attach this easily as the DLT and hdrlen are only given on interface creation. Add a function to allow us to query the DLT and hdrlen from a current BPF attachment and after if_attach_internal() manually re-add the if_bpf attachment using these values. Found by panics triggered by nd6 packets running past BPF_MTAP() with no proper if_bpf pointer on the interface. Also add a basic DDB show function to investigate the if_bpf attachment of an interface. Reviewed by: gnn MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D5896 --- sys/net/bpf.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ sys/net/bpf.h | 3 +++ sys/net/if.c | 11 +++++++++ 3 files changed, 76 insertions(+) diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 54dd1842e554..5f2ef71b95da 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include "opt_bpf.h" #include "opt_compat.h" +#include "opt_ddb.h" #include "opt_netgraph.h" #include @@ -67,6 +68,10 @@ __FBSDID("$FreeBSD$"); #include +#ifdef DDB +#include +#endif + #include #include #include @@ -2569,6 +2574,32 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) if_printf(ifp, "bpf attached\n"); } +#ifdef VIMAGE +/* + * When moving interfaces between vnet instances we need a way to + * query the dlt and hdrlen before detach so we can re-attch the if_bpf + * after the vmove. We unfortunately have no device driver infrastructure + * to query the interface for these values after creation/attach, thus + * add this as a workaround. + */ +int +bpf_get_bp_params(struct bpf_if *bp, u_int *bif_dlt, u_int *bif_hdrlen) +{ + + if (bp == NULL) + return (ENXIO); + if (bif_dlt == NULL && bif_hdrlen == NULL) + return (0); + + if (bif_dlt != NULL) + *bif_dlt = bp->bif_dlt; + if (bif_hdrlen != NULL) + *bif_hdrlen = bp->bif_hdrlen; + + return (0); +} +#endif + /* * Detach bpf from an interface. This involves detaching each descriptor * associated with the interface. Notify each descriptor as it's detached @@ -2977,3 +3008,34 @@ bpf_validate(const struct bpf_insn *f, int len) } #endif /* !DEV_BPF && !NETGRAPH_BPF */ + +#ifdef DDB +static void +bpf_show_bpf_if(struct bpf_if *bpf_if) +{ + + if (bpf_if == NULL) + return; + db_printf("%p:\n", bpf_if); +#define BPF_DB_PRINTF(f, e) db_printf(" %s = " f "\n", #e, bpf_if->e); + /* bif_ext.bif_next */ + /* bif_ext.bif_dlist */ + BPF_DB_PRINTF("%#x", bif_dlt); + BPF_DB_PRINTF("%u", bif_hdrlen); + BPF_DB_PRINTF("%p", bif_ifp); + /* bif_lock */ + /* bif_wlist */ + BPF_DB_PRINTF("%#x", bif_flags); +} + +DB_SHOW_COMMAND(bpf_if, db_show_bpf_if) +{ + + if (!have_addr) { + db_printf("usage: show bpf_if \n"); + return; + } + + bpf_show_bpf_if((struct bpf_if *)addr); +} +#endif diff --git a/sys/net/bpf.h b/sys/net/bpf.h index a74b521e5fef..0ffc15ac2a95 100644 --- a/sys/net/bpf.h +++ b/sys/net/bpf.h @@ -1469,6 +1469,9 @@ void bpf_mtap2(struct bpf_if *, void *, u_int, struct mbuf *); void bpfattach(struct ifnet *, u_int, u_int); void bpfattach2(struct ifnet *, u_int, u_int, struct bpf_if **); void bpfdetach(struct ifnet *); +#ifdef VIMAGE +int bpf_get_bp_params(struct bpf_if *, u_int *, u_int *); +#endif void bpfilterattach(int); u_int bpf_filter(const struct bpf_insn *, u_char *, u_int, u_int); diff --git a/sys/net/if.c b/sys/net/if.c index b9e524cdad89..2c44c87b009d 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1021,8 +1021,16 @@ void if_vmove(struct ifnet *ifp, struct vnet *new_vnet) { struct if_clone *ifc; + u_int bif_dlt, bif_hdrlen; int rc; + /* + * if_detach_internal() will call the eventhandler to notify + * interface departure. That will detach if_bpf. We need to + * safe the dlt and hdrlen so we can re-attach it later. + */ + bpf_get_bp_params(ifp->if_bpf, &bif_dlt, &bif_hdrlen); + /* * Detach from current vnet, but preserve LLADDR info, do not * mark as dead etc. so that the ifnet can be reattached later. @@ -1062,6 +1070,9 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet) if_attach_internal(ifp, 1, ifc); + if (ifp->if_bpf == NULL) + bpfattach(ifp, bif_dlt, bif_hdrlen); + CURVNET_RESTORE(); }