]> err.no Git - linux-2.6/blobdiff - net/ipv4/fib_trie.c
[FIB]: Avoid using static variables without proper locking
[linux-2.6] / net / ipv4 / fib_trie.c
index 9ca786a6fd3c8a7546b86e00dc81ae1de6fd45c0..72c78c2209d55acde507b44541aeaf2c371f66c5 100644 (file)
@@ -54,7 +54,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -73,6 +73,7 @@
 #include <linux/netlink.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <net/net_namespace.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/route.h>
 #include <net/ip_fib.h>
 #include "fib_lookup.h"
 
-#undef CONFIG_IP_FIB_TRIE_STATS
 #define MAX_STAT_DEPTH 32
 
 #define KEYLENGTH (8*sizeof(t_key))
-#define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l))
-#define TKEY_GET_MASK(offset, bits) (((bits)==0)?0:((t_key)(-1) << (KEYLENGTH - bits) >> offset))
 
 typedef unsigned int t_key;
 
 #define T_TNODE 0
 #define T_LEAF  1
 #define NODE_TYPE_MASK 0x1UL
-#define NODE_PARENT(node) \
-       ((struct tnode *)rcu_dereference(((node)->parent & ~NODE_TYPE_MASK)))
-
 #define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK)
 
-#define NODE_SET_PARENT(node, ptr)             \
-       rcu_assign_pointer((node)->parent,      \
-                          ((unsigned long)(ptr)) | NODE_TYPE(node))
-
 #define IS_TNODE(n) (!(n->parent & T_LEAF))
 #define IS_LEAF(n) (n->parent & T_LEAF)
 
 struct node {
-       t_key key;
        unsigned long parent;
+       t_key key;
 };
 
 struct leaf {
-       t_key key;
        unsigned long parent;
+       t_key key;
        struct hlist_head list;
        struct rcu_head rcu;
 };
@@ -125,12 +116,12 @@ struct leaf_info {
 };
 
 struct tnode {
-       t_key key;
        unsigned long parent;
-       unsigned short pos:5;           /* 2log(KEYLENGTH) bits needed */
-       unsigned short bits:5;          /* 2log(KEYLENGTH) bits needed */
-       unsigned short full_children;   /* KEYLENGTH bits needed */
-       unsigned short empty_children;  /* KEYLENGTH bits needed */
+       t_key key;
+       unsigned char pos;              /* 2log(KEYLENGTH) bits needed */
+       unsigned char bits;             /* 2log(KEYLENGTH) bits needed */
+       unsigned int full_children;     /* KEYLENGTH bits needed */
+       unsigned int empty_children;    /* KEYLENGTH bits needed */
        struct rcu_head rcu;
        struct node *child[0];
 };
@@ -161,7 +152,6 @@ struct trie {
        struct trie_use_stats stats;
 #endif
        int size;
-       unsigned int revision;
 };
 
 static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
@@ -172,8 +162,20 @@ static struct tnode *halve(struct trie *t, struct tnode *tn);
 static void tnode_free(struct tnode *tn);
 
 static struct kmem_cache *fn_alias_kmem __read_mostly;
-static struct trie *trie_local = NULL, *trie_main = NULL;
 
+static inline struct tnode *node_parent(struct node *node)
+{
+       struct tnode *ret;
+
+       ret = (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
+       return rcu_dereference(ret);
+}
+
+static inline void node_set_parent(struct node *node, struct tnode *ptr)
+{
+       rcu_assign_pointer(node->parent,
+                          (unsigned long)ptr | NODE_TYPE(node));
+}
 
 /* rcu_read_lock needs to be hold by caller from readside */
 
@@ -189,6 +191,11 @@ static inline int tnode_child_length(const struct tnode *tn)
        return 1 << tn->bits;
 }
 
+static inline t_key mask_pfx(t_key k, unsigned short l)
+{
+       return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l);
+}
+
 static inline t_key tkey_extract_bits(t_key a, int offset, int bits)
 {
        if (offset < KEYLENGTH)
@@ -290,10 +297,10 @@ static inline void check_tnode(const struct tnode *tn)
        WARN_ON(tn && tn->pos+tn->bits > 32);
 }
 
