Index | Thread | Search

From:
David Gwynne <david@gwynne.id.au>
Subject:
move some pf_status counters to per cpu counters
To:
tech@openbsd.org
Date:
Fri, 28 Nov 2025 09:22:19 +1000

Download raw body.

Thread
currently there's a bunch of global pf stats that are collected in a
single struct. we've been moving counters in other subsystems to per cpu
counters, it makes sense to follow suit here.

this is the lowest hanging fruit in pf_status. the search counter is
updated every time the state table is searched, which is a lot. once
this is in i can move a few of the other chunks of stats to per cpu
counters too.

ok?

Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
diff -u -p -r1.1219 pf.c
--- pf.c	11 Nov 2025 04:06:20 -0000	1.1219
+++ pf.c	27 Nov 2025 23:14:43 -0000
@@ -49,6 +49,7 @@
 #include <sys/pool.h>
 #include <sys/proc.h>
 #include <sys/rwlock.h>
+#include <sys/percpu.h>
 #include <sys/syslog.h>
 
 #include <crypto/sha2.h>
@@ -101,6 +102,7 @@ struct pf_queuehead	*pf_queues_active;
 struct pf_queuehead	*pf_queues_inactive;
 
 struct pf_status	 pf_status;
+static struct cpumem	*pf_status_fcounters;
 
 struct mutex		 pf_inp_mtx = MUTEX_INITIALIZER(IPL_SOFTNET);
 
@@ -1337,7 +1339,7 @@ pf_state_insert(struct pfi_kif *kif, str
 		return (-1);
 	}
 	pf_state_list_insert(&pf_state_list, st);
-	pf_status.fcounters[FCNT_STATE_INSERT]++;
+	counters_inc(pf_status_fcounters, FCNT_STATE_INSERT);
 	pf_status.states++;
 	pfi_kif_ref(kif, PFI_KIF_REF_STATE);
 	PF_STATE_EXIT_WRITE();
