diff options
author | Gleb Smirnoff <glebius@FreeBSD.org> | 2015-03-17 12:19:28 +0000 |
---|---|---|
committer | Gleb Smirnoff <glebius@FreeBSD.org> | 2015-03-17 12:19:28 +0000 |
commit | 3e8c6d74bb723946a98cf90912738dad1a22e727 (patch) | |
tree | f826787537eaba7f60f6bcab776cabe232724b21 /sys/netpfil/pf | |
parent | 89c481cfd4c24c14fbc9ea96436c4d634e3777a7 (diff) | |
download | src-3e8c6d74bb723946a98cf90912738dad1a22e727.tar.gz src-3e8c6d74bb723946a98cf90912738dad1a22e727.zip |
Always lock the hash row of a source node when updating its 'states' counter.
PR: 182401
Sponsored by: Nginx, Inc.
Notes
Notes:
svn path=/head/; revision=280169
Diffstat (limited to 'sys/netpfil/pf')
-rw-r--r-- | sys/netpfil/pf/pf.c | 111 | ||||
-rw-r--r-- | sys/netpfil/pf/pf_ioctl.c | 14 |
2 files changed, 59 insertions, 66 deletions
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 7c3ddb808de0..ce0c6bd97078 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -649,7 +649,10 @@ pf_find_src_node(struct pf_addr *src, struct pf_rule *rule, sa_family_t af, ((af == AF_INET && n->addr.v4.s_addr == src->v4.s_addr) || (af == AF_INET6 && bcmp(&n->addr, src, sizeof(*src)) == 0))) break; - if (n != NULL || returnlocked == 0) + if (n != NULL) { + n->states++; + PF_HASHROW_UNLOCK(sh); + } else if (returnlocked == 0) PF_HASHROW_UNLOCK(sh); return (n); @@ -693,6 +696,7 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, LIST_INSERT_HEAD(&sh->nodes, *sn, entry); (*sn)->creation = time_uptime; (*sn)->ruletype = rule->action; + (*sn)->states = 1; if ((*sn)->rule.ptr != NULL) counter_u64_add((*sn)->rule.ptr->src_nodes, 1); PF_HASHROW_UNLOCK(sh); @@ -709,37 +713,13 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, } void -pf_unlink_src_node_locked(struct pf_src_node *src) +pf_unlink_src_node(struct pf_src_node *src) { -#ifdef INVARIANTS - struct pf_srchash *sh; - sh = &V_pf_srchash[pf_hashsrc(&src->addr, src->af)]; - PF_HASHROW_ASSERT(sh); -#endif + PF_HASHROW_ASSERT(&V_pf_srchash[pf_hashsrc(&src->addr, src->af)]); LIST_REMOVE(src, entry); if (src->rule.ptr) counter_u64_add(src->rule.ptr->src_nodes, -1); - counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); -} - -void -pf_unlink_src_node(struct pf_src_node *src) -{ - struct pf_srchash *sh; - - sh = &V_pf_srchash[pf_hashsrc(&src->addr, src->af)]; - PF_HASHROW_LOCK(sh); - pf_unlink_src_node_locked(src); - PF_HASHROW_UNLOCK(sh); -} - -static void -pf_free_src_node(struct pf_src_node *sn) -{ - - KASSERT(sn->states == 0, ("%s: %p has refs", __func__, sn)); - uma_zfree(V_pf_sources_z, sn); } u_int @@ -749,10 +729,12 @@ pf_free_src_nodes(struct pf_src_node_list *head) u_int count = 0; LIST_FOREACH_SAFE(sn, head, entry, tmp) { - pf_free_src_node(sn); + uma_zfree(V_pf_sources_z, sn); count++; } + counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], count); + return (count); } @@ -1542,7 +1524,7 @@ pf_purge_expired_src_nodes() PF_HASHROW_LOCK(sh); LIST_FOREACH_SAFE(cur, &sh->nodes, entry, next) if (cur->states == 0 && cur->expire <= time_uptime) { - pf_unlink_src_node_locked(cur); + pf_unlink_src_node(cur); LIST_INSERT_HEAD(&freelist, cur, entry); } else if (cur->rule.ptr != NULL) cur->rule.ptr->rule_flag |= PFRULE_REFS; @@ -1557,27 +1539,31 @@ pf_purge_expired_src_nodes() static void pf_src_tree_remove_state(struct pf_state *s) { - u_int32_t timeout; + struct pf_src_node *sn; + struct pf_srchash *sh; + uint32_t timeout; + + timeout = s->rule.ptr->timeout[PFTM_SRC_NODE] ? + s->rule.ptr->timeout[PFTM_SRC_NODE] : + V_pf_default_rule.timeout[PFTM_SRC_NODE]; if (s->src_node != NULL) { + sn = s->src_node; + sh = &V_pf_srchash[pf_hashsrc(&sn->addr, sn->af)]; + PF_HASHROW_LOCK(sh); if (s->src.tcp_est) - --s->src_node->conn; - if (--s->src_node->states == 0) { - timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; - if (!timeout) - timeout = - V_pf_default_rule.timeout[PFTM_SRC_NODE]; - s->src_node->expire = time_uptime + timeout; - } + --sn->conn; + if (--sn->states == 0) + sn->expire = time_uptime + timeout; + PF_HASHROW_UNLOCK(sh); } if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) { - if (--s->nat_src_node->states == 0) { - timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; - if (!timeout) - timeout = - V_pf_default_rule.timeout[PFTM_SRC_NODE]; - s->nat_src_node->expire = time_uptime + timeout; - } + sn = s->nat_src_node; + sh = &V_pf_srchash[pf_hashsrc(&sn->addr, sn->af)]; + PF_HASHROW_LOCK(sh); + if (--sn->states == 0) + sn->expire = time_uptime + timeout; + PF_HASHROW_UNLOCK(sh); } s->src_node = s->nat_src_node = NULL; } @@ -3563,15 +3549,12 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, s->creation = time_uptime; s->expire = time_uptime; - if (sn != NULL) { + if (sn != NULL) s->src_node = sn; - s->src_node->states++; - } if (nsn != NULL) { /* XXX We only modify one side for now. */ PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); s->nat_src_node = nsn; - s->nat_src_node->states++; } if (pd->proto == IPPROTO_TCP) { if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, @@ -3669,14 +3652,32 @@ csfailed: if (nk != NULL) uma_zfree(V_pf_state_key_z, nk); - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - pf_unlink_src_node(sn); - pf_free_src_node(sn); + if (sn != NULL) { + struct pf_srchash *sh; + + sh = &V_pf_srchash[pf_hashsrc(&sn->addr, sn->af)]; + PF_HASHROW_LOCK(sh); + if (--sn->states == 0 && sn->expire == 0) { + pf_unlink_src_node(sn); + uma_zfree(V_pf_sources_z, sn); + counter_u64_add( + V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); + } + PF_HASHROW_UNLOCK(sh); } - if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) { - pf_unlink_src_node(nsn); - pf_free_src_node(nsn); + if (nsn != sn && nsn != NULL) { + struct pf_srchash *sh; + + sh = &V_pf_srchash[pf_hashsrc(&nsn->addr, nsn->af)]; + PF_HASHROW_LOCK(sh); + if (--nsn->states == 1 && nsn->expire == 0) { + pf_unlink_src_node(nsn); + uma_zfree(V_pf_sources_z, nsn); + counter_u64_add( + V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); + } + PF_HASHROW_UNLOCK(sh); } return (PF_DROP); diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 213e49cb52f5..359d9de71eb0 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -3436,7 +3436,7 @@ pf_kill_srcnodes(struct pfioc_src_node_kill *psnk) &psnk->psnk_dst.addr.v.a.addr, &psnk->psnk_dst.addr.v.a.mask, &sn->raddr, sn->af)) { - pf_unlink_src_node_locked(sn); + pf_unlink_src_node(sn); LIST_INSERT_HEAD(&kill, sn, entry); sn->expire = 1; } @@ -3449,18 +3449,10 @@ pf_kill_srcnodes(struct pfioc_src_node_kill *psnk) PF_HASHROW_LOCK(ih); LIST_FOREACH(s, &ih->states, entry) { - if (s->src_node && s->src_node->expire == 1) { -#ifdef INVARIANTS - s->src_node->states--; -#endif + if (s->src_node && s->src_node->expire == 1) s->src_node = NULL; - } - if (s->nat_src_node && s->nat_src_node->expire == 1) { -#ifdef INVARIANTS - s->nat_src_node->states--; -#endif + if (s->nat_src_node && s->nat_src_node->expire == 1) s->nat_src_node = NULL; - } } PF_HASHROW_UNLOCK(ih); } |