]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - net/ipv4/fib_trie.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6.git] / net / ipv4 / fib_trie.c
index a7d089eb042ed6e33b678f97220624bcf0429ecc..58c25ea5a5c19ef58ec204d79c209744bfc6a59a 100644 (file)
  *
  *   Hans Liss <hans.liss@its.uu.se>  Uppsala Universitet
  *
- * This work is based on the LPC-trie which is originally descibed in:
+ * This work is based on the LPC-trie which is originally described in:
  *
  * An experimental study of compression methods for dynamic tries
  * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
- * http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
+ * http://www.csc.kth.se/~snilsson/software/dyntrie2/
  *
  *
  * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
  * IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
  *
- * Version:    $Id: fib_trie.c,v 1.3 2005/06/08 14:20:01 robert Exp $
- *
  *
  * Code from fib_hash has been reused which includes the following header:
  *
@@ -50,7 +48,7 @@
  *             Patrick McHardy <kaber@trash.net>
  */
 
-#define VERSION "0.408"
+#define VERSION "0.409"
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -73,6 +71,8 @@
 #include <linux/netlink.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/prefetch.h>
 #include <net/net_namespace.h>
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -96,7 +96,7 @@ typedef unsigned int t_key;
 #define IS_TNODE(n) (!(n->parent & T_LEAF))
 #define IS_LEAF(n) (n->parent & T_LEAF)
 
-struct node {
+struct rt_trie_node {
        unsigned long parent;
        t_key key;
 };
@@ -122,8 +122,12 @@ struct tnode {
        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];
+       union {
+               struct rcu_head rcu;
+               struct work_struct work;
+               struct tnode *tnode_free;
+       };
+       struct rt_trie_node __rcu *child[0];
 };
 
 #ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -148,53 +152,84 @@ struct trie_stat {
 };
 
 struct trie {
-       struct node *trie;
+       struct rt_trie_node __rcu *trie;
 #ifdef CONFIG_IP_FIB_TRIE_STATS
        struct trie_use_stats stats;
 #endif
 };
 
-static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n,
+static void put_child(struct trie *t, struct tnode *tn, int i, struct rt_trie_node *n);
+static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
                                  int wasfull);
-static struct node *resize(struct trie *t, struct tnode *tn);
+static struct rt_trie_node *resize(struct trie *t, struct tnode *tn);
 static struct tnode *inflate(struct trie *t, struct tnode *tn);
 static struct tnode *halve(struct trie *t, struct tnode *tn);
-static void tnode_free(struct tnode *tn);
+/* tnodes to free after resize(); protected by RTNL */
+static struct tnode *tnode_free_head;
+static size_t tnode_free_size;
+
+/*
+ * synchronize_rcu after call_rcu for that many pages; it should be especially
+ * useful before resizing the root node with PREEMPT_NONE configs; the value was
+ * obtained experimentally, aiming to avoid visible slowdown.
+ */
+static const int sync_pages = 128;
 
 static struct kmem_cache *fn_alias_kmem __read_mostly;
 static struct kmem_cache *trie_leaf_kmem __read_mostly;
 
-static inline struct tnode *node_parent(struct node *node)
+/*
+ * caller must hold RTNL
+ */
+static inline struct tnode *node_parent(const struct rt_trie_node *node)
 {
-       return (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
+       unsigned long parent;
+
+       parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held());
+
+       return (struct tnode *)(parent & ~NODE_TYPE_MASK);
 }
 
-static inline struct tnode *node_parent_rcu(struct node *node)
+/*
+ * caller must hold RCU read lock or RTNL
+ */
+static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
 {
-       struct tnode *ret = node_parent(node);
+       unsigned long parent;
+
+       parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() ||
+                                                          lockdep_rtnl_is_held());
 
-       return rcu_dereference(ret);
+       return (struct tnode *)(parent & ~NODE_TYPE_MASK);
 }
 
-static inline void node_set_parent(struct node *node, struct tnode *ptr)
+/* Same as rcu_assign_pointer
+ * but that macro() assumes that value is a pointer.
+ */
+static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
 {
-       rcu_assign_pointer(node->parent,
-                          (unsigned long)ptr | NODE_TYPE(node));
+       smp_wmb();
+       node->parent = (unsigned long)ptr | NODE_TYPE(node);
 }
 
-static inline struct node *tnode_get_child(struct tnode *tn, unsigned int i)
+/*
+ * caller must hold RTNL
+ */
+static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
 {
        BUG_ON(i >= 1U << tn->bits);
 
-       return tn->child[i];
+       return rtnl_dereference(tn->child[i]);
 }
 
-static inline struct node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
+/*
+ * caller must hold RCU read lock or RTNL
+ */
+static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
 {
-       struct node *ret = tnode_get_child(tn, i);
+       BUG_ON(i >= 1U << tn->bits);
 
-       return rcu_dereference(ret);
+       return rcu_dereference_rtnl(tn->child[i]);
 }
 
 static inline int tnode_child_length(const struct tnode *tn)
@@ -202,12 +237,12 @@ 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)
+static inline t_key mask_pfx(t_key k, unsigned int l)
 {
        return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l);
 }
 
