Date: Fri, 22 Nov 2013 19:22:26 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r258480 - head/sys/netpfil/pf Message-ID: <201311221922.rAMJMQHR016434@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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!!! */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201311221922.rAMJMQHR016434>