git: 53a341d0e445 - main - pf: use counter_rate() for rate checking
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 25 Jun 2025 17:56:39 UTC
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);