Date: Wed, 11 Aug 2021 15:22:43 GMT From: Mateusz Guzik <mjg@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: fff80a6992f1 - stable/13 - pf: add hybrid 32- an 64- bit counters Message-ID: <202108111522.17BFMhuj064297@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=fff80a6992f1ba13f2261b066d70a3a97d8837e4 commit fff80a6992f1ba13f2261b066d70a3a97d8837e4 Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2021-07-22 20:47:24 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> CommitDate: 2021-08-11 13:37:53 +0000 pf: add hybrid 32- an 64- bit counters Numerous counters got migrated from straight uint64_t to the counter(9) API. Unfortunately the implementation comes with a significiant performance hit on some platforms and cannot be easily fixed. Work around the problem by implementing a pf-specific variant. Reviewed by: kp Sponsored by: Rubicon Communications, LLC ("Netgate") (cherry picked from commit defdcdd5648dc1ea789bc54bb45108fcab546a6b) --- sys/net/pfvar.h | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sys/netpfil/pf/pf.c | 28 ++++++- 2 files changed, 245 insertions(+), 1 deletion(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 55ecbecf657a..e381279a113f 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -43,9 +43,11 @@ #include <sys/nv.h> #include <sys/refcount.h> #include <sys/sysctl.h> +#include <sys/smp.h> #include <sys/lock.h> #include <sys/rmlock.h> #include <sys/tree.h> +#include <sys/seqc.h> #include <vm/uma.h> #include <net/radix.h> @@ -64,6 +66,222 @@ #ifdef _KERNEL +#if defined(__arm__) +#define PF_WANT_32_TO_64_COUNTER +#endif + +/* + * A hybrid of 32-bit and 64-bit counters which can be used on platforms where + * counter(9) is very expensive. + * + * As 32-bit counters are expected to overflow, a periodic job sums them up to + * a saved 64-bit state. Fetching the value still walks all CPUs to get the most + * current snapshot. + */ +#ifdef PF_WANT_32_TO_64_COUNTER +struct pf_counter_u64_pcpu { + u_int32_t current; + u_int32_t snapshot; +}; + +struct pf_counter_u64 { + struct pf_counter_u64_pcpu *pfcu64_pcpu; + u_int64_t pfcu64_value; + seqc_t pfcu64_seqc; +}; + +static inline int +pf_counter_u64_init(struct pf_counter_u64 *pfcu64, int flags) +{ + + pfcu64->pfcu64_value = 0; + pfcu64->pfcu64_seqc = 0; + pfcu64->pfcu64_pcpu = uma_zalloc_pcpu(pcpu_zone_8, flags | M_ZERO); + if (__predict_false(pfcu64->pfcu64_pcpu == NULL)) + return (ENOMEM); + return (0); +} + +static inline void +pf_counter_u64_deinit(struct pf_counter_u64 *pfcu64) +{ + + uma_zfree_pcpu(pcpu_zone_8, pfcu64->pfcu64_pcpu); +} + +static inline void +pf_counter_u64_critical_enter(void) +{ + + critical_enter(); +} + +static inline void +pf_counter_u64_critical_exit(void) +{ + + critical_exit(); +} + +static inline void +pf_counter_u64_add_protected(struct pf_counter_u64 *pfcu64, uint32_t n) +{ + struct pf_counter_u64_pcpu *pcpu; + u_int32_t val; + + MPASS(curthread->td_critnest > 0); + pcpu = zpcpu_get(pfcu64->pfcu64_pcpu); + val = atomic_load_int(&pcpu->current); + atomic_store_int(&pcpu->current, val + n); +} + +static inline void +pf_counter_u64_add(struct pf_counter_u64 *pfcu64, uint32_t n) +{ + + critical_enter(); + pf_counter_u64_add_protected(pfcu64, n); + critical_exit(); +} + +static inline u_int64_t +pf_counter_u64_periodic(struct pf_counter_u64 *pfcu64) +{ + struct pf_counter_u64_pcpu *pcpu; + u_int64_t sum; + u_int32_t val; + int cpu; + + MPASS(curthread->td_critnest > 0); + seqc_write_begin(&pfcu64->pfcu64_seqc); + sum = pfcu64->pfcu64_value; + CPU_FOREACH(cpu) { + pcpu = zpcpu_get_cpu(pfcu64->pfcu64_pcpu, cpu); + val = atomic_load_int(&pcpu->current); + sum += (uint32_t)(val - pcpu->snapshot); + pcpu->snapshot = val; + } + pfcu64->pfcu64_value = sum; + seqc_write_end(&pfcu64->pfcu64_seqc); + return (sum); +} + +static inline u_int64_t +pf_counter_u64_fetch(struct pf_counter_u64 *pfcu64) +{ + struct pf_counter_u64_pcpu *pcpu; + u_int64_t sum; + seqc_t seqc; + int cpu; + + for (;;) { + seqc = seqc_read(&pfcu64->pfcu64_seqc); + sum = 0; + CPU_FOREACH(cpu) { + pcpu = zpcpu_get_cpu(pfcu64->pfcu64_pcpu, cpu); + sum += (uint32_t)(atomic_load_int(&pcpu->current) -pcpu->snapshot); + } + sum += pfcu64->pfcu64_value; + if (seqc_consistent(&pfcu64->pfcu64_seqc, seqc)) + break; + } + return (sum); +} + +static inline void +pf_counter_u64_zero_protected(struct pf_counter_u64 *pfcu64) +{ + struct pf_counter_u64_pcpu *pcpu; + int cpu; + + MPASS(curthread->td_critnest > 0); + seqc_write_begin(&pfcu64->pfcu64_seqc); + CPU_FOREACH(cpu) { + pcpu = zpcpu_get_cpu(pfcu64->pfcu64_pcpu, cpu); + pcpu->snapshot = atomic_load_int(&pcpu->current); + } + pfcu64->pfcu64_value = 0; + seqc_write_end(&pfcu64->pfcu64_seqc); +} + +static inline void +pf_counter_u64_zero(struct pf_counter_u64 *pfcu64) +{ + + critical_enter(); + pf_counter_u64_zero_protected(pfcu64); + critical_exit(); +} +#else +struct pf_counter_u64 { + counter_u64_t counter; +}; + +static inline int +pf_counter_u64_init(struct pf_counter_u64 *pfcu64, int flags) +{ + + pfcu64->counter = counter_u64_alloc(flags); + if (__predict_false(pfcu64->counter == NULL)) + return (ENOMEM); + return (0); +} + +static inline void +pf_counter_u64_deinit(struct pf_counter_u64 *pfcu64) +{ + + counter_u64_free(pfcu64->counter); +} + +static inline void +pf_counter_u64_critical_enter(void) +{ + +} + +static inline void +pf_counter_u64_critical_exit(void) +{ + +} + +static inline void +pf_counter_u64_add_protected(struct pf_counter_u64 *pfcu64, uint32_t n) +{ + + counter_u64_add(pfcu64->counter, n); +} + +static inline void +pf_counter_u64_add(struct pf_counter_u64 *pfcu64, uint32_t n) +{ + + pf_counter_u64_add_protected(pfcu64, n); +} + +static inline u_int64_t +pf_counter_u64_fetch(struct pf_counter_u64 *pfcu64) +{ + + return (counter_u64_fetch(pfcu64->counter)); +} + +static inline void +pf_counter_u64_zero_protected(struct pf_counter_u64 *pfcu64) +{ + + counter_u64_zero(pfcu64->counter); +} + +static inline void +pf_counter_u64_zero(struct pf_counter_u64 *pfcu64) +{ + + pf_counter_u64_zero_protected(pfcu64); +} +#endif + SYSCTL_DECL(_net_pf); MALLOC_DECLARE(M_PFHASH); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 0db9eaed1ac4..b74491bb88d0 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -154,6 +154,11 @@ VNET_DECLARE(int, pf_vnet_active); VNET_DEFINE_STATIC(uint32_t, pf_purge_idx); #define V_pf_purge_idx VNET(pf_purge_idx) +#ifdef PF_WANT_32_TO_64_COUNTER +VNET_DEFINE_STATIC(uint32_t, pf_counter_periodic_iter); +#define V_pf_counter_periodic_iter VNET(pf_counter_periodic_iter) +#endif + /* * Queue for pf_intr() sends. */ @@ -1509,6 +1514,25 @@ pf_intr(void *v) CURVNET_RESTORE(); } +#define pf_purge_thread_period (hz / 10) + +#ifdef PF_WANT_32_TO_64_COUNTER +static void +pf_counter_u64_periodic_main(void) +{ + PF_RULES_RLOCK_TRACKER; + + V_pf_counter_periodic_iter++; + + PF_RULES_RLOCK(); + pf_counter_u64_critical_enter(); + pf_counter_u64_critical_exit(); + PF_RULES_RUNLOCK(); +} +#else +#define pf_counter_u64_periodic_main() do { } while (0) +#endif + void pf_purge_thread(void *unused __unused) { @@ -1516,7 +1540,7 @@ pf_purge_thread(void *unused __unused) sx_xlock(&pf_end_lock); while (pf_end_threads == 0) { - sx_sleep(pf_purge_thread, &pf_end_lock, 0, "pftm", hz / 10); + sx_sleep(pf_purge_thread, &pf_end_lock, 0, "pftm", pf_purge_thread_period); VNET_LIST_RLOCK(); VNET_FOREACH(vnet_iter) { @@ -1528,6 +1552,8 @@ pf_purge_thread(void *unused __unused) continue; } + pf_counter_u64_periodic_main(); + /* * Process 1/interval fraction of the state * table every run.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202108111522.17BFMhuj064297>