gss_krb5: add remaining pieces to enable AES encryption support
[safe/jmp/linux-2.6] / net / ipv6 / ip6_fib.c
index 944095c..6b82e02 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/in6.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 
 #ifdef         CONFIG_PROC_FS
 #include <linux/proc_fs.h>
@@ -93,29 +94,20 @@ static __u32 rt_sernum;
 
 static void fib6_gc_timer_cb(unsigned long arg);
 
-static struct fib6_walker_t fib6_walker_list = {
-       .prev   = &fib6_walker_list,
-       .next   = &fib6_walker_list,
-};
-
-#define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next)
+static LIST_HEAD(fib6_walkers);
+#define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh)
 
 static inline void fib6_walker_link(struct fib6_walker_t *w)
 {
        write_lock_bh(&fib6_walker_lock);
-       w->next = fib6_walker_list.next;
-       w->prev = &fib6_walker_list;
-       w->next->prev = w;
-       w->prev->next = w;
+       list_add(&w->lh, &fib6_walkers);
        write_unlock_bh(&fib6_walker_lock);
 }
 
 static inline void fib6_walker_unlink(struct fib6_walker_t *w)
 {
        write_lock_bh(&fib6_walker_lock);
-       w->next->prev = w->prev;
-       w->prev->next = w->next;
-       w->prev = w->next = w;
+       list_del(&w->lh);
        write_unlock_bh(&fib6_walker_lock);
 }
 static __inline__ u32 fib6_new_sernum(void)
@@ -164,12 +156,6 @@ static __inline__ void rt6_release(struct rt6_info *rt)
                dst_free(&rt->u.dst);
 }
 
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-#define FIB_TABLE_HASHSZ 256
-#else
-#define FIB_TABLE_HASHSZ 1
-#endif
-
 static void fib6_link_table(struct net *net, struct fib6_table *tb)
 {
        unsigned int h;
@@ -180,7 +166,7 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb)
         */
        rwlock_init(&tb->tb6_lock);
 
-       h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);
+       h = tb->tb6_id & (FIB6_TABLE_HASHSZ - 1);
 
        /*
         * No protection necessary, this is the only list mutatation
@@ -231,7 +217,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
 
        if (id == 0)
                id = RT6_TABLE_MAIN;
-       h = id & (FIB_TABLE_HASHSZ - 1);
+       h = id & (FIB6_TABLE_HASHSZ - 1);
        rcu_read_lock();
        head = &net->ipv6.fib_table_hash[h];
        hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
@@ -245,7 +231,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
        return NULL;
 }
 
-static void fib6_tables_init(struct net *net)
+static void __net_init fib6_tables_init(struct net *net)
 {
        fib6_link_table(net, net->ipv6.fib6_main_tbl);
        fib6_link_table(net, net->ipv6.fib6_local_tbl);
@@ -268,7 +254,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
        return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
 }
 
-static void fib6_tables_init(struct net *net)
+static void __net_init fib6_tables_init(struct net *net)
 {
        fib6_link_table(net, net->ipv6.fib6_main_tbl);
 }
@@ -287,7 +273,7 @@ static int fib6_dump_node(struct fib6_walker_t *w)
                        w->leaf = rt;
                        return 1;
                }
-               BUG_TRAP(res!=0);
+               WARN_ON(res == 0);
        }
        w->leaf = NULL;
        return 0;
@@ -298,6 +284,10 @@ static void fib6_dump_end(struct netlink_callback *cb)
        struct fib6_walker_t *w = (void*)cb->args[2];
 
        if (w) {
+               if (cb->args[4]) {
+                       cb->args[4] = 0;
+                       fib6_walker_unlink(w);
+               }
                cb->args[2] = 0;
                kfree(w);
        }
@@ -321,24 +311,35 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
        w->root = &table->tb6_root;
 
        if (cb->args[4] == 0) {
+               w->count = 0;
+               w->skip = 0;
+
                read_lock_bh(&table->tb6_lock);
                res = fib6_walk(w);
                read_unlock_bh(&table->tb6_lock);
-               if (res > 0)
+               if (res > 0) {
                        cb->args[4] = 1;
+                       cb->args[5] = w->root->fn_sernum;
+               }
        } else {
+               if (cb->args[5] != w->root->fn_sernum) {
+                       /* Begin at the root if the tree changed */
+                       cb->args[5] = w->root->fn_sernum;
+                       w->state = FWS_INIT;
+                       w->node = w->root;
+                       w->skip = w->count;
+               } else
+                       w->skip = 0;
+
                read_lock_bh(&table->tb6_lock);
                res = fib6_walk_continue(w);
                read_unlock_bh(&table->tb6_lock);
-               if (res != 0) {
-                       if (res < 0)
-                               fib6_walker_unlink(w);
-                       goto end;
+               if (res <= 0) {
+                       fib6_walker_unlink(w);
+                       cb->args[4] = 0;
                }
-               fib6_walker_unlink(w);
-               cb->args[4] = 0;
        }