-static int halve_threshold = 25;
-static int inflate_threshold = 50;
-static int halve_threshold_root = 8;
-static int inflate_threshold_root = 15;
+static const int halve_threshold = 25;
+static const int inflate_threshold = 50;
+static const int halve_threshold_root = 8;
+static const int inflate_threshold_root = 15;
 
 
 static void __alias_free_mem(struct rcu_head *head)
@@ -322,12 +329,12 @@ static inline void free_leaf_info(struct leaf_info *leaf)
        call_rcu(&leaf->rcu, __leaf_info_free_rcu);
 }
 
-static struct tnode *tnode_alloc(unsigned int size)
+static struct tnode *tnode_alloc(size_t size)
 {
        struct page *pages;
 
        if (size <= PAGE_SIZE)
-               return kcalloc(size, 1, GFP_KERNEL);
+               return kzalloc(size, GFP_KERNEL);
 
        pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size));
        if (!pages)
@@ -339,8 +346,8 @@ static struct tnode *tnode_alloc(unsigned int size)
 static void __tnode_free_rcu(struct rcu_head *head)
 {
        struct tnode *tn = container_of(head, struct tnode, rcu);
-       unsigned int size = sizeof(struct tnode) +
-               (1 << tn->bits) * sizeof(struct node *);
+       size_t size = sizeof(struct tnode) +
+                     (sizeof(struct node *) << tn->bits);
 
        if (size <= PAGE_SIZE)
                kfree(tn);
@@ -379,12 +386,10 @@ static struct leaf_info *leaf_info_new(int plen)
 
 static struct tnode* tnode_new(t_key key, int pos, int bits)
 {
-       int nchildren = 1<<bits;
-       int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
+       size_t sz = sizeof(struct tnode) + (sizeof(struct node *) << bits);
        struct tnode *tn = tnode_alloc(sz);
 
        if (tn) {
-               memset(tn, 0, sz);
                tn->parent = T_TNODE;
                tn->pos = pos;
                tn->bits = bits;
@@ -393,8 +398,8 @@ static struct tnode* tnode_new(t_key key, int pos, int bits)
                tn->empty_children = 1<<bits;
        }
 
-       pr_debug("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode),
-                (unsigned int) (sizeof(struct node) * 1<<bits));
+       pr_debug("AT %p s=%u %lu\n", tn, (unsigned int) sizeof(struct tnode),
+                (unsigned long) (sizeof(struct node) << bits));
        return tn;
 }
 
@@ -446,7 +451,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int w
                tn->full_children++;
 
        if (n)
-               NODE_SET_PARENT(n, tn);
+               node_set_parent(n, tn);
 
        rcu_assign_pointer(tn->child[i], n);
 }
@@ -481,7 +486,7 @@ static struct node *resize(struct trie *t, struct tnode *tn)
                                continue;
 
                        /* compress one level */
-                       NODE_SET_PARENT(n, NULL);
+                       node_set_parent(n, NULL);
                        tnode_free(tn);
                        return n;
                }
@@ -636,7 +641,7 @@ static struct node *resize(struct trie *t, struct tnode *tn)
 
                        /* compress one level */
 
-                       NODE_SET_PARENT(n, NULL);
+                       node_set_parent(n, NULL);
                        tnode_free(tn);
                        return n;
                }
@@ -646,7 +651,6 @@ static struct node *resize(struct trie *t, struct tnode *tn)
 
 static struct tnode *inflate(struct trie *t, struct tnode *tn)
 {
-       struct tnode *inode;
        struct tnode *oldtnode = tn;
        int olen = tnode_child_length(tn);
        int i;
@@ -673,7 +677,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
                    inode->pos == oldtnode->pos + oldtnode->bits &&
                    inode->bits > 1) {
                        struct tnode *left, *right;
-                       t_key m = TKEY_GET_MASK(inode->pos, 1);
+                       t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos;
 
                        left = tnode_new(inode->key&(~m), inode->pos + 1,
                                         inode->bits - 1);
@@ -694,6 +698,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
        }
 
        for (i = 0; i < olen; i++) {
+               struct tnode *inode;
                struct node *node = tnode_get_child(oldtnode, i);
                struct tnode *left, *right;
                int size, j;
@@ -867,19 +872,6 @@ nomem:
        }
 }
 
