From: David Gwynne Subject: move some pf_status counters to per cpu counters To: tech@openbsd.org Date: Fri, 28 Nov 2025 09:22:19 +1000 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 #include #include +#include #include #include @@ -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_ */