Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net/npf NPF: fix the reference counting and share the ac...



details:   https://anonhg.NetBSD.org/src/rev/f39b67ee757c
branches:  trunk
changeset: 334022:f39b67ee757c
user:      rmind <rmind%NetBSD.org@localhost>
date:      Wed Nov 26 21:25:35 2014 +0000

description:
NPF: fix the reference counting and share the active NAT portmap correctly
when performing the reload.  Should fixes PR/49412, reported by kardel@.

diffstat:

 sys/net/npf/npf_nat.c     |  23 ++++++++++++--------
 sys/net/npf/npf_ruleset.c |  51 +++++++++++++++++++---------------------------
 2 files changed, 35 insertions(+), 39 deletions(-)

diffs (151 lines):

diff -r c761e9f30916 -r f39b67ee757c sys/net/npf/npf_nat.c
--- a/sys/net/npf/npf_nat.c     Wed Nov 26 20:46:46 2014 +0000
+++ b/sys/net/npf/npf_nat.c     Wed Nov 26 21:25:35 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: npf_nat.c,v 1.34 2014/08/24 20:36:30 rmind Exp $       */
+/*     $NetBSD: npf_nat.c,v 1.35 2014/11/26 21:25:35 rmind Exp $       */
 
 /*-
  * Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org>
@@ -71,7 +71,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.34 2014/08/24 20:36:30 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.35 2014/11/26 21:25:35 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -313,9 +313,10 @@
                kpause("npfgcnat", false, 1, NULL);
        }
        KASSERT(LIST_EMPTY(&np->n_nat_list));
+       KASSERT(pm == NULL || pm->p_refcnt > 0);
 
        /* Destroy the port map, on last reference. */
-       if (pm && --pm->p_refcnt == 0) {
+       if (pm && atomic_dec_uint_nv(&pm->p_refcnt) == 0) {
                KASSERT((np->n_flags & NPF_NAT_PORTMAP) != 0);
                kmem_free(pm, PORTMAP_MEM_SIZE);
        }
@@ -373,17 +374,21 @@
        if (memcmp(&np->n_taddr, &mnp->n_taddr, np->n_alen) != 0) {
                return false;
        }
-       /* If NAT policy has an old port map - drop the reference. */
        mpm = mnp->n_portmap;
-       if (mpm) {
-               /* Note: at this point we cannot hold a last reference. */
-               KASSERT(mpm->p_refcnt > 1);
-               mpm->p_refcnt--;
+       KASSERT(mpm == NULL || mpm->p_refcnt > 0);
+
+       /*
+        * If NAT policy has an old port map - drop the reference
+        * and destroy the port map if it was the last.
+        */
+       if (mpm && atomic_dec_uint_nv(&mpm->p_refcnt) == 0) {
+               kmem_free(mpm, PORTMAP_MEM_SIZE);
        }
+
        /* Share the port map. */
        pm = np->n_portmap;
+       atomic_inc_uint(&pm->p_refcnt);
        mnp->n_portmap = pm;
-       pm->p_refcnt++;
        return true;
 }
 
diff -r c761e9f30916 -r f39b67ee757c sys/net/npf/npf_ruleset.c
--- a/sys/net/npf/npf_ruleset.c Wed Nov 26 20:46:46 2014 +0000
+++ b/sys/net/npf/npf_ruleset.c Wed Nov 26 21:25:35 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: npf_ruleset.c,v 1.37 2014/08/11 01:54:12 rmind Exp $   */
+/*     $NetBSD: npf_ruleset.c,v 1.38 2014/11/26 21:25:35 rmind Exp $   */
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.37 2014/08/11 01:54:12 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.38 2014/11/26 21:25:35 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -421,22 +421,6 @@
 }
 
 /*
- * npf_ruleset_cmpnat: find a matching NAT policy in the ruleset.
- */
-static inline npf_rule_t *
-npf_ruleset_cmpnat(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
-{
-       npf_rule_t *rl;
-
-       /* Find a matching NAT policy in the old ruleset. */
-       LIST_FOREACH(rl, &rlset->rs_all, r_aentry) {
-               if (rl->r_natp && npf_nat_cmppolicy(rl->r_natp, mnp))
-                       break;
-       }
-       return rl;
-}
-
-/*
  * npf_ruleset_reload: prepare the new ruleset by scanning the active
  * ruleset and 1) sharing the dynamic rules 2) sharing NAT policies.
  *
@@ -492,18 +476,30 @@
                        continue;
                }
 
+               /*
+                * First, try to share the active port map.  If this
+                * policy will be unused, npf_nat_freepolicy() will
+                * drop the reference.
+                */
+               npf_ruleset_sharepm(oldset, np);
+
                /* Does it match with any policy in the active ruleset? */
-               if ((actrl = npf_ruleset_cmpnat(oldset, np)) == NULL) {
+               LIST_FOREACH(actrl, &oldset->rs_all, r_aentry) {
+                       if (!actrl->r_natp)
+                               continue;
+                       if ((actrl->r_attr & NPF_RULE_KEEPNAT) != 0)
+                               continue;
+                       if (npf_nat_cmppolicy(actrl->r_natp, np))
+                               break;
+               }
+               if (!actrl) {
+                       /* No: just set the ID and continue. */
                        npf_nat_setid(np, ++nid);
                        continue;
                }
 
-               /*
-                * Inherit the matching NAT policy and check other ones
-                * in the new ruleset for sharing the portmap.
-                */
+               /* Yes: inherit the matching NAT policy. */
                rl->r_natp = actrl->r_natp;
-               npf_ruleset_sharepm(newset, rl->r_natp);
                npf_nat_setid(rl->r_natp, ++nid);
 
                /*
@@ -525,13 +521,8 @@
        npf_natpolicy_t *np;
        npf_rule_t *rl;
 
-       /* Find a matching NAT policy in the old ruleset. */
+       /* Find a matching NAT policy in the old ruleset; skip the self. */
        LIST_FOREACH(rl, &rlset->rs_all, r_aentry) {
-               /*
-                * NAT policy might not yet be set during the creation of
-                * the ruleset (in such case, rule is for our policy), or
-                * policies might be equal due to rule exchange on reload.
-                */
                np = rl->r_natp;
                if (np == NULL || np == mnp)
                        continue;



Home | Main Index | Thread Index | Old Index