-end:
+
        return res;
 }
 
@@ -378,9 +379,10 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 
        arg.skb = skb;
        arg.cb = cb;
+       arg.net = net;
        w->args = &arg;
 
-       for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
+       for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
                e = 0;
                head = &net->ipv6.fib_table_hash[h];
                hlist_for_each_entry(tb, node, head, tb6_hlist) {
@@ -661,16 +663,16 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 
 static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt)
 {
-       if (!timer_pending(net->ipv6.ip6_fib_timer) &&
+       if (!timer_pending(&net->ipv6.ip6_fib_timer) &&
            (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE)))
-               mod_timer(net->ipv6.ip6_fib_timer,
+               mod_timer(&net->ipv6.ip6_fib_timer,
                          jiffies + net->ipv6.sysctl.ip6_rt_gc_interval);
 }
 
 void fib6_force_start_gc(struct net *net)
 {
-       if (!timer_pending(net->ipv6.ip6_fib_timer))
-               mod_timer(net->ipv6.ip6_fib_timer,
+       if (!timer_pending(&net->ipv6.ip6_fib_timer))
+               mod_timer(&net->ipv6.ip6_fib_timer,
                          jiffies + net->ipv6.sysctl.ip6_rt_gc_interval);
 }
 
@@ -778,7 +780,7 @@ out:
                        pn->leaf = fib6_find_prefix(info->nl_net, pn);
 #if RT6_DEBUG >= 2
                        if (!pn->leaf) {
-                               BUG_TRAP(pn->leaf != NULL);
+                               WARN_ON(pn->leaf == NULL);
                                pn->leaf = info->nl_net->ipv6.ip6_null_entry;
                        }
 #endif
@@ -942,7 +944,7 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
 
 #ifdef CONFIG_IPV6_SUBTREES
        if (src_len) {
-               BUG_TRAP(saddr!=NULL);
+               WARN_ON(saddr == NULL);
                if (fn && fn->subtree)
                        fn = fib6_locate_1(fn->subtree, saddr, src_len,
                                           offsetof(struct rt6_info, rt6i_src));
@@ -996,9 +998,9 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                RT6_TRACE("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter);
                iter++;
 
-               BUG_TRAP(!(fn->fn_flags&RTN_RTINFO));
-               BUG_TRAP(!(fn->fn_flags&RTN_TL_ROOT));
-               BUG_TRAP(fn->leaf==NULL);
+               WARN_ON(fn->fn_flags & RTN_RTINFO);
+               WARN_ON(fn->fn_flags & RTN_TL_ROOT);
+               WARN_ON(fn->leaf != NULL);
 
                children = 0;
                child = NULL;
@@ -1014,7 +1016,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                        fn->leaf = fib6_find_prefix(net, fn);
 #if RT6_DEBUG >= 2
                        if (fn->leaf==NULL) {
-                               BUG_TRAP(fn->leaf);
+                               WARN_ON(!fn->leaf);
                                fn->leaf = net->ipv6.ip6_null_entry;
                        }
 #endif
@@ -1025,16 +1027,17 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                pn = fn->parent;
 #ifdef CONFIG_IPV6_SUBTREES
                if (FIB6_SUBTREE(pn) == fn) {
-                       BUG_TRAP(fn->fn_flags&RTN_ROOT);
+                       WARN_ON(!(fn->fn_flags & RTN_ROOT));
                        FIB6_SUBTREE(pn) = NULL;
                        nstate = FWS_L;
                } else {
-                       BUG_TRAP(!(fn->fn_flags&RTN_ROOT));
+                       WARN_ON(fn->fn_flags & RTN_ROOT);
 #endif
                        if (pn->right == fn) pn->right = child;
                        else if (pn->left == fn) pn->left = child;
 #if RT6_DEBUG >= 2
-                       else BUG_TRAP(0);
+                       else
+                               WARN_ON(1);
 #endif
                        if (child)
                                child->parent = pn;
@@ -1154,14 +1157,14 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
 
 #if RT6_DEBUG >= 2
        if (rt->u.dst.obsolete>0) {
-               BUG_TRAP(fn==NULL);
+               WARN_ON(fn != NULL);
                return -ENOENT;
        }
 #endif
        if (fn == NULL || rt == net->ipv6.ip6_null_entry)
                return -ENOENT;
 
-       BUG_TRAP(fn->fn_flags&RTN_RTINFO);
+       WARN_ON(!(fn->fn_flags & RTN_RTINFO));
 
        if (!(rt->rt6i_flags&RTF_CACHE)) {
                struct fib6_node *pn = fn;
@@ -1253,9 +1256,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w)
                        w->leaf = fn->leaf;
                case FWS_C:
                        if (w->leaf && fn->fn_flags&RTN_RTINFO) {
-                               int err = w->func(w);
+                               int err;
+
+                               if (w->count < w->skip) {
+                                       w->count++;
+                                       continue;
+                               }
+
+                               err = w->func(w);
                                if (err)
                                        return err;
+
+                               w->count++;
                                continue;
                        }
                        w->state = FWS_U;
@@ -1266,7 +1278,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w)
                        w->node = pn;
 #ifdef CONFIG_IPV6_SUBTREES
                        if (FIB6_SUBTREE(pn) == fn) {
-                               BUG_TRAP(fn->fn_flags&RTN_ROOT);
+                               WARN_ON(!(fn->fn_flags & RTN_ROOT));
                                w->state = FWS_L;
                                continue;
                        }
@@ -1281,7 +1293,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w)
                                continue;
                        }
 #if RT6_DEBUG >= 2
-                       BUG_TRAP(0);
+                       WARN_ON(1);
 #endif
                }
        }
