aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2022-02-01 17:25:57 +0000
committerKristof Provost <kp@FreeBSD.org>2022-02-05 09:29:34 +0000
commitb21826bf15f7ec1e206fa3cfdf40691f84fb1d8e (patch)
tree3cda0e8c606325383d9eb82b29ecb7cab67bd5fa
parent610b97ebaa9172dfe77a03d334756bfb09e398a2 (diff)
downloadsrc-b21826bf15f7ec1e206fa3cfdf40691f84fb1d8e.tar.gz
src-b21826bf15f7ec1e206fa3cfdf40691f84fb1d8e.zip
pf: deal with tables gaining or losing counters
When we create a table without counters, add an entry and later re-define the table to have counters we wound up trying to read non-existent counters. We now cope with this by attempting to add them if needed, removing them when they're no longer needed and not trying to read from counters that are not present. MFC after: 2 weeks Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D34131
-rw-r--r--sys/netpfil/pf/pf_table.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c
index 4cfe5d61e83e..2352e43cb342 100644
--- a/sys/netpfil/pf/pf_table.c
+++ b/sys/netpfil/pf/pf_table.c
@@ -103,7 +103,8 @@ struct pfr_walktree {
PFRW_GET_ADDRS,
PFRW_GET_ASTATS,
PFRW_POOL_GET,
- PFRW_DYNADDR_UPDATE
+ PFRW_DYNADDR_UPDATE,
+ PFRW_COUNTERS
} pfrw_op;
union {
struct pfr_addr *pfrw1_addr;
@@ -1032,7 +1033,8 @@ pfr_copyout_astats(struct pfr_astats *as, const struct pfr_kentry *ke,
pfr_copyout_addr(&as->pfras_a, ke);
as->pfras_tzero = kc->pfrkc_tzero;
- if (! (w->pfrw_flags & PFR_TFLAG_COUNTERS)) {
+ if (! (w->pfrw_flags & PFR_TFLAG_COUNTERS) ||
+ kc->pfrkc_counters == NULL) {
bzero(as->pfras_packets, sizeof(as->pfras_packets));
bzero(as->pfras_bytes, sizeof(as->pfras_bytes));
as->pfras_a.pfra_fback = PFR_FB_NOCOUNT;
@@ -1114,6 +1116,21 @@ pfr_walktree(struct radix_node *rn, void *arg)
}
break;
}
+ case PFRW_COUNTERS:
+ {
+ if (w->pfrw_flags & PFR_TFLAG_COUNTERS) {
+ if (ke->pfrke_counters.pfrkc_counters != NULL)
+ break;
+ ke->pfrke_counters.pfrkc_counters =
+ uma_zalloc_pcpu(V_pfr_kentry_counter_z,
+ M_NOWAIT | M_ZERO);
+ } else {
+ uma_zfree_pcpu(V_pfr_kentry_counter_z,
+ ke->pfrke_counters.pfrkc_counters);
+ ke->pfrke_counters.pfrkc_counters = NULL;
+ }
+ break;
+ }
}
return (0);
}
@@ -1818,6 +1835,7 @@ static void
pfr_setflags_ktable(struct pfr_ktable *kt, int newf)
{
struct pfr_kentryworkq addrq;
+ struct pfr_walktree w;
PF_RULES_WASSERT();
@@ -1838,6 +1856,20 @@ pfr_setflags_ktable(struct pfr_ktable *kt, int newf)
V_pfr_ktable_cnt--;
return;
}
+ if (newf & PFR_TFLAG_COUNTERS && ! (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) {
+ bzero(&w, sizeof(w));
+ w.pfrw_op = PFRW_COUNTERS;
+ w.pfrw_flags |= PFR_TFLAG_COUNTERS;
+ kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w);
+ kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w);
+ }
+ if (! (newf & PFR_TFLAG_COUNTERS) && (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) {
+ bzero(&w, sizeof(w));
+ w.pfrw_op = PFRW_COUNTERS;
+ w.pfrw_flags |= 0;
+ kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w);
+ kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, pfr_walktree, &w);
+ }
if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
pfr_enqueue_addrs(kt, &addrq, NULL, 0);
pfr_remove_kentries(kt, &addrq);