-static void trie_init(struct trie *t)
-{
-       if (!t)
-               return;
-
-       t->size = 0;
-       rcu_assign_pointer(t->trie, NULL);
-       t->revision = 0;
-#ifdef CONFIG_IP_FIB_TRIE_STATS
-       memset(&t->stats, 0, sizeof(struct trie_use_stats));
-#endif
-}
-
 /* readside must use rcu_read_lock currently dump routines
  via get_fa_head and dump */
 
@@ -961,24 +953,21 @@ fib_find_node(struct trie *t, u32 key)
 static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
 {
        int wasfull;
-       t_key cindex, key;
-       struct tnode *tp = NULL;
-
-       key = tn->key;
-
-       while (tn != NULL && NODE_PARENT(tn) != NULL) {
+       t_key cindex, key = tn->key;
+       struct tnode *tp;
 
-               tp = NODE_PARENT(tn);
+       while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) {
                cindex = tkey_extract_bits(key, tp->pos, tp->bits);
                wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
                tn = (struct tnode *) resize (t, (struct tnode *)tn);
                tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);
 
-               if (!NODE_PARENT(tn))
+               tp = node_parent((struct node *) tn);
+               if (!tp)
                        break;
-
-               tn = NODE_PARENT(tn);
+               tn = tp;
        }
+
        /* Handle last (top) tnode */
        if (IS_TNODE(tn))
                tn = (struct tnode*) resize(t, (struct tnode *)tn);
@@ -988,8 +977,7 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
 
 /* only used from updater-side */
 
-static  struct list_head *
-fib_insert_node(struct trie *t, int *err, u32 key, int plen)
+static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 {
        int pos, newpos;
        struct tnode *tp = NULL, *tn = NULL;
@@ -1031,7 +1019,7 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
                        pos = tn->pos + tn->bits;
                        n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
 
-                       BUG_ON(n && NODE_PARENT(n) != tn);
+                       BUG_ON(n && node_parent(n) != tn);
                } else
                        break;
        }
@@ -1047,14 +1035,11 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
        /* Case 1: n is a leaf. Compare prefixes */
 
        if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
-               struct leaf *l = (struct leaf *) n;
-
+               l = (struct leaf *) n;
                li = leaf_info_new(plen);
 
-               if (!li) {
-                       *err = -ENOMEM;
-                       goto err;
-               }
+               if (!li)
+                       return NULL;
 
                fa_head = &li->falh;
                insert_leaf_info(&l->list, li);
@@ -1063,18 +1048,15 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
        t->size++;
        l = leaf_new();
 
-       if (!l) {
-               *err = -ENOMEM;
-               goto err;
-       }
+       if (!l)
+               return NULL;
 
        l->key = key;
        li = leaf_info_new(plen);
 
        if (!li) {
                tnode_free((struct tnode *) l);
-               *err = -ENOMEM;
-               goto err;
+               return NULL;
        }
 
        fa_head = &li->falh;
@@ -1083,7 +1065,7 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
        if (t->trie && n == NULL) {
                /* Case 2: n is NULL, and will just insert a new leaf */
 
-               NODE_SET_PARENT(l, tp);
+               node_set_parent((struct node *)l, tp);
 
                cindex = tkey_extract_bits(key, tp->pos, tp->bits);
                put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
@@ -1110,11 +1092,10 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
                if (!tn) {
                        free_leaf_info(li);
                        tnode_free((struct tnode *) l);
-                       *err = -ENOMEM;
-                       goto err;
+                       return NULL;
                }
 
-               NODE_SET_PARENT(tn, tp);
+               node_set_parent((struct node *)tn, tp);
 
                missbit = tkey_extract_bits(key, newpos, 1);
                put_child(t, tn, missbit, (struct node *)l);
@@ -1137,8 +1118,6 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
 
        rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
 done:
-       t->revision++;
-err:
        return fa_head;
 }
 
@@ -1207,6 +1186,9 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
                        struct fib_info *fi_drop;
                        u8 state;
 
+                       if (fi->fib_treeref > 1)
+                               goto out;
+
                        err = -ENOBUFS;
                        new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
                        if (new_fa == NULL)
