radix: Fix the non-per-cpu radix tree usage.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 1 Feb 2011 08:09:26 +0000 (16:09 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 1 Feb 2011 08:09:26 +0000 (16:09 +0800)
- Install a mask radix tree in each radix tree, while, mask radix tree does
  not have mask radix tree (of course).
- rn_cpumaskhead() is added to provide the global per-cpu mask radix tree.
- rn_inithead() requires a mask radix tree as paramter.  Mask radix tree is
  initialized by passing NULL.  INET/INET6/ATALK pass the mask radix tree
  obtained from rn_cpumaskhead(), i.e. the old sementics.
- pf(4) now creates its own mask radix tree, and all of its internal radix
  trees will use that mask radix tree instead of the global per-cpu mask
  radix tree.  pf(4) radix tree operations are protected by its own token.
- rn_addmask() requires a mask radix tree, instead of using the global
  per-cpu mask radix tree.  For most cases, the caller has access to the
  radix tree that has a mask radix tree installed.  For _rtmask_lookup(),
  which is always called from route_output(), we could safely assume that
  global per-cpu mask radix tree is used.

This is mainly used to fix the following bug concerning global per-cpu
mask radix tree:
Before this commit, pf(4) could create mask on CPU0's mask radix tree,
while the deletion of the mask happens on other CPUs, which results pf(4)'s
radix tree operation to fail (can't locate the mask).

Dragonfly-bug: http://bugs.dragonflybsd.org/issue1969
Root-cause-found-by: Jan Lentfer <Jan.Lentfer@web.de>
sys/net/pf/pf.c
sys/net/pf/pf_ioctl.c
sys/net/pf/pf_table.c
sys/net/pf/pfvar.h
sys/net/radix.c
sys/net/radix.h
sys/net/route.c
sys/netinet/in_rmx.c
sys/netinet6/in6_rmx.c
sys/netproto/atalk/at_rmx.c

index f5fc240..086f7a3 100644 (file)
@@ -112,6 +112,9 @@ struct lwkt_token pf_token = LWKT_TOKEN_INITIALIZER(pf_token);
  * Global variables
  */
 
+/* mask radix tree */
+struct radix_node_head *pf_maskhead;
+
 /* state tables */
 struct pf_state_tree    pf_statetbl;
 
index b5236ac..575da54 100644 (file)
@@ -230,6 +230,11 @@ pfattach(void)
        u_int32_t *my_timeout = pf_default_rule.timeout;
        int error = 1;
 
+       if (!rn_inithead((void **)&pf_maskhead, NULL, 0)) {
+               kprintf("pf mask radix tree create failed\n");
+               return ENOMEM;
+       }
+
        do {
                ZONE_CREATE(pf_src_tree_pl,struct pf_src_node, "pfsrctrpl");
                ZONE_CREATE(pf_rule_pl,    struct pf_rule, "pfrulepl");
@@ -3263,6 +3268,16 @@ pf_load(void)
        return (0);
 }
 
+static int
+pf_mask_del(struct radix_node *rn, void *arg)
+{
+       struct radix_node_head *rnh = rnh;
+
+       rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
+       Free(rn);
+       return 0;
+}
+
 static int
 pf_unload(void)
 {
@@ -3297,6 +3312,12 @@ pf_unload(void)
        lockuninit(&pf_consistency_lock);
        lockuninit(&pf_mod_lck);
        lwkt_reltoken(&pf_token);
+
+       if (pf_maskhead != NULL) {
+               pf_maskhead->rnh_walktree(pf_maskhead,
+                       pf_mask_del, pf_maskhead);
+               Free(pf_maskhead);
+       }
        return 0;
 }
 
index 368bb9f..82eb679 100644 (file)
@@ -1909,9 +1909,10 @@ pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset)
                rs->tables++;
        }
 
