[IPv4]: FIB configuration using struct fib_config
[pandora-kernel.git] / net / ipv4 / fib_trie.c
index ccd3efc..41bef0a 100644 (file)
@@ -50,9 +50,8 @@
  *             Patrick McHardy <kaber@trash.net>
  */
 
-#define VERSION "0.406"
+#define VERSION "0.407"
 
-#include <linux/config.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -314,11 +313,6 @@ static void __leaf_free_rcu(struct rcu_head *head)
        kfree(container_of(head, struct leaf, rcu));
 }
 
-static inline void free_leaf(struct leaf *leaf)
-{
-       call_rcu(&leaf->rcu, __leaf_free_rcu);
-}
-
 static void __leaf_info_free_rcu(struct rcu_head *head)
 {
        kfree(container_of(head, struct leaf_info, rcu));
@@ -357,7 +351,12 @@ static void __tnode_free_rcu(struct rcu_head *head)
 
 static inline void tnode_free(struct tnode *tn)
 {
-       call_rcu(&tn->rcu, __tnode_free_rcu);
+       if(IS_LEAF(tn)) {
+               struct leaf *l = (struct leaf *) tn;
+               call_rcu_bh(&l->rcu, __leaf_free_rcu);
+       }
+        else
+               call_rcu(&tn->rcu, __tnode_free_rcu);
 }
 
 static struct leaf *leaf_new(void)
@@ -1125,17 +1124,14 @@ err:
        return fa_head;
 }
 
-static int
-fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
-              struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
+static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
 {
        struct trie *t = (struct trie *) tb->tb_data;
        struct fib_alias *fa, *new_fa;
        struct list_head *fa_head = NULL;
        struct fib_info *fi;
-       int plen = r->rtm_dst_len;
-       int type = r->rtm_type;
-       u8 tos = r->rtm_tos;
+       int plen = cfg->fc_dst_len;
+       u8 tos = cfg->fc_tos;
        u32 key, mask;
        int err;
        struct leaf *l;
@@ -1143,13 +1139,9 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
        if (plen > 32)
                return -EINVAL;
 
-       key = 0;
-       if (rta->rta_dst)
-               memcpy(&key, rta->rta_dst, 4);
-
-       key = ntohl(key);
+       key = ntohl(cfg->fc_dst);
 
-       pr_debug("Insert table=%d %08x/%d\n", tb->tb_id, key, plen);
+       pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
 
        mask = ntohl(inet_make_mask(plen));
 
@@ -1158,10 +1150,11 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
 
        key = key & mask;
 
-       fi = fib_create_info(r, rta, nlhdr, &err);
-
-       if (!fi)
+       fi = fib_create_info(cfg);
+       if (IS_ERR(fi)) {
+               err = PTR_ERR(fi);
                goto err;
+       }
 
        l = fib_find_node(t, key);
        fa = NULL;
@@ -1186,10 +1179,10 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                struct fib_alias *fa_orig;
 
                err = -EEXIST;
-               if (nlhdr->nlmsg_flags & NLM_F_EXCL)
+               if (cfg->fc_nlflags & NLM_F_EXCL)
                        goto out;
 
-               if (nlhdr->nlmsg_flags & NLM_F_REPLACE) {
+               if (cfg->fc_nlflags & NLM_F_REPLACE) {
                        struct fib_info *fi_drop;
                        u8 state;
 
@@ -1201,8 +1194,8 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                        fi_drop = fa->fa_info;
                        new_fa->fa_tos = fa->fa_tos;
                        new_fa->fa_info = fi;
-                       new_fa->fa_type = type;
-                       new_fa->fa_scope = r->rtm_scope;
+                       new_fa->fa_type = cfg->fc_type;
+                       new_fa->fa_scope = cfg->fc_scope;
                        state = fa->fa_state;
                        new_fa->fa_state &= ~FA_S_ACCESSED;
 
@@ -1225,17 +1218,17 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                                break;
                        if (fa->fa_info->fib_priority != fi->fib_priority)
                                break;
-                       if (fa->fa_type == type &&
-                           fa->fa_scope == r->rtm_scope &&
+                       if (fa->fa_type == cfg->fc_type &&
+                           fa->fa_scope == cfg->fc_scope &&
                            fa->fa_info == fi) {
                                goto out;
                        }
                }
-               if (!(nlhdr->nlmsg_flags & NLM_F_APPEND))
+               if (!(cfg->fc_nlflags & NLM_F_APPEND))
                        fa = fa_orig;
        }
        err = -ENOENT;
-       if (!(nlhdr->nlmsg_flags & NLM_F_CREATE))
+       if (!(cfg->fc_nlflags & NLM_F_CREATE))
                goto out;
 
        err = -ENOBUFS;
@@ -1245,16 +1238,16 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
 
        new_fa->fa_info = fi;
        new_fa->fa_tos = tos;
-       new_fa->fa_type = type;
-       new_fa->fa_scope = r->rtm_scope;
+       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.
         */
 
        if (!fa_head) {
-               fa_head = fib_insert_node(t, &err, key, plen);
                err = 0;
+               fa_head = fib_insert_node(t, &err, key, plen);
                if (err)
                        goto out_free_new_fa;
        }
@@ -1263,7 +1256,8 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                          (fa ? &fa->fa_list : fa_head));
 
        rt_cache_flush(-1);
-       rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
+       rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
+                 &cfg->fc_nlinfo);
 succeeded:
        return 0;
 