@@ -1269,10 +1251,11 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
         */
 
        if (!fa_head) {
-               err = 0;
-               fa_head = fib_insert_node(t, &err, key, plen);
-               if (err)
+               fa_head = fib_insert_node(t, key, plen);
+               if (unlikely(!fa_head)) {
+                       err = -ENOMEM;
                        goto out_free_new_fa;
+               }
        }
 
        list_add_tail_rcu(&new_fa->fa_list,
@@ -1364,7 +1347,8 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
                bits = pn->bits;
 
                if (!chopped_off)
-                       cindex = tkey_extract_bits(MASK_PFX(key, current_prefix_length), pos, bits);
+                       cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
+                                                  pos, bits);
 
                n = tnode_get_child(pn, cindex);
 
@@ -1450,8 +1434,8 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
                 * to find a matching prefix.
                 */
 
-               node_prefix = MASK_PFX(cn->key, cn->pos);
-               key_prefix = MASK_PFX(key, cn->pos);
+               node_prefix = mask_pfx(cn->key, cn->pos);
+               key_prefix = mask_pfx(key, cn->pos);
                pref_mismatch = key_prefix^node_prefix;
                mp = 0;
 
@@ -1495,12 +1479,13 @@ backtrace:
                if (chopped_off <= pn->bits) {
                        cindex &= ~(1 << (chopped_off-1));
                } else {
-                       if (NODE_PARENT(pn) == NULL)
+                       struct tnode *parent = node_parent((struct node *) pn);
+                       if (!parent)
                                goto failed;
 
                        /* Get Child's index */
-                       cindex = tkey_extract_bits(pn->key, NODE_PARENT(pn)->pos, NODE_PARENT(pn)->bits);
-                       pn = NODE_PARENT(pn);
+                       cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits);
+                       pn = parent;
                        chopped_off = 0;
 
 #ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -1536,7 +1521,7 @@ static int trie_leaf_remove(struct trie *t, t_key key)
                check_tnode(tn);
                n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits));
 
-               BUG_ON(n && NODE_PARENT(n) != tn);
+               BUG_ON(n && node_parent(n) != tn);
        }
        l = (struct leaf *) n;
 
@@ -1548,10 +1533,9 @@ static int trie_leaf_remove(struct trie *t, t_key key)
         * Remove the leaf and rebalance the tree
         */
 
-       t->revision++;
        t->size--;
 
-       tp = NODE_PARENT(n);
+       tp = node_parent(n);
        tnode_free((struct tnode *) n);
 
        if (tp) {
@@ -1703,7 +1687,7 @@ static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
 
                p = (struct tnode*) trie;  /* Start */
        } else
-               p = (struct tnode *) NODE_PARENT(c);
+               p = node_parent(c);
 
        while (p) {
                int pos, last;
@@ -1740,7 +1724,7 @@ static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
 up:
                /* No more children go up one step  */
                c = (struct node *) p;
-               p = (struct tnode *) NODE_PARENT(p);
+               p = node_parent(c);
        }
        return NULL; /* Ready. Root of trie */
 }
@@ -1754,8 +1738,6 @@ static int fn_trie_flush(struct fib_table *tb)
        struct leaf *ll = NULL, *l = NULL;
        int found = 0, h;
 
-       t->revision++;
-
        for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
                found += trie_flush_leaf(t, l);
 
@@ -1771,8 +1753,6 @@ static int fn_trie_flush(struct fib_table *tb)
        return found;
 }
 
-static int trie_last_dflt = -1;
-
 static void
 fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
 {
@@ -1819,39 +1799,29 @@ fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
                        if (next_fi != res->fi)
                                break;
                } else if (!fib_detect_death(fi, order, &last_resort,
-                                            &last_idx, &trie_last_dflt)) {
-                       if (res->fi)
-                               fib_info_put(res->fi);
-                       res->fi = fi;
-                       atomic_inc(&fi->fib_clntref);
-                       trie_last_dflt = order;
+                                            &last_idx, tb->tb_default)) {
+                       fib_result_assign(res, fi);
+                       tb->tb_default = order;
                        goto out;
                }
                fi = next_fi;
                order++;
        }
        if (order <= 0 || fi == NULL) {
-               trie_last_dflt = -1;
+               tb->tb_default = -1;
                goto out;
        }
 
