Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 25 Jun 2025 17:56:39 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 53a341d0e445 - main - pf: use counter_rate() for rate checking
Message-ID:  <202506251756.55PHudsV035318@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=53a341d0e445269590dcb32f8c8320c3459a21c4

commit 53a341d0e445269590dcb32f8c8320c3459a21c4
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-06-05 16:45:28 +0000
Commit:     Kristof Provost <kp@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);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202506251756.55PHudsV035318>