@@ -1323,7 +1335,7 @@ static int fib6_clean_node(struct fib6_walker_t *w)
                        }
                        return 0;
                }
-               BUG_TRAP(res==0);
+               WARN_ON(res != 0);
        }
        w->leaf = rt;
        return 0;
@@ -1349,6 +1361,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root,
        c.w.root = root;
        c.w.func = fib6_clean_node;
        c.w.prune = prune;
+       c.w.count = 0;
+       c.w.skip = 0;
        c.func = func;
        c.arg = arg;
        c.net = net;
@@ -1365,7 +1379,7 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
        unsigned int h;
 
        rcu_read_lock();
-       for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+       for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
                head = &net->ipv6.fib_table_hash[h];
                hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
                        write_lock_bh(&table->tb6_lock);
@@ -1447,27 +1461,23 @@ void fib6_run_gc(unsigned long expires, struct net *net)
                gc_args.timeout = expires ? (int)expires :
                        net->ipv6.sysctl.ip6_rt_gc_interval;
        } else {
-               local_bh_disable();
-               if (!spin_trylock(&fib6_gc_lock)) {
-                       mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ);
-                       local_bh_enable();
+               if (!spin_trylock_bh(&fib6_gc_lock)) {
+                       mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
                        return;
                }
                gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
        }
-       gc_args.more = 0;
 
-       icmp6_dst_gc(&gc_args.more);
+       gc_args.more = icmp6_dst_gc();
 
        fib6_clean_all(net, fib6_age, 0, NULL);
 
        if (gc_args.more)
-               mod_timer(net->ipv6.ip6_fib_timer, jiffies +
-                         net->ipv6.sysctl.ip6_rt_gc_interval);
-       else {
-               del_timer(net->ipv6.ip6_fib_timer);
-               net->ipv6.ip6_fib_timer->expires = 0;
-       }
+               mod_timer(&net->ipv6.ip6_fib_timer,
+                         round_jiffies(jiffies
+                                       + net->ipv6.sysctl.ip6_rt_gc_interval));
+       else
+               del_timer(&net->ipv6.ip6_fib_timer);
        spin_unlock_bh(&fib6_gc_lock);
 }
 
@@ -1476,26 +1486,17 @@ static void fib6_gc_timer_cb(unsigned long arg)
        fib6_run_gc(0, (struct net *)arg);
 }
 
-static int fib6_net_init(struct net *net)
+static int __net_init fib6_net_init(struct net *net)
 {
-       int ret;
-       struct timer_list *timer;
-
-       ret = -ENOMEM;
-       timer = kzalloc(sizeof(*timer), GFP_KERNEL);
-       if (!timer)
-               goto out;
-
-       setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net);
-       net->ipv6.ip6_fib_timer = timer;
+       setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net);
 
        net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
        if (!net->ipv6.rt6_stats)
                goto out_timer;
 
-       net->ipv6.fib_table_hash =
-               kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
-                       GFP_KERNEL);
+       net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ,
+                                          sizeof(*net->ipv6.fib_table_hash),
+                                          GFP_KERNEL);
        if (!net->ipv6.fib_table_hash)
                goto out_rt6_stats;
 
@@ -1521,9 +1522,7 @@ static int fib6_net_init(struct net *net)
 #endif
        fib6_tables_init(net);
 
-       ret = 0;
-out:
-       return ret;
+       return 0;
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 out_fib6_main_tbl:
@@ -1534,15 +1533,14 @@ out_fib_table_hash:
 out_rt6_stats:
        kfree(net->ipv6.rt6_stats);
 out_timer:
-       kfree(timer);
-       goto out;
+       return -ENOMEM;
  }
 
 static void fib6_net_exit(struct net *net)
 {
        rt6_ifdown(net, NULL);
-       del_timer_sync(net->ipv6.ip6_fib_timer);
-       kfree(net->ipv6.ip6_fib_timer);
+       del_timer_sync(&net->ipv6.ip6_fib_timer);
+
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
        kfree(net->ipv6.fib6_local_tbl);
 #endif