-static inline t_key tkey_extract_bits(t_key a, int offset, int bits)
+static inline t_key tkey_extract_bits(t_key a, unsigned int offset, unsigned int bits)
 {
        if (offset < KEYLENGTH)
                return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
@@ -310,9 +345,8 @@ static inline void check_tnode(const struct tnode *tn)
 
 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 const int halve_threshold_root = 15;
+static const int inflate_threshold_root = 30;
 
 static void __alias_free_mem(struct rcu_head *head)
 {
@@ -331,51 +365,77 @@ static void __leaf_free_rcu(struct rcu_head *head)
        kmem_cache_free(trie_leaf_kmem, l);
 }
 
-static void __leaf_info_free_rcu(struct rcu_head *head)
+static inline void free_leaf(struct leaf *l)
 {
-       kfree(container_of(head, struct leaf_info, rcu));
+       call_rcu_bh(&l->rcu, __leaf_free_rcu);
 }
 
 static inline void free_leaf_info(struct leaf_info *leaf)
 {
-       call_rcu(&leaf->rcu, __leaf_info_free_rcu);
+       kfree_rcu(leaf, rcu);
 }
 
 static struct tnode *tnode_alloc(size_t size)
 {
-       struct page *pages;
-
        if (size <= PAGE_SIZE)
                return kzalloc(size, GFP_KERNEL);
+       else
+               return vzalloc(size);
+}
 
-       pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size));
-       if (!pages)
-               return NULL;
-
-       return page_address(pages);
+static void __tnode_vfree(struct work_struct *arg)
+{
+       struct tnode *tn = container_of(arg, struct tnode, work);
+       vfree(tn);
 }
 
 static void __tnode_free_rcu(struct rcu_head *head)
 {
        struct tnode *tn = container_of(head, struct tnode, rcu);
        size_t size = sizeof(struct tnode) +
-                     (sizeof(struct node *) << tn->bits);
+                     (sizeof(struct rt_trie_node *) << tn->bits);
 
        if (size <= PAGE_SIZE)
                kfree(tn);
-       else
-               free_pages((unsigned long)tn, get_order(size));
+       else {
+               INIT_WORK(&tn->work, __tnode_vfree);
+               schedule_work(&tn->work);
+       }
 }
 
 static inline void tnode_free(struct tnode *tn)
 {
-       if (IS_LEAF(tn)) {
-               struct leaf *l = (struct leaf *) tn;
-               call_rcu_bh(&l->rcu, __leaf_free_rcu);
-       } else
+       if (IS_LEAF(tn))
+               free_leaf((struct leaf *) tn);
+       else
                call_rcu(&tn->rcu, __tnode_free_rcu);
 }
 
+static void tnode_free_safe(struct tnode *tn)
+{
+       BUG_ON(IS_LEAF(tn));
+       tn->tnode_free = tnode_free_head;
+       tnode_free_head = tn;
+       tnode_free_size += sizeof(struct tnode) +
+                          (sizeof(struct rt_trie_node *) << tn->bits);
+}
+
+static void tnode_free_flush(void)
+{
+       struct tnode *tn;
+
+       while ((tn = tnode_free_head)) {
+               tnode_free_head = tn->tnode_free;
+               tn->tnode_free = NULL;
+               tnode_free(tn);
+       }
+
+       if (tnode_free_size >= PAGE_SIZE * sync_pages) {
+               tnode_free_size = 0;
+               synchronize_rcu();
+       }
+}
+
 static struct leaf *leaf_new(void)
 {
        struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
@@ -398,7 +458,7 @@ static struct leaf_info *leaf_info_new(int plen)
 
 static struct tnode *tnode_new(t_key key, int pos, int bits)
 {
-       size_t sz = sizeof(struct tnode) + (sizeof(struct node *) << bits);
+       size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits);
        struct tnode *tn = tnode_alloc(sz);
 
        if (tn) {
@@ -410,8 +470,8 @@ static struct tnode *tnode_new(t_key key, int pos, int bits)
                tn->empty_children = 1<<bits;
        }
 
-       pr_debug("AT %p s=%u %lu\n", tn, (unsigned int) sizeof(struct tnode),
-                (unsigned long) (sizeof(struct node) << bits));
+       pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode),
+                sizeof(struct rt_trie_node) << bits);
        return tn;
 }
 
@@ -420,7 +480,7 @@ static struct tnode *tnode_new(t_key key, int pos, int bits)
  * and no bits are skipped. See discussion in dyntree paper p. 6
  */
 
-static inline int tnode_full(const struct tnode *tn, const struct node *n)
+static inline int tnode_full(const struct tnode *tn, const struct rt_trie_node *n)
 {
        if (n == NULL || IS_LEAF(n))
                return 0;
@@ -429,7 +489,7 @@ static inline int tnode_full(const struct tnode *tn, const struct node *n)
 }
 
 static inline void put_child(struct trie *t, struct tnode *tn, int i,
-                            struct node *n)
+                            struct rt_trie_node *n)
 {
        tnode_put_child_reorg(tn, i, n, -1);
 }
@@ -439,10 +499,10 @@ static inline void put_child(struct trie *t, struct tnode *tn, int i,
   * Update the value of full_children and empty_children.
   */
 
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n,
+static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
                                  int wasfull)
 {
-       struct node *chi = tn->child[i];
+       struct rt_trie_node *chi = rtnl_dereference(tn->child[i]);
        int isfull;
 
        BUG_ON(i >= 1<<tn->bits);
@@ -469,14 +529,14 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n,
        rcu_assign_pointer(tn->child[i], n);
 }
 
