pfil hooks patch (was Re: GENERIC and firewall modules)

Matthew Dillon dillon at apollo.backplane.com
Wed May 26 11:55:50 PDT 2004


    I'd like people that both use and do not use the packet filter to try
    this patch.  It should be operationally equivalent, but skips a lot of
    code if no filters are loaded.

						-Matt

Index: net/pfil.c
===================================================================
RCS file: /cvs/src/sys/net/pfil.c,v
retrieving revision 1.1
diff -u -r1.1 pfil.c
--- net/pfil.c	2 Dec 2003 09:18:17 -0000	1.1
+++ net/pfil.c	26 May 2004 18:42:35 -0000
@@ -41,11 +41,11 @@
 #include <net/if.h>
 #include <net/pfil.h>
 
-static int pfil_list_add(pfil_list_t *,
+static int pfil_list_add(struct pfil_head *,
     int (*)(void *, struct mbuf **, struct ifnet *, int), void *, int);
 
-static int pfil_list_remove(pfil_list_t *,
-    int (*)(void *, struct mbuf **, struct ifnet *, int), void *);
+static int pfil_list_remove(struct pfil_head *,
+    int (*)(void *, struct mbuf **, struct ifnet *, int), void *, int);
 
 LIST_HEAD(, pfil_head) pfil_head_list =
     LIST_HEAD_INITIALIZER(&pfil_head_list);
@@ -92,6 +92,7 @@
 
 	TAILQ_INIT(&ph->ph_in);
 	TAILQ_INIT(&ph->ph_out);
+	ph->ph_hashooks = 0;
 
 	LIST_INSERT_HEAD(&pfil_head_list, ph, ph_list);
 
@@ -143,15 +144,15 @@
 	int err = 0;
 
 	if (flags & PFIL_IN) {
-		err = pfil_list_add(&ph->ph_in, func, arg, flags & ~PFIL_OUT);
+		err = pfil_list_add(ph, func, arg, flags & ~PFIL_OUT);
 		if (err)
 			return err;
 	}
 	if (flags & PFIL_OUT) {
-		err = pfil_list_add(&ph->ph_out, func, arg, flags & ~PFIL_IN);
+		err = pfil_list_add(ph, func, arg, flags & ~PFIL_IN);
 		if (err) {
 			if (flags & PFIL_IN)
-				pfil_list_remove(&ph->ph_in, func, arg);
+				pfil_list_remove(ph, func, arg, PFIL_IN);
 			return err;
 		}
 	}
@@ -159,11 +160,14 @@
 }
 
 static int
-pfil_list_add(pfil_list_t *list,
+pfil_list_add(struct pfil_head *ph,
     int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg,
     int flags)
 {
 	struct packet_filter_hook *pfh;
+	pfil_list_t *list;
+
+	list = (flags & PFIL_IN) ? &ph->ph_in : ph->ph_out;
 
 	/*
 	 * First make sure the hook is not already there.
@@ -191,8 +195,8 @@
 		TAILQ_INSERT_HEAD(list, pfh, pfil_link);
 	else
 		TAILQ_INSERT_TAIL(list, pfh, pfil_link);
-
-	return 0;
+	ph->ph_hashooks = 1;
+	return (0);
 }
 
 /*
@@ -206,27 +210,33 @@
 	int err = 0;
 
 	if (flags & PFIL_IN)
-		err = pfil_list_remove(&ph->ph_in, func, arg);
+		err = pfil_list_remove(ph, func, arg, PFIL_IN);
 	if ((err == 0) && (flags & PFIL_OUT))
-		err = pfil_list_remove(&ph->ph_out, func, arg);
+		err = pfil_list_remove(ph, func, arg, PFIL_OUT);
 	return err;
 }
 
 /*
  * pfil_list_remove is an internal function that takes a function off the
- * specified list.
+ * specified list.  Clear ph_hashooks if no functions remain on any list.
  */
 static int
-pfil_list_remove(pfil_list_t *list,
-    int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg)
+pfil_list_remove(struct pfil_head *ph,
+    int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg,
+    int flags)
 {
 	struct packet_filter_hook *pfh;
+	pfil_list_t *list;
+
+	list = (flags & PFIL_IN) ? &ph->ph_in : &ph->ph_out;
 
 	for (pfh = TAILQ_FIRST(list); pfh != NULL;
 	     pfh = TAILQ_NEXT(pfh, pfil_link)) {
 		if (pfh->pfil_func == func && pfh->pfil_arg == arg) {
 			TAILQ_REMOVE(list, pfh, pfil_link);
 			free(pfh, M_IFADDR);
+			if (TAILQ_EMPTY(&ph->ph_in) && TAILQ_EMPTY(&ph->ph_out))
+				ph->ph_hashooks = 0;
 			return 0;
 		}
 	}
Index: net/pfil.h
===================================================================
RCS file: /cvs/src/sys/net/pfil.h,v
retrieving revision 1.1
diff -u -r1.1 pfil.h
--- net/pfil.h	2 Dec 2003 09:18:17 -0000	1.1
+++ net/pfil.h	26 May 2004 18:43:25 -0000
@@ -66,6 +66,7 @@
 	pfil_list_t	ph_in;
 	pfil_list_t	ph_out;
 	int		ph_type;
+	int		ph_hashooks;	/* 0 if no hooks installed */
 	union {
 		u_long		phu_val;
 		void		*phu_ptr;
@@ -76,8 +77,7 @@
 };
 typedef struct pfil_head pfil_head_t;
 
-int	pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *,
-	    int);
+int	pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *, int);
 
 int	pfil_add_hook(int (*func)(void *, struct mbuf **,
 	    struct ifnet *, int), void *, int, struct pfil_head *);
@@ -99,6 +99,16 @@
 		return (TAILQ_FIRST(&ph->ph_out));
 	else
 		return (NULL);
+}
+
+/*
+ * Used for a quick shortcut around the pfil routines if no hooks have been
+ * installed.
+ */
+static __inline int
+pfil_hashooks(struct pfil_head *ph)
+{
+	return(ph->ph_hashooks);
 }
 
 /* XXX */
Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.25
diff -u -r1.25 ip_input.c
--- netinet/ip_input.c	4 May 2004 11:53:26 -0000	1.25
+++ netinet/ip_input.c	26 May 2004 18:44:17 -0000
@@ -564,13 +564,17 @@
 	 *     by NAT rewriting). When this happens, tell
 	 *     ip_forward to do the right thing.
 	 */
