[NETNS][IPV6] ip6_fib - make it per network namespace
The fib table for ipv6 are moved to the network namespace structure.
All references to them are made relatively to the network namespace.
All external calls to the ip6_fib functions taking the network
namespace parameter are made using the init_net variable, so the
ip6_fib engine is ready for the namespaces but the callers not yet.
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 953d604..4d4c8ac 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -181,10 +181,11 @@
* exported functions
*/
-extern struct fib6_table * fib6_get_table(u32 id);
-extern struct fib6_table * fib6_new_table(u32 id);
-extern struct dst_entry * fib6_rule_lookup(struct flowi *fl, int flags,
- pol_lookup_t lookup);
+extern struct fib6_table *fib6_get_table(struct net *net, u32 id);
+extern struct fib6_table *fib6_new_table(struct net *net, u32 id);
+extern struct dst_entry *fib6_rule_lookup(struct net *net,
+ struct flowi *fl, int flags,
+ pol_lookup_t lookup);
extern struct fib6_node *fib6_lookup(struct fib6_node *root,
struct in6_addr *daddr,
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 82623d3..b065326 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -36,6 +36,11 @@
struct xt_table *ip6table_mangle;
struct xt_table *ip6table_raw;
#endif
+ struct hlist_head *fib_table_hash;
+ struct fib6_table *fib6_main_tbl;
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ struct fib6_table *fib6_local_tbl;
+#endif
struct sock **icmp_sk;
};
#endif
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 157db3a..03ad23a 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -31,8 +31,8 @@
static struct fib_rules_ops fib6_rules_ops;
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
- pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+ int flags, pol_lookup_t lookup)
{
struct fib_lookup_arg arg = {
.lookup_ptr = lookup,
@@ -71,7 +71,7 @@
goto discard_pkt;
}
- table = fib6_get_table(rule->table);
+ table = fib6_get_table(&init_net, rule->table);
if (table)
rt = lookup(table, flp, flags);
@@ -151,7 +151,7 @@
if (rule->table == RT6_TABLE_UNSPEC)
goto errout;
- if (fib6_new_table(rule->table) == NULL) {
+ if (fib6_new_table(&init_net, rule->table) == NULL) {
err = -ENOBUFS;
goto errout;
}
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 04d7749..7b549f0 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -166,16 +166,13 @@
dst_free(&rt->u.dst);
}
-static struct fib6_table *fib6_main_tbl;
-
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
#define FIB_TABLE_HASHSZ 256
#else
#define FIB_TABLE_HASHSZ 1
#endif
-static struct hlist_head *fib_table_hash;
-static void fib6_link_table(struct fib6_table *tb)
+static void fib6_link_table(struct net *net, struct fib6_table *tb)
{
unsigned int h;
@@ -191,13 +188,11 @@
* No protection necessary, this is the only list mutatation
* operation, tables never disappear once they exist.
*/
- hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
+ hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]);
}
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-static struct fib6_table *fib6_local_tbl;
-
static struct fib6_table *fib6_alloc_table(u32 id)
{
struct fib6_table *table;
@@ -212,26 +207,27 @@
return table;
}
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
{
struct fib6_table *tb;
if (id == 0)
id = RT6_TABLE_MAIN;
- tb = fib6_get_table(id);
+ tb = fib6_get_table(net, id);
if (tb)
return tb;
tb = fib6_alloc_table(id);
if (tb != NULL)
- fib6_link_table(tb);
+ fib6_link_table(net, tb);
return tb;
}
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
{
struct fib6_table *tb;
+ struct hlist_head *head;
struct hlist_node *node;
unsigned int h;
@@ -239,7 +235,8 @@
id = RT6_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
rcu_read_lock();
- hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
+ head = &net->ipv6.fib_table_hash[h];
+ hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
if (tb->tb6_id == id) {
rcu_read_unlock();
return tb;
@@ -250,33 +247,32 @@
return NULL;
}
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
{
- fib6_link_table(fib6_main_tbl);
- fib6_link_table(fib6_local_tbl);
+ fib6_link_table(net, net->ipv6.fib6_main_tbl);
+ fib6_link_table(net, net->ipv6.fib6_local_tbl);
}
-
#else
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
{
- return fib6_get_table(id);
+ return fib6_get_table(net, id);
}
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
{
- return fib6_main_tbl;
+ return net->ipv6.fib6_main_tbl;
}
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
- pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+ int flags, pol_lookup_t lookup)
{
- return (struct dst_entry *) lookup(fib6_main_tbl, fl, flags);
+ return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags);
}
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
{
- fib6_link_table(fib6_main_tbl);
+ fib6_link_table(net, net->ipv6.fib6_main_tbl);
}
#endif
@@ -357,11 +353,9 @@
struct fib6_walker_t *w;
struct fib6_table *tb;
struct hlist_node *node;
+ struct hlist_head *head;
int res = 0;
- if (net != &init_net)
- return 0;
-
s_h = cb->args[0];
s_e = cb->args[1];
@@ -390,7 +384,8 @@
for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
e = 0;
- hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) {
+ head = &net->ipv6.fib_table_hash[h];
+ hlist_for_each_entry(tb, node, head, tb6_hlist) {
if (e < s_e)
goto next;
res = fib6_dump_table(tb, skb, cb);
@@ -1360,12 +1355,13 @@
{
struct fib6_table *table;
struct hlist_node *node;
+ struct hlist_head *head;
unsigned int h;
rcu_read_lock();
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
- hlist_for_each_entry_rcu(table, node, &fib_table_hash[h],
- tb6_hlist) {
+ head = &init_net.ipv6.fib_table_hash[h];
+ hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
write_lock_bh(&table->tb6_lock);
fib6_clean_tree(&table->tb6_root, func, prune, arg);
write_unlock_bh(&table->tb6_lock);
@@ -1466,6 +1462,66 @@
spin_unlock_bh(&fib6_gc_lock);
}
+static int fib6_net_init(struct net *net)
+{
+ int ret;
+
+ ret = -ENOMEM;
+ net->ipv6.fib_table_hash =
+ kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
+ GFP_KERNEL);
+ if (!net->ipv6.fib_table_hash)
+ goto out;
+
+ net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
+ GFP_KERNEL);
+ if (!net->ipv6.fib6_main_tbl)
+ goto out_fib_table_hash;
+
+ net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
+ net->ipv6.fib6_main_tbl->tb6_root.leaf = &ip6_null_entry;
+ net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
+ RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
+ GFP_KERNEL);
+ if (!net->ipv6.fib6_local_tbl)
+ goto out_fib6_main_tbl;
+ net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
+ net->ipv6.fib6_local_tbl->tb6_root.leaf = &ip6_null_entry;
+ net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
+ RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+#endif
+ fib6_tables_init(net);
+
+ ret = 0;
+out:
+ return ret;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+out_fib6_main_tbl:
+ kfree(net->ipv6.fib6_main_tbl);
+#endif
+out_fib_table_hash:
+ kfree(net->ipv6.fib_table_hash);
+ goto out;
+ }
+
+static void fib6_net_exit(struct net *net)
+{
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ kfree(net->ipv6.fib6_local_tbl);
+#endif
+ kfree(net->ipv6.fib6_main_tbl);
+ kfree(net->ipv6.fib_table_hash);
+}
+
+static struct pernet_operations fib6_net_ops = {
+ .init = fib6_net_init,
+ .exit = fib6_net_exit,
+};
+
int __init fib6_init(void)
{
int ret = -ENOMEM;
@@ -1476,45 +1532,18 @@
if (!fib6_node_kmem)
goto out;
- fib_table_hash = kzalloc(sizeof(*fib_table_hash)*FIB_TABLE_HASHSZ,
- GFP_KERNEL);
- if (!fib_table_hash)
+ ret = register_pernet_subsys(&fib6_net_ops);
+ if (ret)
goto out_kmem_cache_create;
- fib6_main_tbl = kzalloc(sizeof(*fib6_main_tbl), GFP_KERNEL);
- if (!fib6_main_tbl)
- goto out_fib_table_hash;
-
- fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
- fib6_main_tbl->tb6_root.leaf = &ip6_null_entry;
- fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
-
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- fib6_local_tbl = kzalloc(sizeof(*fib6_local_tbl), GFP_KERNEL);
- if (!fib6_local_tbl)
- goto out_fib6_main_tbl;
-
- fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
- fib6_local_tbl->tb6_root.leaf = &ip6_null_entry;
- fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
-#endif
-
- fib6_tables_init();
-
ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
if (ret)
- goto out_fib6_local_tbl;
+ goto out_unregister_subsys;
out:
return ret;
-out_fib6_local_tbl:
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- kfree(fib6_local_tbl);
-out_fib6_main_tbl:
-#endif
- kfree(fib6_main_tbl);
-out_fib_table_hash:
- kfree(fib_table_hash);
+out_unregister_subsys:
+ unregister_pernet_subsys(&fib6_net_ops);
out_kmem_cache_create:
kmem_cache_destroy(fib6_node_kmem);
goto out;
@@ -1523,10 +1552,6 @@
void fib6_gc_cleanup(void)
{
del_timer(&ip6_fib_timer);
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- kfree(fib6_local_tbl);
-#endif
- kfree(fib6_main_tbl);
- kfree(fib_table_hash);
+ unregister_pernet_subsys(&fib6_net_ops);
kmem_cache_destroy(fib6_node_kmem);
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index cd71745..09206f7 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -571,7 +571,7 @@
flags |= RT6_LOOKUP_F_HAS_SADDR;
}
- dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
+ dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_lookup);
if (dst->error == 0)
return (struct rt6_info *) dst;
@@ -758,7 +758,7 @@
if (rt6_need_strict(&iph->daddr))
flags |= RT6_LOOKUP_F_IFACE;
- skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
+ skb->dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_input);
}
static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
@@ -777,7 +777,7 @@
if (!ipv6_addr_any(&fl->fl6_src))
flags |= RT6_LOOKUP_F_HAS_SADDR;
- return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
+ return fib6_rule_lookup(&init_net, fl, flags, ip6_pol_route_output);
}
EXPORT_SYMBOL(ip6_route_output);
@@ -1069,7 +1069,7 @@
if (cfg->fc_metric == 0)
cfg->fc_metric = IP6_RT_PRIO_USER;
- table = fib6_new_table(cfg->fc_table);
+ table = fib6_new_table(&init_net, cfg->fc_table);
if (table == NULL) {
err = -ENOBUFS;
goto out;
@@ -1275,7 +1275,7 @@
struct rt6_info *rt;
int err = -ESRCH;
- table = fib6_get_table(cfg->fc_table);
+ table = fib6_get_table(&init_net, cfg->fc_table);
if (table == NULL)
return err;
@@ -1390,7 +1390,9 @@
if (rt6_need_strict(dest))
flags |= RT6_LOOKUP_F_IFACE;
- return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
+ return (struct rt6_info *)fib6_rule_lookup(&init_net,
+ (struct flowi *)&rdfl,
+ flags, __ip6_route_redirect);
}
void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
@@ -1589,7 +1591,7 @@
struct rt6_info *rt = NULL;
struct fib6_table *table;
- table = fib6_get_table(RT6_TABLE_INFO);
+ table = fib6_get_table(&init_net, RT6_TABLE_INFO);
if (table == NULL)
return NULL;
@@ -1644,7 +1646,7 @@
struct rt6_info *rt;
struct fib6_table *table;
- table = fib6_get_table(RT6_TABLE_DFLT);
+ table = fib6_get_table(&init_net, RT6_TABLE_DFLT);
if (table == NULL)
return NULL;
@@ -1688,7 +1690,7 @@
struct fib6_table *table;
/* NOTE: Keep consistent with rt6_get_dflt_router */
- table = fib6_get_table(RT6_TABLE_DFLT);
+ table = fib6_get_table(&init_net, RT6_TABLE_DFLT);
if (table == NULL)
return;
@@ -1851,7 +1853,7 @@
ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
rt->rt6i_dst.plen = 128;
- rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL);
+ rt->rt6i_table = fib6_get_table(&init_net, RT6_TABLE_LOCAL);
atomic_set(&rt->u.dst.__refcnt, 1);