-static struct node *resize(struct trie *t, struct tnode *tn)
+#define MAX_WORK 10
+static struct rt_trie_node *resize(struct trie *t, struct tnode *tn)
 {
        int i;
-       int err = 0;
        struct tnode *old_tn;
        int inflate_threshold_use;
        int halve_threshold_use;
-       int max_resize;
+       int max_work;
 
        if (!tn)
                return NULL;
@@ -486,23 +546,12 @@ static struct node *resize(struct trie *t, struct tnode *tn)
 
        /* No children */
        if (tn->empty_children == tnode_child_length(tn)) {
-               tnode_free(tn);
+               tnode_free_safe(tn);
                return NULL;
        }
        /* One child */
        if (tn->empty_children == tnode_child_length(tn) - 1)
-               for (i = 0; i < tnode_child_length(tn); i++) {
-                       struct node *n;
-
-                       n = tn->child[i];
-                       if (!n)
-                               continue;
-
-                       /* compress one level */
-                       node_set_parent(n, NULL);
-                       tnode_free(tn);
-                       return n;
-               }
+               goto one_child;
        /*
         * Double as long as the resulting node has a number of
         * nonempty nodes that are above the threshold.
@@ -571,14 +620,16 @@ static struct node *resize(struct trie *t, struct tnode *tn)
 
        /* Keep root node larger  */
 
-       if (!tn->parent)
+       if (!node_parent((struct rt_trie_node *)tn)) {
                inflate_threshold_use = inflate_threshold_root;
-       else
+               halve_threshold_use = halve_threshold_root;
+       } else {
                inflate_threshold_use = inflate_threshold;
+               halve_threshold_use = halve_threshold;
+       }
 
-       err = 0;
-       max_resize = 10;
-       while ((tn->full_children > 0 &&  max_resize-- &&
+       max_work = MAX_WORK;
+       while ((tn->full_children > 0 &&  max_work-- &&
                50 * (tn->full_children + tnode_child_length(tn)
                      - tn->empty_children)
                >= inflate_threshold_use * tnode_child_length(tn))) {
@@ -595,35 +646,19 @@ static struct node *resize(struct trie *t, struct tnode *tn)
                }
        }
 
-       if (max_resize < 0) {
-               if (!tn->parent)
-                       pr_warning("Fix inflate_threshold_root."
-                                  " Now=%d size=%d bits\n",
-                                  inflate_threshold_root, tn->bits);
-               else
-                       pr_warning("Fix inflate_threshold."
-                                  " Now=%d size=%d bits\n",
-                                  inflate_threshold, tn->bits);
-       }
-
        check_tnode(tn);
 
+       /* Return if at least one inflate is run */
+       if (max_work != MAX_WORK)
+               return (struct rt_trie_node *) tn;
+
        /*
         * Halve as long as the number of empty children in this
         * node is above threshold.
         */
 
-
-       /* Keep root node larger  */
-
-       if (!tn->parent)
-               halve_threshold_use = halve_threshold_root;
-       else
-               halve_threshold_use = halve_threshold;
-
-       err = 0;
-       max_resize = 10;
-       while (tn->bits > 1 &&  max_resize-- &&
+       max_work = MAX_WORK;
+       while (tn->bits > 1 &&  max_work-- &&
               100 * (tnode_child_length(tn) - tn->empty_children) <
               halve_threshold_use * tnode_child_length(tn)) {
 
@@ -638,34 +673,39 @@ static struct node *resize(struct trie *t, struct tnode *tn)
                }
        }
 
-       if (max_resize < 0) {
-               if (!tn->parent)
-                       pr_warning("Fix halve_threshold_root."
-                                  " Now=%d size=%d bits\n",
-                                  halve_threshold_root, tn->bits);
-               else
-                       pr_warning("Fix halve_threshold."
-                                  " Now=%d size=%d bits\n",
-                                  halve_threshold, tn->bits);
-       }
 
        /* Only one child remains */
-       if (tn->empty_children == tnode_child_length(tn) - 1)
+       if (tn->empty_children == tnode_child_length(tn) - 1) {
+one_child:
                for (i = 0; i < tnode_child_length(tn); i++) {
-                       struct node *n;
+                       struct rt_trie_node *n;
 
-                       n = tn->child[i];
+                       n = rtnl_dereference(tn->child[i]);
                        if (!n)
                                continue;
 
                        /* compress one level */
 
                        node_set_parent(n, NULL);
-                       tnode_free(tn);
+                       tnode_free_safe(tn);
                        return n;
                }
+       }
+       return (struct rt_trie_node *) tn;
+}
+
+
+static void tnode_clean_free(struct tnode *tn)
+{
+       int i;
+       struct tnode *tofree;
 
-       return (struct node *) tn;
+       for (i = 0; i < tnode_child_length(tn); i++) {
+               tofree = (struct tnode *)rtnl_dereference(tn->child[i]);
+               if (tofree)
+                       tnode_free(tofree);
+       }
+       tnode_free(tn);
 }
 
 static struct tnode *inflate(struct trie *t, struct tnode *tn)
@@ -712,14 +752,14 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
                                goto nomem;
                        }
 
-                       put_child(t, tn, 2*i, (struct node *) left);
-                       put_child(t, tn, 2*i+1, (struct node *) right);
+                       put_child(t, tn, 2*i, (struct rt_trie_node *) left);
+                       put_child(t, tn, 2*i+1, (struct rt_trie_node *) right);
                }
        }
 
        for (i = 0; i < olen; i++) {
                struct tnode *inode;
-               struct node *node = tnode_get_child(oldtnode, i);
+               struct rt_trie_node *node = tnode_get_child(oldtnode, i);
                struct tnode *left, *right;
                int size, j;
 
@@ -744,10 +784,10 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
                inode = (struct tnode *) node;
 
                if (inode->bits == 1) {
-                       put_child(t, tn, 2*i, inode->child[0]);
-                       put_child(t, tn, 2*i+1, inode->child[1]);
+                       put_child(t, tn, 2*i, rtnl_dereference(inode->child[0]));
+                       put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1]));
 
-                       tnode_free(inode);
+                       tnode_free_safe(inode);
                        continue;
                }
 
@@ -786,35 +826,25 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
 
                size = tnode_child_length(left);
                for (j = 0; j < size; j++) {
-                       put_child(t, left, j, inode->child[j]);
-                       put_child(t, right, j, inode->child[j + size]);
+                       put_child(t, left, j, rtnl_dereference(inode->child[j]));
+                       put_child(t, right, j, rtnl_dereference(inode->child[j + size]));
                }
                put_child(t, tn, 2*i, resize(t, left));
                put_child(t, tn, 2*i+1, resize(t, right));
 
-               tnode_free(inode);
+               tnode_free_safe(inode);
        }
-       tnode_free(oldtnode);
+       tnode_free_safe(oldtnode);
        return tn;
 nomem:
-       {
-               int size = tnode_child_length(tn);
-               int j;
-
-               for (j = 0; j < size; j++)
-                       if (tn->child[j])
-                               tnode_free((struct tnode *)tn->child[j]);
-
-               tnode_free(tn);
-
-               return ERR_PTR(-ENOMEM);
-       }
+       tnode_clean_free(tn);
+       return ERR_PTR(-ENOMEM);
 }
 
 static struct tnode *halve(struct trie *t, struct tnode *tn)
 {
        struct tnode *oldtnode = tn;
-       struct node *left, *right;
+       struct rt_trie_node *left, *right;
        int i;
        int olen = tnode_child_length(tn);
 
@@ -845,7 +875,7 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
                        if (!newn)
                                goto nomem;
 
-                       put_child(t, tn, i/2, (struct node *)newn);
+                       put_child(t, tn, i/2, (struct rt_trie_node *)newn);
                }
 
        }