-	odst = ip->ip_dst;
-	if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN))
-		return;
-	if (m == NULL)			/* consumed by filter */
-		return;
-	ip = mtod(m, struct ip *);
-	using_srcrt = (odst.s_addr != ip->ip_dst.s_addr);
+	if (pfil_has_hooks(&inet_pfil_hook)) {
+		odst = ip->ip_dst;
+		if (pfil_run_hooks(&inet_pfil_hook, &m, 
+		    m->m_pkthdr.rcvif, PFIL_IN)) {
+			return;
+		}
+		if (m == NULL)			/* consumed by filter */
+			return;
+		ip = mtod(m, struct ip *);
+		using_srcrt = (odst.s_addr != ip->ip_dst.s_addr);
+	}
 #endif
 
 	if (fw_enable && IPFW_LOADED) {
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.12
diff -u -r1.12 ip_output.c
--- netinet/ip_output.c	13 Apr 2004 00:14:01 -0000	1.12
+++ netinet/ip_output.c	26 May 2004 18:45:05 -0000
@@ -730,10 +730,12 @@
 	/*
 	 * Run through list of hooks for output packets.
 	 */
-	error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT);
-	if (error != 0 || m == NULL)
-		goto done;
-	ip = mtod(m, struct ip *);
+	if (pfil_has_hooks(&inet_pfil_hook)) {
+		error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT);
+		if (error != 0 || m == NULL)
+			goto done;
+		ip = mtod(m, struct ip *);
+	}
 #endif /* PFIL_HOOKS */
 
 	/*
Index: netinet6/ip6_forward.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_forward.c,v
retrieving revision 1.7
diff -u -r1.7 ip6_forward.c
--- netinet6/ip6_forward.c	20 May 2004 18:30:36 -0000	1.7
+++ netinet6/ip6_forward.c	26 May 2004 18:45:45 -0000
@@ -519,12 +519,15 @@
 	/*
 	 * Run through list of hooks for output packets.
 	 */
-	error = pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT);
-	if (error != 0)
-		goto senderr;
-	if (m == NULL)
-		goto freecopy;
-	ip6 = mtod(m, struct ip6_hdr *);
+	if (pfil_has_hooks(&inet6_pfil_hook)) {
+		error = pfil_run_hooks(&inet6_pfil_hook, &m, 
+					rt->rt_ifp, PFIL_OUT);
+		if (error != 0)
+			goto senderr;
+		if (m == NULL)
+			goto freecopy;
+		ip6 = mtod(m, struct ip6_hdr *);
+	}
 #endif /* PFIL_HOOKS */
 
 	error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.16
diff -u -r1.16 ip6_input.c
--- netinet6/ip6_input.c	20 May 2004 18:30:36 -0000	1.16
+++ netinet6/ip6_input.c	26 May 2004 18:46:17 -0000
@@ -359,13 +359,17 @@
 	 *     (e.g. by NAT rewriting). When this happens,
 	 *     tell ip6_forward to do the right thing.
 	 */
-	odst = ip6->ip6_dst;
-	if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN))
-		goto bad2;
-	if (m == NULL)			/* consumed by filter */
-		goto bad2;
-	ip6 = mtod(m, struct ip6_hdr *);
-	srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);
+	if (pfil_has_hooks(&inet6_pfil_hook)) {
+		odst = ip6->ip6_dst;
+		if (pfil_run_hooks(&inet6_pfil_hook, &m,
+		    m->m_pkthdr.rcvif, PFIL_IN)) {
+			goto bad2;
+		}
+		if (m == NULL)			/* consumed by filter */
+			goto bad2;
+		ip6 = mtod(m, struct ip6_hdr *);
+		srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);
+	}
 #endif /* PFIL_HOOKS */
 
 	ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.10
diff -u -r1.10 ip6_output.c
--- netinet6/ip6_output.c	20 May 2004 18:30:36 -0000	1.10
+++ netinet6/ip6_output.c	26 May 2004 18:46:32 -0000
@@ -922,10 +922,12 @@
 	/*
 	 * Run through list of hooks for output packets.
 	 */
-	error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT);
-	if (error != 0 || m == NULL)
-		goto done;
-	ip6 = mtod(m, struct ip6_hdr *);
+	if (pfil_has_hooks(&inet6_pfil_hook)) {
+		error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT);
+		if (error != 0 || m == NULL)
+			goto done;
+		ip6 = mtod(m, struct ip6_hdr *);
+	}
 #endif /* PFIL_HOOKS */
 	/*
 	 * Send the packet to the outgoing interface.





More information about the Kernel mailing list