svn commit: r258480 - head/sys/netpfil/pf
Gleb Smirnoff
glebius at FreeBSD.org
Fri Nov 22 19:22:26 UTC 2013
Author: glebius
Date: Fri Nov 22 19:22:26 2013
New Revision: 258480
URL: http://svnweb.freebsd.org/changeset/base/258480
Log:
The DIOCKILLSRCNODES operation was implemented with O(m*n) complexity,
where "m" is number of source nodes and "n" is number of states. Thus,
on heavy loaded router its processing consumed a lot of CPU time.
Reimplement it with O(m+n) complexity. We first scan through source
nodes and disconnect matching ones, putting them on the freelist and
marking with a cookie value in their expire field. Then we scan through
the states, detecting references to source nodes with a cookie, and
disconnect them as well. Then the freelist is passed to pf_free_src_nodes().
In collaboration with: Kajetan Staszkiewicz <kajetan.staszkiewicz innogames.de>
PR: kern/176763
Sponsored by: InnoGames GmbH
Sponsored by: Nginx, Inc.
Modified:
head/sys/netpfil/pf/pf_ioctl.c
Modified: head/sys/netpfil/pf/pf_ioctl.c
==============================================================================
--- head/sys/netpfil/pf/pf_ioctl.c Fri Nov 22 19:16:34 2013 (r258479)
+++ head/sys/netpfil/pf/pf_ioctl.c Fri Nov 22 19:22:26 2013 (r258480)
@@ -155,6 +155,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 *);
/*
@@ -3143,45 +3144,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;
@@ -3400,6 +3365,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!!!
*/
More information about the svn-src-head
mailing list