@@ -876,21 +906,11 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
                put_child(t, newBinNode, 1, right);
                put_child(t, tn, i/2, resize(t, newBinNode));
        }
-       tnode_free(oldtnode);
+       tnode_free_safe(oldtnode);
        return tn;
 nomem:
-       {
-               int size = tnode_child_length(tn);
-               int j;
-
-               for (j = 0; j < size; j++)
-                       if (tn->child[j])
-                               tnode_free((struct tnode *)tn->child[j]);
-
-               tnode_free(tn);
-
-               return ERR_PTR(-ENOMEM);
-       }
+       tnode_clean_free(tn);
+       return ERR_PTR(-ENOMEM);
 }
 
 /* readside must use rcu_read_lock currently dump routines
@@ -947,10 +967,10 @@ fib_find_node(struct trie *t, u32 key)
 {
        int pos;
        struct tnode *tn;
-       struct node *n;
+       struct rt_trie_node *n;
 
        pos = 0;
-       n = rcu_dereference(t->trie);
+       n = rcu_dereference_rtnl(t->trie);
 
        while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {
                tn = (struct tnode *) n;
@@ -974,21 +994,27 @@ fib_find_node(struct trie *t, u32 key)
        return NULL;
 }
 
-static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
+static void trie_rebalance(struct trie *t, struct tnode *tn)
 {
        int wasfull;
-       t_key cindex, key = tn->key;
+       t_key cindex, key;
        struct tnode *tp;
 
-       while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) {
+       key = tn->key;
+
+       while (tn != NULL && (tp = node_parent((struct rt_trie_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);
+                                     (struct rt_trie_node *)tn, wasfull);
 
-               tp = node_parent((struct node *) tn);
+               tp = node_parent((struct rt_trie_node *) tn);
+               if (!tp)
+                       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
+
+               tnode_free_flush();
                if (!tp)
                        break;
                tn = tp;
@@ -998,7 +1024,8 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
        if (IS_TNODE(tn))
                tn = (struct tnode *)resize(t, (struct tnode *)tn);
 
-       return (struct node *)tn;
+       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
+       tnode_free_flush();
 }
 
 /* only used from updater-side */
@@ -1007,7 +1034,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 {
        int pos, newpos;
        struct tnode *tp = NULL, *tn = NULL;
-       struct node *n;
+       struct rt_trie_node *n;
        struct leaf *l;
        int missbit;
        struct list_head *fa_head = NULL;
@@ -1015,7 +1042,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
        t_key cindex;
 
        pos = 0;
-       n = t->trie;
+       n = rtnl_dereference(t->trie);
 
        /* If we point to NULL, stop. Either the tree is empty and we should
         * just put a new leaf in if, or we have reached an empty child slot,
@@ -1083,7 +1110,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
        li = leaf_info_new(plen);
 
        if (!li) {
-               tnode_free((struct tnode *) l);
+               free_leaf(l);
                return NULL;
        }
 
@@ -1093,10 +1120,10 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
        if (t->trie && n == NULL) {
                /* Case 2: n is NULL, and will just insert a new leaf */
 
-               node_set_parent((struct node *)l, tp);
+               node_set_parent((struct rt_trie_node *)l, tp);
 
                cindex = tkey_extract_bits(key, tp->pos, tp->bits);
-               put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
+               put_child(t, (struct tnode *)tp, cindex, (struct rt_trie_node *)l);
        } else {
                /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
                /*
@@ -1119,22 +1146,22 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 
                if (!tn) {
                        free_leaf_info(li);
-                       tnode_free((struct tnode *) l);
+                       free_leaf(l);
                        return NULL;
                }
 
-               node_set_parent((struct node *)tn, tp);
+               node_set_parent((struct rt_trie_node *)tn, tp);
 
                missbit = tkey_extract_bits(key, newpos, 1);
-               put_child(t, tn, missbit, (struct node *)l);
+               put_child(t, tn, missbit, (struct rt_trie_node *)l);
                put_child(t, tn, 1-missbit, n);
 
                if (tp) {
                        cindex = tkey_extract_bits(key, tp->pos, tp->bits);
                        put_child(t, (struct tnode *)tp, cindex,
-                                 (struct node *)tn);
+                                 (struct rt_trie_node *)tn);
                } else {
-                       rcu_assign_pointer(t->trie, (struct node *)tn);
+                       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
                        tp = tn;
                }
        }
@@ -1146,7 +1173,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 
        /* Rebalance the trie */
 
-       rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
+       trie_rebalance(t, tp);
 done:
        return fa_head;
 }
@@ -1154,7 +1181,7 @@ done:
 /*
  * Caller must hold RTNL.
  */
