The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=53a341d0e445269590dcb32f8c8320c3459a21c4
commit 53a341d0e445269590dcb32f8c8320c3459a21c4 Author: Kristof Provost <k...@freebsd.org> AuthorDate: 2025-06-05 16:45:28 +0000 Commit: Kristof Provost <k...@freebsd.org> CommitDate: 2025-06-25 17:56:23 +0000 pf: use counter_rate() for rate checking This has the advantage of not requiring a lock. The current src node code runs the rate check under a lock, so this won't immediately improve performance. This prepares the way for future work, introducing packet rate matching on rules, where the lack of lock will be important. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D50797 --- sys/net/pfvar.h | 10 +++++++++- sys/netpfil/pf/pf.c | 42 +++++++++++++++--------------------------- sys/netpfil/pf/pf_ioctl.c | 15 ++++++--------- sys/netpfil/pf/pf_nl.c | 15 +++++---------- 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 24095ea28b24..8afba0525351 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -793,6 +793,12 @@ struct pf_keth_rule { uint32_t ridentifier; }; +struct pf_kthreshold { + uint32_t limit; + uint32_t seconds; + struct counter_rate *cr; +}; + RB_HEAD(pf_krule_global, pf_krule); RB_PROTOTYPE(pf_krule_global, pf_krule, entry_global, pf_krule_compare); @@ -926,7 +932,7 @@ struct pf_ksrc_node { counter_u64_t packets[2]; u_int32_t states; u_int32_t conn; - struct pf_threshold conn_rate; + struct pf_kthreshold conn_rate; u_int32_t creation; u_int32_t expire; sa_family_t af; @@ -2520,6 +2526,8 @@ struct pf_state_key *pf_alloc_state_key(int); int pf_translate(struct pf_pdesc *, struct pf_addr *, u_int16_t, struct pf_addr *, u_int16_t, u_int16_t, int); int pf_translate_af(struct pf_pdesc *); +bool pf_init_threshold(struct pf_kthreshold *, uint32_t, uint32_t); + void pfr_initialize(void); void pfr_cleanup(void); int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 03179541b890..09762abb2a16 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -307,10 +307,7 @@ VNET_DEFINE(uma_zone_t, pf_udp_mapping_z); VNET_DEFINE(struct unrhdr64, pf_stateid); static void pf_src_tree_remove_state(struct pf_kstate *); -static void pf_init_threshold(struct pf_threshold *, u_int32_t, - u_int32_t); -static void pf_add_threshold(struct pf_threshold *); -static int pf_check_threshold(struct pf_threshold *); +static int pf_check_threshold(struct pf_kthreshold *); static void pf_change_ap(struct pf_pdesc *, struct pf_addr *, u_int16_t *, struct pf_addr *, u_int16_t); @@ -795,34 +792,21 @@ pf_set_protostate(struct pf_kstate *s, int which, u_int8_t newstate) s->src.state = newstate; } -static void -pf_init_threshold(struct pf_threshold *threshold, +bool +pf_init_threshold(struct pf_kthreshold *threshold, u_int32_t limit, u_int32_t seconds) { - threshold->limit = limit * PF_THRESHOLD_MULT; + threshold->limit = limit; threshold->seconds = seconds; - threshold->count = 0; - threshold->last = time_uptime; -} - -static void -pf_add_threshold(struct pf_threshold *threshold) -{ - u_int32_t t = time_uptime, diff = t - threshold->last; + threshold->cr = counter_rate_alloc(M_NOWAIT, seconds); - if (diff >= threshold->seconds) - threshold->count = 0; - else - threshold->count -= threshold->count * diff / - threshold->seconds; - threshold->count += PF_THRESHOLD_MULT; - threshold->last = t; + return (threshold->cr != NULL); } static int -pf_check_threshold(struct pf_threshold *threshold) +pf_check_threshold(struct pf_kthreshold *threshold) { - return (threshold->count > threshold->limit); + return (counter_ratecheck(threshold->cr, threshold->limit) < 0); } static bool @@ -837,7 +821,6 @@ pf_src_connlimit(struct pf_kstate *state) src_node->conn++; state->src.tcp_est = 1; - pf_add_threshold(&src_node->conn_rate); if (state->rule->max_src_conn && state->rule->max_src_conn < @@ -1031,6 +1014,7 @@ pf_free_src_node(struct pf_ksrc_node *sn) counter_u64_free(sn->bytes[i]); counter_u64_free(sn->packets[i]); } + counter_rate_free(sn->conn_rate.cr); uma_zfree(V_pf_sources_z, sn); } @@ -1095,9 +1079,13 @@ pf_insert_src_node(struct pf_ksrc_node *sns[PF_SN_MAX], } if (sn_type == PF_SN_LIMIT) - pf_init_threshold(&(*sn)->conn_rate, + if (! pf_init_threshold(&(*sn)->conn_rate, rule->max_src_conn_rate.limit, - rule->max_src_conn_rate.seconds); + rule->max_src_conn_rate.seconds)) { + pf_free_src_node(*sn); + reason = PFRES_MEMORY; + goto done; + } MPASS((*sn)->lock == NULL); (*sn)->lock = &(*sh)->lock; diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index c8ad007e2e92..c312ad001a60 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -1537,7 +1537,7 @@ pf_addr_copyout(struct pf_addr_wrap *addr) static void pf_src_node_copy(const struct pf_ksrc_node *in, struct pf_src_node *out) { - int secs = time_uptime, diff; + int secs = time_uptime; bzero(out, sizeof(struct pf_src_node)); @@ -1564,14 +1564,11 @@ pf_src_node_copy(const struct pf_ksrc_node *in, struct pf_src_node *out) out->expire = 0; /* Adjust the connection rate estimate. */ - out->conn_rate = in->conn_rate; - diff = secs - in->conn_rate.last; - if (diff >= in->conn_rate.seconds) - out->conn_rate.count = 0; - else - out->conn_rate.count -= - in->conn_rate.count * diff / - in->conn_rate.seconds; + out->conn_rate.limit = in->conn_rate.limit; + out->conn_rate.seconds = in->conn_rate.seconds; + /* If there's no limit there's no counter_rate. */ + if (in->conn_rate.cr != NULL) + out->conn_rate.count = counter_rate_get(in->conn_rate.cr); } #ifdef ALTQ diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index 4d631568f991..a975501794e6 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -1728,23 +1728,18 @@ pf_handle_get_ruleset(struct nlmsghdr *hdr, struct nl_pstate *npt) static bool nlattr_add_pf_threshold(struct nl_writer *nw, int attrtype, - struct pf_threshold *t, int secs) + struct pf_kthreshold *t) { int off = nlattr_add_nested(nw, attrtype); - int diff, conn_rate_count; + int conn_rate_count = 0; /* Adjust the connection rate estimate. */ - conn_rate_count = t->count; - diff = secs - t->last; - if (diff >= t->seconds) - conn_rate_count = 0; - else - conn_rate_count -= t->count * diff / t->seconds; + if (t->cr != NULL) + conn_rate_count = counter_rate_get(t->cr); nlattr_add_u32(nw, PF_TH_LIMIT, t->limit); nlattr_add_u32(nw, PF_TH_SECONDS, t->seconds); nlattr_add_u32(nw, PF_TH_COUNT, conn_rate_count); - nlattr_add_u32(nw, PF_TH_LAST, t->last); nlattr_set_len(nw, off); @@ -1803,7 +1798,7 @@ pf_handle_get_srcnodes(struct nlmsghdr *hdr, struct nl_pstate *npt) nlattr_add_u64(nw, PF_SN_EXPIRE, 0); nlattr_add_pf_threshold(nw, PF_SN_CONNECTION_RATE, - &n->conn_rate, secs); + &n->conn_rate); nlattr_add_u8(nw, PF_SN_NODE_TYPE, n->type);