Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_table.c
Show First 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | struct pfr_walktree { | ||||
union { | union { | ||||
struct pfr_addr *pfrw1_addr; | struct pfr_addr *pfrw1_addr; | ||||
struct pfr_astats *pfrw1_astats; | struct pfr_astats *pfrw1_astats; | ||||
struct pfr_kentryworkq *pfrw1_workq; | struct pfr_kentryworkq *pfrw1_workq; | ||||
struct pfr_kentry *pfrw1_kentry; | struct pfr_kentry *pfrw1_kentry; | ||||
struct pfi_dynaddr *pfrw1_dyn; | struct pfi_dynaddr *pfrw1_dyn; | ||||
} pfrw_1; | } pfrw_1; | ||||
int pfrw_free; | int pfrw_free; | ||||
int pfrw_flags; | |||||
}; | }; | ||||
#define pfrw_addr pfrw_1.pfrw1_addr | #define pfrw_addr pfrw_1.pfrw1_addr | ||||
#define pfrw_astats pfrw_1.pfrw1_astats | #define pfrw_astats pfrw_1.pfrw1_astats | ||||
#define pfrw_workq pfrw_1.pfrw1_workq | #define pfrw_workq pfrw_1.pfrw1_workq | ||||
#define pfrw_kentry pfrw_1.pfrw1_kentry | #define pfrw_kentry pfrw_1.pfrw1_kentry | ||||
#define pfrw_dyn pfrw_1.pfrw1_dyn | #define pfrw_dyn pfrw_1.pfrw1_dyn | ||||
#define pfrw_cnt pfrw_free | #define pfrw_cnt pfrw_free | ||||
#define senderr(e) do { rv = (e); goto _bad; } while (0) | #define senderr(e) do { rv = (e); goto _bad; } while (0) | ||||
static MALLOC_DEFINE(M_PFTABLE, "pf_table", "pf(4) tables structures"); | static MALLOC_DEFINE(M_PFTABLE, "pf_table", "pf(4) tables structures"); | ||||
VNET_DEFINE_STATIC(uma_zone_t, pfr_kentry_z); | VNET_DEFINE_STATIC(uma_zone_t, pfr_kentry_z); | ||||
#define V_pfr_kentry_z VNET(pfr_kentry_z) | #define V_pfr_kentry_z VNET(pfr_kentry_z) | ||||
VNET_DEFINE_STATIC(uma_zone_t, pfr_kcounters_z); | |||||
#define V_pfr_kcounters_z VNET(pfr_kcounters_z) | |||||
static struct pf_addr pfr_ffaddr = { | static struct pf_addr pfr_ffaddr = { | ||||
.addr32 = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } | .addr32 = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } | ||||
}; | }; | ||||
static void pfr_copyout_astats(struct pfr_astats *, | |||||
const struct pfr_kentry *, | |||||
const struct pfr_walktree *); | |||||
static void pfr_copyout_addr(struct pfr_addr *, | static void pfr_copyout_addr(struct pfr_addr *, | ||||
struct pfr_kentry *ke); | const struct pfr_kentry *ke); | ||||
static int pfr_validate_addr(struct pfr_addr *); | static int pfr_validate_addr(struct pfr_addr *); | ||||
static void pfr_enqueue_addrs(struct pfr_ktable *, | static void pfr_enqueue_addrs(struct pfr_ktable *, | ||||
struct pfr_kentryworkq *, int *, int); | struct pfr_kentryworkq *, int *, int); | ||||
static void pfr_mark_addrs(struct pfr_ktable *); | static void pfr_mark_addrs(struct pfr_ktable *); | ||||
static struct pfr_kentry | static struct pfr_kentry | ||||
*pfr_lookup_addr(struct pfr_ktable *, | *pfr_lookup_addr(struct pfr_ktable *, | ||||
struct pfr_addr *, int); | struct pfr_addr *, int); | ||||
static bool pfr_create_kentry_counter(struct pfr_kcounters *, | |||||
int, int); | |||||
static struct pfr_kentry *pfr_create_kentry(struct pfr_addr *); | static struct pfr_kentry *pfr_create_kentry(struct pfr_addr *); | ||||
static void pfr_destroy_kentries(struct pfr_kentryworkq *); | static void pfr_destroy_kentries(struct pfr_kentryworkq *); | ||||
static void pfr_destroy_kentry_counter(struct pfr_kcounters *, | |||||
int, int); | |||||
static void pfr_destroy_kentry(struct pfr_kentry *); | static void pfr_destroy_kentry(struct pfr_kentry *); | ||||
static void pfr_insert_kentries(struct pfr_ktable *, | static void pfr_insert_kentries(struct pfr_ktable *, | ||||
struct pfr_kentryworkq *, long); | struct pfr_kentryworkq *, long); | ||||
static void pfr_remove_kentries(struct pfr_ktable *, | static void pfr_remove_kentries(struct pfr_ktable *, | ||||
struct pfr_kentryworkq *); | struct pfr_kentryworkq *); | ||||
static void pfr_clstats_kentries(struct pfr_kentryworkq *, long, | static void pfr_clstats_kentries(struct pfr_kentryworkq *, long, | ||||
int); | int); | ||||
static void pfr_reset_feedback(struct pfr_addr *, int); | static void pfr_reset_feedback(struct pfr_addr *, int); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
pfr_initialize(void) | pfr_initialize(void) | ||||
{ | { | ||||
V_pfr_kentry_z = uma_zcreate("pf table entries", | V_pfr_kentry_z = uma_zcreate("pf table entries", | ||||
sizeof(struct pfr_kentry), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, | sizeof(struct pfr_kentry), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, | ||||
0); | 0); | ||||
V_pfr_kcounters_z = uma_zcreate("pf table counters", | |||||
sizeof(struct pfr_kcounters), NULL, NULL, NULL, NULL, | |||||
UMA_ALIGN_PTR, 0); | |||||
V_pf_limits[PF_LIMIT_TABLE_ENTRIES].zone = V_pfr_kentry_z; | V_pf_limits[PF_LIMIT_TABLE_ENTRIES].zone = V_pfr_kentry_z; | ||||
V_pf_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; | V_pf_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; | ||||
} | } | ||||
void | void | ||||
pfr_cleanup(void) | pfr_cleanup(void) | ||||
{ | { | ||||
uma_zdestroy(V_pfr_kentry_z); | uma_zdestroy(V_pfr_kentry_z); | ||||
uma_zdestroy(V_pfr_kcounters_z); | |||||
} | } | ||||
int | int | ||||
pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) | pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) | ||||
{ | { | ||||
struct pfr_ktable *kt; | struct pfr_ktable *kt; | ||||
struct pfr_kentryworkq workq; | struct pfr_kentryworkq workq; | ||||
▲ Show 20 Lines • Show All 377 Lines • ▼ Show 20 Lines | if (kt->pfrkt_cnt > *size) { | ||||
*size = kt->pfrkt_cnt; | *size = kt->pfrkt_cnt; | ||||
return (0); | return (0); | ||||
} | } | ||||
bzero(&w, sizeof(w)); | bzero(&w, sizeof(w)); | ||||
w.pfrw_op = PFRW_GET_ASTATS; | w.pfrw_op = PFRW_GET_ASTATS; | ||||
w.pfrw_astats = addr; | w.pfrw_astats = addr; | ||||
w.pfrw_free = kt->pfrkt_cnt; | w.pfrw_free = kt->pfrkt_cnt; | ||||
/* | |||||
* Flags below are for backward compatibility. It was possible to have | |||||
* a table without per-entry counters. Now they are always allocated, | |||||
* we just discard data when reading it if table is not configured to | |||||
* have counters. | |||||
*/ | |||||
w.pfrw_flags = kt->pfrkt_flags; | |||||
rv = kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); | rv = kt->pfrkt_ip4->rnh_walktree(&kt->pfrkt_ip4->rh, pfr_walktree, &w); | ||||
if (!rv) | if (!rv) | ||||
rv = kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, | rv = kt->pfrkt_ip6->rnh_walktree(&kt->pfrkt_ip6->rh, | ||||
pfr_walktree, &w); | pfr_walktree, &w); | ||||
if (!rv && (flags & PFR_FLAG_CLSTATS)) { | if (!rv && (flags & PFR_FLAG_CLSTATS)) { | ||||
pfr_enqueue_addrs(kt, &workq, NULL, 0); | pfr_enqueue_addrs(kt, &workq, NULL, 0); | ||||
pfr_clstats_kentries(&workq, tzero, 0); | pfr_clstats_kentries(&workq, tzero, 0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | if (ADDR_NETWORK(ad)) { | ||||
if (ke && KENTRY_RNF_ROOT(ke)) | if (ke && KENTRY_RNF_ROOT(ke)) | ||||
ke = NULL; | ke = NULL; | ||||
if (exact && ke && KENTRY_NETWORK(ke)) | if (exact && ke && KENTRY_NETWORK(ke)) | ||||
ke = NULL; | ke = NULL; | ||||
} | } | ||||
return (ke); | return (ke); | ||||
} | } | ||||
static bool | |||||
pfr_create_kentry_counter(struct pfr_kcounters *kc, int pfr_dir, int pfr_op) | |||||
{ | |||||
kc->pfrkc_packets[pfr_dir][pfr_op] = counter_u64_alloc(M_NOWAIT); | |||||
if (! kc->pfrkc_packets[pfr_dir][pfr_op]) | |||||
return (false); | |||||
kc->pfrkc_bytes[pfr_dir][pfr_op] = counter_u64_alloc(M_NOWAIT); | |||||
if (! kc->pfrkc_bytes[pfr_dir][pfr_op]) | |||||
glebius: Let's put a comment that previous allocation isn't leaked, since any failure of… | |||||
return (false); | |||||
kc->pfrkc_tzero = 0; | |||||
return (true); | |||||
} | |||||
static struct pfr_kentry * | static struct pfr_kentry * | ||||
pfr_create_kentry(struct pfr_addr *ad) | pfr_create_kentry(struct pfr_addr *ad) | ||||
{ | { | ||||
struct pfr_kentry *ke; | struct pfr_kentry *ke; | ||||
int pfr_dir, pfr_op; | |||||
ke = uma_zalloc(V_pfr_kentry_z, M_NOWAIT | M_ZERO); | ke = uma_zalloc(V_pfr_kentry_z, M_NOWAIT | M_ZERO); | ||||
if (ke == NULL) | if (ke == NULL) | ||||
return (NULL); | return (NULL); | ||||
if (ad->pfra_af == AF_INET) | if (ad->pfra_af == AF_INET) | ||||
FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); | FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); | ||||
else if (ad->pfra_af == AF_INET6) | else if (ad->pfra_af == AF_INET6) | ||||
FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr); | FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr); | ||||
ke->pfrke_af = ad->pfra_af; | ke->pfrke_af = ad->pfra_af; | ||||
ke->pfrke_net = ad->pfra_net; | ke->pfrke_net = ad->pfra_net; | ||||
ke->pfrke_not = ad->pfra_not; | ke->pfrke_not = ad->pfra_not; | ||||
for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) | |||||
for (pfr_op = 0; pfr_op < PFR_OP_ADDR_MAX; pfr_op ++) { | |||||
if (! pfr_create_kentry_counter(&ke->pfrke_counters, | |||||
pfr_dir, pfr_op)) { | |||||
pfr_destroy_kentry(ke); | |||||
return (NULL); | |||||
} | |||||
} | |||||
return (ke); | return (ke); | ||||
} | } | ||||
static void | static void | ||||
pfr_destroy_kentries(struct pfr_kentryworkq *workq) | pfr_destroy_kentries(struct pfr_kentryworkq *workq) | ||||
{ | { | ||||
struct pfr_kentry *p, *q; | struct pfr_kentry *p, *q; | ||||
for (p = SLIST_FIRST(workq); p != NULL; p = q) { | for (p = SLIST_FIRST(workq); p != NULL; p = q) { | ||||
q = SLIST_NEXT(p, pfrke_workq); | q = SLIST_NEXT(p, pfrke_workq); | ||||
pfr_destroy_kentry(p); | pfr_destroy_kentry(p); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
pfr_destroy_kentry_counter(struct pfr_kcounters *kc, int pfr_dir, int pfr_op) | |||||
{ | |||||
counter_u64_free(kc->pfrkc_packets[pfr_dir][pfr_op]); | |||||
counter_u64_free(kc->pfrkc_bytes[pfr_dir][pfr_op]); | |||||
} | |||||
static void | |||||
pfr_destroy_kentry(struct pfr_kentry *ke) | pfr_destroy_kentry(struct pfr_kentry *ke) | ||||
{ | { | ||||
if (ke->pfrke_counters) | int pfr_dir, pfr_op; | ||||
uma_zfree(V_pfr_kcounters_z, ke->pfrke_counters); | |||||
for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) | |||||
for (pfr_op = 0; pfr_op < PFR_OP_ADDR_MAX; pfr_op ++) | |||||
pfr_destroy_kentry_counter(&ke->pfrke_counters, | |||||
pfr_dir, pfr_op); | |||||
uma_zfree(V_pfr_kentry_z, ke); | uma_zfree(V_pfr_kentry_z, ke); | ||||
} | } | ||||
static void | static void | ||||
pfr_insert_kentries(struct pfr_ktable *kt, | pfr_insert_kentries(struct pfr_ktable *kt, | ||||
struct pfr_kentryworkq *workq, long tzero) | struct pfr_kentryworkq *workq, long tzero) | ||||
{ | { | ||||
struct pfr_kentry *p; | struct pfr_kentry *p; | ||||
int rv, n = 0; | int rv, n = 0; | ||||
SLIST_FOREACH(p, workq, pfrke_workq) { | SLIST_FOREACH(p, workq, pfrke_workq) { | ||||
rv = pfr_route_kentry(kt, p); | rv = pfr_route_kentry(kt, p); | ||||
if (rv) { | if (rv) { | ||||
printf("pfr_insert_kentries: cannot route entry " | printf("pfr_insert_kentries: cannot route entry " | ||||
"(code=%d).\n", rv); | "(code=%d).\n", rv); | ||||
break; | break; | ||||
} | } | ||||
p->pfrke_tzero = tzero; | p->pfrke_counters.pfrkc_tzero = tzero; | ||||
n++; | n++; | ||||
} | } | ||||
kt->pfrkt_cnt += n; | kt->pfrkt_cnt += n; | ||||
} | } | ||||
int | int | ||||
pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero) | pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero) | ||||
{ | { | ||||
struct pfr_kentry *p; | struct pfr_kentry *p; | ||||
int rv; | int rv; | ||||
p = pfr_lookup_addr(kt, ad, 1); | p = pfr_lookup_addr(kt, ad, 1); | ||||
if (p != NULL) | if (p != NULL) | ||||
return (0); | return (0); | ||||
p = pfr_create_kentry(ad); | p = pfr_create_kentry(ad); | ||||
if (p == NULL) | if (p == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
rv = pfr_route_kentry(kt, p); | rv = pfr_route_kentry(kt, p); | ||||
if (rv) | if (rv) | ||||
return (rv); | return (rv); | ||||
p->pfrke_tzero = tzero; | p->pfrke_counters.pfrkc_tzero = tzero; | ||||
kt->pfrkt_cnt++; | kt->pfrkt_cnt++; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
pfr_remove_kentries(struct pfr_ktable *kt, | pfr_remove_kentries(struct pfr_ktable *kt, | ||||
struct pfr_kentryworkq *workq) | struct pfr_kentryworkq *workq) | ||||
Show All 18 Lines | pfr_clean_node_mask(struct pfr_ktable *kt, | ||||
SLIST_FOREACH(p, workq, pfrke_workq) | SLIST_FOREACH(p, workq, pfrke_workq) | ||||
pfr_unroute_kentry(kt, p); | pfr_unroute_kentry(kt, p); | ||||
} | } | ||||
static void | static void | ||||
pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange) | pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange) | ||||
{ | { | ||||
struct pfr_kentry *p; | struct pfr_kentry *p; | ||||
int pfr_dir, pfr_op; | |||||
SLIST_FOREACH(p, workq, pfrke_workq) { | SLIST_FOREACH(p, workq, pfrke_workq) { | ||||
if (negchange) | if (negchange) | ||||
p->pfrke_not = !p->pfrke_not; | p->pfrke_not = !p->pfrke_not; | ||||
if (p->pfrke_counters) { | for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { | ||||
uma_zfree(V_pfr_kcounters_z, p->pfrke_counters); | for (pfr_op = 0; pfr_op < PFR_OP_ADDR_MAX; pfr_op ++) { | ||||
p->pfrke_counters = NULL; | counter_u64_zero(p->pfrke_counters. | ||||
pfrkc_packets[pfr_dir][pfr_op]); | |||||
counter_u64_zero(p->pfrke_counters. | |||||
pfrkc_bytes[pfr_dir][pfr_op]); | |||||
} | } | ||||
p->pfrke_tzero = tzero; | |||||
} | } | ||||
p->pfrke_counters.pfrkc_tzero = tzero; | |||||
} | } | ||||
} | |||||
static void | static void | ||||
pfr_reset_feedback(struct pfr_addr *addr, int size) | pfr_reset_feedback(struct pfr_addr *addr, int size) | ||||
{ | { | ||||
struct pfr_addr *ad; | struct pfr_addr *ad; | ||||
int i; | int i; | ||||
for (i = 0, ad = addr; i < size; i++, ad++) | for (i = 0, ad = addr; i < size; i++, ad++) | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) | ||||
if (rn == NULL) { | if (rn == NULL) { | ||||
printf("pfr_unroute_kentry: delete failed.\n"); | printf("pfr_unroute_kentry: delete failed.\n"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke) | pfr_copyout_addr(struct pfr_addr *ad, const struct pfr_kentry *ke) | ||||
{ | { | ||||
bzero(ad, sizeof(*ad)); | bzero(ad, sizeof(*ad)); | ||||
if (ke == NULL) | if (ke == NULL) | ||||
return; | return; | ||||
ad->pfra_af = ke->pfrke_af; | ad->pfra_af = ke->pfrke_af; | ||||
ad->pfra_net = ke->pfrke_net; | ad->pfra_net = ke->pfrke_net; | ||||
ad->pfra_not = ke->pfrke_not; | ad->pfra_not = ke->pfrke_not; | ||||
if (ad->pfra_af == AF_INET) | if (ad->pfra_af == AF_INET) | ||||
ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr; | ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr; | ||||
else if (ad->pfra_af == AF_INET6) | else if (ad->pfra_af == AF_INET6) | ||||
ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr; | ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr; | ||||
} | } | ||||
static void | |||||
pfr_copyout_astats(struct pfr_astats *as, const struct pfr_kentry *ke, | |||||
const struct pfr_walktree *w) | |||||
{ | |||||
int dir, op; | |||||
const struct pfr_kcounters *kc = &ke->pfrke_counters; | |||||
pfr_copyout_addr(&as->pfras_a, ke); | |||||
as->pfras_tzero = kc->pfrkc_tzero; | |||||
if (! (w->pfrw_flags & PFR_TFLAG_COUNTERS)) { | |||||
bzero(as->pfras_packets, sizeof(as->pfras_packets)); | |||||
bzero(as->pfras_bytes, sizeof(as->pfras_bytes)); | |||||
as->pfras_a.pfra_fback = PFR_FB_NOCOUNT; | |||||
return; | |||||
} | |||||
for (dir = 0; dir < PFR_DIR_MAX; dir ++) { | |||||
for (op = 0; op < PFR_OP_ADDR_MAX; op ++) { | |||||
as->pfras_packets[dir][op] = | |||||
counter_u64_fetch(kc->pfrkc_packets[dir][op]); | |||||
as->pfras_bytes[dir][op] = | |||||
counter_u64_fetch(kc->pfrkc_bytes[dir][op]); | |||||
} | |||||
} | |||||
} | |||||
static int | static int | ||||
pfr_walktree(struct radix_node *rn, void *arg) | pfr_walktree(struct radix_node *rn, void *arg) | ||||
{ | { | ||||
struct pfr_kentry *ke = (struct pfr_kentry *)rn; | struct pfr_kentry *ke = (struct pfr_kentry *)rn; | ||||
struct pfr_walktree *w = arg; | struct pfr_walktree *w = arg; | ||||
switch (w->pfrw_op) { | switch (w->pfrw_op) { | ||||
case PFRW_MARK: | case PFRW_MARK: | ||||
Show All 12 Lines | if (w->pfrw_free-- > 0) { | ||||
pfr_copyout_addr(w->pfrw_addr, ke); | pfr_copyout_addr(w->pfrw_addr, ke); | ||||
w->pfrw_addr++; | w->pfrw_addr++; | ||||
} | } | ||||
break; | break; | ||||
case PFRW_GET_ASTATS: | case PFRW_GET_ASTATS: | ||||
if (w->pfrw_free-- > 0) { | if (w->pfrw_free-- > 0) { | ||||
struct pfr_astats as; | struct pfr_astats as; | ||||
pfr_copyout_addr(&as.pfras_a, ke); | pfr_copyout_astats(&as, ke, w); | ||||
if (ke->pfrke_counters) { | |||||
bcopy(ke->pfrke_counters->pfrkc_packets, | |||||
as.pfras_packets, sizeof(as.pfras_packets)); | |||||
bcopy(ke->pfrke_counters->pfrkc_bytes, | |||||
as.pfras_bytes, sizeof(as.pfras_bytes)); | |||||
} else { | |||||
bzero(as.pfras_packets, sizeof(as.pfras_packets)); | |||||
bzero(as.pfras_bytes, sizeof(as.pfras_bytes)); | |||||
as.pfras_a.pfra_fback = PFR_FB_NOCOUNT; | |||||
} | |||||
as.pfras_tzero = ke->pfrke_tzero; | |||||
bcopy(&as, w->pfrw_astats, sizeof(as)); | bcopy(&as, w->pfrw_astats, sizeof(as)); | ||||
w->pfrw_astats++; | w->pfrw_astats++; | ||||
} | } | ||||
break; | break; | ||||
case PFRW_POOL_GET: | case PFRW_POOL_GET: | ||||
if (ke->pfrke_not) | if (ke->pfrke_not) | ||||
break; /* negative entries are ignored */ | break; /* negative entries are ignored */ | ||||
if (!w->pfrw_cnt--) { | if (!w->pfrw_cnt--) { | ||||
▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, | pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, | ||||
int flags) | int flags) | ||||
{ | { | ||||
struct pfr_ktable *p; | struct pfr_ktable *p; | ||||
struct pfr_ktableworkq workq; | struct pfr_ktableworkq workq; | ||||
int n, nn; | int n, nn; | ||||
long tzero = time_second; | long tzero = time_second; | ||||
int pfr_dir, pfr_op; | |||||
/* XXX PFR_FLAG_CLSTATS disabled */ | /* XXX PFR_FLAG_CLSTATS disabled */ | ||||
ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); | ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); | ||||
if (pfr_fix_anchor(filter->pfrt_anchor)) | if (pfr_fix_anchor(filter->pfrt_anchor)) | ||||
return (EINVAL); | return (EINVAL); | ||||
n = nn = pfr_table_count(filter, flags); | n = nn = pfr_table_count(filter, flags); | ||||
if (n < 0) | if (n < 0) | ||||
return (ENOENT); | return (ENOENT); | ||||
if (n > *size) { | if (n > *size) { | ||||
*size = n; | *size = n; | ||||
return (0); | return (0); | ||||
} | } | ||||
SLIST_INIT(&workq); | SLIST_INIT(&workq); | ||||
RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { | RB_FOREACH(p, pfr_ktablehead, &V_pfr_ktables) { | ||||
if (pfr_skip_table(filter, p, flags)) | if (pfr_skip_table(filter, p, flags)) | ||||
continue; | continue; | ||||
if (n-- <= 0) | if (n-- <= 0) | ||||
continue; | continue; | ||||
bcopy(&p->pfrkt_ts, tbl++, sizeof(*tbl)); | bcopy(&p->pfrkt_kts.pfrts_t, &tbl->pfrts_t, | ||||
sizeof(struct pfr_table)); | |||||
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]); | |||||
tbl->pfrts_bytes[pfr_dir][pfr_op] = | |||||
counter_u64_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_tzero = p->pfrkt_tzero; | |||||
tbl->pfrts_cnt = p->pfrkt_cnt; | |||||
for (pfr_op = 0; pfr_op < PFR_REFCNT_MAX; pfr_op++) | |||||
tbl->pfrts_refcnt[pfr_op] = p->pfrkt_refcnt[pfr_op]; | |||||
tbl++; | |||||
SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); | SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); | ||||
} | } | ||||
if (flags & PFR_FLAG_CLSTATS) | if (flags & PFR_FLAG_CLSTATS) | ||||
pfr_clstats_ktables(&workq, tzero, | pfr_clstats_ktables(&workq, tzero, | ||||
flags & PFR_FLAG_ADDRSTOO); | flags & PFR_FLAG_ADDRSTOO); | ||||
KASSERT(n == 0, ("%s: corruption detected (%d)", __func__, n)); | KASSERT(n == 0, ("%s: corruption detected (%d)", __func__, n)); | ||||
▲ Show 20 Lines • Show All 317 Lines • ▼ Show 20 Lines | for (p = SLIST_FIRST(&addrq); p != NULL; p = next) { | ||||
q = pfr_lookup_addr(kt, &ad, 1); | q = pfr_lookup_addr(kt, &ad, 1); | ||||
if (q != NULL) { | if (q != NULL) { | ||||
if (q->pfrke_not != p->pfrke_not) | if (q->pfrke_not != p->pfrke_not) | ||||
SLIST_INSERT_HEAD(&changeq, q, | SLIST_INSERT_HEAD(&changeq, q, | ||||
pfrke_workq); | pfrke_workq); | ||||
q->pfrke_mark = 1; | q->pfrke_mark = 1; | ||||
SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq); | SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq); | ||||
} else { | } else { | ||||
p->pfrke_tzero = tzero; | p->pfrke_counters.pfrkc_tzero = tzero; | ||||
SLIST_INSERT_HEAD(&addq, p, pfrke_workq); | SLIST_INSERT_HEAD(&addq, p, pfrke_workq); | ||||
} | } | ||||
} | } | ||||
pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY); | pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY); | ||||
pfr_insert_kentries(kt, &addq, tzero); | pfr_insert_kentries(kt, &addq, tzero); | ||||
pfr_remove_kentries(kt, &delq); | pfr_remove_kentries(kt, &delq); | ||||
pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); | pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG); | ||||
pfr_destroy_kentries(&garbageq); | pfr_destroy_kentries(&garbageq); | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse) | ||||
SLIST_FOREACH(p, workq, pfrkt_workq) | SLIST_FOREACH(p, workq, pfrkt_workq) | ||||
pfr_clstats_ktable(p, tzero, recurse); | pfr_clstats_ktable(p, tzero, recurse); | ||||
} | } | ||||
static void | static void | ||||
pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse) | pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse) | ||||
{ | { | ||||
struct pfr_kentryworkq addrq; | struct pfr_kentryworkq addrq; | ||||
int pfr_dir, pfr_op; | |||||
if (recurse) { | if (recurse) { | ||||
pfr_enqueue_addrs(kt, &addrq, NULL, 0); | pfr_enqueue_addrs(kt, &addrq, NULL, 0); | ||||
pfr_clstats_kentries(&addrq, tzero, 0); | pfr_clstats_kentries(&addrq, tzero, 0); | ||||
} | } | ||||
bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets)); | for (pfr_dir = 0; pfr_dir < PFR_DIR_MAX; pfr_dir ++) { | ||||
bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes)); | for (pfr_op = 0; pfr_op < PFR_OP_TABLE_MAX; pfr_op ++) { | ||||
kt->pfrkt_match = kt->pfrkt_nomatch = 0; | counter_u64_zero(kt->pfrkt_packets[pfr_dir][pfr_op]); | ||||
counter_u64_zero(kt->pfrkt_bytes[pfr_dir][pfr_op]); | |||||
} | |||||
} | |||||
counter_u64_zero(kt->pfrkt_match); | |||||
counter_u64_zero(kt->pfrkt_nomatch); | |||||
kt->pfrkt_tzero = tzero; | kt->pfrkt_tzero = tzero; | ||||
} | } | ||||
static struct pfr_ktable * | static struct pfr_ktable * | ||||
pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset) | pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset) | ||||
{ | { | ||||
struct pfr_ktable *kt; | struct pfr_ktable *kt; | ||||
struct pf_ruleset *rs; | struct pf_ruleset *rs; | ||||
int pfr_dir, pfr_op; | |||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
kt = malloc(sizeof(*kt), M_PFTABLE, M_NOWAIT|M_ZERO); | kt = malloc(sizeof(*kt), M_PFTABLE, M_NOWAIT|M_ZERO); | ||||
if (kt == NULL) | if (kt == NULL) | ||||
return (NULL); | return (NULL); | ||||
kt->pfrkt_t = *tbl; | kt->pfrkt_t = *tbl; | ||||
if (attachruleset) { | if (attachruleset) { | ||||
rs = pf_find_or_create_ruleset(tbl->pfrt_anchor); | rs = pf_find_or_create_ruleset(tbl->pfrt_anchor); | ||||
if (!rs) { | if (!rs) { | ||||
pfr_destroy_ktable(kt, 0); | pfr_destroy_ktable(kt, 0); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
kt->pfrkt_rs = rs; | kt->pfrkt_rs = rs; | ||||
rs->tables++; | rs->tables++; | ||||
} | } | ||||
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]) { | |||||
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]) { | |||||
pfr_destroy_ktable(kt, 0); | |||||
return (NULL); | |||||
} | |||||
} | |||||
} | |||||
kt->pfrkt_match = counter_u64_alloc(M_NOWAIT); | |||||
if (! kt->pfrkt_match) { | |||||
pfr_destroy_ktable(kt, 0); | |||||
return (NULL); | |||||
} | |||||
kt->pfrkt_nomatch = counter_u64_alloc(M_NOWAIT); | |||||
if (! kt->pfrkt_nomatch) { | |||||
pfr_destroy_ktable(kt, 0); | |||||
return (NULL); | |||||
} | |||||
if (!rn_inithead((void **)&kt->pfrkt_ip4, | if (!rn_inithead((void **)&kt->pfrkt_ip4, | ||||
offsetof(struct sockaddr_in, sin_addr) * 8) || | offsetof(struct sockaddr_in, sin_addr) * 8) || | ||||
!rn_inithead((void **)&kt->pfrkt_ip6, | !rn_inithead((void **)&kt->pfrkt_ip6, | ||||
offsetof(struct sockaddr_in6, sin6_addr) * 8)) { | offsetof(struct sockaddr_in6, sin6_addr) * 8)) { | ||||
pfr_destroy_ktable(kt, 0); | pfr_destroy_ktable(kt, 0); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
kt->pfrkt_tzero = tzero; | kt->pfrkt_tzero = tzero; | ||||
Show All 11 Lines | for (p = SLIST_FIRST(workq); p; p = q) { | ||||
pfr_destroy_ktable(p, flushaddr); | pfr_destroy_ktable(p, flushaddr); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) | pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) | ||||
{ | { | ||||
struct pfr_kentryworkq addrq; | struct pfr_kentryworkq addrq; | ||||
int pfr_dir, pfr_op; | |||||
if (flushaddr) { | if (flushaddr) { | ||||
pfr_enqueue_addrs(kt, &addrq, NULL, 0); | pfr_enqueue_addrs(kt, &addrq, NULL, 0); | ||||
pfr_clean_node_mask(kt, &addrq); | pfr_clean_node_mask(kt, &addrq); | ||||
pfr_destroy_kentries(&addrq); | pfr_destroy_kentries(&addrq); | ||||
} | } | ||||
if (kt->pfrkt_ip4 != NULL) | if (kt->pfrkt_ip4 != NULL) | ||||
rn_detachhead((void **)&kt->pfrkt_ip4); | rn_detachhead((void **)&kt->pfrkt_ip4); | ||||
if (kt->pfrkt_ip6 != NULL) | if (kt->pfrkt_ip6 != NULL) | ||||
rn_detachhead((void **)&kt->pfrkt_ip6); | rn_detachhead((void **)&kt->pfrkt_ip6); | ||||
if (kt->pfrkt_shadow != NULL) | if (kt->pfrkt_shadow != NULL) | ||||
pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); | pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); | ||||
if (kt->pfrkt_rs != NULL) { | if (kt->pfrkt_rs != NULL) { | ||||
kt->pfrkt_rs->tables--; | kt->pfrkt_rs->tables--; | ||||
pf_remove_if_empty_ruleset(kt->pfrkt_rs); | pf_remove_if_empty_ruleset(kt->pfrkt_rs); | ||||
} | } | ||||
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]); | |||||
} | |||||
} | |||||
counter_u64_free(kt->pfrkt_match); | |||||
counter_u64_free(kt->pfrkt_nomatch); | |||||
free(kt, M_PFTABLE); | free(kt, M_PFTABLE); | ||||
} | } | ||||
static int | static int | ||||
pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) | pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) | ||||
{ | { | ||||
int d; | int d; | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | case AF_INET6: | ||||
if (ke && KENTRY_RNF_ROOT(ke)) | if (ke && KENTRY_RNF_ROOT(ke)) | ||||
ke = NULL; | ke = NULL; | ||||
break; | break; | ||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
} | } | ||||
match = (ke && !ke->pfrke_not); | match = (ke && !ke->pfrke_not); | ||||
if (match) | if (match) | ||||
kt->pfrkt_match++; | counter_u64_add(kt->pfrkt_match, 1); | ||||
else | else | ||||
kt->pfrkt_nomatch++; | counter_u64_add(kt->pfrkt_nomatch, 1); | ||||
return (match); | return (match); | ||||
} | } | ||||
void | void | ||||
pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, | pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, | ||||
u_int64_t len, int dir_out, int op_pass, int notrule) | u_int64_t len, int dir_out, int op_pass, int notrule) | ||||
{ | { | ||||
struct pfr_kentry *ke = NULL; | struct pfr_kentry *ke = NULL; | ||||
Show All 38 Lines | default: | ||||
panic("%s: unknown address family %u", __func__, af); | panic("%s: unknown address family %u", __func__, af); | ||||
} | } | ||||
if ((ke == NULL || ke->pfrke_not) != notrule) { | if ((ke == NULL || ke->pfrke_not) != notrule) { | ||||
if (op_pass != PFR_OP_PASS) | if (op_pass != PFR_OP_PASS) | ||||
DPFPRINTF(PF_DEBUG_URGENT, | DPFPRINTF(PF_DEBUG_URGENT, | ||||
("pfr_update_stats: assertion failed.\n")); | ("pfr_update_stats: assertion failed.\n")); | ||||
op_pass = PFR_OP_XPASS; | op_pass = PFR_OP_XPASS; | ||||
} | } | ||||
kt->pfrkt_packets[dir_out][op_pass]++; | counter_u64_add(kt->pfrkt_packets[dir_out][op_pass], 1); | ||||
kt->pfrkt_bytes[dir_out][op_pass] += len; | counter_u64_add(kt->pfrkt_bytes[dir_out][op_pass], len); | ||||
if (ke != NULL && op_pass != PFR_OP_XPASS && | if (ke != NULL && op_pass != PFR_OP_XPASS && | ||||
(kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { | (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { | ||||
if (ke->pfrke_counters == NULL) | counter_u64_add(ke->pfrke_counters. | ||||
ke->pfrke_counters = uma_zalloc(V_pfr_kcounters_z, | pfrkc_packets[dir_out][op_pass], 1); | ||||
M_NOWAIT | M_ZERO); | counter_u64_add(ke->pfrke_counters. | ||||
if (ke->pfrke_counters != NULL) { | pfrkc_bytes[dir_out][op_pass], len); | ||||
ke->pfrke_counters->pfrkc_packets[dir_out][op_pass]++; | |||||
ke->pfrke_counters->pfrkc_bytes[dir_out][op_pass] += len; | |||||
} | } | ||||
} | } | ||||
} | |||||
struct pfr_ktable * | struct pfr_ktable * | ||||
pfr_attach_table(struct pf_ruleset *rs, char *name) | pfr_attach_table(struct pf_ruleset *rs, char *name) | ||||
{ | { | ||||
struct pfr_ktable *kt, *rt; | struct pfr_ktable *kt, *rt; | ||||
struct pfr_table tbl; | struct pfr_table tbl; | ||||
struct pf_anchor *ac = rs->anchor; | struct pf_anchor *ac = rs->anchor; | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, | ||||
if (counter != NULL && idx >= 0) | if (counter != NULL && idx >= 0) | ||||
use_counter = 1; | use_counter = 1; | ||||
if (idx < 0) | if (idx < 0) | ||||
idx = 0; | idx = 0; | ||||
_next_block: | _next_block: | ||||
ke = pfr_kentry_byidx(kt, idx, af); | ke = pfr_kentry_byidx(kt, idx, af); | ||||
if (ke == NULL) { | if (ke == NULL) { | ||||
kt->pfrkt_nomatch++; | counter_u64_add(kt->pfrkt_nomatch, 1); | ||||
return (1); | return (1); | ||||
} | } | ||||
pfr_prepare_network(&umask, af, ke->pfrke_net); | pfr_prepare_network(&umask, af, ke->pfrke_net); | ||||
cur = SUNION2PF(&ke->pfrke_sa, af); | cur = SUNION2PF(&ke->pfrke_sa, af); | ||||
mask = SUNION2PF(&umask, af); | mask = SUNION2PF(&umask, af); | ||||
if (use_counter) { | if (use_counter) { | ||||
/* is supplied address within block? */ | /* is supplied address within block? */ | ||||
if (!PF_MATCHA(0, cur, mask, counter, af)) { | if (!PF_MATCHA(0, cur, mask, counter, af)) { | ||||
/* no, go to next block in table */ | /* no, go to next block in table */ | ||||
idx++; | idx++; | ||||
use_counter = 0; | use_counter = 0; | ||||
goto _next_block; | goto _next_block; | ||||
} | } | ||||
PF_ACPY(addr, counter, af); | PF_ACPY(addr, counter, af); | ||||
} else { | } else { | ||||
/* use first address of block */ | /* use first address of block */ | ||||
PF_ACPY(addr, cur, af); | PF_ACPY(addr, cur, af); | ||||
} | } | ||||
if (!KENTRY_NETWORK(ke)) { | if (!KENTRY_NETWORK(ke)) { | ||||
/* this is a single IP address - no possible nested block */ | /* this is a single IP address - no possible nested block */ | ||||
PF_ACPY(counter, addr, af); | PF_ACPY(counter, addr, af); | ||||
*pidx = idx; | *pidx = idx; | ||||
kt->pfrkt_match++; | counter_u64_add(kt->pfrkt_match, 1); | ||||
return (0); | return (0); | ||||
} | } | ||||
for (;;) { | for (;;) { | ||||
/* we don't want to use a nested block */ | /* we don't want to use a nested block */ | ||||
switch (af) { | switch (af) { | ||||
case AF_INET: | case AF_INET: | ||||
ke2 = (struct pfr_kentry *)rn_match(&uaddr, | ke2 = (struct pfr_kentry *)rn_match(&uaddr, | ||||
&kt->pfrkt_ip4->rh); | &kt->pfrkt_ip4->rh); | ||||
break; | break; | ||||
case AF_INET6: | case AF_INET6: | ||||
ke2 = (struct pfr_kentry *)rn_match(&uaddr, | ke2 = (struct pfr_kentry *)rn_match(&uaddr, | ||||
&kt->pfrkt_ip6->rh); | &kt->pfrkt_ip6->rh); | ||||
break; | break; | ||||
} | } | ||||
/* no need to check KENTRY_RNF_ROOT() here */ | /* no need to check KENTRY_RNF_ROOT() here */ | ||||
if (ke2 == ke) { | if (ke2 == ke) { | ||||
/* lookup return the same block - perfect */ | /* lookup return the same block - perfect */ | ||||
PF_ACPY(counter, addr, af); | PF_ACPY(counter, addr, af); | ||||
*pidx = idx; | *pidx = idx; | ||||
kt->pfrkt_match++; | counter_u64_add(kt->pfrkt_match, 1); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* we need to increase the counter past the nested block */ | /* we need to increase the counter past the nested block */ | ||||
pfr_prepare_network(&umask, AF_INET, ke2->pfrke_net); | pfr_prepare_network(&umask, AF_INET, ke2->pfrke_net); | ||||
PF_POOLMASK(addr, addr, SUNION2PF(&umask, af), &pfr_ffaddr, af); | PF_POOLMASK(addr, addr, SUNION2PF(&umask, af), &pfr_ffaddr, af); | ||||
PF_AINC(addr, af); | PF_AINC(addr, af); | ||||
if (!PF_MATCHA(0, cur, mask, addr, af)) { | if (!PF_MATCHA(0, cur, mask, addr, af)) { | ||||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |
Let's put a comment that previous allocation isn't leaked, since any failure of pfr_create_kentry_counter() is followed by pfr_destroy_kentry(ke).