-static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
 {
        struct trie *t = (struct trie *) tb->tb_data;
        struct fib_alias *fa, *new_fa;
@@ -1227,7 +1254,6 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
                        if (fa->fa_info->fib_priority != fi->fib_priority)
                                break;
                        if (fa->fa_type == cfg->fc_type &&
-                           fa->fa_scope == cfg->fc_scope &&
                            fa->fa_info == fi) {
                                fa_match = fa;
                                break;
@@ -1253,7 +1279,6 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
                        new_fa->fa_tos = fa->fa_tos;
                        new_fa->fa_info = fi;
                        new_fa->fa_type = cfg->fc_type;
-                       new_fa->fa_scope = cfg->fc_scope;
                        state = fa->fa_state;
                        new_fa->fa_state = state & ~FA_S_ACCESSED;
 
@@ -1262,7 +1287,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
 
                        fib_release_info(fi_drop);
                        if (state & FA_S_ACCESSED)
-                               rt_cache_flush(-1);
+                               rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
                        rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,
                                tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);
 
@@ -1290,7 +1315,6 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
        new_fa->fa_info = fi;
        new_fa->fa_tos = tos;
        new_fa->fa_type = cfg->fc_type;
-       new_fa->fa_scope = cfg->fc_scope;
        new_fa->fa_state = 0;
        /*
         * Insert new entry to the list.
@@ -1304,10 +1328,13 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
                }
        }
 
+       if (!plen)
+               tb->tb_num_default++;
+
        list_add_tail_rcu(&new_fa->fa_list,
                          (fa ? &fa->fa_list : fa_head));
 
-       rt_cache_flush(-1);
+       rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
        rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
                  &cfg->fc_nlinfo, 0);
 succeeded:
@@ -1322,53 +1349,86 @@ err:
 }
 
 /* should be called with rcu_read_lock */
-static int check_leaf(struct trie *t, struct leaf *l,
-                     t_key key,  const struct flowi *flp,
-                     struct fib_result *res)
+static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l,
+                     t_key key,  const struct flowi4 *flp,
+                     struct fib_result *res, int fib_flags)
 {
        struct leaf_info *li;
        struct hlist_head *hhead = &l->list;
        struct hlist_node *node;
 
        hlist_for_each_entry_rcu(li, node, hhead, hlist) {
-               int err;
+               struct fib_alias *fa;
                int plen = li->plen;
                __be32 mask = inet_make_mask(plen);
 
                if (l->key != (key & ntohl(mask)))
                        continue;
 
-               err = fib_semantic_match(&li->falh, flp, res,
-                                        htonl(l->key), mask, plen);
+               list_for_each_entry_rcu(fa, &li->falh, fa_list) {
+                       struct fib_info *fi = fa->fa_info;
+                       int nhsel, err;
+
+                       if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
+                               continue;
+                       if (fa->fa_info->fib_scope < flp->flowi4_scope)
+                               continue;
+                       fib_alias_accessed(fa);
+                       err = fib_props[fa->fa_type].error;
+                       if (err) {
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+                               t->stats.semantic_match_passed++;
+#endif
+                               return err;
+                       }
+                       if (fi->fib_flags & RTNH_F_DEAD)
+                               continue;
+                       for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
+                               const struct fib_nh *nh = &fi->fib_nh[nhsel];
+
+                               if (nh->nh_flags & RTNH_F_DEAD)
+                                       continue;
+                               if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
+                                       continue;
 
 #ifdef CONFIG_IP_FIB_TRIE_STATS
-               if (err <= 0)
-                       t->stats.semantic_match_passed++;
-               else
-                       t->stats.semantic_match_miss++;
+                               t->stats.semantic_match_passed++;
+#endif
+                               res->prefixlen = plen;
+                               res->nh_sel = nhsel;
+                               res->type = fa->fa_type;
+                               res->scope = fa->fa_info->fib_scope;
+                               res->fi = fi;
+                               res->table = tb;
+                               res->fa_head = &li->falh;
+                               if (!(fib_flags & FIB_LOOKUP_NOREF))
+                                       atomic_inc(&res->fi->fib_clntref);
+                               return 0;
+                       }
+               }
+
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+               t->stats.semantic_match_miss++;
 #endif
-               if (err <= 0)
-                       return plen;
        }
 
-       return -1;
+       return 1;
 }
 
-static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
-                         struct fib_result *res)
+int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
+                    struct fib_result *res, int fib_flags)
 {
        struct trie *t = (struct trie *) tb->tb_data;
-       int plen, ret = 0;
-       struct node *n;
+       int ret;
+       struct rt_trie_node *n;
        struct tnode *pn;
-       int pos, bits;
-       t_key key = ntohl(flp->fl4_dst);
-       int chopped_off;
+       unsigned int pos, bits;
+       t_key key = ntohl(flp->daddr);
+       unsigned int chopped_off;
        t_key cindex = 0;
-       int current_prefix_length = KEYLENGTH;
+       unsigned int current_prefix_length = KEYLENGTH;
        struct tnode *cn;
-       t_key node_prefix, key_prefix, pref_mismatch;
-       int mp;
+       t_key pref_mismatch;
 
        rcu_read_lock();
 
@@ -1382,10 +1442,7 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
 
        /* Just a leaf? */
        if (IS_LEAF(n)) {
-               plen = check_leaf(t, (struct leaf *)n, key, flp, res);
-               if (plen < 0)
-                       goto failed;
-               ret = 0;
+               ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
                goto found;
        }
 
@@ -1400,7 +1457,7 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
                        cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
                                                   pos, bits);
 
-               n = tnode_get_child(pn, cindex);
+               n = tnode_get_child_rcu(pn, cindex);
 
                if (n == NULL) {
 #ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -1410,11 +1467,9 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
                }
 
                if (IS_LEAF(n)) {
-                       plen = check_leaf(t, (struct leaf *)n, key, flp, res);
-                       if (plen < 0)
+                       ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
+                       if (ret > 0)
                                goto backtrace;
-
-                       ret = 0;
                        goto found;
                }
 
@@ -1488,10 +1543,7 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
                 * matching prefix.
                 */
 
-               node_prefix = mask_pfx(cn->key, cn->pos);
-               key_prefix = mask_pfx(key, cn->pos);
-               pref_mismatch = key_prefix^node_prefix;
-               mp = 0;
+               pref_mismatch = mask_pfx(cn->key ^ key, cn->pos);
 
                /*
                 * In short: If skipped bits in this node do not match
@@ -1499,13 +1551,9 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
                 * state.directly.
                 */
                if (pref_mismatch) {
-                       while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
-                               mp++;
-                               pref_mismatch = pref_mismatch << 1;
-                       }
-                       key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
+                       int mp = KEYLENGTH - fls(pref_mismatch);
 
-                       if (key_prefix != 0)
+                       if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0)
                                goto backtrace;
 
                        if (current_prefix_length >= cn->pos)
