Commit 8ed67789 authored by Daniel Lezcano's avatar Daniel Lezcano Committed by David S. Miller

[NETNS][IPV6] rt6_info - move rt6_info structure inside the namespace

The rt6_info structures are moved inside the network namespace
structure. All references to these structures are now relative to the
initial network namespace.
Signed-off-by: default avatarDaniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: default avatarBenjamin Thery <benjamin.thery@bull.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bdb3289f
...@@ -174,7 +174,8 @@ struct fib6_table { ...@@ -174,7 +174,8 @@ struct fib6_table {
#define RT6_TABLE_LOCAL RT6_TABLE_MAIN #define RT6_TABLE_LOCAL RT6_TABLE_MAIN
#endif #endif
typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *, typedef struct rt6_info *(*pol_lookup_t)(struct net *,
struct fib6_table *,
struct flowi *, int); struct flowi *, int);
/* /*
......
...@@ -36,11 +36,14 @@ struct netns_ipv6 { ...@@ -36,11 +36,14 @@ struct netns_ipv6 {
struct xt_table *ip6table_mangle; struct xt_table *ip6table_mangle;
struct xt_table *ip6table_raw; struct xt_table *ip6table_raw;
#endif #endif
struct rt6_info *ip6_null_entry;
struct rt6_statistics *rt6_stats; struct rt6_statistics *rt6_stats;
struct timer_list *ip6_fib_timer; struct timer_list *ip6_fib_timer;
struct hlist_head *fib_table_hash; struct hlist_head *fib_table_hash;
struct fib6_table *fib6_main_tbl; struct fib6_table *fib6_main_tbl;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
struct rt6_info *ip6_prohibit_entry;
struct rt6_info *ip6_blk_hole_entry;
struct fib6_table *fib6_local_tbl; struct fib6_table *fib6_local_tbl;
struct fib_rules_ops *fib6_rules_ops; struct fib_rules_ops *fib6_rules_ops;
#endif #endif
......
...@@ -4301,15 +4301,6 @@ int __init addrconf_init(void) ...@@ -4301,15 +4301,6 @@ int __init addrconf_init(void)
if (err) if (err)
goto errlo; goto errlo;
ip6_null_entry->u.dst.dev = init_net.loopback_dev;
ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
#endif
register_netdevice_notifier(&ipv6_dev_notf); register_netdevice_notifier(&ipv6_dev_notf);
addrconf_verify(0); addrconf_verify(0);
......
...@@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, ...@@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
if (arg.result) if (arg.result)
return arg.result; return arg.result;
dst_hold(&ip6_null_entry->u.dst); dst_hold(&net->ipv6.ip6_null_entry->u.dst);
return &ip6_null_entry->u.dst; return &net->ipv6.ip6_null_entry->u.dst;
} }
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
...@@ -52,28 +52,29 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, ...@@ -52,28 +52,29 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
{ {
struct rt6_info *rt = NULL; struct rt6_info *rt = NULL;
struct fib6_table *table; struct fib6_table *table;
struct net *net = rule->fr_net;
pol_lookup_t lookup = arg->lookup_ptr; pol_lookup_t lookup = arg->lookup_ptr;
switch (rule->action) { switch (rule->action) {
case FR_ACT_TO_TBL: case FR_ACT_TO_TBL:
break; break;
case FR_ACT_UNREACHABLE: case FR_ACT_UNREACHABLE:
rt = ip6_null_entry; rt = net->ipv6.ip6_null_entry;
goto discard_pkt; goto discard_pkt;
default: default:
case FR_ACT_BLACKHOLE: case FR_ACT_BLACKHOLE:
rt = ip6_blk_hole_entry; rt = net->ipv6.ip6_blk_hole_entry;
goto discard_pkt; goto discard_pkt;
case FR_ACT_PROHIBIT: case FR_ACT_PROHIBIT:
rt = ip6_prohibit_entry; rt = net->ipv6.ip6_prohibit_entry;
goto discard_pkt; goto discard_pkt;
} }
table = fib6_get_table(rule->fr_net, rule->table); table = fib6_get_table(net, rule->table);
if (table) if (table)
rt = lookup(table, flp, flags); rt = lookup(net, table, flp, flags);
if (rt != ip6_null_entry) { if (rt != net->ipv6.ip6_null_entry) {
struct fib6_rule *r = (struct fib6_rule *)rule; struct fib6_rule *r = (struct fib6_rule *)rule;
/* /*
......
...@@ -79,8 +79,8 @@ static DEFINE_RWLOCK(fib6_walker_lock); ...@@ -79,8 +79,8 @@ static DEFINE_RWLOCK(fib6_walker_lock);
static void fib6_prune_clones(struct net *net, struct fib6_node *fn, static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
struct rt6_info *rt); struct rt6_info *rt);
static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
static int fib6_walk(struct fib6_walker_t *w); static int fib6_walk(struct fib6_walker_t *w);
static int fib6_walk_continue(struct fib6_walker_t *w); static int fib6_walk_continue(struct fib6_walker_t *w);
...@@ -193,14 +193,14 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb) ...@@ -193,14 +193,14 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb)
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
static struct fib6_table *fib6_alloc_table(u32 id) static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
{ {
struct fib6_table *table; struct fib6_table *table;
table = kzalloc(sizeof(*table), GFP_ATOMIC); table = kzalloc(sizeof(*table), GFP_ATOMIC);
if (table != NULL) { if (table != NULL) {
table->tb6_id = id; table->tb6_id = id;
table->tb6_root.leaf = ip6_null_entry; table->tb6_root.leaf = net->ipv6.ip6_null_entry;
table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
} }
...@@ -217,7 +217,7 @@ struct fib6_table *fib6_new_table(struct net *net, u32 id) ...@@ -217,7 +217,7 @@ struct fib6_table *fib6_new_table(struct net *net, u32 id)
if (tb) if (tb)
return tb; return tb;
tb = fib6_alloc_table(id); tb = fib6_alloc_table(net, id);
if (tb != NULL) if (tb != NULL)
fib6_link_table(net, tb); fib6_link_table(net, tb);
...@@ -267,7 +267,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) ...@@ -267,7 +267,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
int flags, pol_lookup_t lookup) int flags, pol_lookup_t lookup)
{ {
return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags); return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
} }
static void fib6_tables_init(struct net *net) static void fib6_tables_init(struct net *net)
...@@ -717,8 +717,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) ...@@ -717,8 +717,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
if (sfn == NULL) if (sfn == NULL)
goto st_failure; goto st_failure;
sfn->leaf = ip6_null_entry; sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
atomic_inc(&ip6_null_entry->rt6i_ref); atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
sfn->fn_flags = RTN_ROOT; sfn->fn_flags = RTN_ROOT;
sfn->fn_sernum = fib6_new_sernum(); sfn->fn_sernum = fib6_new_sernum();
...@@ -773,11 +773,11 @@ out: ...@@ -773,11 +773,11 @@ out:
* super-tree leaf node we have to find a new one for it. * super-tree leaf node we have to find a new one for it.
*/ */
if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
pn->leaf = fib6_find_prefix(pn); pn->leaf = fib6_find_prefix(info->nl_net, pn);
#if RT6_DEBUG >= 2 #if RT6_DEBUG >= 2
if (!pn->leaf) { if (!pn->leaf) {
BUG_TRAP(pn->leaf != NULL); BUG_TRAP(pn->leaf != NULL);
pn->leaf = ip6_null_entry; pn->leaf = info->nl_net->ipv6.ip6_null_entry;
} }
#endif #endif
atomic_inc(&pn->leaf->rt6i_ref); atomic_inc(&pn->leaf->rt6i_ref);
...@@ -793,7 +793,7 @@ out: ...@@ -793,7 +793,7 @@ out:
*/ */
st_failure: st_failure:
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
fib6_repair_tree(fn); fib6_repair_tree(info->nl_net, fn);
dst_free(&rt->u.dst); dst_free(&rt->u.dst);
return err; return err;
#endif #endif
...@@ -959,10 +959,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root, ...@@ -959,10 +959,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
* *
*/ */
static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
{ {
if (fn->fn_flags&RTN_ROOT) if (fn->fn_flags&RTN_ROOT)
return ip6_null_entry; return net->ipv6.ip6_null_entry;
while(fn) { while(fn) {
if(fn->left) if(fn->left)
...@@ -981,7 +981,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) ...@@ -981,7 +981,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
* is the node we want to try and remove. * is the node we want to try and remove.
*/ */
static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) static struct fib6_node *fib6_repair_tree(struct net *net,
struct fib6_node *fn)
{ {
int children; int children;
int nstate; int nstate;
...@@ -1008,11 +1009,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) ...@@ -1008,11 +1009,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
|| (children && fn->fn_flags&RTN_ROOT) || (children && fn->fn_flags&RTN_ROOT)
#endif #endif
) { ) {
fn->leaf = fib6_find_prefix(fn); fn->leaf = fib6_find_prefix(net, fn);
#if RT6_DEBUG >= 2 #if RT6_DEBUG >= 2
if (fn->leaf==NULL) { if (fn->leaf==NULL) {
BUG_TRAP(fn->leaf); BUG_TRAP(fn->leaf);
fn->leaf = ip6_null_entry; fn->leaf = net->ipv6.ip6_null_entry;
} }
#endif #endif
atomic_inc(&fn->leaf->rt6i_ref); atomic_inc(&fn->leaf->rt6i_ref);
...@@ -1117,7 +1118,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, ...@@ -1117,7 +1118,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
if (fn->leaf == NULL) { if (fn->leaf == NULL) {
fn->fn_flags &= ~RTN_RTINFO; fn->fn_flags &= ~RTN_RTINFO;
net->ipv6.rt6_stats->fib_route_nodes--; net->ipv6.rt6_stats->fib_route_nodes--;
fn = fib6_repair_tree(fn); fn = fib6_repair_tree(net, fn);
} }
if (atomic_read(&rt->rt6i_ref) != 1) { if (atomic_read(&rt->rt6i_ref) != 1) {
...@@ -1129,7 +1130,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, ...@@ -1129,7 +1130,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
*/ */
while (fn) { while (fn) {
if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
fn->leaf = fib6_find_prefix(fn); fn->leaf = fib6_find_prefix(net, fn);
atomic_inc(&fn->leaf->rt6i_ref); atomic_inc(&fn->leaf->rt6i_ref);
rt6_release(rt); rt6_release(rt);
} }
...@@ -1145,6 +1146,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, ...@@ -1145,6 +1146,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
int fib6_del(struct rt6_info *rt, struct nl_info *info) int fib6_del(struct rt6_info *rt, struct nl_info *info)
{ {
struct net *net = info->nl_net;
struct fib6_node *fn = rt->rt6i_node; struct fib6_node *fn = rt->rt6i_node;
struct rt6_info **rtp; struct rt6_info **rtp;
...@@ -1154,7 +1156,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) ...@@ -1154,7 +1156,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
return -ENOENT; return -ENOENT;
} }
#endif #endif
if (fn == NULL || rt == ip6_null_entry) if (fn == NULL || rt == net->ipv6.ip6_null_entry)
return -ENOENT; return -ENOENT;
BUG_TRAP(fn->fn_flags&RTN_RTINFO); BUG_TRAP(fn->fn_flags&RTN_RTINFO);
...@@ -1501,7 +1503,7 @@ static int fib6_net_init(struct net *net) ...@@ -1501,7 +1503,7 @@ static int fib6_net_init(struct net *net)
goto out_fib_table_hash; goto out_fib_table_hash;
net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; 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.leaf = net->ipv6.ip6_null_entry;
net->ipv6.fib6_main_tbl->tb6_root.fn_flags = net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
...@@ -1511,7 +1513,7 @@ static int fib6_net_init(struct net *net) ...@@ -1511,7 +1513,7 @@ static int fib6_net_init(struct net *net)
if (!net->ipv6.fib6_local_tbl) if (!net->ipv6.fib6_local_tbl)
goto out_fib6_main_tbl; goto out_fib6_main_tbl;
net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; 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.leaf = net->ipv6.ip6_null_entry;
net->ipv6.fib6_local_tbl->tb6_root.fn_flags = net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
#endif #endif
...@@ -1536,6 +1538,7 @@ out_timer: ...@@ -1536,6 +1538,7 @@ out_timer:
static void fib6_net_exit(struct net *net) static void fib6_net_exit(struct net *net)
{ {
rt6_ifdown(net, NULL);
del_timer(net->ipv6.ip6_fib_timer); del_timer(net->ipv6.ip6_fib_timer);
kfree(net->ipv6.ip6_fib_timer); kfree(net->ipv6.ip6_fib_timer);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
......
...@@ -145,8 +145,6 @@ static struct rt6_info ip6_null_entry_template = { ...@@ -145,8 +145,6 @@ static struct rt6_info ip6_null_entry_template = {
.rt6i_ref = ATOMIC_INIT(1), .rt6i_ref = ATOMIC_INIT(1),
}; };
struct rt6_info *ip6_null_entry;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES #ifdef CONFIG_IPV6_MULTIPLE_TABLES
static int ip6_pkt_prohibit(struct sk_buff *skb); static int ip6_pkt_prohibit(struct sk_buff *skb);
...@@ -170,8 +168,6 @@ struct rt6_info ip6_prohibit_entry_template = { ...@@ -170,8 +168,6 @@ struct rt6_info ip6_prohibit_entry_template = {
.rt6i_ref = ATOMIC_INIT(1), .rt6i_ref = ATOMIC_INIT(1),
}; };
struct rt6_info *ip6_prohibit_entry;
static struct rt6_info ip6_blk_hole_entry_template = { static struct rt6_info ip6_blk_hole_entry_template = {
.u = { .u = {
.dst = { .dst = {
...@@ -190,8 +186,6 @@ static struct rt6_info ip6_blk_hole_entry_template = { ...@@ -190,8 +186,6 @@ static struct rt6_info ip6_blk_hole_entry_template = {
.rt6i_ref = ATOMIC_INIT(1), .rt6i_ref = ATOMIC_INIT(1),
}; };
struct rt6_info *ip6_blk_hole_entry;
#endif #endif
/* allocate dst with ip6_dst_ops */ /* allocate dst with ip6_dst_ops */
...@@ -245,7 +239,8 @@ static inline int rt6_need_strict(struct in6_addr *daddr) ...@@ -245,7 +239,8 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
* Route lookup. Any table->tb6_lock is implied. * Route lookup. Any table->tb6_lock is implied.
*/ */
static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, static inline struct rt6_info *rt6_device_match(struct net *net,
struct rt6_info *rt,
int oif, int oif,
int strict) int strict)
{ {
...@@ -274,7 +269,7 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, ...@@ -274,7 +269,7 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
return local; return local;
if (strict) if (strict)
return ip6_null_entry; return net->ipv6.ip6_null_entry;
} }
return rt; return rt;
} }
...@@ -415,6 +410,7 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn, ...@@ -415,6 +410,7 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
{ {
struct rt6_info *match, *rt0; struct rt6_info *match, *rt0;
struct net *net;
RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
__FUNCTION__, fn->leaf, oif); __FUNCTION__, fn->leaf, oif);
...@@ -440,7 +436,8 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) ...@@ -440,7 +436,8 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
RT6_TRACE("%s() => %p\n", RT6_TRACE("%s() => %p\n",
__FUNCTION__, match); __FUNCTION__, match);
return (match ? match : ip6_null_entry); net = rt0->rt6i_dev->nd_net;
return (match ? match : net->ipv6.ip6_null_entry);
} }
#ifdef CONFIG_IPV6_ROUTE_INFO #ifdef CONFIG_IPV6_ROUTE_INFO
...@@ -523,9 +520,9 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, ...@@ -523,9 +520,9 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
} }
#endif #endif
#define BACKTRACK(saddr) \ #define BACKTRACK(__net, saddr) \
do { \ do { \
if (rt == ip6_null_entry) { \ if (rt == __net->ipv6.ip6_null_entry) { \
struct fib6_node *pn; \ struct fib6_node *pn; \
while (1) { \ while (1) { \
if (fn->fn_flags & RTN_TL_ROOT) \ if (fn->fn_flags & RTN_TL_ROOT) \
...@@ -541,7 +538,8 @@ do { \ ...@@ -541,7 +538,8 @@ do { \
} \ } \
} while(0) } while(0)
static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, static struct rt6_info *ip6_pol_route_lookup(struct net *net,
struct fib6_table *table,
struct flowi *fl, int flags) struct flowi *fl, int flags)
{ {
struct fib6_node *fn; struct fib6_node *fn;
...@@ -551,8 +549,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, ...@@ -551,8 +549,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart: restart:
rt = fn->leaf; rt = fn->leaf;
rt = rt6_device_match(rt, fl->oif, flags); rt = rt6_device_match(net, rt, fl->oif, flags);
BACKTRACK(&fl->fl6_src); BACKTRACK(net, &fl->fl6_src);
out: out:
dst_use(&rt->u.dst, jiffies); dst_use(&rt->u.dst, jiffies);
read_unlock_bh(&table->tb6_lock); read_unlock_bh(&table->tb6_lock);
...@@ -668,8 +666,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d ...@@ -668,8 +666,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
return rt; return rt;
} }
static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif, static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
struct flowi *fl, int flags) struct flowi *fl, int flags)
{ {
struct fib6_node *fn; struct fib6_node *fn;
struct rt6_info *rt, *nrt; struct rt6_info *rt, *nrt;
...@@ -688,8 +686,9 @@ restart_2: ...@@ -688,8 +686,9 @@ restart_2:
restart: restart:
rt = rt6_select(fn, oif, strict | reachable); rt = rt6_select(fn, oif, strict | reachable);
BACKTRACK(&fl->fl6_src);
if (rt == ip6_null_entry || BACKTRACK(net, &fl->fl6_src);
if (rt == net->ipv6.ip6_null_entry ||
rt->rt6i_flags & RTF_CACHE) rt->rt6i_flags & RTF_CACHE)
goto out; goto out;
...@@ -707,7 +706,7 @@ restart: ...@@ -707,7 +706,7 @@ restart:
} }
dst_release(&rt->u.dst); dst_release(&rt->u.dst);
rt = nrt ? : ip6_null_entry; rt = nrt ? : net->ipv6.ip6_null_entry;
dst_hold(&rt->u.dst); dst_hold(&rt->u.dst);
if (nrt) { if (nrt) {
...@@ -740,10 +739,10 @@ out2: ...@@ -740,10 +739,10 @@ out2:
return rt; return rt;
} }
static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
struct flowi *fl, int flags) struct flowi *fl, int flags)
{ {
return ip6_pol_route(table, fl->iif, fl, flags); return ip6_pol_route(net, table, fl->iif, fl, flags);
} }
void ip6_route_input(struct sk_buff *skb) void ip6_route_input(struct sk_buff *skb)
...@@ -770,10 +769,10 @@ void ip6_route_input(struct sk_buff *skb) ...@@ -770,10 +769,10 @@ void ip6_route_input(struct sk_buff *skb)
skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
} }
static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
struct flowi *fl, int flags) struct flowi *fl, int flags)
{ {
return ip6_pol_route(table, fl->oif, fl, flags); return ip6_pol_route(net, table, fl->oif, fl, flags);
} }
struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
...@@ -1259,8 +1258,9 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) ...@@ -1259,8 +1258,9 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
{ {
int err; int err;
struct fib6_table *table; struct fib6_table *table;
struct net *net = rt->rt6i_dev->nd_net;
if (rt == ip6_null_entry) if (rt == net->ipv6.ip6_null_entry)
return -ENOENT; return -ENOENT;
table = rt->rt6i_table; table = rt->rt6i_table;
...@@ -1329,7 +1329,8 @@ struct ip6rd_flowi { ...@@ -1329,7 +1329,8 @@ struct ip6rd_flowi {
struct in6_addr gateway; struct in6_addr gateway;
}; };
static struct rt6_info *__ip6_route_redirect(struct fib6_table *table, static struct rt6_info *__ip6_route_redirect(struct net *net,
struct fib6_table *table,
struct flowi *fl, struct flowi *fl,
int flags) int flags)
{ {
...@@ -1372,8 +1373,8 @@ restart: ...@@ -1372,8 +1373,8 @@ restart:
} }
if (!rt) if (!rt)
rt = ip6_null_entry; rt = net->ipv6.ip6_null_entry;
BACKTRACK(&fl->fl6_src); BACKTRACK(net, &fl->fl6_src);
out: out:
dst_hold(&rt->u.dst); dst_hold(&rt->u.dst);
...@@ -1415,10 +1416,11 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, ...@@ -1415,10 +1416,11 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
{ {
struct rt6_info *rt, *nrt = NULL; struct rt6_info *rt, *nrt = NULL;
struct netevent_redirect netevent; struct netevent_redirect netevent;
struct net *net = neigh->dev->nd_net;
rt = ip6_route_redirect(dest, src, saddr, neigh->dev); rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
if (rt == ip6_null_entry) { if (rt == net->ipv6.ip6_null_entry) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
"for redirect target\n"); "for redirect target\n");
...@@ -1886,10 +1888,18 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, ...@@ -1886,10 +1888,18 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
return rt; return rt;
} }
struct arg_dev_net {
struct net_device *dev;
struct net *net;
};
static int fib6_ifdown(struct rt6_info *rt, void *arg) static int fib6_ifdown(struct rt6_info *rt, void *arg)
{ {
if (((void*)rt->rt6i_dev == arg || arg == NULL) && struct net_device *dev = ((struct arg_dev_net *)arg)->dev;
rt != ip6_null_entry) { struct net *net = ((struct arg_dev_net *)arg)->net;
if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
rt != net->ipv6.ip6_null_entry) {
RT6_TRACE("deleted by ifdown %p\n", rt); RT6_TRACE("deleted by ifdown %p\n", rt);
return -1; return -1;
} }
...@@ -1898,7 +1908,12 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg) ...@@ -1898,7 +1908,12 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg)
void rt6_ifdown(struct net *net, struct net_device *dev) void rt6_ifdown(struct net *net, struct net_device *dev)
{ {
fib6_clean_all(net, fib6_ifdown, 0, dev); struct arg_dev_net adn = {
.dev = dev,
.net = net,
};
fib6_clean_all(net, fib6_ifdown, 0, &adn);
} }
struct rt6_mtu_change_arg struct rt6_mtu_change_arg
...@@ -2289,6 +2304,26 @@ errout: ...@@ -2289,6 +2304,26 @@ errout:
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
} }
static int ip6_route_dev_notify(struct notifier_block *this,
unsigned long event, void *data)
{
struct net_device *dev = (struct net_device *)data;
struct net *net = dev->nd_net;
if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
net->ipv6.ip6_null_entry->u.dst.dev = dev;
net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.ip6_prohibit_entry->u.dst.dev = dev;
net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev;
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
#endif
}
return NOTIFY_OK;
}
/* /*
* /proc * /proc
*/ */
...@@ -2535,11 +2570,47 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) ...@@ -2535,11 +2570,47 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net)
static int ip6_route_net_init(struct net *net) static int ip6_route_net_init(struct net *net)
{ {
int ret = 0;
ret = -ENOMEM;
net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
sizeof(*net->ipv6.ip6_null_entry),
GFP_KERNEL);
if (!net->ipv6.ip6_null_entry)
goto out;
net->ipv6.ip6_null_entry->u.dst.path =
(struct dst_entry *)net->ipv6.ip6_null_entry;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
sizeof(*net->ipv6.ip6_prohibit_entry),
GFP_KERNEL);
if (!net->ipv6.ip6_prohibit_entry) {
kfree(net->ipv6.ip6_null_entry);
goto out;
}
net->ipv6.ip6_prohibit_entry->u.dst.path =
(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
sizeof(*net->ipv6.ip6_blk_hole_entry),
GFP_KERNEL);
if (!net->ipv6.ip6_blk_hole_entry) {
kfree(net->ipv6.ip6_null_entry);
kfree(net->ipv6.ip6_prohibit_entry);
goto out;
}
net->ipv6.ip6_blk_hole_entry->u.dst.path =
(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
#endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
#endif #endif
return 0; ret = 0;
out:
return ret;
} }
static void ip6_route_net_exit(struct net *net) static void ip6_route_net_exit(struct net *net)
...@@ -2548,7 +2619,11 @@ static void ip6_route_net_exit(struct net *net) ...@@ -2548,7 +2619,11 @@ static void ip6_route_net_exit(struct net *net)
proc_net_remove(net, "ipv6_route"); proc_net_remove(net, "ipv6_route");
proc_net_remove(net, "rt6_stats"); proc_net_remove(net, "rt6_stats");
#endif #endif
rt6_ifdown(net, NULL); kfree(net->ipv6.ip6_null_entry);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
kfree(net->ipv6.ip6_prohibit_entry);
kfree(net->ipv6.ip6_blk_hole_entry);
#endif
} }
static struct pernet_operations ip6_route_net_ops = { static struct pernet_operations ip6_route_net_ops = {
...@@ -2556,6 +2631,11 @@ static struct pernet_operations ip6_route_net_ops = { ...@@ -2556,6 +2631,11 @@ static struct pernet_operations ip6_route_net_ops = {
.exit = ip6_route_net_exit, .exit = ip6_route_net_exit,
}; };
static struct notifier_block ip6_route_dev_notifier = {
.notifier_call = ip6_route_dev_notify,
.priority = 0,
};
int __init ip6_route_init(void) int __init ip6_route_init(void)
{ {
int ret; int ret;
...@@ -2568,30 +2648,24 @@ int __init ip6_route_init(void) ...@@ -2568,30 +2648,24 @@ int __init ip6_route_init(void)
ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
ret = -ENOMEM; ret = register_pernet_subsys(&ip6_route_net_ops);
ip6_null_entry = kmemdup(&ip6_null_entry_template, if (ret)
sizeof(*ip6_null_entry), GFP_KERNEL);
if (!ip6_null_entry)
goto out_kmem_cache; goto out_kmem_cache;
ip6_null_entry->u.dst.path = (struct dst_entry *)ip6_null_entry;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
sizeof(*ip6_prohibit_entry), GFP_KERNEL);
if (!ip6_prohibit_entry)
goto out_ip6_null_entry;
ip6_prohibit_entry->u.dst.path = (struct dst_entry *)ip6_prohibit_entry;
ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
sizeof(*ip6_blk_hole_entry), GFP_KERNEL);
if (!ip6_blk_hole_entry)
goto out_ip6_prohibit_entry;
ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)ip6_blk_hole_entry;
#endif
/* Registering of the loopback is done before this portion of code,
* the loopback reference in rt6_info will not be taken, do it
* manually for init_net */
init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
#endif
ret = fib6_init(); ret = fib6_init();
if (ret) if (ret)
goto out_ip6_blk_hole_entry; goto out_register_subsys;
ret = xfrm6_init(); ret = xfrm6_init();
if (ret) if (ret)
...@@ -2607,9 +2681,10 @@ int __init ip6_route_init(void) ...@@ -2607,9 +2681,10 @@ int __init ip6_route_init(void)
__rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
goto fib6_rules_init; goto fib6_rules_init;
ret = register_pernet_subsys(&ip6_route_net_ops); ret = register_netdevice_notifier(&ip6_route_dev_notifier);
if (ret) if (ret)
goto fib6_rules_init; goto fib6_rules_init;
out: out:
return ret; return ret;
...@@ -2619,14 +2694,8 @@ xfrm6_init: ...@@ -2619,14 +2694,8 @@ xfrm6_init:
xfrm6_fini(); xfrm6_fini();
out_fib6_init: out_fib6_init:
fib6_gc_cleanup(); fib6_gc_cleanup();
out_ip6_blk_hole_entry: out_register_subsys:
#ifdef CONFIG_IPV6_MULTIPLE_TABLES unregister_pernet_subsys(&ip6_route_net_ops);
kfree(ip6_blk_hole_entry);
out_ip6_prohibit_entry:
kfree(ip6_prohibit_entry);
out_ip6_null_entry:
#endif
kfree(ip6_null_entry);
out_kmem_cache: out_kmem_cache:
kmem_cache_destroy(ip6_dst_ops.kmem_cachep); kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
goto out; goto out;
...@@ -2634,15 +2703,10 @@ out_kmem_cache: ...@@ -2634,15 +2703,10 @@ out_kmem_cache:
void ip6_route_cleanup(void) void ip6_route_cleanup(void)
{ {
unregister_pernet_subsys(&ip6_route_net_ops); unregister_netdevice_notifier(&ip6_route_dev_notifier);
fib6_rules_cleanup(); fib6_rules_cleanup();
xfrm6_fini(); xfrm6_fini();
fib6_gc_cleanup(); fib6_gc_cleanup();
unregister_pernet_subsys(&ip6_route_net_ops);
kmem_cache_destroy(ip6_dst_ops.kmem_cachep); kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
kfree(ip6_null_entry);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
kfree(ip6_prohibit_entry);
kfree(ip6_blk_hole_entry);
#endif
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment