diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index c11455837072..b830c69f0d87 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -128,10 +128,17 @@ extern struct rmlock pf_rules_lock; #define PF_RULES_RUNLOCK() rm_runlock(&pf_rules_lock, &_pf_rules_tracker) #define PF_RULES_WLOCK() rm_wlock(&pf_rules_lock) #define PF_RULES_WUNLOCK() rm_wunlock(&pf_rules_lock) +#define PF_RULES_WOWNED() rm_wowned(&pf_rules_lock) #define PF_RULES_ASSERT() rm_assert(&pf_rules_lock, RA_LOCKED) #define PF_RULES_RASSERT() rm_assert(&pf_rules_lock, RA_RLOCKED) #define PF_RULES_WASSERT() rm_assert(&pf_rules_lock, RA_WLOCKED) +extern struct mtx pf_table_stats_lock; +#define PF_TABLE_STATS_LOCK() mtx_lock(&pf_table_stats_lock) +#define PF_TABLE_STATS_UNLOCK() mtx_unlock(&pf_table_stats_lock) +#define PF_TABLE_STATS_OWNED() mtx_owned(&pf_table_stats_lock) +#define PF_TABLE_STATS_ASSERT() mtx_assert(&pf_rules_lock, MA_OWNED) + extern struct sx pf_end_lock; #define PF_MODVER 1 @@ -814,16 +821,70 @@ struct pfr_tstats { int pfrts_refcnt[PFR_REFCNT_MAX]; }; +#ifdef _KERNEL + +struct pfr_kstate_counter { + counter_u64_t pkc_pcpu; + u_int64_t pkc_zero; +}; + +static inline int +pfr_kstate_counter_init(struct pfr_kstate_counter *pfrc, int flags) +{ + + pfrc->pkc_zero = 0; + pfrc->pkc_pcpu = counter_u64_alloc(flags); + if (pfrc->pkc_pcpu == NULL) + return (ENOMEM); + return (0); +} + +static inline void +pfr_kstate_counter_deinit(struct pfr_kstate_counter *pfrc) +{ + + counter_u64_free(pfrc->pkc_pcpu); +} + +static inline u_int64_t +pfr_kstate_counter_fetch(struct pfr_kstate_counter *pfrc) +{ + u_int64_t c; + + c = counter_u64_fetch(pfrc->pkc_pcpu); + c -= pfrc->pkc_zero; + return (c); +} + +static inline void +pfr_kstate_counter_zero(struct pfr_kstate_counter *pfrc) +{ + u_int64_t c; + + c = counter_u64_fetch(pfrc->pkc_pcpu); + pfrc->pkc_zero = c; +} + +static inline void +pfr_kstate_counter_add(struct pfr_kstate_counter *pfrc, int64_t n) +{ + + counter_u64_add(pfrc->pkc_pcpu, n); +} + struct pfr_ktstats { struct pfr_table pfrts_t; - counter_u64_t pfrkts_packets[PFR_DIR_MAX][PFR_OP_TABLE_MAX]; - counter_u64_t pfrkts_bytes[PFR_DIR_MAX][PFR_OP_TABLE_MAX]; - counter_u64_t pfrkts_match; - counter_u64_t pfrkts_nomatch; + struct pfr_kstate_counter pfrkts_packets[PFR_DIR_MAX][PFR_OP_TABLE_MAX]; + struct pfr_kstate_counter pfrkts_bytes[PFR_DIR_MAX][PFR_OP_TABLE_MAX]; + struct pfr_kstate_counter pfrkts_match; + struct pfr_kstate_counter pfrkts_nomatch; long pfrkts_tzero; int pfrkts_cnt; int pfrkts_refcnt[PFR_REFCNT_MAX]; }; + +#endif /* _KERNEL */ + #define pfrts_name pfrts_t.pfrt_name #define pfrts_flags pfrts_t.pfrt_flags diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 6edbd60b8d07..8a05631cc9fa 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -212,6 +212,10 @@ struct mtx pf_unlnkdrules_mtx; MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules", MTX_DEF); +struct mtx pf_table_stats_lock; +MTX_SYSINIT(pf_table_stats_lock, &pf_table_stats_lock, "pf table stats", + MTX_DEF); + VNET_DEFINE_STATIC(uma_zone_t, pf_sources_z); #define V_pf_sources_z VNET(pf_sources_z) uma_zone_t pf_mtag_z; diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 0ce39db05c15..b8b82b80c2e0 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -3740,10 +3740,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td error = ENODEV; break; } - PF_RULES_WLOCK(); + PF_TABLE_STATS_LOCK(); + PF_RULES_RLOCK(); n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); if (n < 0) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + PF_TABLE_STATS_UNLOCK(); error = EINVAL; break; } @@ -3754,12 +3756,14 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td sizeof(struct pfr_tstats), M_TEMP, M_NOWAIT); if (pfrtstats == NULL) { error = ENOMEM; - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + PF_TABLE_STATS_UNLOCK(); break; } error = pfr_get_tstats(&io->pfrio_table, pfrtstats, &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + PF_TABLE_STATS_UNLOCK(); if (error == 0) error = copyout(pfrtstats, io->pfrio_buffer, totlen); free(pfrtstats, M_TEMP); @@ -3798,10 +3802,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td break; } - PF_RULES_WLOCK(); + PF_TABLE_STATS_LOCK(); + PF_RULES_RLOCK(); error = pfr_clr_tstats(pfrts, io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + PF_TABLE_STATS_UNLOCK(); free(pfrts, M_TEMP); break; } diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index e9fd5f133c3f..8dbab5e7bbe1 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -1327,15 +1327,15 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { tbl->pfrts_packets[pfr_dir][pfr_op] = - counter_u64_fetch( - p->pfrkt_packets[pfr_dir][pfr_op]); + pfr_kstate_counter_fetch( + &p->pfrkt_packets[pfr_dir][pfr_op]); tbl->pfrts_bytes[pfr_dir][pfr_op] = - counter_u64_fetch( - p->pfrkt_bytes[pfr_dir][pfr_op]); + pfr_kstate_counter_fetch( + &p->pfrkt_bytes[pfr_dir][pfr_op]); } } - tbl->pfrts_match = counter_u64_fetch(p->pfrkt_match); - tbl->pfrts_nomatch = counter_u64_fetch(p->pfrkt_nomatch); + tbl->pfrts_match = pfr_kstate_counter_fetch(&p->pfrkt_match); + tbl->pfrts_nomatch = pfr_kstate_counter_fetch(&p->pfrkt_nomatch); tbl->pfrts_tzero = p->pfrkt_tzero; tbl->pfrts_cnt = p->pfrkt_cnt; for (pfr_op = 0; pfr_op < PFR_REFCNT_MAX; pfr_op++) @@ -1865,18 +1865,20 @@ pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse) struct pfr_kentryworkq addrq; int pfr_dir, pfr_op; + MPASS(PF_TABLE_STATS_OWNED() || PF_RULES_WOWNED()); + if (recurse) { pfr_enqueue_addrs(kt, &addrq, NULL, 0); pfr_clstats_kentries(kt, &addrq, tzero, 0); } for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { - counter_u64_zero(kt->pfrkt_packets[pfr_dir][pfr_op]); - counter_u64_zero(kt->pfrkt_bytes[pfr_dir][pfr_op]); + pfr_kstate_counter_zero(&kt->pfrkt_packets[pfr_dir][pfr_op]); + pfr_kstate_counter_zero(&kt->pfrkt_bytes[pfr_dir][pfr_op]); } } - counter_u64_zero(kt->pfrkt_match); - counter_u64_zero(kt->pfrkt_nomatch); + pfr_kstate_counter_zero(&kt->pfrkt_match); + pfr_kstate_counter_zero(&kt->pfrkt_nomatch); kt->pfrkt_tzero = tzero; } @@ -1906,28 +1908,24 @@ pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset) for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { - kt->pfrkt_packets[pfr_dir][pfr_op] = - counter_u64_alloc(M_NOWAIT); - if (! kt->pfrkt_packets[pfr_dir][pfr_op]) { + if (pfr_kstate_counter_init( + &kt->pfrkt_packets[pfr_dir][pfr_op], M_NOWAIT) != 0) { pfr_destroy_ktable(kt, 0); return (NULL); } - kt->pfrkt_bytes[pfr_dir][pfr_op] = - counter_u64_alloc(M_NOWAIT); - if (! kt->pfrkt_bytes[pfr_dir][pfr_op]) { + if (pfr_kstate_counter_init( + &kt->pfrkt_bytes[pfr_dir][pfr_op], M_NOWAIT) != 0) { pfr_destroy_ktable(kt, 0); return (NULL); } } } - kt->pfrkt_match = counter_u64_alloc(M_NOWAIT); - if (! kt->pfrkt_match) { + if (pfr_kstate_counter_init(&kt->pfrkt_match, M_NOWAIT) != 0) { pfr_destroy_ktable(kt, 0); return (NULL); } - kt->pfrkt_nomatch = counter_u64_alloc(M_NOWAIT); - if (! kt->pfrkt_nomatch) { + if (pfr_kstate_counter_init(&kt->pfrkt_nomatch, M_NOWAIT) != 0) { pfr_destroy_ktable(kt, 0); return (NULL); } @@ -1978,12 +1976,12 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) } for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { - counter_u64_free(kt->pfrkt_packets[pfr_dir][pfr_op]); - counter_u64_free(kt->pfrkt_bytes[pfr_dir][pfr_op]); + pfr_kstate_counter_deinit(&kt->pfrkt_packets[pfr_dir][pfr_op]); + pfr_kstate_counter_deinit(&kt->pfrkt_bytes[pfr_dir][pfr_op]); } } - counter_u64_free(kt->pfrkt_match); - counter_u64_free(kt->pfrkt_nomatch); + pfr_kstate_counter_deinit(&kt->pfrkt_match); + pfr_kstate_counter_deinit(&kt->pfrkt_nomatch); free(kt, M_PFTABLE); } @@ -2053,9 +2051,9 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) } match = (ke && !ke->pfrke_not); if (match) - counter_u64_add(kt->pfrkt_match, 1); + pfr_kstate_counter_add(&kt->pfrkt_match, 1); else - counter_u64_add(kt->pfrkt_nomatch, 1); + pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); return (match); } @@ -2110,8 +2108,8 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, ("pfr_update_stats: assertion failed.\n")); op_pass = PFR_OP_XPASS; } - counter_u64_add(kt->pfrkt_packets[dir_out][op_pass], 1); - counter_u64_add(kt->pfrkt_bytes[dir_out][op_pass], len); + pfr_kstate_counter_add(&kt->pfrkt_packets[dir_out][op_pass], 1); + pfr_kstate_counter_add(&kt->pfrkt_bytes[dir_out][op_pass], len); if (ke != NULL && op_pass != PFR_OP_XPASS && (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { counter_u64_add(pfr_kentry_counter(&ke->pfrke_counters, @@ -2207,7 +2205,7 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, _next_block: ke = pfr_kentry_byidx(kt, idx, af); if (ke == NULL) { - counter_u64_add(kt->pfrkt_nomatch, 1); + pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); return (1); } pfr_prepare_network(&umask, af, ke->pfrke_net); @@ -2232,7 +2230,7 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, /* this is a single IP address - no possible nested block */ PF_ACPY(counter, addr, af); *pidx = idx; - counter_u64_add(kt->pfrkt_match, 1); + pfr_kstate_counter_add(&kt->pfrkt_match, 1); return (0); } for (;;) { @@ -2252,7 +2250,7 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, /* lookup return the same block - perfect */ PF_ACPY(counter, addr, af); *pidx = idx; - counter_u64_add(kt->pfrkt_match, 1); + pfr_kstate_counter_add(&kt->pfrkt_match, 1); return (0); }