@@ -1537,7 +1585,7 @@ backtrace:
                if (chopped_off <= pn->bits) {
                        cindex &= ~(1 << (chopped_off-1));
                } else {
-                       struct tnode *parent = node_parent((struct node *) pn);
+                       struct tnode *parent = node_parent_rcu((struct rt_trie_node *) pn);
                        if (!parent)
                                goto failed;
 
@@ -1564,24 +1612,24 @@ found:
  */
 static void trie_leaf_remove(struct trie *t, struct leaf *l)
 {
-       struct tnode *tp = node_parent((struct node *) l);
+       struct tnode *tp = node_parent((struct rt_trie_node *) l);
 
        pr_debug("entering trie_leaf_remove(%p)\n", l);
 
        if (tp) {
                t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
                put_child(t, (struct tnode *)tp, cindex, NULL);
-               rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
+               trie_rebalance(t, tp);
        } else
                rcu_assign_pointer(t->trie, NULL);
 
-       tnode_free((struct tnode *) l);
+       free_leaf(l);
 }
 
 /*
  * Caller must hold RTNL.
  */
-static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
 {
        struct trie *t = (struct trie *) tb->tb_data;
        u32 key, mask;
@@ -1625,7 +1673,9 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
 
                if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) &&
                    (cfg->fc_scope == RT_SCOPE_NOWHERE ||
-                    fa->fa_scope == cfg->fc_scope) &&
+                    fa->fa_info->fib_scope == cfg->fc_scope) &&
+                   (!cfg->fc_prefsrc ||
+                    fi->fib_prefsrc == cfg->fc_prefsrc) &&
                    (!cfg->fc_protocol ||
                     fi->fib_protocol == cfg->fc_protocol) &&
                    fib_nh_match(cfg, fi) == 0) {
@@ -1646,6 +1696,9 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
 
        list_del_rcu(&fa->fa_list);
 
+       if (!plen)
+               tb->tb_num_default--;
+
        if (list_empty(fa_head)) {
                hlist_del_rcu(&li->hlist);
                free_leaf_info(li);
@@ -1655,14 +1708,14 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
                trie_leaf_remove(t, l);
 
        if (fa->fa_state & FA_S_ACCESSED)
-               rt_cache_flush(-1);
+               rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
 
        fib_release_info(fa->fa_info);
        alias_free_mem_rcu(fa);
        return 0;
 }
 
-static int trie_flush_list(struct trie *t, struct list_head *head)
+static int trie_flush_list(struct list_head *head)
 {
        struct fib_alias *fa, *fa_node;
        int found = 0;
@@ -1680,7 +1733,7 @@ static int trie_flush_list(struct trie *t, struct list_head *head)
        return found;
 }
 
-static int trie_flush_leaf(struct trie *t, struct leaf *l)
+static int trie_flush_leaf(struct leaf *l)
 {
        int found = 0;
        struct hlist_head *lih = &l->list;
@@ -1688,7 +1741,7 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
        struct leaf_info *li = NULL;
 
        hlist_for_each_entry_safe(li, node, tmp, lih, hlist) {
-               found += trie_flush_list(t, &li->falh);
+               found += trie_flush_list(&li->falh);
 
                if (list_empty(&li->falh)) {
                        hlist_del_rcu(&li->hlist);
@@ -1702,7 +1755,7 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
  * Scan for the next right leaf starting at node p->child[idx]
  * Since we have back pointer, no recursion necessary.
  */
-static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
+static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c)
 {
        do {
                t_key idx;
@@ -1718,7 +1771,7 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
                                continue;
 
                        if (IS_LEAF(c)) {
-                               prefetch(p->child[idx]);
+                               prefetch(rcu_dereference_rtnl(p->child[idx]));
                                return (struct leaf *) c;
                        }
 
@@ -1728,15 +1781,15 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
                }
 
                /* Node empty, walk back up to parent */
-               c = (struct node *) p;
-       } while ( (p = node_parent_rcu(c)) != NULL);
+               c = (struct rt_trie_node *) p;
+       } while ((p = node_parent_rcu(c)) != NULL);
 
        return NULL; /* Root of trie */
 }
 
 static struct leaf *trie_firstleaf(struct trie *t)
 {
-       struct tnode *n = (struct tnode *) rcu_dereference(t->trie);
+       struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie);
 
        if (!n)
                return NULL;
@@ -1749,8 +1802,8 @@ static struct leaf *trie_firstleaf(struct trie *t)
 
 static struct leaf *trie_nextleaf(struct leaf *l)
 {
-       struct node *c = (struct node *) l;
-       struct tnode *p = node_parent(c);
+       struct rt_trie_node *c = (struct rt_trie_node *) l;
+       struct tnode *p = node_parent_rcu(c);
 
        if (!p)
                return NULL;    /* trie with just one leaf */
@@ -1772,14 +1825,14 @@ static struct leaf *trie_leafindex(struct trie *t, int index)
 /*
  * Caller must hold RTNL.
  */
-static int fn_trie_flush(struct fib_table *tb)
+int fib_table_flush(struct fib_table *tb)
 {
        struct trie *t = (struct trie *) tb->tb_data;
        struct leaf *l, *ll = NULL;
        int found = 0;
 
        for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
-               found += trie_flush_leaf(t, l);
+               found += trie_flush_leaf(l);
 
                if (ll && hlist_empty(&ll->list))
                        trie_leaf_remove(t, ll);
@@ -1793,77 +1846,9 @@ static int fn_trie_flush(struct fib_table *tb)
        return found;
 }
 
-static void fn_trie_select_default(struct fib_table *tb,
-                                  const struct flowi *flp,
-                                  struct fib_result *res)
+void fib_free_table(struct fib_table *tb)
 {
-       struct trie *t = (struct trie *) tb->tb_data;
-       int order, last_idx;
-       struct fib_info *fi = NULL;
-       struct fib_info *last_resort;
-       struct fib_alias *fa = NULL;
-       struct list_head *fa_head;
-       struct leaf *l;
-
-       last_idx = -1;
-       last_resort = NULL;
-       order = -1;
-
-       rcu_read_lock();
-
-       l = fib_find_node(t, 0);
-       if (!l)
-               goto out;
-
-       fa_head = get_fa_head(l, 0);
-       if (!fa_head)
-               goto out;
-
-       if (list_empty(fa_head))
-               goto out;
-
-       list_for_each_entry_rcu(fa, fa_head, fa_list) {
-               struct fib_info *next_fi = fa->fa_info;
-
-               if (fa->fa_scope != res->scope ||
-                   fa->fa_type != RTN_UNICAST)
-                       continue;
-
-               if (next_fi->fib_priority > res->fi->fib_priority)
-                       break;
-               if (!next_fi->fib_nh[0].nh_gw ||
-                   next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
-                       continue;
-               fa->fa_state |= FA_S_ACCESSED;
-
-               if (fi == NULL) {
-                       if (next_fi != res->fi)
-                               break;
-               } else if (!fib_detect_death(fi, order, &last_resort,
-                                            &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) {
-               tb->tb_default = -1;
-               goto out;
-       }
-
-       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)
-               fib_result_assign(res, last_resort);
-       tb->tb_default = last_idx;
-out:
-       rcu_read_unlock();
+       kfree(tb);
 }
 
 static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
@@ -1890,7 +1875,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
                                  RTM_NEWROUTE,
                                  tb->tb_id,
                                  fa->fa_type,
-                                 fa->fa_scope,
                                  xkey,
                                  plen,
                                  fa->fa_tos,
@@ -1938,8 +1922,8 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
        return skb->len;
 }
 
-static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
-                       struct netlink_callback *cb)
+int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
+                  struct netlink_callback *cb)
 {
        struct leaf *l;
        struct trie *t = (struct trie *) tb->tb_data;
@@ -1980,7 +1964,7 @@ static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
        return skb->len;
 }
 
-void __init fib_hash_init(void)
+void __init fib_trie_init(void)
 {
        fn_alias_kmem = kmem_cache_create("ip_fib_alias",
                                          sizeof(struct fib_alias),
@@ -1993,8 +1977,7 @@ void __init fib_hash_init(void)
 }
 
 
-/* Fix more generic FIB names for init later */
-struct fib_table *fib_hash_table(u32 id)
+struct fib_table *fib_trie_table(u32 id)
 {
        struct fib_table *tb;
        struct trie *t;
@@ -2006,19 +1989,11 @@ struct fib_table *fib_hash_table(u32 id)
 
        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;
+       tb->tb_num_default = 0;
 
        t = (struct trie *) tb->tb_data;
        memset(t, 0, sizeof(*t));
 
-       if (id == RT_TABLE_LOCAL)
-               pr_info("IPv4 FIB: Using LC-trie version %s\n", VERSION);
-
        return tb;
 }
 
@@ -2028,14 +2003,14 @@ struct fib_trie_iter {
        struct seq_net_private p;
        struct fib_table *tb;
        struct tnode *tnode;
-       unsigned index;
-       unsigned depth;
+       unsigned int index;
+       unsigned int depth;
 };
 
-static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
+static struct rt_trie_node *fib_trie_get_next(struct fib_trie_iter *iter)
 {
        struct tnode *tn = iter->tnode;
-       unsigned cindex = iter->index;
+       unsigned int cindex = iter->index;
        struct tnode *p;
 
        /* A single entry routing table */
@@ -2046,7 +2021,7 @@ static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
                 iter->tnode, iter->index, iter->depth);
 rescan:
        while (cindex < (1<<tn->bits)) {
-               struct node *n = tnode_get_child_rcu(tn, cindex);
+               struct rt_trie_node *n = tnode_get_child_rcu(tn, cindex);
 
                if (n) {
                        if (IS_LEAF(n)) {
@@ -2065,7 +2040,7 @@ rescan:
        }
 
        /* Current node exhausted, pop back up */
-       p = node_parent_rcu((struct node *)tn);
+       p = node_parent_rcu((struct rt_trie_node *)tn);
        if (p) {
                cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
                tn = p;
@@ -2077,10 +2052,10 @@ rescan:
        return NULL;
 }
 
-static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
+static struct rt_trie_node *fib_trie_get_first(struct fib_trie_iter *iter,
                                       struct trie *t)
 {
-       struct node *n;
+       struct rt_trie_node *n;
 
        if (!t)
                return NULL;
@@ -2104,7 +2079,7 @@ static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
 
 static void trie_collect_stats(struct trie *t, struct trie_stat *s)
 {
-       struct node *n;
+       struct rt_trie_node *n;
        struct fib_trie_iter iter;
 
        memset(s, 0, sizeof(*s));
@@ -2144,7 +2119,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
  */
 static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
 {
-       unsigned i, max, pointers, bytes, avdepth;
+       unsigned int i, max, pointers, bytes, avdepth;
 
        if (stat->leaves)
                avdepth = stat->totdepth*100 / stat->leaves;
@@ -2177,7 +2152,7 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
        seq_putc(seq, '\n');
        seq_printf(seq, "\tPointers: %u\n", pointers);
 
-       bytes += sizeof(struct node *) * pointers;
+       bytes += sizeof(struct rt_trie_node *) * pointers;
        seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers);
        seq_printf(seq, "Total size: %u  kB\n", (bytes + 1023) / 1024);
 }
@@ -2247,25 +2222,7 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
 
 static int fib_triestat_seq_open(struct inode *inode, struct file *file)
 {
-       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);
+       return single_open_net(inode, file, fib_triestat_seq_show);
 }
 
 static const struct file_operations fib_triestat_fops = {
@@ -2273,12 +2230,13 @@ static const struct file_operations fib_triestat_fops = {
        .open   = fib_triestat_seq_open,
        .read   = seq_read,
        .llseek = seq_lseek,
-       .release = fib_triestat_seq_release,
+       .release = single_release_net,
 };
 
-static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos)
+static struct rt_trie_node *fib_trie_get_idx(struct seq_file *seq, loff_t pos)
 {
-       struct net *net = iter->p.net;
+       struct fib_trie_iter *iter = seq->private;
+       struct net *net = seq_file_net(seq);
        loff_t idx = 0;
        unsigned int h;
 
@@ -2288,7 +2246,7 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos)
                struct fib_table *tb;
 
                hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
-                       struct node *n;
+                       struct rt_trie_node *n;
 
                        for (n = fib_trie_get_first(iter,
                                                    (struct trie *) tb->tb_data);
@@ -2306,20 +2264,18 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos)
 static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(RCU)
 {
-       struct fib_trie_iter *iter = seq->private;
-
        rcu_read_lock();
-       return fib_trie_get_idx(iter, *pos);
+       return fib_trie_get_idx(seq, *pos);
 }
 
 static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct fib_trie_iter *iter = seq->private;
-       struct net *net = iter->p.net;
+       struct net *net = seq_file_net(seq);
        struct fib_table *tb = iter->tb;
        struct hlist_node *tb_node;
        unsigned int h;
-       struct node *n;
+       struct rt_trie_node *n;
 
        ++*pos;
        /* next node in same table */
@@ -2329,7 +2285,7 @@ static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
        /* walk rest of this hash chain */
        h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
-       while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+       while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) {
                tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
                n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
                if (n)
@@ -2360,7 +2316,8 @@ static void fib_trie_seq_stop(struct seq_file *seq, void *v)
 
 static void seq_indent(struct seq_file *seq, int n)
 {
-       while (n-- > 0) seq_puts(seq, "   ");
+       while (n-- > 0)
+               seq_puts(seq, "   ");
 }
 
 static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s)
@@ -2377,7 +2334,7 @@ static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s)
        }
 }
 
