git: b3a68a2ec3f1 - main - pf: convert DIOCRCLRTSTATS to netlink

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Wed, 26 Mar 2025 22:56:54 UTC
The branch main has been updated by kp:

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

commit b3a68a2ec3f132183cadbdf86967ab912938a74e
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-03-22 05:54:39 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-03-26 22:54:36 +0000

    pf: convert DIOCRCLRTSTATS to netlink
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 lib/libpfctl/libpfctl.c  | 45 +++++++++++++++++++++++++++++++++++++++++++++
 lib/libpfctl/libpfctl.h  |  2 ++
 sbin/pfctl/pfctl.h       |  1 -
 sbin/pfctl/pfctl_radix.c | 23 -----------------------
 sbin/pfctl/pfctl_table.c |  2 +-
 sys/netpfil/pf/pf_nl.c   | 45 +++++++++++++++++++++++++++++++++++++++++++++
 sys/netpfil/pf/pf_nl.h   |  2 ++
 7 files changed, 95 insertions(+), 25 deletions(-)

diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index e1cae22e2f3e..d84a66063647 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -3279,3 +3279,48 @@ pfctl_get_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
 	return (e.error);
 }
 
+static struct snl_attr_parser ap_tstats_clr[] = {
+	{ .type = PF_TS_NZERO, .off = 0, .cb = snl_attr_get_uint64 },
+};
+SNL_DECLARE_PARSER(tstats_clr_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats_clr);
+
+int
+pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
+    int *nzero, int flags)
+{
+	struct snl_writer nw;
+	struct snl_errmsg_data e = {};
+	struct nlmsghdr *hdr;
+	uint64_t zero;
+	uint32_t seq_id;
+	int family_id;
+
+	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+	if (family_id == 0)
+		return (ENOTSUP);
+
+	snl_init_writer(&h->ss, &nw);
+	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_CLR_TSTATS);
+
+	snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
+	snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
+	snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
+	snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
+
+	if ((hdr = snl_finalize_msg(&nw)) == NULL)
+		return (ENXIO);
+
+	seq_id = hdr->nlmsg_seq;
+
+	if (!snl_send_message(&h->ss, hdr))
+		return (ENXIO);
+
+	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+		if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &zero))
+			continue;
+		if (nzero)
+			*nzero = (uint32_t)zero;
+	}
+
+	return (e.error);
+}
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index c1c1da66746b..d8a7d1b6ebc4 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -554,5 +554,7 @@ int	pfctl_del_table(struct pfctl_handle *h, struct pfr_table *table,
 typedef int (*pfctl_get_tstats_fn)(const struct pfr_tstats *t, void *arg);
 int	pfctl_get_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
 	    pfctl_get_tstats_fn fn, void *arg);
+int	pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
+	    int *nzero, int flags);
 
 #endif
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index ffd37cf023a6..468328e12f38 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -60,7 +60,6 @@ int	 pfr_add_table(struct pfr_table *, int *, int);
 int	 pfr_del_table(struct pfr_table *, int *, int);
 int	 pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int);
 int	 pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int);
-int	 pfr_clr_tstats(struct pfr_table *, int, int *, int);
 int	 pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int);
 int	 pfr_clr_addrs(struct pfr_table *, int *, int);
 int	 pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c
index 3b0cc615e5a2..1d1918e29f44 100644
--- a/sbin/pfctl/pfctl_radix.c
+++ b/sbin/pfctl/pfctl_radix.c
@@ -234,29 +234,6 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
 	return (0);
 }
 
-int
-pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
-{
-	struct pfioc_table io;
-
-	if (size < 0 || (size && !tbl)) {
-		errno = EINVAL;
-		return (-1);
-	}
-	bzero(&io, sizeof io);
-	io.pfrio_flags = flags;
-	io.pfrio_buffer = tbl;
-	io.pfrio_esize = sizeof(*tbl);
-	io.pfrio_size = size;
-	if (ioctl(dev, DIOCRCLRTSTATS, &io)) {
-		pfr_report_error(tbl, &io, "clear tstats from");
-		return (-1);
-	}
-	if (nzero)
-		*nzero = io.pfrio_nzero;
-	return (0);
-}
-
 int
 pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
     int *nmatch, int flags)
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
index 57f7354b0172..834f74811ea2 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -396,7 +396,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
 					    opts & PF_OPT_USEDNS);
 	} else if (!strcmp(command, "zero")) {
 		flags |= PFR_FLAG_ADDRSTOO;
-		RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
+		RVTEST(pfctl_clear_tstats(pfh, &table, &nzero, flags));
 		xprintf(opts, "%d table/stats cleared", nzero);
 	} else
 		warnx("pfctl_table: unknown command '%s'", command);
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index f34bb71839b3..3a5ae2f233b4 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -2035,6 +2035,44 @@ pf_handle_get_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
 	return (error);
 }
 
+static int
+pf_handle_clear_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+	struct pfioc_table attrs = { 0 };
+	struct nl_writer *nw = npt->nw;
+	struct genlmsghdr *ghdr_new;
+	int error;
+	int nzero;
+
+	PF_RULES_RLOCK_TRACKER;
+
+	error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
+	if (error != 0)
+		return (error);
+
+	PF_TABLE_STATS_LOCK();
+	PF_RULES_RLOCK();
+	error = pfr_clr_tstats(&attrs.pfrio_table, 1,
+	    &nzero, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
+	PF_RULES_RUNLOCK();
+	PF_TABLE_STATS_UNLOCK();
+
+	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+		return (ENOMEM);
+
+	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+	ghdr_new->cmd = PFNL_CMD_CLR_TSTATS;
+	ghdr_new->version = 0;
+	ghdr_new->reserved = 0;
+
+	nlattr_add_u64(nw, PF_TS_NZERO, nzero);
+
+	if (! nlmsg_end(nw))
+		error = ENOMEM;
+
+	return (error);
+}
+
 static const struct nlhdr_parser *all_parsers[] = {
 	&state_parser,
 	&addrule_parser,
@@ -2257,6 +2295,13 @@ static const struct genl_cmd pf_cmds[] = {
 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
 		.cmd_priv = PRIV_NETINET_PF,
 	},
+	{
+		.cmd_num = PFNL_CMD_CLR_TSTATS,
+		.cmd_name = "CLR_TSTATS",
+		.cmd_cb = pf_handle_clear_tstats,
+		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+		.cmd_priv = PRIV_NETINET_PF,
+	},
 };
 
 void
diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h
index ed01d3427fc4..55cc9c991b18 100644
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -65,6 +65,7 @@ enum {
 	PFNL_CMD_ADD_TABLE = 27,
 	PFNL_CMD_DEL_TABLE = 28,
 	PFNL_CMD_GET_TSTATS = 29,
+	PFNL_CMD_CLR_TSTATS = 30,
 	__PFNL_CMD_MAX,
 };
 #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@@ -453,6 +454,7 @@ enum pf_tstats_t {
 	PF_TS_TZERO		= 6, /* u64 */
 	PF_TS_CNT		= 7, /* u64 */
 	PF_TS_REFCNT		= 8, /* u64 array */
+	PF_TS_NZERO		= 9, /* u64 */
 };
 
 #ifdef _KERNEL