@@ -1355,7 +1357,7 @@ pf_state_insert(struct pfi_kif *kif, str
 struct pf_state *
 pf_find_state_byid(struct pf_state_cmp *key)
 {
-	pf_status.fcounters[FCNT_STATE_SEARCH]++;
+	counters_inc(pf_status_fcounters, FCNT_STATE_SEARCH);
 
 	return (RBT_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
 }
@@ -1402,7 +1404,7 @@ pf_find_state(struct pf_pdesc *pd, struc
 	struct pf_state_item	*si;
 	struct pf_state		*st = NULL;
 
-	pf_status.fcounters[FCNT_STATE_SEARCH]++;
+	counters_inc(pf_status_fcounters, FCNT_STATE_SEARCH);
 	if (pf_status.debug >= LOG_DEBUG) {
 		log(LOG_DEBUG, "pf: key search, %s on %s: ",
 		    pd->dir == PF_OUT ? "out" : "in", pd->kif->pfik_name);
@@ -1503,7 +1505,7 @@ pf_find_state_all(struct pf_state_key_cm
 	struct pf_state_key	*sk;
 	struct pf_state_item	*si, *ret = NULL;
 
-	pf_status.fcounters[FCNT_STATE_SEARCH]++;
+	counters_inc(pf_status_fcounters, FCNT_STATE_SEARCH);
 
 	sk = RBT_FIND(pf_state_tree, &pf_statetbl, (struct pf_state_key *)key);
 
@@ -2226,7 +2228,7 @@ pf_free_state(struct pf_state *st)
 	if (st->tag)
 		pf_tag_unref(st->tag);
 	pf_state_unref(st);
-	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
+	counters_inc(pf_status_fcounters, FCNT_STATE_REMOVALS);
 	pf_status.states--;
 }
 
@@ -9054,4 +9056,41 @@ pf_pktenqueue_delayed(void *arg)
 		m_freem(pdy->m);
 
 	pool_put(&pf_pktdelay_pl, pdy);
+}
+
+void
+pf_status_init(void)
+{
+	memset(&pf_status, 0, sizeof(pf_status));
+	pf_status.debug = LOG_ERR;
+	pf_status.reass = PF_REASS_ENABLED;
+
+	/* XXX do our best to avoid a conflict */
+	pf_status.hostid = arc4random();
+
+	pf_status_fcounters = counters_alloc(FCNT_MAX);
+}
+
+void
+pf_status_clear(void)
+{
+	PF_ASSERT_LOCKED();
+	counters_zero(pf_status_fcounters, FCNT_MAX);
+}
+
+void
+pf_status_read(struct pf_status *pfs)
+{
+	uint64_t scratch[FCNT_MAX];
+
+	NET_LOCK();
+	PF_LOCK();
+	PF_FRAG_LOCK();
+	memcpy(pfs, &pf_status, sizeof(struct pf_status));
+	PF_FRAG_UNLOCK();
+	pfi_update_status(pfs->ifname, pfs);
+	PF_UNLOCK();
+	NET_UNLOCK();
+
+	counters_read(pf_status_fcounters, pfs->fcounters, FCNT_MAX, scratch);
 }
Index: pf_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net/pf_ioctl.c,v
diff -u -p -r1.426 pf_ioctl.c
--- pf_ioctl.c	20 Nov 2025 10:47:44 -0000	1.426
+++ pf_ioctl.c	27 Nov 2025 23:14:43 -0000
@@ -290,12 +290,7 @@ pfattach(int num)
 	pf_default_rule.route.addr.type =  PF_ADDR_NONE;
 
 	pf_normalize_init();
-	memset(&pf_status, 0, sizeof(pf_status));
-	pf_status.debug = LOG_ERR;
-	pf_status.reass = PF_REASS_ENABLED;
-
-	/* XXX do our best to avoid a conflict */
-	pf_status.hostid = arc4random();
+	pf_status_init();
 
 	pf_default_rule_new = pf_default_rule;
 
@@ -2914,18 +2909,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
 		error = pf_states_get((struct pfioc_states *)addr);
 		break;
 
-	case DIOCGETSTATUS: {
-		struct pf_status *s = (struct pf_status *)addr;
-		NET_LOCK();
-		PF_LOCK();
-		PF_FRAG_LOCK();
-		memcpy(s, &pf_status, sizeof(struct pf_status));
-		PF_FRAG_UNLOCK();
-		pfi_update_status(s->ifname, s);
-		PF_UNLOCK();
-		NET_UNLOCK();
+	case DIOCGETSTATUS:
+		pf_status_read((struct pf_status *)addr);
 		break;
-	}
 
 	case DIOCSETSTATUSIF: {
 		struct pfioc_iface	*pi = (struct pfioc_iface *)addr;
@@ -2958,8 +2944,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
 			goto fail;
 		}
 
+		pf_status_clear();
 		memset(pf_status.counters, 0, sizeof(pf_status.counters));
-		memset(pf_status.fcounters, 0, sizeof(pf_status.fcounters));
 		memset(pf_status.scounters, 0, sizeof(pf_status.scounters));
 		PF_FRAG_LOCK();
 		memset(pf_status.ncounters, 0, sizeof(pf_status.ncounters));
@@ -4215,14 +4201,7 @@ pf_sysctl(void *oldp, size_t *oldlenp, v
 {
 	struct pf_status	pfs;
 
-	NET_LOCK_SHARED();
-	PF_LOCK();
-	PF_FRAG_LOCK();
-	memcpy(&pfs, &pf_status, sizeof(struct pf_status));
-	PF_FRAG_UNLOCK();
-	pfi_update_status(pfs.ifname, &pfs);
-	PF_UNLOCK();
-	NET_UNLOCK_SHARED();
+	pf_status_read(&pfs);
 
 	return sysctl_rdstruct(oldp, oldlenp, newp, &pfs, sizeof(pfs));
 }
Index: pfvar_priv.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar_priv.h,v
diff -u -p -r1.39 pfvar_priv.h
--- pfvar_priv.h	11 Nov 2025 04:06:20 -0000	1.39
+++ pfvar_priv.h	27 Nov 2025 23:14:43 -0000
@@ -680,6 +680,10 @@ u_int16_t		pf_pkt_hash(sa_family_t, uint
 			    const struct pf_addr *, const struct pf_addr *,
 			    uint16_t, uint16_t);
 
+void			pf_status_init(void);
+void			pf_status_clear(void);
+void			pf_status_read(struct pf_status *);
+
 #endif /* _KERNEL */
 
 #endif /* _NET_PFVAR_PRIV_H_ */