-static const char *rtn_type_names[__RTN_MAX] = {
+static const char *const rtn_type_names[__RTN_MAX] = {
        [RTN_UNSPEC] = "UNSPEC",
        [RTN_UNICAST] = "UNICAST",
        [RTN_LOCAL] = "LOCAL",
@@ -2392,7 +2349,7 @@ static const char *rtn_type_names[__RTN_MAX] = {
        [RTN_XRESOLVE] = "XRESOLVE",
 };
 
-static inline const char *rtn_type(char *buf, size_t len, unsigned t)
+static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
 {
        if (t < __RTN_MAX && rtn_type_names[t])
                return rtn_type_names[t];
@@ -2404,7 +2361,7 @@ static inline const char *rtn_type(char *buf, size_t len, unsigned t)
 static int fib_trie_seq_show(struct seq_file *seq, void *v)
 {
        const struct fib_trie_iter *iter = seq->private;
-       struct node *n = v;
+       struct rt_trie_node *n = v;
 
        if (!node_parent_rcu(n))
                fib_table_print(seq, iter->tb);
@@ -2414,8 +2371,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
                __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",
-                          NIPQUAD(prf), tn->pos, tn->bits, tn->full_children,
+               seq_printf(seq, "  +-- %pI4/%d %d %d %d\n",
+                          &prf, tn->pos, tn->bits, tn->full_children,
                           tn->empty_children);
 
        } else {
@@ -2425,7 +2382,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
                __be32 val = htonl(l->key);
 
                seq_indent(seq, iter->depth);
-               seq_printf(seq, "  |-- %d.%d.%d.%d\n", NIPQUAD(val));
+               seq_printf(seq, "  |-- %pI4\n", &val);
 
                hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
                        struct fib_alias *fa;
@@ -2436,7 +2393,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
                                seq_indent(seq, iter->depth+1);
                                seq_printf(seq, "  /%d %s %s", li->plen,
                                           rtn_scope(buf1, sizeof(buf1),
-                                                    fa->fa_scope),
+                                                    fa->fa_info->fib_scope),
                                           rtn_type(buf2, sizeof(buf2),
                                                    fa->fa_type));
                                if (fa->fa_tos)
@@ -2510,7 +2467,7 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
        struct fib_table *tb;
 
        rcu_read_lock();
-       tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
+       tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN);
        if (!tb)
                return NULL;
 
@@ -2548,13 +2505,12 @@ static void fib_route_seq_stop(struct seq_file *seq, void *v)
        rcu_read_unlock();
 }
 
-static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
+static unsigned int fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
 {
-       static unsigned type2flags[RTN_MAX + 1] = {
-               [7] = RTF_REJECT, [8] = RTF_REJECT,
-       };
-       unsigned flags = type2flags[type];
+       unsigned int flags = 0;
 
+       if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
+               flags = RTF_REJECT;
        if (fi && fi->fib_nh->nh_gw)
                flags |= RTF_GATEWAY;
        if (mask == htonl(0xFFFFFFFF))
@@ -2566,7 +2522,7 @@ static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
 /*
  *     This outputs /proc/net/route.
  *     The format of the file is not supposed to be changed
- *     and needs to be same as fib_hash output to avoid breaking
+ *     and needs to be same as fib_hash output to avoid breaking
  *     legacy utilities
  */
 static int fib_route_seq_show(struct seq_file *seq, void *v)
@@ -2591,16 +2547,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 
                list_for_each_entry_rcu(fa, &li->falh, fa_list) {
                        const struct fib_info *fi = fa->fa_info;
-                       unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
-                       char bf[128];
+                       unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
+                       int len;
 
                        if (fa->fa_type == RTN_BROADCAST
                            || fa->fa_type == RTN_MULTICAST)
                                continue;
 
                        if (fi)
-                               snprintf(bf, sizeof(bf),
-                                        "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+                               seq_printf(seq,
+                                        "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
+                                        "%d\t%08X\t%d\t%u\t%u%n",
                                         fi->fib_dev ? fi->fib_dev->name : "*",
                                         prefix,
                                         fi->fib_nh->nh_gw, flags, 0, 0,
@@ -2609,14 +2566,15 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
                                         (fi->fib_advmss ?
                                          fi->fib_advmss + 40 : 0),
                                         fi->fib_window,
-                                        fi->fib_rtt >> 3);
+                                        fi->fib_rtt >> 3, &len);
                        else
-                               snprintf(bf, sizeof(bf),
-                                        "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+                               seq_printf(seq,
+                                        "*\t%08X\t%08X\t%04X\t%d\t%u\t"
+                                        "%d\t%08X\t%d\t%u\t%u%n",
                                         prefix, 0, flags, 0, 0, 0,
-                                        mask, 0, 0, 0);
+                                        mask, 0, 0, 0, &len);
 
-                       seq_printf(seq, "%-127s\n", bf);
+                       seq_printf(seq, "%*s\n", 127 - len, "");
                }
        }