@@ -1282,18 +1276,18 @@ static inline int check_leaf(struct trie *t, struct leaf *l,
                             struct fib_result *res)
 {
        int err, i;
-       t_key mask;
+       __be32 mask;
        struct leaf_info *li;
        struct hlist_head *hhead = &l->list;
        struct hlist_node *node;
 
        hlist_for_each_entry_rcu(li, node, hhead, hlist) {
                i = li->plen;
-               mask = ntohl(inet_make_mask(i));
-               if (l->key != (key & mask))
+               mask = inet_make_mask(i);
+               if (l->key != (key & ntohl(mask)))
                        continue;
 
-               if ((err = fib_semantic_match(&li->falh, flp, res, l->key, mask, i)) <= 0) {
+               if ((err = fib_semantic_match(&li->falh, flp, res, htonl(l->key), mask, i)) <= 0) {
                        *plen = i;
 #ifdef CONFIG_IP_FIB_TRIE_STATS
                        t->stats.semantic_match_passed++;
@@ -1549,28 +1543,21 @@ static int trie_leaf_remove(struct trie *t, t_key key)
        return 1;
 }
 
-static int
-fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
-               struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
+static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
 {
        struct trie *t = (struct trie *) tb->tb_data;
        u32 key, mask;
-       int plen = r->rtm_dst_len;
-       u8 tos = r->rtm_tos;
+       int plen = cfg->fc_dst_len;
+       u8 tos = cfg->fc_tos;
        struct fib_alias *fa, *fa_to_delete;
        struct list_head *fa_head;
        struct leaf *l;
        struct leaf_info *li;
 
-
        if (plen > 32)
                return -EINVAL;
 
-       key = 0;
-       if (rta->rta_dst)
-               memcpy(&key, rta->rta_dst, 4);
-
-       key = ntohl(key);
+       key = ntohl(cfg->fc_dst);
        mask = ntohl(inet_make_mask(plen));
 
        if (key & ~mask)
@@ -1599,13 +1586,12 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                if (fa->fa_tos != tos)
                        break;
 
-               if ((!r->rtm_type ||
-                    fa->fa_type == r->rtm_type) &&
-                   (r->rtm_scope == RT_SCOPE_NOWHERE ||
-                    fa->fa_scope == r->rtm_scope) &&
-                   (!r->rtm_protocol ||
-                    fi->fib_protocol == r->rtm_protocol) &&
-                   fib_nh_match(r, nlhdr, rta, fi) == 0) {
+               if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) &&
+                   (cfg->fc_scope == RT_SCOPE_NOWHERE ||
+                    fa->fa_scope == cfg->fc_scope) &&
+                   (!cfg->fc_protocol ||
+                    fi->fib_protocol == cfg->fc_protocol) &&
+                   fib_nh_match(cfg, fi) == 0) {
                        fa_to_delete = fa;
                        break;
                }
@@ -1615,7 +1601,8 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                return -ESRCH;
 
        fa = fa_to_delete;
-       rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);
+       rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id,
+                 &cfg->fc_nlinfo);
 
        l = fib_find_node(t, key);
        li = find_leaf_info(l, plen);
@@ -1849,7 +1836,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
 
        u32 xkey = htonl(key);
 
-       s_i = cb->args[3];
+       s_i = cb->args[4];
        i = 0;
 
        /* rcu_read_lock is hold by caller */
@@ -1871,12 +1858,12 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
                                  plen,
                                  fa->fa_tos,
                                  fa->fa_info, 0) < 0) {
-                       cb->args[3] = i;
+                       cb->args[4] = i;
                        return -1;
                }
                i++;
        }
-       cb->args[3] = i;
+       cb->args[4] = i;
        return skb->len;
 }
 
@@ -1887,14 +1874,14 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, str
        struct list_head *fa_head;
        struct leaf *l = NULL;
 
-       s_h = cb->args[2];
+       s_h = cb->args[3];
 
        for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
                if (h < s_h)
                        continue;
                if (h > s_h)
-                       memset(&cb->args[3], 0,
-                              sizeof(cb->args) - 3*sizeof(cb->args[0]));
+                       memset(&cb->args[4], 0,
+                              sizeof(cb->args) - 4*sizeof(cb->args[0]));
 
                fa_head = get_fa_head(l, plen);
 
@@ -1905,11 +1892,11 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, str
                        continue;
 
                if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
-                       cb->args[2] = h;
+                       cb->args[3] = h;
                        return -1;
                }
        }
-       cb->args[2] = h;
+       cb->args[3] = h;
        return skb->len;
 }
 
@@ -1918,23 +1905,23 @@ static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
        int m, s_m;
        struct trie *t = (struct trie *) tb->tb_data;
 
-       s_m = cb->args[1];
+       s_m = cb->args[2];
 
        rcu_read_lock();
        for (m = 0; m <= 32; m++) {
                if (m < s_m)
                        continue;
                if (m > s_m)
-                       memset(&cb->args[2], 0,
-                               sizeof(cb->args) - 2*sizeof(cb->args[0]));
+                       memset(&cb->args[3], 0,
+                               sizeof(cb->args) - 3*sizeof(cb->args[0]));
 
                if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
-                       cb->args[1] = m;
+                       cb->args[2] = m;
                        goto out;
                }
        }
        rcu_read_unlock();
-       cb->args[1] = m;
+       cb->args[2] = m;
        return skb->len;
 out:
        rcu_read_unlock();
@@ -1944,9 +1931,9 @@ out:
 /* Fix more generic FIB names for init later */
 
 #ifdef CONFIG_IP_MULTIPLE_TABLES
-struct fib_table * fib_hash_init(int id)
+struct fib_table * fib_hash_init(u32 id)
 #else
-struct fib_table * __init fib_hash_init(int id)
+struct fib_table * __init fib_hash_init(u32 id)
 #endif
 {
        struct fib_table *tb;