git: 6b7c2680039b - main - pf: Only hook the Ethernet pfil hook when we have rules

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Wed, 02 Mar 2022 16:00:45 UTC
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=6b7c2680039b4e1b1d571bf4f443d99878a7fbc0

commit 6b7c2680039b4e1b1d571bf4f443d99878a7fbc0
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-02-16 12:42:31 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2022-03-02 16:00:04 +0000

    pf: Only hook the Ethernet pfil hook when we have rules
    
    Avoid the overhead of the Ethernet pfil hooks if we don't have any
    Ethernet rules.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D31742
---
 sys/netpfil/pf/pf_ioctl.c | 59 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 53 insertions(+), 6 deletions(-)

diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index b2537720bb7e..b116d6e91a7b 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -240,7 +240,9 @@ static pfil_return_t pf_check6_out(struct mbuf **m, struct ifnet *ifp,
     int flags, void *ruleset __unused, struct inpcb *inp);
 #endif
 
+static void		hook_pf_eth(void);
 static void		hook_pf(void);
+static void		dehook_pf_eth(void);
 static void		dehook_pf(void);
 static int		shutdown_pf(void);
 static int		pf_load(void);
@@ -254,6 +256,8 @@ static struct cdevsw pf_cdevsw = {
 
 volatile VNET_DEFINE_STATIC(int, pf_pfil_hooked);
 #define V_pf_pfil_hooked	VNET(pf_pfil_hooked)
+volatile VNET_DEFINE_STATIC(int, pf_pfil_eth_hooked);
+#define V_pf_pfil_eth_hooked	VNET(pf_pfil_eth_hooked)
 
 /*
  * We need a flag that is neither hooked nor running to know when
@@ -372,6 +376,7 @@ pfattach_vnet(void)
 	V_pf_status.debug = PF_DEBUG_URGENT;
 
 	V_pf_pfil_hooked = 0;
+	V_pf_pfil_eth_hooked = 0;
 
 	/* XXX do our best to avoid a conflict */
 	V_pf_status.hostid = arc4random();
@@ -2470,6 +2475,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 			int cpu;
 
 			hook_pf();
+			if (! TAILQ_EMPTY(&V_pf_keth->rules))
+				hook_pf_eth();
 			V_pf_status.running = 1;
 			V_pf_status.since = time_second;
 
@@ -2487,6 +2494,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 		else {
 			V_pf_status.running = 0;
 			dehook_pf();
+			dehook_pf_eth();
 			V_pf_status.since = time_second;
 			DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
 		}
@@ -5027,6 +5035,13 @@ DIOCCHANGEADDR_error:
 			}
 		}
 		PF_RULES_WUNLOCK();
+
+		/* Only hook into EtherNet taffic if we've got rules for it. */
+		if (! TAILQ_EMPTY(&V_pf_keth->rules))
+			hook_pf_eth();
+		else
+			dehook_pf_eth();
+
 		free(ioes, M_TEMP);
 		break;
 	}
@@ -6076,13 +6091,13 @@ VNET_DEFINE_STATIC(pfil_hook_t, pf_ip6_out_hook);
 #endif
 
 static void
-hook_pf(void)
+hook_pf_eth(void)
 {
 	struct pfil_hook_args pha;
 	struct pfil_link_args pla;
 	int ret __diagused;
 
-	if (V_pf_pfil_hooked)
+	if (V_pf_pfil_eth_hooked)
 		return;
 
 	pha.pa_version = PFIL_VERSION;
@@ -6099,7 +6114,8 @@ hook_pf(void)
 	pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR;
 	pla.pa_head = V_link_pfil_head;
 	pla.pa_hook = V_pf_eth_in_hook;
-	(void)pfil_link(&pla);
+	ret = pfil_link(&pla);
+	MPASS(ret == 0);
 	pha.pa_func = pf_eth_check_out;
 	pha.pa_flags = PFIL_OUT;
 	pha.pa_rulname = "eth-out";
@@ -6107,7 +6123,27 @@ hook_pf(void)
 	pla.pa_flags = PFIL_OUT | PFIL_HEADPTR | PFIL_HOOKPTR;
 	pla.pa_head = V_link_pfil_head;
 	pla.pa_hook = V_pf_eth_out_hook;
-	(void)pfil_link(&pla);
+	ret = pfil_link(&pla);
+	MPASS(ret == 0);
+
+	V_pf_pfil_eth_hooked = 1;
+}
+
+static void
+hook_pf(void)
+{
+	struct pfil_hook_args pha;
+	struct pfil_link_args pla;
+	int ret;
+
+	if (V_pf_pfil_hooked)
+		return;
+
+	pha.pa_version = PFIL_VERSION;
+	pha.pa_modname = "pf";
+	pha.pa_ruleset = NULL;
+
+	pla.pa_version = PFIL_VERSION;
 
 #ifdef INET
 	pha.pa_type = PFIL_TYPE_IP4;
@@ -6156,15 +6192,25 @@ hook_pf(void)
 }
 
 static void
-dehook_pf(void)
+dehook_pf_eth(void)
 {
 
-	if (V_pf_pfil_hooked == 0)
+	if (V_pf_pfil_eth_hooked == 0)
 		return;
 
 	pfil_remove_hook(V_pf_eth_in_hook);
 	pfil_remove_hook(V_pf_eth_out_hook);
 
+	V_pf_pfil_eth_hooked = 0;
+}
+
+static void
+dehook_pf(void)
+{
+
+	if (V_pf_pfil_hooked == 0)
+		return;
+
 #ifdef INET
 	pfil_remove_hook(V_pf_ip4_in_hook);
 	pfil_remove_hook(V_pf_ip4_out_hook);
@@ -6231,6 +6277,7 @@ pf_unload_vnet(void)
 	V_pf_vnet_active = 0;
 	V_pf_status.running = 0;
 	dehook_pf();
+	dehook_pf_eth();
 
 	PF_RULES_WLOCK();
 	pf_syncookies_cleanup();