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);
 

Reply via email to