Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_if.c
Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <net/pfvar.h> | #include <net/pfvar.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
VNET_DEFINE(struct pfi_kif *, pfi_all); | VNET_DEFINE(struct pfi_kkif *, pfi_all); | ||||
VNET_DEFINE_STATIC(long, pfi_update); | VNET_DEFINE_STATIC(long, pfi_update); | ||||
#define V_pfi_update VNET(pfi_update) | #define V_pfi_update VNET(pfi_update) | ||||
#define PFI_BUFFER_MAX 0x10000 | #define PFI_BUFFER_MAX 0x10000 | ||||
VNET_DECLARE(int, pf_vnet_active); | VNET_DECLARE(int, pf_vnet_active); | ||||
#define V_pf_vnet_active VNET(pf_vnet_active) | #define V_pf_vnet_active VNET(pf_vnet_active) | ||||
VNET_DEFINE_STATIC(struct pfr_addr *, pfi_buffer); | VNET_DEFINE_STATIC(struct pfr_addr *, pfi_buffer); | ||||
VNET_DEFINE_STATIC(int, pfi_buffer_cnt); | VNET_DEFINE_STATIC(int, pfi_buffer_cnt); | ||||
VNET_DEFINE_STATIC(int, pfi_buffer_max); | VNET_DEFINE_STATIC(int, pfi_buffer_max); | ||||
#define V_pfi_buffer VNET(pfi_buffer) | #define V_pfi_buffer VNET(pfi_buffer) | ||||
#define V_pfi_buffer_cnt VNET(pfi_buffer_cnt) | #define V_pfi_buffer_cnt VNET(pfi_buffer_cnt) | ||||
#define V_pfi_buffer_max VNET(pfi_buffer_max) | #define V_pfi_buffer_max VNET(pfi_buffer_max) | ||||
eventhandler_tag pfi_attach_cookie; | eventhandler_tag pfi_attach_cookie; | ||||
eventhandler_tag pfi_detach_cookie; | eventhandler_tag pfi_detach_cookie; | ||||
eventhandler_tag pfi_attach_group_cookie; | eventhandler_tag pfi_attach_group_cookie; | ||||
eventhandler_tag pfi_change_group_cookie; | eventhandler_tag pfi_change_group_cookie; | ||||
eventhandler_tag pfi_detach_group_cookie; | eventhandler_tag pfi_detach_group_cookie; | ||||
eventhandler_tag pfi_ifaddr_event_cookie; | eventhandler_tag pfi_ifaddr_event_cookie; | ||||
static void pfi_attach_ifnet(struct ifnet *, struct pfi_kif *); | static void pfi_attach_ifnet(struct ifnet *, struct pfi_kkif *); | ||||
static void pfi_attach_ifgroup(struct ifg_group *, struct pfi_kif *); | static void pfi_attach_ifgroup(struct ifg_group *, struct pfi_kkif *); | ||||
static void pfi_kif_update(struct pfi_kif *); | static void pfi_kkif_update(struct pfi_kkif *); | ||||
static void pfi_dynaddr_update(struct pfi_dynaddr *dyn); | static void pfi_dynaddr_update(struct pfi_dynaddr *dyn); | ||||
static void pfi_table_update(struct pfr_ktable *, struct pfi_kif *, int, | static void pfi_table_update(struct pfr_ktable *, struct pfi_kkif *, int, | ||||
int); | int); | ||||
static void pfi_instance_add(struct ifnet *, int, int); | static void pfi_instance_add(struct ifnet *, int, int); | ||||
static void pfi_address_add(struct sockaddr *, int, int); | static void pfi_address_add(struct sockaddr *, int, int); | ||||
static int pfi_if_compare(struct pfi_kif *, struct pfi_kif *); | static int pfi_kkif_compare(struct pfi_kkif *, struct pfi_kkif *); | ||||
static int pfi_skip_if(const char *, struct pfi_kif *); | static int pfi_skip_if(const char *, struct pfi_kkif *); | ||||
static int pfi_unmask(void *); | static int pfi_unmask(void *); | ||||
static void pfi_attach_ifnet_event(void * __unused, struct ifnet *); | static void pfi_attach_ifnet_event(void * __unused, struct ifnet *); | ||||
static void pfi_detach_ifnet_event(void * __unused, struct ifnet *); | static void pfi_detach_ifnet_event(void * __unused, struct ifnet *); | ||||
static void pfi_attach_group_event(void * __unused, struct ifg_group *); | static void pfi_attach_group_event(void * __unused, struct ifg_group *); | ||||
static void pfi_change_group_event(void * __unused, char *); | static void pfi_change_group_event(void * __unused, char *); | ||||
static void pfi_detach_group_event(void * __unused, struct ifg_group *); | static void pfi_detach_group_event(void * __unused, struct ifg_group *); | ||||
static void pfi_ifaddr_event(void * __unused, struct ifnet *); | static void pfi_ifaddr_event(void * __unused, struct ifnet *); | ||||
RB_HEAD(pfi_ifhead, pfi_kif); | RB_HEAD(pfi_ifhead, pfi_kkif); | ||||
static RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); | static RB_PROTOTYPE(pfi_ifhead, pfi_kkif, pfik_tree, pfi_kkif_compare); | ||||
static RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); | static RB_GENERATE(pfi_ifhead, pfi_kkif, pfik_tree, pfi_kkif_compare); | ||||
VNET_DEFINE_STATIC(struct pfi_ifhead, pfi_ifs); | VNET_DEFINE_STATIC(struct pfi_ifhead, pfi_ifs); | ||||
#define V_pfi_ifs VNET(pfi_ifs) | #define V_pfi_ifs VNET(pfi_ifs) | ||||
#define PFI_BUFFER_MAX 0x10000 | #define PFI_BUFFER_MAX 0x10000 | ||||
MALLOC_DEFINE(PFI_MTYPE, "pf_ifnet", "pf(4) interface database"); | MALLOC_DEFINE(PFI_MTYPE, "pf_ifnet", "pf(4) interface database"); | ||||
LIST_HEAD(pfi_list, pfi_kif); | LIST_HEAD(pfi_list, pfi_kkif); | ||||
VNET_DEFINE_STATIC(struct pfi_list, pfi_unlinked_kifs); | VNET_DEFINE_STATIC(struct pfi_list, pfi_unlinked_kifs); | ||||
#define V_pfi_unlinked_kifs VNET(pfi_unlinked_kifs) | #define V_pfi_unlinked_kifs VNET(pfi_unlinked_kifs) | ||||
static struct mtx pfi_unlnkdkifs_mtx; | static struct mtx pfi_unlnkdkifs_mtx; | ||||
MTX_SYSINIT(pfi_unlnkdkifs_mtx, &pfi_unlnkdkifs_mtx, "pf unlinked interfaces", | MTX_SYSINIT(pfi_unlnkdkifs_mtx, &pfi_unlnkdkifs_mtx, "pf unlinked interfaces", | ||||
MTX_DEF); | MTX_DEF); | ||||
void | void | ||||
pfi_initialize_vnet(void) | pfi_initialize_vnet(void) | ||||
{ | { | ||||
struct pfi_list kifs = LIST_HEAD_INITIALIZER(); | struct pfi_list kifs = LIST_HEAD_INITIALIZER(); | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *kif; | struct pfi_kkif *kif; | ||||
struct ifg_group *ifg; | struct ifg_group *ifg; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
int nkifs; | int nkifs; | ||||
V_pfi_buffer_max = 64; | V_pfi_buffer_max = 64; | ||||
V_pfi_buffer = malloc(V_pfi_buffer_max * sizeof(*V_pfi_buffer), | V_pfi_buffer = malloc(V_pfi_buffer_max * sizeof(*V_pfi_buffer), | ||||
PFI_MTYPE, M_WAITOK); | PFI_MTYPE, M_WAITOK); | ||||
nkifs = 1; /* one for V_pfi_all */ | nkifs = 1; /* one for V_pfi_all */ | ||||
IFNET_RLOCK(); | IFNET_RLOCK(); | ||||
CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) | CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) | ||||
nkifs++; | nkifs++; | ||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) | CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) | ||||
nkifs++; | nkifs++; | ||||
for (int n = 0; n < nkifs; n++) { | for (int n = 0; n < nkifs; n++) { | ||||
kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | ||||
LIST_INSERT_HEAD(&kifs, kif, pfik_list); | LIST_INSERT_HEAD(&kifs, kif, pfik_list); | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
kif = LIST_FIRST(&kifs); | kif = LIST_FIRST(&kifs); | ||||
LIST_REMOVE(kif, pfik_list); | LIST_REMOVE(kif, pfik_list); | ||||
V_pfi_all = pfi_kif_attach(kif, IFG_ALL); | V_pfi_all = pfi_kkif_attach(kif, IFG_ALL); | ||||
CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) { | CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) { | ||||
kif = LIST_FIRST(&kifs); | kif = LIST_FIRST(&kifs); | ||||
LIST_REMOVE(kif, pfik_list); | LIST_REMOVE(kif, pfik_list); | ||||
pfi_attach_ifgroup(ifg, kif); | pfi_attach_ifgroup(ifg, kif); | ||||
} | } | ||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | ||||
kif = LIST_FIRST(&kifs); | kif = LIST_FIRST(&kifs); | ||||
LIST_REMOVE(kif, pfik_list); | LIST_REMOVE(kif, pfik_list); | ||||
Show All 22 Lines | pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event, | ||||
pfi_detach_group_event, NULL, EVENTHANDLER_PRI_ANY); | pfi_detach_group_event, NULL, EVENTHANDLER_PRI_ANY); | ||||
pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event, | pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event, | ||||
pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY); | pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY); | ||||
} | } | ||||
void | void | ||||
pfi_cleanup_vnet(void) | pfi_cleanup_vnet(void) | ||||
{ | { | ||||
struct pfi_kif *kif; | struct pfi_kkif *kif; | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
V_pfi_all = NULL; | V_pfi_all = NULL; | ||||
while ((kif = RB_MIN(pfi_ifhead, &V_pfi_ifs))) { | while ((kif = RB_MIN(pfi_ifhead, &V_pfi_ifs))) { | ||||
RB_REMOVE(pfi_ifhead, &V_pfi_ifs, kif); | RB_REMOVE(pfi_ifhead, &V_pfi_ifs, kif); | ||||
if (kif->pfik_group) | if (kif->pfik_group) | ||||
kif->pfik_group->ifg_pf_kif = NULL; | kif->pfik_group->ifg_pf_kif = NULL; | ||||
Show All 21 Lines | pfi_cleanup(void) | ||||
EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie); | EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie); | ||||
EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie); | EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie); | ||||
EVENTHANDLER_DEREGISTER(group_attach_event, pfi_attach_group_cookie); | EVENTHANDLER_DEREGISTER(group_attach_event, pfi_attach_group_cookie); | ||||
EVENTHANDLER_DEREGISTER(group_change_event, pfi_change_group_cookie); | EVENTHANDLER_DEREGISTER(group_change_event, pfi_change_group_cookie); | ||||
EVENTHANDLER_DEREGISTER(group_detach_event, pfi_detach_group_cookie); | EVENTHANDLER_DEREGISTER(group_detach_event, pfi_detach_group_cookie); | ||||
EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie); | EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie); | ||||
} | } | ||||
struct pfi_kif * | struct pfi_kkif * | ||||
pfi_kif_find(const char *kif_name) | pfi_kkif_find(const char *kif_name) | ||||
{ | { | ||||
struct pfi_kif_cmp s; | struct pfi_kif_cmp s; | ||||
PF_RULES_ASSERT(); | PF_RULES_ASSERT(); | ||||
bzero(&s, sizeof(s)); | bzero(&s, sizeof(s)); | ||||
strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name)); | strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name)); | ||||
return (RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kif *)&s)); | return (RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kkif *)&s)); | ||||
} | } | ||||
struct pfi_kif * | struct pfi_kkif * | ||||
pfi_kif_attach(struct pfi_kif *kif, const char *kif_name) | pfi_kkif_attach(struct pfi_kkif *kif, const char *kif_name) | ||||
{ | { | ||||
struct pfi_kif *kif1; | struct pfi_kkif *kif1; | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
KASSERT(kif != NULL, ("%s: null kif", __func__)); | KASSERT(kif != NULL, ("%s: null kif", __func__)); | ||||
kif1 = pfi_kif_find(kif_name); | kif1 = pfi_kkif_find(kif_name); | ||||
if (kif1 != NULL) { | if (kif1 != NULL) { | ||||
free(kif, PFI_MTYPE); | free(kif, PFI_MTYPE); | ||||
return (kif1); | return (kif1); | ||||
} | } | ||||
bzero(kif, sizeof(*kif)); | bzero(kif, sizeof(*kif)); | ||||
strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name)); | strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name)); | ||||
/* | /* | ||||
* It seems that the value of time_second is in unintialzied state | * It seems that the value of time_second is in unintialzied state | ||||
* when pf sets interface statistics clear time in boot phase if pf | * when pf sets interface statistics clear time in boot phase if pf | ||||
* was statically linked to kernel. Instead of setting the bogus | * was statically linked to kernel. Instead of setting the bogus | ||||
* time value have pfi_get_ifaces handle this case. In | * time value have pfi_get_ifaces handle this case. In | ||||
* pfi_get_ifaces it uses time_second if it sees the time is 0. | * pfi_get_ifaces it uses time_second if it sees the time is 0. | ||||
*/ | */ | ||||
kif->pfik_tzero = time_second > 1 ? time_second : 0; | kif->pfik_tzero = time_second > 1 ? time_second : 0; | ||||
TAILQ_INIT(&kif->pfik_dynaddrs); | TAILQ_INIT(&kif->pfik_dynaddrs); | ||||
RB_INSERT(pfi_ifhead, &V_pfi_ifs, kif); | RB_INSERT(pfi_ifhead, &V_pfi_ifs, kif); | ||||
return (kif); | return (kif); | ||||
} | } | ||||
void | void | ||||
pfi_kif_ref(struct pfi_kif *kif) | pfi_kkif_ref(struct pfi_kkif *kif) | ||||
{ | { | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
kif->pfik_rulerefs++; | kif->pfik_rulerefs++; | ||||
} | } | ||||
void | void | ||||
pfi_kif_unref(struct pfi_kif *kif) | pfi_kkif_unref(struct pfi_kkif *kif) | ||||
{ | { | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
KASSERT(kif->pfik_rulerefs > 0, ("%s: %p has zero refs", __func__, kif)); | KASSERT(kif->pfik_rulerefs > 0, ("%s: %p has zero refs", __func__, kif)); | ||||
kif->pfik_rulerefs--; | kif->pfik_rulerefs--; | ||||
if (kif->pfik_rulerefs > 0) | if (kif->pfik_rulerefs > 0) | ||||
Show All 10 Lines | pfi_kkif_unref(struct pfi_kkif *kif) | ||||
kif->pfik_flags |= PFI_IFLAG_REFS; | kif->pfik_flags |= PFI_IFLAG_REFS; | ||||
mtx_lock(&pfi_unlnkdkifs_mtx); | mtx_lock(&pfi_unlnkdkifs_mtx); | ||||
LIST_INSERT_HEAD(&V_pfi_unlinked_kifs, kif, pfik_list); | LIST_INSERT_HEAD(&V_pfi_unlinked_kifs, kif, pfik_list); | ||||
mtx_unlock(&pfi_unlnkdkifs_mtx); | mtx_unlock(&pfi_unlnkdkifs_mtx); | ||||
} | } | ||||
void | void | ||||
pfi_kif_purge(void) | pfi_kkif_purge(void) | ||||
{ | { | ||||
struct pfi_kif *kif, *kif1; | struct pfi_kkif *kif, *kif1; | ||||
/* | /* | ||||
* Do naive mark-and-sweep garbage collecting of old kifs. | * Do naive mark-and-sweep garbage collecting of old kifs. | ||||
* Reference flag is raised by pf_purge_expired_states(). | * Reference flag is raised by pf_purge_expired_states(). | ||||
*/ | */ | ||||
mtx_lock(&pfi_unlnkdkifs_mtx); | mtx_lock(&pfi_unlnkdkifs_mtx); | ||||
LIST_FOREACH_SAFE(kif, &V_pfi_unlinked_kifs, pfik_list, kif1) { | LIST_FOREACH_SAFE(kif, &V_pfi_unlinked_kifs, pfik_list, kif1) { | ||||
if (!(kif->pfik_flags & PFI_IFLAG_REFS)) { | if (!(kif->pfik_flags & PFI_IFLAG_REFS)) { | ||||
LIST_REMOVE(kif, pfik_list); | LIST_REMOVE(kif, pfik_list); | ||||
free(kif, PFI_MTYPE); | free(kif, PFI_MTYPE); | ||||
} else | } else | ||||
kif->pfik_flags &= ~PFI_IFLAG_REFS; | kif->pfik_flags &= ~PFI_IFLAG_REFS; | ||||
} | } | ||||
mtx_unlock(&pfi_unlnkdkifs_mtx); | mtx_unlock(&pfi_unlnkdkifs_mtx); | ||||
} | } | ||||
int | int | ||||
pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif) | pfi_kkif_match(struct pfi_kkif *rule_kif, struct pfi_kkif *packet_kif) | ||||
{ | { | ||||
struct ifg_list *p; | struct ifg_list *p; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
if (rule_kif == NULL || rule_kif == packet_kif) | if (rule_kif == NULL || rule_kif == packet_kif) | ||||
return (1); | return (1); | ||||
if (rule_kif->pfik_group != NULL) { | if (rule_kif->pfik_group != NULL) { | ||||
CK_STAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) | CK_STAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) | ||||
if (p->ifgl_group == rule_kif->pfik_group) | if (p->ifgl_group == rule_kif->pfik_group) | ||||
return (1); | return (1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
pfi_attach_ifnet(struct ifnet *ifp, struct pfi_kif *kif) | pfi_attach_ifnet(struct ifnet *ifp, struct pfi_kkif *kif) | ||||
{ | { | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
V_pfi_update++; | V_pfi_update++; | ||||
kif = pfi_kif_attach(kif, ifp->if_xname); | kif = pfi_kkif_attach(kif, ifp->if_xname); | ||||
if_ref(ifp); | if_ref(ifp); | ||||
kif->pfik_ifp = ifp; | kif->pfik_ifp = ifp; | ||||
ifp->if_pf_kif = kif; | ifp->if_pf_kif = kif; | ||||
pfi_kif_update(kif); | pfi_kkif_update(kif); | ||||
} | } | ||||
static void | static void | ||||
pfi_attach_ifgroup(struct ifg_group *ifg, struct pfi_kif *kif) | pfi_attach_ifgroup(struct ifg_group *ifg, struct pfi_kkif *kif) | ||||
{ | { | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
V_pfi_update++; | V_pfi_update++; | ||||
kif = pfi_kif_attach(kif, ifg->ifg_group); | kif = pfi_kkif_attach(kif, ifg->ifg_group); | ||||
kif->pfik_group = ifg; | kif->pfik_group = ifg; | ||||
ifg->ifg_pf_kif = kif; | ifg->ifg_pf_kif = kif; | ||||
} | } | ||||
int | int | ||||
pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) | pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) | ||||
{ | { | ||||
switch (af) { | switch (af) { | ||||
Show All 30 Lines | |||||
int | int | ||||
pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) | pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_dynaddr *dyn; | struct pfi_dynaddr *dyn; | ||||
char tblname[PF_TABLE_NAME_SIZE]; | char tblname[PF_TABLE_NAME_SIZE]; | ||||
struct pf_kruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
struct pfi_kif *kif; | struct pfi_kkif *kif; | ||||
int rv = 0; | int rv = 0; | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
KASSERT(aw->type == PF_ADDR_DYNIFTL, ("%s: type %u", | KASSERT(aw->type == PF_ADDR_DYNIFTL, ("%s: type %u", | ||||
__func__, aw->type)); | __func__, aw->type)); | ||||
KASSERT(aw->p.dyn == NULL, ("%s: dyn is %p", __func__, aw->p.dyn)); | KASSERT(aw->p.dyn == NULL, ("%s: dyn is %p", __func__, aw->p.dyn)); | ||||
if ((dyn = malloc(sizeof(*dyn), PFI_MTYPE, M_NOWAIT | M_ZERO)) == NULL) | if ((dyn = malloc(sizeof(*dyn), PFI_MTYPE, M_NOWAIT | M_ZERO)) == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT)) == NULL) { | if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT)) == NULL) { | ||||
free(dyn, PFI_MTYPE); | free(dyn, PFI_MTYPE); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
if (!strcmp(aw->v.ifname, "self")) | if (!strcmp(aw->v.ifname, "self")) | ||||
dyn->pfid_kif = pfi_kif_attach(kif, IFG_ALL); | dyn->pfid_kif = pfi_kkif_attach(kif, IFG_ALL); | ||||
else | else | ||||
dyn->pfid_kif = pfi_kif_attach(kif, aw->v.ifname); | dyn->pfid_kif = pfi_kkif_attach(kif, aw->v.ifname); | ||||
pfi_kif_ref(dyn->pfid_kif); | pfi_kkif_ref(dyn->pfid_kif); | ||||
dyn->pfid_net = pfi_unmask(&aw->v.a.mask); | dyn->pfid_net = pfi_unmask(&aw->v.a.mask); | ||||
if (af == AF_INET && dyn->pfid_net == 32) | if (af == AF_INET && dyn->pfid_net == 32) | ||||
dyn->pfid_net = 128; | dyn->pfid_net = 128; | ||||
strlcpy(tblname, aw->v.ifname, sizeof(tblname)); | strlcpy(tblname, aw->v.ifname, sizeof(tblname)); | ||||
if (aw->iflags & PFI_AFLAG_NETWORK) | if (aw->iflags & PFI_AFLAG_NETWORK) | ||||
strlcat(tblname, ":network", sizeof(tblname)); | strlcat(tblname, ":network", sizeof(tblname)); | ||||
if (aw->iflags & PFI_AFLAG_BROADCAST) | if (aw->iflags & PFI_AFLAG_BROADCAST) | ||||
Show All 17 Lines | pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) | ||||
dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; | dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; | ||||
dyn->pfid_iflags = aw->iflags; | dyn->pfid_iflags = aw->iflags; | ||||
dyn->pfid_af = af; | dyn->pfid_af = af; | ||||
TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); | TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); | ||||
aw->p.dyn = dyn; | aw->p.dyn = dyn; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
pfi_kif_update(dyn->pfid_kif); | pfi_kkif_update(dyn->pfid_kif); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
return (0); | return (0); | ||||
_bad: | _bad: | ||||
if (dyn->pfid_kt != NULL) | if (dyn->pfid_kt != NULL) | ||||
pfr_detach_table(dyn->pfid_kt); | pfr_detach_table(dyn->pfid_kt); | ||||
if (ruleset != NULL) | if (ruleset != NULL) | ||||
pf_remove_if_empty_kruleset(ruleset); | pf_remove_if_empty_kruleset(ruleset); | ||||
if (dyn->pfid_kif != NULL) | if (dyn->pfid_kif != NULL) | ||||
pfi_kif_unref(dyn->pfid_kif); | pfi_kkif_unref(dyn->pfid_kif); | ||||
free(dyn, PFI_MTYPE); | free(dyn, PFI_MTYPE); | ||||
return (rv); | return (rv); | ||||
} | } | ||||
static void | static void | ||||
pfi_kif_update(struct pfi_kif *kif) | pfi_kkif_update(struct pfi_kkif *kif) | ||||
{ | { | ||||
struct ifg_list *ifgl; | struct ifg_list *ifgl; | ||||
struct ifg_member *ifgm; | struct ifg_member *ifgm; | ||||
struct pfi_dynaddr *p; | struct pfi_dynaddr *p; | ||||
struct pfi_kif *tmpkif; | struct pfi_kkif *tmpkif; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
/* update all dynaddr */ | /* update all dynaddr */ | ||||
TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry) | TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry) | ||||
pfi_dynaddr_update(p); | pfi_dynaddr_update(p); | ||||
/* Apply group flags to new members. */ | /* Apply group flags to new members. */ | ||||
if (kif->pfik_group != NULL) { | if (kif->pfik_group != NULL) { | ||||
CK_STAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, | CK_STAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, | ||||
ifgm_next) { | ifgm_next) { | ||||
tmpkif = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif; | tmpkif = (struct pfi_kkif *)ifgm->ifgm_ifp->if_pf_kif; | ||||
if (tmpkif == NULL) | if (tmpkif == NULL) | ||||
continue; | continue; | ||||
tmpkif->pfik_flags |= kif->pfik_flags; | tmpkif->pfik_flags |= kif->pfik_flags; | ||||
} | } | ||||
} | } | ||||
/* again for all groups kif is member of */ | /* again for all groups kif is member of */ | ||||
if (kif->pfik_ifp != NULL) { | if (kif->pfik_ifp != NULL) { | ||||
CK_STAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) | CK_STAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) | ||||
pfi_kif_update((struct pfi_kif *) | pfi_kkif_update((struct pfi_kkif *) | ||||
ifgl->ifgl_group->ifg_pf_kif); | ifgl->ifgl_group->ifg_pf_kif); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
pfi_dynaddr_update(struct pfi_dynaddr *dyn) | pfi_dynaddr_update(struct pfi_dynaddr *dyn) | ||||
{ | { | ||||
struct pfi_kif *kif; | struct pfi_kkif *kif; | ||||
struct pfr_ktable *kt; | struct pfr_ktable *kt; | ||||
PF_RULES_WASSERT(); | PF_RULES_WASSERT(); | ||||
KASSERT(dyn && dyn->pfid_kif && dyn->pfid_kt, | KASSERT(dyn && dyn->pfid_kif && dyn->pfid_kt, | ||||
("%s: bad argument", __func__)); | ("%s: bad argument", __func__)); | ||||
kif = dyn->pfid_kif; | kif = dyn->pfid_kif; | ||||
kt = dyn->pfid_kt; | kt = dyn->pfid_kt; | ||||
if (kt->pfrkt_larg != V_pfi_update) { | if (kt->pfrkt_larg != V_pfi_update) { | ||||
/* this table needs to be brought up-to-date */ | /* this table needs to be brought up-to-date */ | ||||
pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); | pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); | ||||
kt->pfrkt_larg = V_pfi_update; | kt->pfrkt_larg = V_pfi_update; | ||||
} | } | ||||
pfr_dynaddr_update(kt, dyn); | pfr_dynaddr_update(kt, dyn); | ||||
} | } | ||||
static void | static void | ||||
pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) | pfi_table_update(struct pfr_ktable *kt, struct pfi_kkif *kif, int net, int flags) | ||||
{ | { | ||||
int e, size2 = 0; | int e, size2 = 0; | ||||
struct ifg_member *ifgm; | struct ifg_member *ifgm; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
V_pfi_buffer_cnt = 0; | V_pfi_buffer_cnt = 0; | ||||
▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
pfi_dynaddr_remove(struct pfi_dynaddr *dyn) | pfi_dynaddr_remove(struct pfi_dynaddr *dyn) | ||||
{ | { | ||||
KASSERT(dyn->pfid_kif != NULL, ("%s: null pfid_kif", __func__)); | KASSERT(dyn->pfid_kif != NULL, ("%s: null pfid_kif", __func__)); | ||||
KASSERT(dyn->pfid_kt != NULL, ("%s: null pfid_kt", __func__)); | KASSERT(dyn->pfid_kt != NULL, ("%s: null pfid_kt", __func__)); | ||||
TAILQ_REMOVE(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); | TAILQ_REMOVE(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); | ||||
pfi_kif_unref(dyn->pfid_kif); | pfi_kkif_unref(dyn->pfid_kif); | ||||
pfr_detach_table(dyn->pfid_kt); | pfr_detach_table(dyn->pfid_kt); | ||||
free(dyn, PFI_MTYPE); | free(dyn, PFI_MTYPE); | ||||
} | } | ||||
void | void | ||||
pfi_dynaddr_copyout(struct pf_addr_wrap *aw) | pfi_dynaddr_copyout(struct pf_addr_wrap *aw) | ||||
{ | { | ||||
KASSERT(aw->type == PF_ADDR_DYNIFTL, | KASSERT(aw->type == PF_ADDR_DYNIFTL, | ||||
("%s: type %u", __func__, aw->type)); | ("%s: type %u", __func__, aw->type)); | ||||
if (aw->p.dyn == NULL || aw->p.dyn->pfid_kif == NULL) | if (aw->p.dyn == NULL || aw->p.dyn->pfid_kif == NULL) | ||||
return; | return; | ||||
aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; | aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; | ||||
} | } | ||||
static int | static int | ||||
pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) | pfi_kkif_compare(struct pfi_kkif *p, struct pfi_kkif *q) | ||||
{ | { | ||||
return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); | return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); | ||||
} | } | ||||
void | void | ||||
pfi_update_status(const char *name, struct pf_status *pfs) | pfi_update_status(const char *name, struct pf_status *pfs) | ||||
{ | { | ||||
struct pfi_kif *p; | struct pfi_kkif *p; | ||||
struct pfi_kif_cmp key; | struct pfi_kif_cmp key; | ||||
struct ifg_member p_member, *ifgm; | struct ifg_member p_member, *ifgm; | ||||
CK_STAILQ_HEAD(, ifg_member) ifg_members; | CK_STAILQ_HEAD(, ifg_member) ifg_members; | ||||
int i, j, k; | int i, j, k; | ||||
strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); | strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); | ||||
p = RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kif *)&key); | p = RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kkif *)&key); | ||||
if (p == NULL) | if (p == NULL) | ||||
return; | return; | ||||
if (p->pfik_group != NULL) { | if (p->pfik_group != NULL) { | ||||
bcopy(&p->pfik_group->ifg_members, &ifg_members, | bcopy(&p->pfik_group->ifg_members, &ifg_members, | ||||
sizeof(ifg_members)); | sizeof(ifg_members)); | ||||
} else { | } else { | ||||
/* build a temporary list for p only */ | /* build a temporary list for p only */ | ||||
bzero(&p_member, sizeof(p_member)); | bzero(&p_member, sizeof(p_member)); | ||||
p_member.ifgm_ifp = p->pfik_ifp; | p_member.ifgm_ifp = p->pfik_ifp; | ||||
CK_STAILQ_INIT(&ifg_members); | CK_STAILQ_INIT(&ifg_members); | ||||
CK_STAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next); | CK_STAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next); | ||||
} | } | ||||
if (pfs) { | if (pfs) { | ||||
bzero(pfs->pcounters, sizeof(pfs->pcounters)); | bzero(pfs->pcounters, sizeof(pfs->pcounters)); | ||||
bzero(pfs->bcounters, sizeof(pfs->bcounters)); | bzero(pfs->bcounters, sizeof(pfs->bcounters)); | ||||
} | } | ||||
CK_STAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) { | CK_STAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) { | ||||
if (ifgm->ifgm_ifp == NULL || ifgm->ifgm_ifp->if_pf_kif == NULL) | if (ifgm->ifgm_ifp == NULL || ifgm->ifgm_ifp->if_pf_kif == NULL) | ||||
continue; | continue; | ||||
p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif; | p = (struct pfi_kkif *)ifgm->ifgm_ifp->if_pf_kif; | ||||
/* just clear statistics */ | /* just clear statistics */ | ||||
if (pfs == NULL) { | if (pfs == NULL) { | ||||
bzero(p->pfik_packets, sizeof(p->pfik_packets)); | bzero(p->pfik_packets, sizeof(p->pfik_packets)); | ||||
bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); | bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); | ||||
p->pfik_tzero = time_second; | p->pfik_tzero = time_second; | ||||
continue; | continue; | ||||
} | } | ||||
for (i = 0; i < 2; i++) | for (i = 0; i < 2; i++) | ||||
for (j = 0; j < 2; j++) | for (j = 0; j < 2; j++) | ||||
for (k = 0; k < 2; k++) { | for (k = 0; k < 2; k++) { | ||||
pfs->pcounters[i][j][k] += | pfs->pcounters[i][j][k] += | ||||
p->pfik_packets[i][j][k]; | p->pfik_packets[i][j][k]; | ||||
pfs->bcounters[i][j] += | pfs->bcounters[i][j] += | ||||
p->pfik_bytes[i][j][k]; | p->pfik_bytes[i][j][k]; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void | |||||
pf_kkif_to_kif(const struct pfi_kkif *kkif, struct pfi_kif *kif) | |||||
{ | |||||
bzero(kif, sizeof(*kif)); | |||||
strlcpy(kif->pfik_name, kkif->pfik_name, sizeof(kif->pfik_name)); | |||||
for (int i = 0; i < 2; i++) { | |||||
for (int j = 0; j < 2; j++) { | |||||
for (int k = 0; k < 2; k++) { | |||||
kif->pfik_packets[i][j][k] = | |||||
kkif->pfik_packets[i][j][k]; | |||||
kif->pfik_bytes[i][j][k] = | |||||
kkif->pfik_bytes[i][j][k]; | |||||
} | |||||
} | |||||
} | |||||
kif->pfik_tzero = kkif->pfik_tzero; | |||||
kif->pfik_rulerefs = kkif->pfik_rulerefs; | |||||
} | |||||
void | void | ||||
pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) | pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *p, *nextp; | struct pfi_kkif *p, *nextp; | ||||
int n = 0; | int n = 0; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
for (p = RB_MIN(pfi_ifhead, &V_pfi_ifs); p; p = nextp) { | for (p = RB_MIN(pfi_ifhead, &V_pfi_ifs); p; p = nextp) { | ||||
nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); | nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); | ||||
if (pfi_skip_if(name, p)) | if (pfi_skip_if(name, p)) | ||||
continue; | continue; | ||||
if (*size <= n++) | if (*size <= n++) | ||||
break; | break; | ||||
if (!p->pfik_tzero) | if (!p->pfik_tzero) | ||||
p->pfik_tzero = time_second; | p->pfik_tzero = time_second; | ||||
bcopy(p, buf++, sizeof(*buf)); | pf_kkif_to_kif(p, buf++); | ||||
nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); | nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); | ||||
} | } | ||||
*size = n; | *size = n; | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
static int | static int | ||||
pfi_skip_if(const char *filter, struct pfi_kif *p) | pfi_skip_if(const char *filter, struct pfi_kkif *p) | ||||
{ | { | ||||
struct ifg_list *i; | struct ifg_list *i; | ||||
int n; | int n; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
if (filter == NULL || !*filter) | if (filter == NULL || !*filter) | ||||
return (0); | return (0); | ||||
Show All 11 Lines | if (!strncmp(i->ifgl_group->ifg_group, filter, IFNAMSIZ)) | ||||
return (0); /* iface is in group "filter" */ | return (0); /* iface is in group "filter" */ | ||||
return (1); | return (1); | ||||
} | } | ||||
int | int | ||||
pfi_set_flags(const char *name, int flags) | pfi_set_flags(const char *name, int flags) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *p, *kif; | struct pfi_kkif *p, *kif; | ||||
kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT); | kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT); | ||||
if (kif == NULL) | if (kif == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
kif = pfi_kif_attach(kif, name); | kif = pfi_kkif_attach(kif, name); | ||||
RB_FOREACH(p, pfi_ifhead, &V_pfi_ifs) { | RB_FOREACH(p, pfi_ifhead, &V_pfi_ifs) { | ||||
if (pfi_skip_if(name, p)) | if (pfi_skip_if(name, p)) | ||||
continue; | continue; | ||||
p->pfik_flags |= flags; | p->pfik_flags |= flags; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
pfi_clear_flags(const char *name, int flags) | pfi_clear_flags(const char *name, int flags) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *p, *tmp; | struct pfi_kkif *p, *tmp; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
RB_FOREACH_SAFE(p, pfi_ifhead, &V_pfi_ifs, tmp) { | RB_FOREACH_SAFE(p, pfi_ifhead, &V_pfi_ifs, tmp) { | ||||
if (pfi_skip_if(name, p)) | if (pfi_skip_if(name, p)) | ||||
continue; | continue; | ||||
p->pfik_flags &= ~flags; | p->pfik_flags &= ~flags; | ||||
if (p->pfik_ifp == NULL && p->pfik_group == NULL && | if (p->pfik_ifp == NULL && p->pfik_group == NULL && | ||||
Show All 26 Lines | pfi_unmask(void *addr) | ||||
} | } | ||||
return (b); | return (b); | ||||
} | } | ||||
static void | static void | ||||
pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) | pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *kif; | struct pfi_kkif *kif; | ||||
if (V_pf_vnet_active == 0) { | if (V_pf_vnet_active == 0) { | ||||
/* Avoid teardown race in the least expensive way. */ | /* Avoid teardown race in the least expensive way. */ | ||||
return; | return; | ||||
} | } | ||||
kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
pfi_attach_ifnet(ifp, kif); | pfi_attach_ifnet(ifp, kif); | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
pf_altq_ifnet_event(ifp, 0); | pf_altq_ifnet_event(ifp, 0); | ||||
#endif | #endif | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
static void | static void | ||||
pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) | pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *kif = (struct pfi_kif *)ifp->if_pf_kif; | struct pfi_kkif *kif = (struct pfi_kkif *)ifp->if_pf_kif; | ||||
if (pfsync_detach_ifnet_ptr) | if (pfsync_detach_ifnet_ptr) | ||||
pfsync_detach_ifnet_ptr(ifp); | pfsync_detach_ifnet_ptr(ifp); | ||||
if (kif == NULL) | if (kif == NULL) | ||||
return; | return; | ||||
if (V_pf_vnet_active == 0) { | if (V_pf_vnet_active == 0) { | ||||
/* Avoid teardown race in the least expensive way. */ | /* Avoid teardown race in the least expensive way. */ | ||||
return; | return; | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
V_pfi_update++; | V_pfi_update++; | ||||
pfi_kif_update(kif); | pfi_kkif_update(kif); | ||||
if (kif->pfik_ifp) | if (kif->pfik_ifp) | ||||
if_rele(kif->pfik_ifp); | if_rele(kif->pfik_ifp); | ||||
kif->pfik_ifp = NULL; | kif->pfik_ifp = NULL; | ||||
ifp->if_pf_kif = NULL; | ifp->if_pf_kif = NULL; | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
pf_altq_ifnet_event(ifp, 1); | pf_altq_ifnet_event(ifp, 1); | ||||
#endif | #endif | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
static void | static void | ||||
pfi_attach_group_event(void *arg __unused, struct ifg_group *ifg) | pfi_attach_group_event(void *arg __unused, struct ifg_group *ifg) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *kif; | struct pfi_kkif *kif; | ||||
if (V_pf_vnet_active == 0) { | if (V_pf_vnet_active == 0) { | ||||
/* Avoid teardown race in the least expensive way. */ | /* Avoid teardown race in the least expensive way. */ | ||||
return; | return; | ||||
} | } | ||||
kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
pfi_attach_ifgroup(ifg, kif); | pfi_attach_ifgroup(ifg, kif); | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
static void | static void | ||||
pfi_change_group_event(void *arg __unused, char *gname) | pfi_change_group_event(void *arg __unused, char *gname) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct pfi_kif *kif; | struct pfi_kkif *kif; | ||||
if (V_pf_vnet_active == 0) { | if (V_pf_vnet_active == 0) { | ||||
/* Avoid teardown race in the least expensive way. */ | /* Avoid teardown race in the least expensive way. */ | ||||
return; | return; | ||||
} | } | ||||
kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
V_pfi_update++; | V_pfi_update++; | ||||
kif = pfi_kif_attach(kif, gname); | kif = pfi_kkif_attach(kif, gname); | ||||
pfi_kif_update(kif); | pfi_kkif_update(kif); | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
static void | static void | ||||
pfi_detach_group_event(void *arg __unused, struct ifg_group *ifg) | pfi_detach_group_event(void *arg __unused, struct ifg_group *ifg) | ||||
{ | { | ||||
struct pfi_kif *kif = (struct pfi_kif *)ifg->ifg_pf_kif; | struct pfi_kkif *kif = (struct pfi_kkif *)ifg->ifg_pf_kif; | ||||
if (kif == NULL) | if (kif == NULL) | ||||
return; | return; | ||||
if (V_pf_vnet_active == 0) { | if (V_pf_vnet_active == 0) { | ||||
/* Avoid teardown race in the least expensive way. */ | /* Avoid teardown race in the least expensive way. */ | ||||
return; | return; | ||||
} | } | ||||
Show All 19 Lines | if (V_pf_vnet_active == 0) { | ||||
return; | return; | ||||
} | } | ||||
PF_RULES_WLOCK(); | PF_RULES_WLOCK(); | ||||
if (ifp->if_pf_kif) { | if (ifp->if_pf_kif) { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
V_pfi_update++; | V_pfi_update++; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
pfi_kif_update(ifp->if_pf_kif); | pfi_kkif_update(ifp->if_pf_kif); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
PF_RULES_WUNLOCK(); | PF_RULES_WUNLOCK(); | ||||
} | } |