summaryrefslogtreecommitdiffstats
path: root/sys/netpfil
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2014-01-22 10:29:15 +0000
committerglebius <glebius@FreeBSD.org>2014-01-22 10:29:15 +0000
commit99ea781723ac0ee95e527398c3fc265fded7e25f (patch)
tree3903a56caa0e3d24455db141ca273c2eeb8fad6c /sys/netpfil
parent5da449f113544b238255af43099c652d5600d9a4 (diff)
downloadFreeBSD-src-99ea781723ac0ee95e527398c3fc265fded7e25f.zip
FreeBSD-src-99ea781723ac0ee95e527398c3fc265fded7e25f.tar.gz
Merge r258478, r258479, r258480, r259719: fixes related to mass source
nodes removal. PR: 176763
Diffstat (limited to 'sys/netpfil')
-rw-r--r--sys/netpfil/pf/pf.c69
-rw-r--r--sys/netpfil/pf/pf_ioctl.c94
2 files changed, 109 insertions, 54 deletions
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 9ef7b5b..8dbed47 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -673,20 +673,53 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
return (0);
}
-static void
-pf_remove_src_node(struct pf_src_node *src)
+void
+pf_unlink_src_node_locked(struct pf_src_node *src)
{
+#ifdef INVARIANTS
struct pf_srchash *sh;
sh = &V_pf_srchash[pf_hashsrc(&src->addr, src->af)];
- PF_HASHROW_LOCK(sh);
+ PF_HASHROW_ASSERT(sh);
+#endif
LIST_REMOVE(src, entry);
- PF_HASHROW_UNLOCK(sh);
-
+ if (src->rule.ptr)
+ src->rule.ptr->src_nodes--;
V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
V_pf_status.src_nodes--;
+}
- uma_zfree(V_pf_sources_z, src);
+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
+pf_free_src_nodes(struct pf_src_node_list *head)
+{
+ struct pf_src_node *sn, *tmp;
+ u_int count = 0;
+
+ LIST_FOREACH_SAFE(sn, head, entry, tmp) {
+ pf_free_src_node(sn);
+ count++;
+ }
+
+ return (count);
}
/* Data storage structures initialization. */
@@ -1456,24 +1489,24 @@ pf_state_expires(const struct pf_state *state)
void
pf_purge_expired_src_nodes()
{
+ struct pf_src_node_list freelist;
struct pf_srchash *sh;
struct pf_src_node *cur, *next;
int i;
+ LIST_INIT(&freelist);
for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask; i++, sh++) {
PF_HASHROW_LOCK(sh);
LIST_FOREACH_SAFE(cur, &sh->nodes, entry, next)
if (cur->states == 0 && cur->expire <= time_uptime) {
- if (cur->rule.ptr != NULL)
- cur->rule.ptr->src_nodes--;
- LIST_REMOVE(cur, entry);
- V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- V_pf_status.src_nodes--;
- uma_zfree(V_pf_sources_z, cur);
+ pf_unlink_src_node_locked(cur);
+ LIST_INSERT_HEAD(&freelist, cur, entry);
} else if (cur->rule.ptr != NULL)
cur->rule.ptr->rule_flag |= PFRULE_REFS;
PF_HASHROW_UNLOCK(sh);
}
+
+ pf_free_src_nodes(&freelist);
}
static void
@@ -3609,11 +3642,15 @@ csfailed:
if (nk != NULL)
uma_zfree(V_pf_state_key_z, nk);
- if (sn != NULL && sn->states == 0 && sn->expire == 0)
- pf_remove_src_node(sn);
+ if (sn != NULL && sn->states == 0 && sn->expire == 0) {
+ pf_unlink_src_node(sn);
+ pf_free_src_node(sn);
+ }
- if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0)
- pf_remove_src_node(nsn);
+ if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) {
+ pf_unlink_src_node(nsn);
+ pf_free_src_node(nsn);
+ }
return (PF_DROP);
}
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 3819fed..c4506a6d 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -151,6 +151,7 @@ struct cdev *pf_dev;
static void pf_clear_states(void);
static int pf_clear_tables(void);
static void pf_clear_srcnodes(struct pf_src_node *);
+static void pf_kill_srcnodes(struct pfioc_src_node_kill *);
static void pf_tbladdr_copyout(struct pf_addr_wrap *);
/*
@@ -3139,45 +3140,9 @@ DIOCCHANGEADDR_error:
break;
}
- case DIOCKILLSRCNODES: {
- struct pfioc_src_node_kill *psnk =
- (struct pfioc_src_node_kill *)addr;
- struct pf_srchash *sh;
- struct pf_src_node *sn;
- u_int i, killed = 0;
-
- for (i = 0, sh = V_pf_srchash; i < V_pf_srchashmask;
- i++, sh++) {
- /*
- * XXXGL: we don't ever acquire sources hash lock
- * but if we ever do, the below call to pf_clear_srcnodes()
- * would lead to a LOR.
- */
- PF_HASHROW_LOCK(sh);
- LIST_FOREACH(sn, &sh->nodes, entry)
- if (PF_MATCHA(psnk->psnk_src.neg,
- &psnk->psnk_src.addr.v.a.addr,
- &psnk->psnk_src.addr.v.a.mask,
- &sn->addr, sn->af) &&
- PF_MATCHA(psnk->psnk_dst.neg,
- &psnk->psnk_dst.addr.v.a.addr,
- &psnk->psnk_dst.addr.v.a.mask,
- &sn->raddr, sn->af)) {
- /* Handle state to src_node linkage */
- if (sn->states != 0)
- pf_clear_srcnodes(sn);
- sn->expire = 1;
- killed++;
- }
- PF_HASHROW_UNLOCK(sh);
- }
-
- if (killed > 0)
- pf_purge_expired_src_nodes();
-
- psnk->psnk_killed = killed;
+ case DIOCKILLSRCNODES:
+ pf_kill_srcnodes((struct pfioc_src_node_kill *)addr);
break;
- }
case DIOCSETHOSTID: {
u_int32_t *hostid = (u_int32_t *)addr;
@@ -3396,6 +3361,59 @@ pf_clear_srcnodes(struct pf_src_node *n)
n->states = 0;
}
}
+
+static void
+pf_kill_srcnodes(struct pfioc_src_node_kill *psnk)
+{
+ struct pf_src_node_list kill;
+
+ LIST_INIT(&kill);
+ for (int i = 0; i <= V_pf_srchashmask; i++) {
+ struct pf_srchash *sh = &V_pf_srchash[i];
+ struct pf_src_node *sn, *tmp;
+
+ PF_HASHROW_LOCK(sh);
+ LIST_FOREACH_SAFE(sn, &sh->nodes, entry, tmp)
+ if (PF_MATCHA(psnk->psnk_src.neg,
+ &psnk->psnk_src.addr.v.a.addr,
+ &psnk->psnk_src.addr.v.a.mask,
+ &sn->addr, sn->af) &&
+ PF_MATCHA(psnk->psnk_dst.neg,
+ &psnk->psnk_dst.addr.v.a.addr,
+ &psnk->psnk_dst.addr.v.a.mask,
+ &sn->raddr, sn->af)) {
+ pf_unlink_src_node_locked(sn);
+ LIST_INSERT_HEAD(&kill, sn, entry);
+ sn->expire = 1;
+ }
+ PF_HASHROW_UNLOCK(sh);
+ }
+
+ for (int i = 0; i <= V_pf_hashmask; i++) {
+ struct pf_idhash *ih = &V_pf_idhash[i];
+ struct pf_state *s;
+
+ 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
+ s->src_node = NULL;
+ }
+ if (s->nat_src_node && s->nat_src_node->expire == 1) {
+#ifdef INVARIANTS
+ s->nat_src_node->states--;
+#endif
+ s->nat_src_node = NULL;
+ }
+ }
+ PF_HASHROW_UNLOCK(ih);
+ }
+
+ psnk->psnk_killed = pf_free_src_nodes(&kill);
+}
+
/*
* XXX - Check for version missmatch!!!
*/
OpenPOWER on IntegriCloud