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

(cherry picked from commit b21826bf15)
This commit is contained in:
Kristof Provost 2022-02-01 18:25:57 +01:00
parent 58df94091a
commit cb6af6551c

View file

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