-       if (!fib_detect_death(fi, order, &last_resort, &last_idx, &trie_last_dflt)) {
-               if (res->fi)
-                       fib_info_put(res->fi);
-               res->fi = fi;
-               atomic_inc(&fi->fib_clntref);
-               trie_last_dflt = order;
+       if (!fib_detect_death(fi, order, &last_resort, &last_idx,
+                               tb->tb_default)) {
+               fib_result_assign(res, fi);
+               tb->tb_default = order;
                goto out;
        }
-       if (last_idx >= 0) {
-               if (res->fi)
-                       fib_info_put(res->fi);
-               res->fi = last_resort;
-               if (last_resort)
-                       atomic_inc(&last_resort->fib_clntref);
-       }
-       trie_last_dflt = last_idx;
- out:;
+       if (last_idx >= 0)
+               fib_result_assign(res, last_resort);
+       tb->tb_default = last_idx;
+out:
        rcu_read_unlock();
 }
 
@@ -1957,11 +1927,7 @@ out:
 
 /* Fix more generic FIB names for init later */
 
-#ifdef CONFIG_IP_MULTIPLE_TABLES
-struct fib_table * fib_hash_init(u32 id)
-#else
-struct fib_table * __init fib_hash_init(u32 id)
-#endif
+struct fib_table *fib_hash_init(u32 id)
 {
        struct fib_table *tb;
        struct trie *t;
@@ -1978,22 +1944,16 @@ struct fib_table * __init fib_hash_init(u32 id)
                return NULL;
 
        tb->tb_id = id;
+       tb->tb_default = -1;
        tb->tb_lookup = fn_trie_lookup;
        tb->tb_insert = fn_trie_insert;
        tb->tb_delete = fn_trie_delete;
        tb->tb_flush = fn_trie_flush;
        tb->tb_select_default = fn_trie_select_default;
        tb->tb_dump = fn_trie_dump;
-       memset(tb->tb_data, 0, sizeof(struct trie));
 
        t = (struct trie *) tb->tb_data;
-
-       trie_init(t);
-
-       if (id == RT_TABLE_LOCAL)
-               trie_local = t;
-       else if (id == RT_TABLE_MAIN)
-               trie_main = t;
+       memset(t, 0, sizeof(*t));
 
        if (id == RT_TABLE_LOCAL)
                printk(KERN_INFO "IPv4 FIB: Using LC-trie version %s\n", VERSION);
@@ -2004,6 +1964,8 @@ struct fib_table * __init fib_hash_init(u32 id)
 #ifdef CONFIG_PROC_FS
 /* Depth first Trie walk iterator */
 struct fib_trie_iter {
+       struct seq_net_private p;
+       struct trie *trie_local, *trie_main;
        struct tnode *tnode;
        struct trie *trie;
        unsigned index;
@@ -2043,7 +2005,7 @@ rescan:
        }
 
        /* Current node exhausted, pop back up */
-       p = NODE_PARENT(tn);
+       p = node_parent((struct node *)tn);
        if (p) {
                cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
                tn = p;
@@ -2128,13 +2090,13 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
        else
                avdepth = 0;
 
-       seq_printf(seq, "\tAver depth:     %d.%02d\n", avdepth / 100, avdepth % 100 );
+       seq_printf(seq, "\tAver depth:     %u.%02d\n", avdepth / 100, avdepth % 100 );
        seq_printf(seq, "\tMax depth:      %u\n", stat->maxdepth);
 
        seq_printf(seq, "\tLeaves:         %u\n", stat->leaves);
 
        bytes = sizeof(struct leaf) * stat->leaves;
-       seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes);
+       seq_printf(seq, "\tInternal nodes: %u\n\t", stat->tnodes);
        bytes += sizeof(struct tnode) * stat->tnodes;
 
        max = MAX_STAT_DEPTH;
@@ -2144,33 +2106,49 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
        pointers = 0;
        for (i = 1; i <= max; i++)
                if (stat->nodesizes[i] != 0) {
-                       seq_printf(seq, "  %d: %d",  i, stat->nodesizes[i]);
+                       seq_printf(seq, "  %u: %u",  i, stat->nodesizes[i]);
                        pointers += (1<<i) * stat->nodesizes[i];
                }
        seq_putc(seq, '\n');
-       seq_printf(seq, "\tPointers: %d\n", pointers);
+       seq_printf(seq, "\tPointers: %u\n", pointers);
 
        bytes += sizeof(struct node *) * pointers;
-       seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers);
-       seq_printf(seq, "Total size: %d  kB\n", (bytes + 1023) / 1024);
+       seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers);
+       seq_printf(seq, "Total size: %u  kB\n", (bytes + 1023) / 1024);
+}
 
 #ifdef CONFIG_IP_FIB_TRIE_STATS
