Skip to content

Commit

Permalink
[NETNS][IPV6] ip6_fib - make it per network namespace
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Daniel Lezcano authored and David S. Miller committed Mar 4, 2008
1 parent e0b8559 commit 58f09b7
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 86 deletions.
9 changes: 5 additions & 4 deletions include/net/ip6_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,11 @@ typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *,
* 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,
Expand Down
5 changes: 5 additions & 0 deletions include/net/netns/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ struct netns_ipv6 {
struct xt_table *ip6table_filter;
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;
};
Expand Down
8 changes: 4 additions & 4 deletions net/ipv6/fib6_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ struct fib6_rule

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,
Expand Down Expand Up @@ -71,7 +71,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
goto discard_pkt;
}

table = fib6_get_table(rule->table);
table = fib6_get_table(&init_net, rule->table);
if (table)
rt = lookup(table, flp, flags);

Expand Down Expand Up @@ -151,7 +151,7 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
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;
}
Expand Down
161 changes: 93 additions & 68 deletions net/ipv6/ip6_fib.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,13 @@ static __inline__ void rt6_release(struct rt6_info *rt)
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;

Expand All @@ -191,13 +188,11 @@ static void fib6_link_table(struct fib6_table *tb)
* 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;
Expand All @@ -212,34 +207,36 @@ static struct fib6_table *fib6_alloc_table(u32 id)
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;

if (id == 0)
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;
Expand All @@ -250,33 +247,32 @@ struct fib6_table *fib6_get_table(u32 id)
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
Expand Down Expand Up @@ -357,11 +353,9 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
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];

Expand Down Expand Up @@ -390,7 +384,8 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)

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);
Expand Down Expand Up @@ -1360,12 +1355,13 @@ void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
{
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);
Expand Down Expand Up @@ -1466,55 +1462,88 @@ void fib6_run_gc(unsigned long dummy)
spin_unlock_bh(&fib6_gc_lock);
}

int __init fib6_init(void)
static int fib6_net_init(struct net *net)
{
int ret = -ENOMEM;
fib6_node_kmem = kmem_cache_create("fib6_nodes",
sizeof(struct fib6_node),
0, SLAB_HWCACHE_ALIGN,
NULL);
if (!fib6_node_kmem)
goto out;
int ret;

fib_table_hash = kzalloc(sizeof(*fib_table_hash)*FIB_TABLE_HASHSZ,
GFP_KERNEL);
if (!fib_table_hash)
goto out_kmem_cache_create;
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;

fib6_main_tbl = kzalloc(sizeof(*fib6_main_tbl), GFP_KERNEL);
if (!fib6_main_tbl)
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;

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;
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
fib6_local_tbl = kzalloc(sizeof(*fib6_local_tbl), GFP_KERNEL);
if (!fib6_local_tbl)
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;

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;
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);

fib6_tables_init();

ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
if (ret)
goto out_fib6_local_tbl;
ret = 0;
out:
return ret;

out_fib6_local_tbl:
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
kfree(fib6_local_tbl);
out_fib6_main_tbl:
kfree(net->ipv6.fib6_main_tbl);
#endif
kfree(fib6_main_tbl);
out_fib_table_hash:
kfree(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;
fib6_node_kmem = kmem_cache_create("fib6_nodes",
sizeof(struct fib6_node),
0, SLAB_HWCACHE_ALIGN,
NULL);
if (!fib6_node_kmem)
goto out;

ret = register_pernet_subsys(&fib6_net_ops);
if (ret)
goto out_kmem_cache_create;

ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
if (ret)
goto out_unregister_subsys;
out:
return ret;

out_unregister_subsys:
unregister_pernet_subsys(&fib6_net_ops);
out_kmem_cache_create:
kmem_cache_destroy(fib6_node_kmem);
goto out;
Expand All @@ -1523,10 +1552,6 @@ int __init fib6_init(void)
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);
}
Loading

0 comments on commit 58f09b7

Please sign in to comment.