svn commit: r241966 - user/andre/tcp_workqueue/sys/net

Andre Oppermann andre at FreeBSD.org
Tue Oct 23 19:26:50 UTC 2012


Author: andre
Date: Tue Oct 23 19:26:49 2012
New Revision: 241966
URL: http://svn.freebsd.org/changeset/base/241966

Log:
  Extend PFIL hooks with explicit hook ordering and reinjecting of
  packets into the chain after a particular hook.
  
  Add pfil_add_hook_order() taking a numerical value between 0-255
  to specify the relative position of this hook in the list of all
  hooks.  Lower numbers have higher ordering (ie. will run first).
  Within a particular order value the last added will be the first
  to run.  Three fixed positions are defined:
   PFIL_ORDER_FIRST	  0
   PFIL_ORDER_DEFAULT	200
   PFIL_ORDER_LAST	255
  
  Previously the order was non-deterministic and dependent on the
  ordering of the add hook calls.  The last added would always
  become the first to run.
  
  Non-ordering aware pfil consumers using the pfil_add_hook() call
  get PFIL_ORDER_DEFAULT assigned resulting in the previous ordering.
  
  The ordering is determined at hookup time by the pfil consumer
  and no tool for later manual re-ordering is provided.  Most well
  known pfil consumers are expected to have a predetermined preferred
  position in the order.  A tool or sysctl reporting the order of
  hooked pfil consumers will be provided later.
  
  Add pfil_run_inject() taking an opaque cookie value obtained with
  pfil_get_cookie() after the hook is added.  Processing of the hook
  chain skips all hooks until after the one with the same cookie.
  The cookie is valid as long as this hook remains hooked.  If no
  cookie is found processing is started with the first hook again.
  If the cookie is invalid processing of all hooks is effectively
  skipped.
  
  With this pfil hooks consumers can dequeue packets for further
  processing and later re-inject them with the next hook.

Modified:
  user/andre/tcp_workqueue/sys/net/pfil.c
  user/andre/tcp_workqueue/sys/net/pfil.h

Modified: user/andre/tcp_workqueue/sys/net/pfil.c
==============================================================================
--- user/andre/tcp_workqueue/sys/net/pfil.c	Tue Oct 23 19:20:50 2012	(r241965)
+++ user/andre/tcp_workqueue/sys/net/pfil.c	Tue Oct 23 19:26:49 2012	(r241966)
@@ -49,7 +49,8 @@
 
 static MTX_DEF_SYSINIT(pfil_global_lock, "pfil_head_list lock", MTX_DEF);
 
-static int pfil_list_add(pfil_list_t *, struct packet_filter_hook *, int);
+static int pfil_list_add(pfil_list_t *, struct packet_filter_hook *, int,
+    uint8_t);
 
 static int pfil_list_remove(pfil_list_t *,
     int (*)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *),
