Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Apr 2016 10:00:38 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r297816 - head/sys/net
Message-ID:  <201604111000.u3BA0cYD089783@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Mon Apr 11 10:00:38 2016
New Revision: 297816
URL: https://svnweb.freebsd.org/changeset/base/297816

Log:
  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

Modified:
  head/sys/net/bpf.c
  head/sys/net/bpf.h
  head/sys/net/if.c

Modified: head/sys/net/bpf.c
==============================================================================
--- head/sys/net/bpf.c	Mon Apr 11 09:52:24 2016	(r297815)
+++ head/sys/net/bpf.c	Mon Apr 11 10:00:38 2016	(r297816)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_bpf.h"
 #include "opt_compat.h"
+#include "opt_ddb.h"
 #include "opt_netgraph.h"
 
 #include <sys/types.h>
@@ -67,6 +68,10 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/socket.h>
 
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
 #include <net/if.h>
 #include <net/if_var.h>
 #include <net/if_dl.h>
@@ -2569,6 +2574,32 @@ bpfattach2(struct ifnet *ifp, u_int dlt,
 		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, i
 }
 
 #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 <struct bpf_if *>\n");
+		return;
+	}
+
+	bpf_show_bpf_if((struct bpf_if *)addr);
+}
+#endif

Modified: head/sys/net/bpf.h
==============================================================================
--- head/sys/net/bpf.h	Mon Apr 11 09:52:24 2016	(r297815)
+++ head/sys/net/bpf.h	Mon Apr 11 10:00:38 2016	(r297816)
@@ -1469,6 +1469,9 @@ void	 bpf_mtap2(struct bpf_if *, void *,
 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);

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Mon Apr 11 09:52:24 2016	(r297815)
+++ head/sys/net/if.c	Mon Apr 11 10:00:38 2016	(r297816)
@@ -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 
 
 	if_attach_internal(ifp, 1, ifc);
 
+	if (ifp->if_bpf == NULL)
+		bpfattach(ifp, bif_dlt, bif_hdrlen);
+
 	CURVNET_RESTORE();
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604111000.u3BA0cYD089783>