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