@@ -63,11 +64,22 @@ VNET_DEFINE(struct rmlock, pfil_lock);
 
 /*
  * pfil_run_hooks() runs the specified packet filter hooks.
+ *
+ * The cookie, if set, skips all hooks before the hook with
+ * the same cookie and continues with the next hook after it.
  */
 int
 pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp,
     int dir, struct inpcb *inp)
 {
+
+	return (pfil_run_inject(ph, mp, ifp, dir, inp, 0));
+}
+
+int
+pfil_run_inject(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp,
+    int dir, struct inpcb *inp, int cookie)
+{
 	struct rm_priotracker rmpt;
 	struct packet_filter_hook *pfh;
 	struct mbuf *m = *mp;
@@ -77,6 +89,12 @@ pfil_run_hooks(struct pfil_head *ph, str
 	KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0"));
 	for (pfh = pfil_hook_get(dir, ph); pfh != NULL;
 	     pfh = TAILQ_NEXT(pfh, pfil_link)) {
+		if (cookie != 0) {
+			/* Continue on the next hook. */
+			if (pfh->pfil_cookie == cookie)
+				cookie = 0;
+			continue;
+		}
 		if (pfh->pfil_func != NULL) {
 			rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir,
 			    inp);
@@ -213,11 +231,21 @@ pfil_head_get(int type, u_long val)
  *	PFIL_OUT	call me on outgoing packets
  *	PFIL_ALL	call me on all of the above
  *	PFIL_WAITOK	OK to call malloc with M_WAITOK.
+ *
+ * The cookie is simply is a random value that should be unique.
  */
 int
 pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int,
   struct inpcb *), void *arg, int flags, struct pfil_head *ph)
 {
+
+	return (pfil_add_hook_order(func, arg, flags, PFIL_ORDER_DEFAULT, ph));
+}
+
+int
+pfil_add_hook_order(int (*func)(void *, struct mbuf **, struct ifnet *, int,
+  struct inpcb *), void *arg, int flags, uint8_t order, struct pfil_head *ph)
+{
 	struct packet_filter_hook *pfh1 = NULL;
 	struct packet_filter_hook *pfh2 = NULL;
 	int err;
@@ -229,6 +257,10 @@ pfil_add_hook(int (*func)(void *, struct
 			err = ENOMEM;
 			goto error;
 		}
+		pfh1->pfil_func = func;
+		pfh1->pfil_arg = arg;
+		pfh1->pfil_cookie = (int)random();
+		pfh1->pfil_order = order;
 	}
 	if (flags & PFIL_OUT) {
 		pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
@@ -237,20 +269,20 @@ pfil_add_hook(int (*func)(void *, struct
 			err = ENOMEM;
 			goto error;
 		}
+		pfh2->pfil_func = func;
+		pfh2->pfil_arg = arg;
+		pfh2->pfil_cookie = (int)random();
+		pfh2->pfil_order = order;
 	}
 	PFIL_WLOCK(ph);
 	if (flags & PFIL_IN) {
-		pfh1->pfil_func = func;
-		pfh1->pfil_arg = arg;
-		err = pfil_list_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT);
+		err = pfil_list_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT, order);
 		if (err)
 			goto locked_error;
 		ph->ph_nhooks++;
 	}
 	if (flags & PFIL_OUT) {
-		pfh2->pfil_func = func;
-		pfh2->pfil_arg = arg;
-		err = pfil_list_add(&ph->ph_out, pfh2, flags & ~PFIL_IN);
+		err = pfil_list_add(&ph->ph_out, pfh2, flags & ~PFIL_IN, order);
 		if (err) {
 			if (flags & PFIL_IN)
 				pfil_list_remove(&ph->ph_in, func, arg);
@@ -295,8 +327,35 @@ pfil_remove_hook(int (*func)(void *, str
 	return (err);
 }
 
+int
+pfil_get_cookie(int (*func)(void *, struct mbuf **, struct ifnet *, int,
+    struct inpcb *), void *arg, int flags, struct pfil_head *ph)
+{
+	pfil_list_t *list;
+	struct packet_filter_hook *pfh;
+	struct rm_priotracker tracker;
+	int cookie = 0;
+
+	PFIL_RLOCK(ph, &tracker);
+	if (flags & PFIL_IN)
+		list = &ph->ph_in;
+	else if (flags & PFIL_OUT)
+		list = &ph->ph_out;
+	else
+		goto out;
+
+	TAILQ_FOREACH(pfh, list, pfil_link)
+		if (pfh->pfil_func == func &&
+		    pfh->pfil_arg == arg)
+			cookie = pfh->pfil_cookie;
+out:
+	PFIL_RUNLOCK(ph, &tracker);
+	return (cookie);
+}
+
 static int
-pfil_list_add(pfil_list_t *list, struct packet_filter_hook *pfh1, int flags)
+pfil_list_add(pfil_list_t *list, struct packet_filter_hook *pfh1, int flags,
+    uint8_t order)
 {
 	struct packet_filter_hook *pfh;
 
@@ -312,10 +371,24 @@ pfil_list_add(pfil_list_t *list, struct 
 	 * Insert the input list in reverse order of the output list so that
 	 * the same path is followed in or out of the kernel.
 	 */
-	if (flags & PFIL_IN)
-		TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
-	else
-		TAILQ_INSERT_TAIL(list, pfh1, pfil_link);
+	if (flags & PFIL_IN) {
+		TAILQ_FOREACH(pfh, list, pfil_link) {
+			if (pfh->pfil_order <= order)
+				break;
+		}
+		if (pfh == NULL)
+			TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
+		else
+			TAILQ_INSERT_BEFORE(pfh, pfh1, pfil_link);
+	} else {
+		TAILQ_FOREACH_REVERSE(pfh, list, pfil_list, pfil_link)
+			if (pfh->pfil_order >= order)
+				break;
+		if (pfh == NULL)
+			TAILQ_INSERT_TAIL(list, pfh1, pfil_link);
+		else
+			TAILQ_INSERT_AFTER(list, pfh, pfh1, pfil_link);
+	}
 	return (0);
 }
 

Modified: user/andre/tcp_workqueue/sys/net/pfil.h
==============================================================================
--- user/andre/tcp_workqueue/sys/net/pfil.h	Tue Oct 23 19:20:50 2012	(r241965)
+++ user/andre/tcp_workqueue/sys/net/pfil.h	Tue Oct 23 19:26:49 2012	(r241966)
@@ -52,8 +52,14 @@ struct packet_filter_hook {
 	int	(*pfil_func)(void *, struct mbuf **, struct ifnet *, int,
 		    struct inpcb *);
 	void	*pfil_arg;
+	int	 pfil_cookie;
+	uint8_t	 pfil_order;
 };
 
+#define	PFIL_ORDER_FIRST	  0
+#define	PFIL_ORDER_DEFAULT	200
+#define	PFIL_ORDER_LAST		255
+
 #define PFIL_IN		0x00000001
 #define PFIL_OUT	0x00000002
 #define PFIL_WAITOK	0x00000004
@@ -89,10 +95,16 @@ struct pfil_head {
 
 int	pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *,
 	    int, struct inpcb *), void *, int, struct pfil_head *);
+int	pfil_add_hook_order(int (*func)(void *, struct mbuf **, struct ifnet *,
+	    int, struct inpcb *), void *, int, uint8_t, struct pfil_head *);
+int	pfil_get_cookie(int (*func)(void *, struct mbuf **, struct ifnet *,
+	    int, struct inpcb *), void *, int, struct pfil_head *);
 int	pfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *,
 	    int, struct inpcb *), void *, int, struct pfil_head *);
 int	pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *,
 	    int, struct inpcb *inp);
+int	pfil_run_inject(struct pfil_head *, struct mbuf **, struct ifnet *,
+	    int, struct inpcb *inp, int cookie);
 
 struct rm_priotracker;	/* Do not require including rmlock header */
 int pfil_try_rlock(struct pfil_head *, struct rm_priotracker *);


More information about the svn-src-user mailing list