OSDN Git Service

Merge branch 'master' into ysato-h8300
[uclinux-h8/linux.git] / include / net / ip_fib.h
index 09a819e..54271ed 100644 (file)
@@ -136,7 +136,7 @@ struct fib_result {
        u32             tclassid;
        struct fib_info *fi;
        struct fib_table *table;
-       struct list_head *fa_head;
+       struct hlist_head *fa_head;
 };
 
 struct fib_result_nl {
@@ -185,7 +185,9 @@ struct fib_table {
        u32                     tb_id;
        int                     tb_default;
        int                     tb_num_default;
-       unsigned long           tb_data[0];
+       struct rcu_head         rcu;
+       unsigned long           *tb_data;
+       unsigned long           __data[0];
 };
 
 int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
@@ -195,10 +197,10 @@ int fib_table_delete(struct fib_table *, struct fib_config *);
 int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
                   struct netlink_callback *cb);
 int fib_table_flush(struct fib_table *table);
+struct fib_table *fib_trie_unmerge(struct fib_table *main_tb);
+void fib_table_flush_external(struct fib_table *table);
 void fib_free_table(struct fib_table *tb);
 
-
-
 #ifndef CONFIG_IP_MULTIPLE_TABLES
 
 #define TABLE_LOCAL_INDEX      (RT_TABLE_LOCAL & (FIB_TABLE_HASHSZ - 1))
@@ -206,12 +208,16 @@ void fib_free_table(struct fib_table *tb);
 
 static inline struct fib_table *fib_get_table(struct net *net, u32 id)
 {
+       struct hlist_node *tb_hlist;
        struct hlist_head *ptr;
 
        ptr = id == RT_TABLE_LOCAL ?
                &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] :
                &net->ipv4.fib_table_hash[TABLE_MAIN_INDEX];
-       return hlist_entry(ptr->first, struct fib_table, tb_hlist);
+
+       tb_hlist = rcu_dereference_rtnl(hlist_first_rcu(ptr));
+
+       return hlist_entry(tb_hlist, struct fib_table, tb_hlist);
 }
 
 static inline struct fib_table *fib_new_table(struct net *net, u32 id)
@@ -222,16 +228,18 @@ static inline struct fib_table *fib_new_table(struct net *net, u32 id)
 static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
                             struct fib_result *res)
 {
-       struct fib_table *table;
+       struct fib_table *tb;
+       int err = -ENETUNREACH;
+
+       rcu_read_lock();
+
+       tb = fib_get_table(net, RT_TABLE_MAIN);
+       if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
+               err = 0;
 
-       table = fib_get_table(net, RT_TABLE_LOCAL);
-       if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
-               return 0;
+       rcu_read_unlock();
 
-       table = fib_get_table(net, RT_TABLE_MAIN);
-       if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
-               return 0;
-       return -ENETUNREACH;
+       return err;
 }
 
 #else /* CONFIG_IP_MULTIPLE_TABLES */
@@ -246,23 +254,29 @@ int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res);
 static inline int fib_lookup(struct net *net, struct flowi4 *flp,
                             struct fib_result *res)
 {
-       if (!net->ipv4.fib_has_custom_rules) {
-               res->tclassid = 0;
-               if (net->ipv4.fib_local &&
-                   !fib_table_lookup(net->ipv4.fib_local, flp, res,
-                                     FIB_LOOKUP_NOREF))
-                       return 0;
-               if (net->ipv4.fib_main &&
-                   !fib_table_lookup(net->ipv4.fib_main, flp, res,
-                                     FIB_LOOKUP_NOREF))
-                       return 0;
-               if (net->ipv4.fib_default &&
-                   !fib_table_lookup(net->ipv4.fib_default, flp, res,
-                                     FIB_LOOKUP_NOREF))
-                       return 0;
-               return -ENETUNREACH;
+       struct fib_table *tb;
+       int err;
+
+       if (net->ipv4.fib_has_custom_rules)
+               return __fib_lookup(net, flp, res);
+
+       rcu_read_lock();
+
+       res->tclassid = 0;
+
+       for (err = 0; !err; err = -ENETUNREACH) {
+               tb = rcu_dereference_rtnl(net->ipv4.fib_main);
+               if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
+                       break;
+
+               tb = rcu_dereference_rtnl(net->ipv4.fib_default);
+               if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
+                       break;
        }
-       return __fib_lookup(net, flp, res);
+
+       rcu_read_unlock();
+
+       return err;
 }
 
 #endif /* CONFIG_IP_MULTIPLE_TABLES */
@@ -286,6 +300,8 @@ static inline int fib_num_tclassid_users(struct net *net)
        return 0;
 }
 #endif
+int fib_unmerge(struct net *net);
+void fib_flush_external(struct net *net);
 
 /* Exported by fib_semantics.c */
 int ip_fib_check_default(__be32 gw, struct net_device *dev);
@@ -296,7 +312,7 @@ void fib_select_multipath(struct fib_result *res);
 
 /* Exported by fib_trie.c */
 void fib_trie_init(void);
-struct fib_table *fib_trie_table(u32 id);
+struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
 
 static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
 {