-       seq_printf(seq, "Counters:\n---------\n");
-       seq_printf(seq,"gets = %d\n", t->stats.gets);
-       seq_printf(seq,"backtracks = %d\n", t->stats.backtrack);
-       seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
-       seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
-       seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
-       seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
-#ifdef CLEAR_STATS
-       memset(&(t->stats), 0, sizeof(t->stats));
-#endif
-#endif /*  CONFIG_IP_FIB_TRIE_STATS */
+static void trie_show_usage(struct seq_file *seq,
+                           const struct trie_use_stats *stats)
+{
+       seq_printf(seq, "\nCounters:\n---------\n");
+       seq_printf(seq,"gets = %u\n", stats->gets);
+       seq_printf(seq,"backtracks = %u\n", stats->backtrack);
+       seq_printf(seq,"semantic match passed = %u\n", stats->semantic_match_passed);
+       seq_printf(seq,"semantic match miss = %u\n", stats->semantic_match_miss);
+       seq_printf(seq,"null node hit= %u\n", stats->null_node_hit);
+       seq_printf(seq,"skipped node resize = %u\n\n", stats->resize_node_skipped);
 }
+#endif /*  CONFIG_IP_FIB_TRIE_STATS */
+
 
 static int fib_triestat_seq_show(struct seq_file *seq, void *v)
 {
+       struct net *net = (struct net *)seq->private;
+       struct trie *trie_local, *trie_main;
        struct trie_stat *stat;
+       struct fib_table *tb;
+
+       trie_local = NULL;
+       tb = fib_get_table(net, RT_TABLE_LOCAL);
+       if (tb)
+               trie_local = (struct trie *) tb->tb_data;
+
+       trie_main = NULL;
+       tb = fib_get_table(net, RT_TABLE_MAIN);
+       if (tb)
+               trie_main = (struct trie *) tb->tb_data;
+
 
        stat = kmalloc(sizeof(*stat), GFP_KERNEL);
        if (!stat)
@@ -2183,12 +2161,18 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
                seq_printf(seq, "Local:\n");
                trie_collect_stats(trie_local, stat);
                trie_show_stats(seq, stat);
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+               trie_show_usage(seq, &trie_local->stats);
+#endif
        }
 
        if (trie_main) {
                seq_printf(seq, "Main:\n");
                trie_collect_stats(trie_main, stat);
                trie_show_stats(seq, stat);
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+               trie_show_usage(seq, &trie_main->stats);
+#endif
        }
        kfree(stat);
 
@@ -2197,7 +2181,25 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
 
 static int fib_triestat_seq_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, fib_triestat_seq_show, NULL);