-       if (!rn_inithead((void **)&kt->pfrkt_ip4,
+       KKASSERT(pf_maskhead != NULL);
+       if (!rn_inithead((void **)&kt->pfrkt_ip4, pf_maskhead,
            offsetof(struct sockaddr_in, sin_addr) * 8) ||
-           !rn_inithead((void **)&kt->pfrkt_ip6,
+           !rn_inithead((void **)&kt->pfrkt_ip6, pf_maskhead,
            offsetof(struct sockaddr_in6, sin6_addr) * 8)) {
                pfr_destroy_ktable(kt, 0);
                return (NULL);
index 0c78eed..fa1c51a 100644 (file)
@@ -1969,6 +1969,7 @@ struct pf_fragment {
 
 #endif /* _KERNEL */
 
+extern struct radix_node_head  *pf_maskhead;
 extern struct pf_anchor_global  pf_anchors;
 extern struct pf_anchor        pf_main_anchor;
 #define pf_main_ruleset        pf_main_anchor.ruleset
index 5fa3ae8..732a84c 100644 (file)
@@ -198,7 +198,8 @@ rn_lookup(char *key, char *mask, struct radix_node_head *head)
        char *netmask = NULL;
 
        if (mask != NULL) {
-               x = rn_addmask(mask, TRUE, head->rnh_treetop->rn_offset);
+               x = rn_addmask(mask, TRUE, head->rnh_treetop->rn_offset,
+                              head->rnh_maskhead);
                if (x == NULL)
                        return (NULL);
                netmask = x->rn_key;
@@ -429,7 +430,8 @@ on1:
 }
 
 struct radix_node *
-rn_addmask(char *netmask, boolean_t search, int skip)
+rn_addmask(char *netmask, boolean_t search, int skip,
+          struct radix_node_head *mask_rnh)
 {
        struct radix_node *x, *saved_x;
        char *cp, *cplim;
@@ -437,7 +439,6 @@ rn_addmask(char *netmask, boolean_t search, int skip)
        boolean_t maskduplicated, isnormal;
        static int last_zeroed = 0;
        char *addmask_key;
-       struct radix_node_head *mask_rnh = mask_rnheads[mycpuid];
 
        if ((mlen = clen(netmask)) > max_keylen)
                mlen = max_keylen;
@@ -566,7 +567,8 @@ rn_addroute(char *key, char *netmask, struct radix_node_head *head,
         * nodes and possibly save time in calculating indices.
         */
        if (netmask != NULL)  {
-               if ((x = rn_addmask(netmask, FALSE, top->rn_offset)) == NULL)
+               if ((x = rn_addmask(netmask, FALSE, top->rn_offset,
+                                   head->rnh_maskhead)) == NULL)
                        return (NULL);
                b_leaf = x->rn_bit;
                b = -1 - x->rn_bit;
@@ -725,7 +727,8 @@ rn_delete(char *key, char *netmask, struct radix_node_head *head)
         * Delete our route from mask lists.
         */
        if (netmask != NULL) {
-               if ((x = rn_addmask(netmask, TRUE, head_off)) == NULL)
+               if ((x = rn_addmask(netmask, TRUE, head_off,
+                                   head->rnh_maskhead)) == NULL)
                        return (NULL);
                netmask = x->rn_key;
                while (tt->rn_mask != netmask)
@@ -1014,7 +1017,7 @@ rn_walktree(struct radix_node_head *h, walktree_f_t *f, void *w)
 }
 
 int
-rn_inithead(void **head, int off)
+rn_inithead(void **head, struct radix_node_head *maskhead, int off)
 {
        struct radix_node_head *rnh;
        struct radix_node *root, *left, *right;
@@ -1042,6 +1045,7 @@ rn_inithead(void **head, int off)
        right->rn_key = rn_ones;
 
        rnh->rnh_treetop = root;
+       rnh->rnh_maskhead = maskhead;
 
        rnh->rnh_addaddr = rn_addroute;
        rnh->rnh_deladdr = rn_delete;
@@ -1080,7 +1084,14 @@ rn_init(void)
                *cp++ = -1;
 
        for (cpu = 0; cpu < ncpus; ++cpu) {
-               if (rn_inithead((void **)&mask_rnheads[cpu], 0) == 0)
+               if (rn_inithead((void **)&mask_rnheads[cpu], NULL, 0) == 0)
                        panic("rn_init 2");
        }
 }
+
+struct radix_node_head *
+rn_cpumaskhead(int cpu)
+{
+       KKASSERT(mask_rnheads[cpu] != NULL);
+       return mask_rnheads[cpu];
+}
index 4346799..3185c09 100644 (file)
@@ -158,6 +158,8 @@ struct radix_node_head {
                    (void *v, char *mask, struct radix_node_head *head);
        struct  radix_node *(*rnh_matchpkt)     /* locate based on packet hdr */
                    (void *v, struct radix_node_head *head);
+
+       struct radix_node_head *rnh_maskhead;
 };
 
 #ifndef _KERNEL
@@ -169,9 +171,11 @@ struct radix_node_head {
 #endif
 
 void                    rn_init (void);
-int                     rn_inithead (void **, int);
+int                     rn_inithead (void **, struct radix_node_head *, int);
+struct radix_node_head *rn_cpumaskhead(int cpu);
 __boolean_t             rn_refines (char *, char *);
-struct radix_node      *rn_addmask (char *, __boolean_t, int),
+struct radix_node      *rn_addmask (char *, __boolean_t, int,
+                                    struct radix_node_head *),
                        *rn_addroute (char *, char *, struct radix_node_head *,
                                      struct radix_node [2]),
                        *rn_delete (char *, char *, struct radix_node_head *),
index 75cb594..7c88f18 100644 (file)
@@ -1788,7 +1788,7 @@ _rtmask_lookup(struct sockaddr *mask, boolean_t search)
        struct radix_node *n;
 
 #define        clen(s) (*(u_char *)(s))
-       n = rn_addmask((char *)mask, search, 1);
+       n = rn_addmask((char *)mask, search, 1, rn_cpumaskhead(mycpuid));
        if (n != NULL &&
            mask->sa_len >= clen(n->rn_key) &&
            bcmp((char *)mask + 1,
index 9fb755c..f80d96f 100644 (file)
@@ -346,7 +346,7 @@ in_inithead(void **head, int off)
 {
        struct radix_node_head *rnh;
 
-       if (!rn_inithead(head, off))
+       if (!rn_inithead(head, rn_cpumaskhead(mycpuid), off))
                return 0;
 
        if (head != (void **)&rt_tables[mycpuid][AF_INET]) /* BOGUS! */
index eadb21c..613b5e9 100644 (file)
@@ -466,7 +466,7 @@ in6_inithead(void **head, int off)
 {
        struct radix_node_head *rnh;
 
-       if (!rn_inithead(head, off))
+       if (!rn_inithead(head, rn_cpumaskhead(mycpuid), off))
                return 0;
 
        if (head != (void **)&rt_tables[mycpuid][AF_INET6]) /* BOGUS! */
index 637d501..81041d1 100644 (file)
@@ -140,7 +140,7 @@ at_inithead(void **head, int off)
 {
        struct radix_node_head *rnh;
 
-       if(!rn_inithead(head, off))
+       if(!rn_inithead(head, rn_cpumaskhead(mycpuid), off))
                return 0;
 
        rnh = *head;