Merge branch 'master' of ../net-2.6/
[linux-2.6.git] / net / ipv4 / fib_trie.c
index f6cdc01..ce6cb34 100644 (file)
@@ -2029,9 +2029,8 @@ struct fib_table *fib_hash_table(u32 id)
 /* Depth first Trie walk iterator */
 struct fib_trie_iter {
        struct seq_net_private p;
-       struct trie *trie_local, *trie_main;
+       struct fib_table *tb;
        struct tnode *tnode;
-       struct trie *trie;
        unsigned index;
        unsigned depth;
 };
@@ -2084,31 +2083,26 @@ rescan:
 static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
                                       struct trie *t)
 {
-       struct node *n ;
+       struct node *n;
 
        if (!t)
                return NULL;
 
        n = rcu_dereference(t->trie);
-
-       if (!iter)
+       if (!n)
                return NULL;
 
-       if (n) {
-               if (IS_TNODE(n)) {
-                       iter->tnode = (struct tnode *) n;
-                       iter->trie = t;
-                       iter->index = 0;
-                       iter->depth = 1;
-               } else {
-                       iter->tnode = NULL;
-                       iter->trie  = t;
-                       iter->index = 0;
-                       iter->depth = 0;
-               }
-               return n;
+       if (IS_TNODE(n)) {
+               iter->tnode = (struct tnode *) n;
+               iter->index = 0;
+               iter->depth = 1;
+       } else {
+               iter->tnode = NULL;
+               iter->index = 0;
+               iter->depth = 0;
        }
-       return NULL;
+
+       return n;
 }
 
 static void trie_collect_stats(struct trie *t, struct trie_stat *s)
@@ -2119,8 +2113,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
        memset(s, 0, sizeof(*s));
 
        rcu_read_lock();
-       for (n = fib_trie_get_first(&iter, t); n;
-            n = fib_trie_get_next(&iter)) {
+       for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) {
                if (IS_LEAF(n)) {
                        struct leaf *l = (struct leaf *)n;
                        struct leaf_info *li;
@@ -2209,36 +2202,48 @@ static void trie_show_usage(struct seq_file *seq,
 }
 #endif /*  CONFIG_IP_FIB_TRIE_STATS */
 
-static void fib_trie_show(struct seq_file *seq, const char *name,
-                         struct trie *trie)
+static void fib_table_print(struct seq_file *seq, struct fib_table *tb)
 {
-       struct trie_stat stat;
-
-       trie_collect_stats(trie, &stat);
-       seq_printf(seq, "%s:\n", name);
-       trie_show_stats(seq, &stat);
-#ifdef CONFIG_IP_FIB_TRIE_STATS
-       trie_show_usage(seq, &trie->stats);
-#endif
+       if (tb->tb_id == RT_TABLE_LOCAL)
+               seq_puts(seq, "Local:\n");
+       else if (tb->tb_id == RT_TABLE_MAIN)
+               seq_puts(seq, "Main:\n");
+       else
+               seq_printf(seq, "Id %d:\n", tb->tb_id);
 }
 
+
 static int fib_triestat_seq_show(struct seq_file *seq, void *v)
 {
        struct net *net = (struct net *)seq->private;
-       struct fib_table *tb;
+       unsigned int h;
 
        seq_printf(seq,
                   "Basic info: size of leaf:"
                   " %Zd bytes, size of tnode: %Zd bytes.\n",
                   sizeof(struct leaf), sizeof(struct tnode));
 
-       tb = fib_get_table(net, RT_TABLE_LOCAL);
-       if (tb)
-               fib_trie_show(seq, "Local", (struct trie *) tb->tb_data);
+       for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+               struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+               struct hlist_node *node;
+               struct fib_table *tb;
+
+               hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
+                       struct trie *t = (struct trie *) tb->tb_data;
+                       struct trie_stat stat;
+
+                       if (!t)
+                               continue;
 
-       tb = fib_get_table(net, RT_TABLE_MAIN);
-       if (tb)
-               fib_trie_show(seq, "Main", (struct trie *) tb->tb_data);
+                       fib_table_print(seq, tb);
+
+                       trie_collect_stats(t, &stat);
+                       trie_show_stats(seq, &stat);
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+                       trie_show_usage(seq, &t->stats);
+#endif
+               }
+       }
 
        return 0;
 }
@@ -2274,23 +2279,30 @@ static const struct file_operations fib_triestat_fops = {
        .release = fib_triestat_seq_release,
 };
 
-static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
-                                     loff_t pos)
+static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos)
 {
+       struct net *net = iter->p.net;
        loff_t idx = 0;
-       struct node *n;
+       unsigned int h;
 
-       for (n = fib_trie_get_first(iter, iter->trie_local);
-            n; ++idx, n = fib_trie_get_next(iter)) {
-               if (pos == idx)
-                       return n;
-       }
+       for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+               struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+               struct hlist_node *node;
+               struct fib_table *tb;
 
-       for (n = fib_trie_get_first(iter, iter->trie_main);
-            n; ++idx, n = fib_trie_get_next(iter)) {
-               if (pos == idx)
-                       return n;
+               hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
+                       struct node *n;
+
+                       for (n = fib_trie_get_first(iter,
+                                                   (struct trie *) tb->tb_data);
+                            n; n = fib_trie_get_next(iter))
+                               if (pos == idx++) {
+                                       iter->tb = tb;
+                                       return n;
+                               }
+               }
        }
+
        return NULL;
 }
 
@@ -2298,43 +2310,49 @@ 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(iter, *pos - 1);
+       return fib_trie_get_idx(iter, *pos);
 }
 
 static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct fib_trie_iter *iter = seq->private;
-       void *l = v;
+       struct net *net = iter->p.net;
+       struct fib_table *tb = iter->tb;
+       struct hlist_node *tb_node;
+       unsigned int h;
+       struct node *n;
 
        ++*pos;
-       if (v == SEQ_START_TOKEN)
-               return fib_trie_get_idx(iter, 0);
-
-       v = fib_trie_get_next(iter);
-       BUG_ON(v == l);
-       if (v)
-               return v;
+       /* next node in same table */
+       n = fib_trie_get_next(iter);
+       if (n)
+               return n;
 
-       /* continue scan in next trie */
-       if (iter->trie == iter->trie_local)
-               return fib_trie_get_first(iter, iter->trie_main);
+       /* walk rest of this hash chain */
+       h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
+       while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+               tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
+               n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
+               if (n)
+                       goto found;
+       }
 
+       /* new hash chain */
+       while (++h < FIB_TABLE_HASHSZ) {
+               struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+               hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) {
+                       n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
+                       if (n)
+                               goto found;
+               }
+       }
        return NULL;
+
+found:
+       iter->tb = tb;
+       return n;
 }
 
 static void fib_trie_seq_stop(struct seq_file *seq, void *v)
@@ -2391,15 +2409,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
        const struct fib_trie_iter *iter = seq->private;
        struct node *n = v;
 
-       if (v == SEQ_START_TOKEN)
-               return 0;
-
-       if (!node_parent_rcu(n)) {
-               if (iter->trie == iter->trie_local)
-                       seq_puts(seq, "<local>:\n");
-               else
-                       seq_puts(seq, "<main>:\n");
-       }
+       if (!node_parent_rcu(n))
+               fib_table_print(seq, iter->tb);
 
        if (IS_TNODE(n)) {
                struct tnode *tn = (struct tnode *) n;