+       int err;
+       struct net *net;
+
+       net = get_proc_net(inode);
+       if (net == NULL)
+               return -ENXIO;
+       err = single_open(file, fib_triestat_seq_show, net);
+       if (err < 0) {
+               put_net(net);
+               return err;
+       }
+       return 0;
+}
+
+static int fib_triestat_seq_release(struct inode *ino, struct file *f)
+{
+       struct seq_file *seq = f->private_data;
+       put_net(seq->private);
+       return single_release(ino, f);
 }
 
 static const struct file_operations fib_triestat_fops = {
@@ -2205,7 +2207,7 @@ static const struct file_operations fib_triestat_fops = {
        .open   = fib_triestat_seq_open,
        .read   = seq_read,
        .llseek = seq_lseek,
-       .release = single_release,
+       .release = fib_triestat_seq_release,
 };
 
 static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
@@ -2214,13 +2216,13 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
        loff_t idx = 0;
        struct node *n;
 
-       for (n = fib_trie_get_first(iter, trie_local);
+       for (n = fib_trie_get_first(iter, iter->trie_local);
             n; ++idx, n = fib_trie_get_next(iter)) {
                if (pos == idx)
                        return n;
        }
 
-       for (n = fib_trie_get_first(iter, trie_main);
+       for (n = fib_trie_get_first(iter, iter->trie_main);
             n; ++idx, n = fib_trie_get_next(iter)) {
                if (pos == idx)
                        return n;
@@ -2229,11 +2231,25 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
 }
 
 static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(RCU)
 {
+       struct fib_trie_iter *iter = seq->private;
+       struct fib_table *tb;
+
+       if (!iter->trie_local) {
+               tb = fib_get_table(iter->p.net, RT_TABLE_LOCAL);
+               if (tb)
+                       iter->trie_local = (struct trie *) tb->tb_data;
+       }
+       if (!iter->trie_main) {
+               tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
+               if (tb)
+                       iter->trie_main = (struct trie *) tb->tb_data;
+       }
        rcu_read_lock();
        if (*pos == 0)
                return SEQ_START_TOKEN;
-       return fib_trie_get_idx(seq->private, *pos - 1);
+       return fib_trie_get_idx(iter, *pos - 1);
 }
 
 static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
@@ -2251,13 +2267,14 @@ static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                return v;
 
        /* continue scan in next trie */
-       if (iter->trie == trie_local)
-               return fib_trie_get_first(iter, trie_main);
+       if (iter->trie == iter->trie_local)
+               return fib_trie_get_first(iter, iter->trie_main);
 
        return NULL;
 }
 
 static void fib_trie_seq_stop(struct seq_file *seq, void *v)
+       __releases(RCU)
 {
        rcu_read_unlock();
 }
@@ -2267,10 +2284,8 @@ static void seq_indent(struct seq_file *seq, int n)
        while (n-- > 0) seq_puts(seq, "   ");
 }
 
-static inline const char *rtn_scope(enum rt_scope_t s)
+static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s)
 {
-       static char buf[32];
-
        switch (s) {
        case RT_SCOPE_UNIVERSE: return "universe";
        case RT_SCOPE_SITE:     return "site";
@@ -2278,7 +2293,7 @@ static inline const char *rtn_scope(enum rt_scope_t s)
        case RT_SCOPE_HOST:     return "host";
        case RT_SCOPE_NOWHERE:  return "nowhere";
        default:
-               snprintf(buf, sizeof(buf), "scope=%d", s);
+               snprintf(buf, len, "scope=%d", s);
                return buf;
        }
 }
@@ -2298,13 +2313,11 @@ static const char *rtn_type_names[__RTN_MAX] = {
        [RTN_XRESOLVE] = "XRESOLVE",
 };
 
-static inline const char *rtn_type(unsigned t)
+static inline const char *rtn_type(char *buf, size_t len, unsigned t)
 {
-       static char buf[32];
-
        if (t < __RTN_MAX && rtn_type_names[t])
                return rtn_type_names[t];
-       snprintf(buf, sizeof(buf), "type %d", t);
+       snprintf(buf, len, "type %u", t);
        return buf;
 }
 
@@ -2317,8 +2330,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
        if (v == SEQ_START_TOKEN)
                return 0;
 
-       if (!NODE_PARENT(n)) {
-               if (iter->trie == trie_local)
+       if (!node_parent(n)) {
+               if (iter->trie == iter->trie_local)
                        seq_puts(seq, "<local>:\n");
                else
                        seq_puts(seq, "<main>:\n");
@@ -2326,7 +2339,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
 
        if (IS_TNODE(n)) {
                struct tnode *tn = (struct tnode *) n;
-               __be32 prf = htonl(MASK_PFX(tn->key, tn->pos));
+               __be32 prf = htonl(mask_pfx(tn->key, tn->pos));
 
                seq_indent(seq, iter->depth-1);
                seq_printf(seq, "  +-- %d.%d.%d.%d/%d %d %d %d\n",
@@ -2342,13 +2355,19 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
                seq_printf(seq, "  |-- %d.%d.%d.%d\n", NIPQUAD(val));
                for (i = 32; i >= 0; i--) {
                        struct leaf_info *li = find_leaf_info(l, i);
+
                        if (li) {
                                struct fib_alias *fa;
+
                                list_for_each_entry_rcu(fa, &li->falh, fa_list) {
+                                       char buf1[32], buf2[32];
+
                                        seq_indent(seq, iter->depth+1);
                                        seq_printf(seq, "  /%d %s %s", i,
-                                                  rtn_scope(fa->fa_scope),
-                                                  rtn_type(fa->fa_type));
+                                                  rtn_scope(buf1, sizeof(buf1),
+                                                            fa->fa_scope),
+                                                  rtn_type(buf2, sizeof(buf2),
+                                                            fa->fa_type));
                                        if (fa->fa_tos)
                                                seq_printf(seq, "tos =%d\n",
                                                           fa->fa_tos);
@@ -2370,25 +2389,8 @@ static const struct seq_operations fib_trie_seq_ops = {
 
 static int fib_trie_seq_open(struct inode *inode, struct file *file)
 {
-       struct seq_file *seq;
-       int rc = -ENOMEM;
-       struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
-       if (!s)
-               goto out;
-
-       rc = seq_open(file, &fib_trie_seq_ops);
-       if (rc)
-               goto out_kfree;
-
-       seq          = file->private_data;
-       seq->private = s;
-       memset(s, 0, sizeof(*s));
-out:
-       return rc;
-out_kfree:
-       kfree(s);
-       goto out;
+       return seq_open_net(inode, file, &fib_trie_seq_ops,
+                           sizeof(struct fib_trie_iter));
 }
 
 static const struct file_operations fib_trie_fops = {
@@ -2396,7 +2398,7 @@ static const struct file_operations fib_trie_fops = {
        .open   = fib_trie_seq_open,
        .read   = seq_read,
        .llseek = seq_lseek,
-       .release = seq_release_private,
+       .release = seq_release_net,
 };
 
 static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
@@ -2434,7 +2436,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
                return 0;
        }
 
-       if (iter->trie == trie_local)
+       if (iter->trie == iter->trie_local)
                return 0;
        if (IS_TNODE(l))
                return 0;
@@ -2491,25 +2493,8 @@ static const struct seq_operations fib_route_seq_ops = {
 
 static int fib_route_seq_open(struct inode *inode, struct file *file)
 {
-       struct seq_file *seq;
-       int rc = -ENOMEM;
-       struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
-       if (!s)
-               goto out;
-
-       rc = seq_open(file, &fib_route_seq_ops);
-       if (rc)
-               goto out_kfree;
-
-       seq          = file->private_data;
-       seq->private = s;
-       memset(s, 0, sizeof(*s));
-out:
-       return rc;
-out_kfree:
-       kfree(s);
-       goto out;
+       return seq_open_net(inode, file, &fib_route_seq_ops,
+                           sizeof(struct fib_trie_iter));
 }
 
 static const struct file_operations fib_route_fops = {
@@ -2517,35 +2502,36 @@ static const struct file_operations fib_route_fops = {
        .open   = fib_route_seq_open,
        .read   = seq_read,
        .llseek = seq_lseek,
-       .release = seq_release_private,
+       .release = seq_release_net,
 };
 
-int __init fib_proc_init(void)
+int __net_init fib_proc_init(struct net *net)
 {
-       if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_fops))
+       if (!proc_net_fops_create(net, "fib_trie", S_IRUGO, &fib_trie_fops))
                goto out1;
 
-       if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_fops))
+       if (!proc_net_fops_create(net, "fib_triestat", S_IRUGO,
+                                 &fib_triestat_fops))
                goto out2;
 
-       if (!proc_net_fops_create("route", S_IRUGO, &fib_route_fops))
+       if (!proc_net_fops_create(net, "route", S_IRUGO, &fib_route_fops))
                goto out3;
 
        return 0;
 
 out3:
-       proc_net_remove("fib_triestat");
+       proc_net_remove(net, "fib_triestat");
 out2:
-       proc_net_remove("fib_trie");
+       proc_net_remove(net, "fib_trie");
 out1:
        return -ENOMEM;
 }
 
-void __init fib_proc_exit(void)
+void __net_exit fib_proc_exit(struct net *net)
 {
-       proc_net_remove("fib_trie");
-       proc_net_remove("fib_triestat");
-       proc_net_remove("route");
+       proc_net_remove(net, "fib_trie");
+       proc_net_remove(net, "fib_triestat");
+       proc_net_remove(net, "route");
 }
 
 #endif /* CONFIG_PROC_FS */