aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf.c9
-rw-r--r--net/ipv6/fib6_rules.c17
-rw-r--r--net/ipv6/ip6_fib.c45
-rw-r--r--net/ipv6/route.c202
4 files changed, 166 insertions, 107 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3192a848a53a..17b06d220e95 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4301,15 +4301,6 @@ int __init addrconf_init(void)
4301 if (err) 4301 if (err)
4302 goto errlo; 4302 goto errlo;
4303 4303
4304 ip6_null_entry->u.dst.dev = init_net.loopback_dev;
4305 ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4306#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4307 ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
4308 ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4309 ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
4310 ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4311#endif
4312
4313 register_netdevice_notifier(&ipv6_dev_notf); 4304 register_netdevice_notifier(&ipv6_dev_notf);
4314 4305
4315 addrconf_verify(0); 4306 addrconf_verify(0);
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index c00055f232c4..55137408f054 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
43 if (arg.result) 43 if (arg.result)
44 return arg.result; 44 return arg.result;
45 45
46 dst_hold(&ip6_null_entry->u.dst); 46 dst_hold(&net->ipv6.ip6_null_entry->u.dst);
47 return &ip6_null_entry->u.dst; 47 return &net->ipv6.ip6_null_entry->u.dst;
48} 48}
49 49
50static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, 50static 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{ 52{
53 struct rt6_info *rt = NULL; 53 struct rt6_info *rt = NULL;
54 struct fib6_table *table; 54 struct fib6_table *table;
55 struct net *net = rule->fr_net;
55 pol_lookup_t lookup = arg->lookup_ptr; 56 pol_lookup_t lookup = arg->lookup_ptr;
56 57
57 switch (rule->action) { 58 switch (rule->action) {
58 case FR_ACT_TO_TBL: 59 case FR_ACT_TO_TBL:
59 break; 60 break;
60 case FR_ACT_UNREACHABLE: 61 case FR_ACT_UNREACHABLE:
61 rt = ip6_null_entry; 62 rt = net->ipv6.ip6_null_entry;
62 goto discard_pkt; 63 goto discard_pkt;
63 default: 64 default:
64 case FR_ACT_BLACKHOLE: 65 case FR_ACT_BLACKHOLE:
65 rt = ip6_blk_hole_entry; 66 rt = net->ipv6.ip6_blk_hole_entry;
66 goto discard_pkt; 67 goto discard_pkt;
67 case FR_ACT_PROHIBIT: 68 case FR_ACT_PROHIBIT:
68 rt = ip6_prohibit_entry; 69 rt = net->ipv6.ip6_prohibit_entry;
69 goto discard_pkt; 70 goto discard_pkt;
70 } 71 }
71 72
72 table = fib6_get_table(rule->fr_net, rule->table); 73 table = fib6_get_table(net, rule->table);
73 if (table) 74 if (table)
74 rt = lookup(table, flp, flags); 75 rt = lookup(net, table, flp, flags);
75 76
76 if (rt != ip6_null_entry) { 77 if (rt != net->ipv6.ip6_null_entry) {
77 struct fib6_rule *r = (struct fib6_rule *)rule; 78 struct fib6_rule *r = (struct fib6_rule *)rule;
78 79
79 /* 80 /*
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index f028f7a1a446..b0814b0082e7 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -79,8 +79,8 @@ static DEFINE_RWLOCK(fib6_walker_lock);
79 79
80static void fib6_prune_clones(struct net *net, struct fib6_node *fn, 80static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
81 struct rt6_info *rt); 81 struct rt6_info *rt);
82static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); 82static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
83static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); 83static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
84static int fib6_walk(struct fib6_walker_t *w); 84static int fib6_walk(struct fib6_walker_t *w);
85static int fib6_walk_continue(struct fib6_walker_t *w); 85static int fib6_walk_continue(struct fib6_walker_t *w);
86 86
@@ -193,14 +193,14 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb)
193 193
194#ifdef CONFIG_IPV6_MULTIPLE_TABLES 194#ifdef CONFIG_IPV6_MULTIPLE_TABLES
195 195
196static struct fib6_table *fib6_alloc_table(u32 id) 196static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
197{ 197{
198 struct fib6_table *table; 198 struct fib6_table *table;
199 199
200 table = kzalloc(sizeof(*table), GFP_ATOMIC); 200 table = kzalloc(sizeof(*table), GFP_ATOMIC);
201 if (table != NULL) { 201 if (table != NULL) {
202 table->tb6_id = id; 202 table->tb6_id = id;
203 table->tb6_root.leaf = ip6_null_entry; 203 table->tb6_root.leaf = net->ipv6.ip6_null_entry;
204 table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; 204 table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
205 } 205 }
206 206
@@ -217,7 +217,7 @@ struct fib6_table *fib6_new_table(struct net *net, u32 id)
217 if (tb) 217 if (tb)
218 return tb; 218 return tb;
219 219
220 tb = fib6_alloc_table(id); 220 tb = fib6_alloc_table(net, id);
221 if (tb != NULL) 221 if (tb != NULL)
222 fib6_link_table(net, tb); 222 fib6_link_table(net, tb);
223 223
@@ -267,7 +267,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
267struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, 267struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
268 int flags, pol_lookup_t lookup) 268 int flags, pol_lookup_t lookup)
269{ 269{
270 return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags); 270 return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
271} 271}
272 272
273static void fib6_tables_init(struct net *net) 273static 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 if (sfn == NULL) 717 if (sfn == NULL)
718 goto st_failure; 718 goto st_failure;
719 719
720 sfn->leaf = ip6_null_entry; 720 sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
721 atomic_inc(&ip6_null_entry->rt6i_ref); 721 atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
722 sfn->fn_flags = RTN_ROOT; 722 sfn->fn_flags = RTN_ROOT;
723 sfn->fn_sernum = fib6_new_sernum(); 723 sfn->fn_sernum = fib6_new_sernum();
724 724
@@ -773,11 +773,11 @@ out:
773 * super-tree leaf node we have to find a new one for it. 773 * super-tree leaf node we have to find a new one for it.
774 */ 774 */
775 if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { 775 if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
776 pn->leaf = fib6_find_prefix(pn); 776 pn->leaf = fib6_find_prefix(info->nl_net, pn);
777#if RT6_DEBUG >= 2 777#if RT6_DEBUG >= 2
778 if (!pn->leaf) { 778 if (!pn->leaf) {
779 BUG_TRAP(pn->leaf != NULL); 779 BUG_TRAP(pn->leaf != NULL);
780 pn->leaf = ip6_null_entry; 780 pn->leaf = info->nl_net->ipv6.ip6_null_entry;
781 } 781 }
782#endif 782#endif
783 atomic_inc(&pn->leaf->rt6i_ref); 783 atomic_inc(&pn->leaf->rt6i_ref);
@@ -793,7 +793,7 @@ out:
793 */ 793 */
794st_failure: 794st_failure:
795 if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) 795 if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
796 fib6_repair_tree(fn); 796 fib6_repair_tree(info->nl_net, fn);
797 dst_free(&rt->u.dst); 797 dst_free(&rt->u.dst);
798 return err; 798 return err;
799#endif 799#endif
@@ -959,10 +959,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
959 * 959 *
960 */ 960 */
961 961
962static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) 962static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
963{ 963{
964 if (fn->fn_flags&RTN_ROOT) 964 if (fn->fn_flags&RTN_ROOT)
965 return ip6_null_entry; 965 return net->ipv6.ip6_null_entry;
966 966
967 while(fn) { 967 while(fn) {
968 if(fn->left) 968 if(fn->left)
@@ -981,7 +981,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
981 * is the node we want to try and remove. 981 * is the node we want to try and remove.
982 */ 982 */
983 983
984static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) 984static struct fib6_node *fib6_repair_tree(struct net *net,
985 struct fib6_node *fn)
985{ 986{
986 int children; 987 int children;
987 int nstate; 988 int nstate;
@@ -1008,11 +1009,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
1008 || (children && fn->fn_flags&RTN_ROOT) 1009 || (children && fn->fn_flags&RTN_ROOT)
1009#endif 1010#endif
1010 ) { 1011 ) {
1011 fn->leaf = fib6_find_prefix(fn); 1012 fn->leaf = fib6_find_prefix(net, fn);
1012#if RT6_DEBUG >= 2 1013#if RT6_DEBUG >= 2
1013 if (fn->leaf==NULL) { 1014 if (fn->leaf==NULL) {
1014 BUG_TRAP(fn->leaf); 1015 BUG_TRAP(fn->leaf);
1015 fn->leaf = ip6_null_entry; 1016 fn->leaf = net->ipv6.ip6_null_entry;
1016 } 1017 }
1017#endif 1018#endif
1018 atomic_inc(&fn->leaf->rt6i_ref); 1019 atomic_inc(&fn->leaf->rt6i_ref);
@@ -1117,7 +1118,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1117 if (fn->leaf == NULL) { 1118 if (fn->leaf == NULL) {
1118 fn->fn_flags &= ~RTN_RTINFO; 1119 fn->fn_flags &= ~RTN_RTINFO;
1119 net->ipv6.rt6_stats->fib_route_nodes--; 1120 net->ipv6.rt6_stats->fib_route_nodes--;
1120 fn = fib6_repair_tree(fn); 1121 fn = fib6_repair_tree(net, fn);
1121 } 1122 }
1122 1123
1123 if (atomic_read(&rt->rt6i_ref) != 1) { 1124 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 */ 1130 */
1130 while (fn) { 1131 while (fn) {
1131 if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { 1132 if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
1132 fn->leaf = fib6_find_prefix(fn); 1133 fn->leaf = fib6_find_prefix(net, fn);
1133 atomic_inc(&fn->leaf->rt6i_ref); 1134 atomic_inc(&fn->leaf->rt6i_ref);
1134 rt6_release(rt); 1135 rt6_release(rt);
1135 } 1136 }
@@ -1145,6 +1146,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1145 1146
1146int fib6_del(struct rt6_info *rt, struct nl_info *info) 1147int fib6_del(struct rt6_info *rt, struct nl_info *info)
1147{ 1148{
1149 struct net *net = info->nl_net;
1148 struct fib6_node *fn = rt->rt6i_node; 1150 struct fib6_node *fn = rt->rt6i_node;
1149 struct rt6_info **rtp; 1151 struct rt6_info **rtp;
1150 1152
@@ -1154,7 +1156,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
1154 return -ENOENT; 1156 return -ENOENT;
1155 } 1157 }
1156#endif 1158#endif
1157 if (fn == NULL || rt == ip6_null_entry) 1159 if (fn == NULL || rt == net->ipv6.ip6_null_entry)
1158 return -ENOENT; 1160 return -ENOENT;
1159 1161
1160 BUG_TRAP(fn->fn_flags&RTN_RTINFO); 1162 BUG_TRAP(fn->fn_flags&RTN_RTINFO);
@@ -1501,7 +1503,7 @@ static int fib6_net_init(struct net *net)
1501 goto out_fib_table_hash; 1503 goto out_fib_table_hash;
1502 1504
1503 net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; 1505 net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
1504 net->ipv6.fib6_main_tbl->tb6_root.leaf = ip6_null_entry; 1506 net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
1505 net->ipv6.fib6_main_tbl->tb6_root.fn_flags = 1507 net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
1506 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; 1508 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1507 1509
@@ -1511,7 +1513,7 @@ static int fib6_net_init(struct net *net)
1511 if (!net->ipv6.fib6_local_tbl) 1513 if (!net->ipv6.fib6_local_tbl)
1512 goto out_fib6_main_tbl; 1514 goto out_fib6_main_tbl;
1513 net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; 1515 net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
1514 net->ipv6.fib6_local_tbl->tb6_root.leaf = ip6_null_entry; 1516 net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
1515 net->ipv6.fib6_local_tbl->tb6_root.fn_flags = 1517 net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
1516 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; 1518 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1517#endif 1519#endif
@@ -1536,6 +1538,7 @@ out_timer:
1536 1538
1537static void fib6_net_exit(struct net *net) 1539static void fib6_net_exit(struct net *net)
1538{ 1540{
1541 rt6_ifdown(net, NULL);
1539 del_timer(net->ipv6.ip6_fib_timer); 1542 del_timer(net->ipv6.ip6_fib_timer);
1540 kfree(net->ipv6.ip6_fib_timer); 1543 kfree(net->ipv6.ip6_fib_timer);
1541#ifdef CONFIG_IPV6_MULTIPLE_TABLES 1544#ifdef CONFIG_IPV6_MULTIPLE_TABLES
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8f954c1e961f..7ff66cebe77c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -145,8 +145,6 @@ static struct rt6_info ip6_null_entry_template = {
145 .rt6i_ref = ATOMIC_INIT(1), 145 .rt6i_ref = ATOMIC_INIT(1),
146}; 146};
147 147
148struct rt6_info *ip6_null_entry;
149
150#ifdef CONFIG_IPV6_MULTIPLE_TABLES 148#ifdef CONFIG_IPV6_MULTIPLE_TABLES
151 149
152static int ip6_pkt_prohibit(struct sk_buff *skb); 150static int ip6_pkt_prohibit(struct sk_buff *skb);
@@ -170,8 +168,6 @@ struct rt6_info ip6_prohibit_entry_template = {
170 .rt6i_ref = ATOMIC_INIT(1), 168 .rt6i_ref = ATOMIC_INIT(1),
171}; 169};
172 170
173struct rt6_info *ip6_prohibit_entry;
174
175static struct rt6_info ip6_blk_hole_entry_template = { 171static struct rt6_info ip6_blk_hole_entry_template = {
176 .u = { 172 .u = {
177 .dst = { 173 .dst = {
@@ -190,8 +186,6 @@ static struct rt6_info ip6_blk_hole_entry_template = {
190 .rt6i_ref = ATOMIC_INIT(1), 186 .rt6i_ref = ATOMIC_INIT(1),
191}; 187};
192 188
193struct rt6_info *ip6_blk_hole_entry;
194
195#endif 189#endif
196 190
197/* allocate dst with ip6_dst_ops */ 191/* allocate dst with ip6_dst_ops */
@@ -245,7 +239,8 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
245 * Route lookup. Any table->tb6_lock is implied. 239 * Route lookup. Any table->tb6_lock is implied.
246 */ 240 */
247 241
248static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, 242static inline struct rt6_info *rt6_device_match(struct net *net,
243 struct rt6_info *rt,
249 int oif, 244 int oif,
250 int strict) 245 int strict)
251{ 246{
@@ -274,7 +269,7 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
274 return local; 269 return local;
275 270
276 if (strict) 271 if (strict)
277 return ip6_null_entry; 272 return net->ipv6.ip6_null_entry;
278 } 273 }
279 return rt; 274 return rt;
280} 275}
@@ -415,6 +410,7 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
415static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) 410static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
416{ 411{
417 struct rt6_info *match, *rt0; 412 struct rt6_info *match, *rt0;
413 struct net *net;
418 414
419 RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", 415 RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
420 __FUNCTION__, fn->leaf, oif); 416 __FUNCTION__, fn->leaf, oif);
@@ -440,7 +436,8 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
440 RT6_TRACE("%s() => %p\n", 436 RT6_TRACE("%s() => %p\n",
441 __FUNCTION__, match); 437 __FUNCTION__, match);
442 438
443 return (match ? match : ip6_null_entry); 439 net = rt0->rt6i_dev->nd_net;
440 return (match ? match : net->ipv6.ip6_null_entry);
444} 441}
445 442
446#ifdef CONFIG_IPV6_ROUTE_INFO 443#ifdef CONFIG_IPV6_ROUTE_INFO
@@ -523,9 +520,9 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
523} 520}
524#endif 521#endif
525 522
526#define BACKTRACK(saddr) \ 523#define BACKTRACK(__net, saddr) \
527do { \ 524do { \
528 if (rt == ip6_null_entry) { \ 525 if (rt == __net->ipv6.ip6_null_entry) { \
529 struct fib6_node *pn; \ 526 struct fib6_node *pn; \
530 while (1) { \ 527 while (1) { \
531 if (fn->fn_flags & RTN_TL_ROOT) \ 528 if (fn->fn_flags & RTN_TL_ROOT) \
@@ -541,7 +538,8 @@ do { \
541 } \ 538 } \
542} while(0) 539} while(0)
543 540
544static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, 541static struct rt6_info *ip6_pol_route_lookup(struct net *net,
542 struct fib6_table *table,
545 struct flowi *fl, int flags) 543 struct flowi *fl, int flags)
546{ 544{
547 struct fib6_node *fn; 545 struct fib6_node *fn;
@@ -551,8 +549,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
551 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); 549 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
552restart: 550restart:
553 rt = fn->leaf; 551 rt = fn->leaf;
554 rt = rt6_device_match(rt, fl->oif, flags); 552 rt = rt6_device_match(net, rt, fl->oif, flags);
555 BACKTRACK(&fl->fl6_src); 553 BACKTRACK(net, &fl->fl6_src);
556out: 554out:
557 dst_use(&rt->u.dst, jiffies); 555 dst_use(&rt->u.dst, jiffies);
558 read_unlock_bh(&table->tb6_lock); 556 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 return rt; 666 return rt;
669} 667}
670 668
671static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif, 669static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
672 struct flowi *fl, int flags) 670 struct flowi *fl, int flags)
673{ 671{
674 struct fib6_node *fn; 672 struct fib6_node *fn;
675 struct rt6_info *rt, *nrt; 673 struct rt6_info *rt, *nrt;
@@ -688,8 +686,9 @@ restart_2:
688 686
689restart: 687restart:
690 rt = rt6_select(fn, oif, strict | reachable); 688 rt = rt6_select(fn, oif, strict | reachable);
691 BACKTRACK(&fl->fl6_src); 689
692 if (rt == ip6_null_entry || 690 BACKTRACK(net, &fl->fl6_src);
691 if (rt == net->ipv6.ip6_null_entry ||
693 rt->rt6i_flags & RTF_CACHE) 692 rt->rt6i_flags & RTF_CACHE)
694 goto out; 693 goto out;
695 694
@@ -707,7 +706,7 @@ restart:
707 } 706 }
708 707
709 dst_release(&rt->u.dst); 708 dst_release(&rt->u.dst);
710 rt = nrt ? : ip6_null_entry; 709 rt = nrt ? : net->ipv6.ip6_null_entry;
711 710
712 dst_hold(&rt->u.dst); 711 dst_hold(&rt->u.dst);
713 if (nrt) { 712 if (nrt) {
@@ -740,10 +739,10 @@ out2:
740 return rt; 739 return rt;
741} 740}
742 741
743static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, 742static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
744 struct flowi *fl, int flags) 743 struct flowi *fl, int flags)
745{ 744{
746 return ip6_pol_route(table, fl->iif, fl, flags); 745 return ip6_pol_route(net, table, fl->iif, fl, flags);
747} 746}
748 747
749void ip6_route_input(struct sk_buff *skb) 748void ip6_route_input(struct sk_buff *skb)
@@ -770,10 +769,10 @@ void ip6_route_input(struct sk_buff *skb)
770 skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); 769 skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
771} 770}
772 771
773static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, 772static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
774 struct flowi *fl, int flags) 773 struct flowi *fl, int flags)
775{ 774{
776 return ip6_pol_route(table, fl->oif, fl, flags); 775 return ip6_pol_route(net, table, fl->oif, fl, flags);
777} 776}
778 777
779struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) 778struct 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{ 1258{
1260 int err; 1259 int err;
1261 struct fib6_table *table; 1260 struct fib6_table *table;
1261 struct net *net = rt->rt6i_dev->nd_net;
1262 1262
1263 if (rt == ip6_null_entry) 1263 if (rt == net->ipv6.ip6_null_entry)
1264 return -ENOENT; 1264 return -ENOENT;
1265 1265
1266 table = rt->rt6i_table; 1266 table = rt->rt6i_table;
@@ -1329,7 +1329,8 @@ struct ip6rd_flowi {
1329 struct in6_addr gateway; 1329 struct in6_addr gateway;
1330}; 1330};
1331 1331
1332static struct rt6_info *__ip6_route_redirect(struct fib6_table *table, 1332static struct rt6_info *__ip6_route_redirect(struct net *net,
1333 struct fib6_table *table,
1333 struct flowi *fl, 1334 struct flowi *fl,
1334 int flags) 1335 int flags)
1335{ 1336{
@@ -1372,8 +1373,8 @@ restart:
1372 } 1373 }
1373 1374
1374 if (!rt) 1375 if (!rt)
1375 rt = ip6_null_entry; 1376 rt = net->ipv6.ip6_null_entry;
1376 BACKTRACK(&fl->fl6_src); 1377 BACKTRACK(net, &fl->fl6_src);
1377out: 1378out:
1378 dst_hold(&rt->u.dst); 1379 dst_hold(&rt->u.dst);
1379 1380
@@ -1415,10 +1416,11 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
1415{ 1416{
1416 struct rt6_info *rt, *nrt = NULL; 1417 struct rt6_info *rt, *nrt = NULL;
1417 struct netevent_redirect netevent; 1418 struct netevent_redirect netevent;
1419 struct net *net = neigh->dev->nd_net;
1418 1420
1419 rt = ip6_route_redirect(dest, src, saddr, neigh->dev); 1421 rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
1420 1422
1421 if (rt == ip6_null_entry) { 1423 if (rt == net->ipv6.ip6_null_entry) {
1422 if (net_ratelimit()) 1424 if (net_ratelimit())
1423 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " 1425 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
1424 "for redirect target\n"); 1426 "for redirect target\n");
@@ -1886,10 +1888,18 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
1886 return rt; 1888 return rt;
1887} 1889}
1888 1890
1891struct arg_dev_net {
1892 struct net_device *dev;
1893 struct net *net;
1894};
1895
1889static int fib6_ifdown(struct rt6_info *rt, void *arg) 1896static int fib6_ifdown(struct rt6_info *rt, void *arg)
1890{ 1897{
1891 if (((void*)rt->rt6i_dev == arg || arg == NULL) && 1898 struct net_device *dev = ((struct arg_dev_net *)arg)->dev;
1892 rt != ip6_null_entry) { 1899 struct net *net = ((struct arg_dev_net *)arg)->net;
1900
1901 if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
1902 rt != net->ipv6.ip6_null_entry) {
1893 RT6_TRACE("deleted by ifdown %p\n", rt); 1903 RT6_TRACE("deleted by ifdown %p\n", rt);
1894 return -1; 1904 return -1;
1895 } 1905 }
@@ -1898,7 +1908,12 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg)
1898 1908
1899void rt6_ifdown(struct net *net, struct net_device *dev) 1909void rt6_ifdown(struct net *net, struct net_device *dev)
1900{ 1910{
1901 fib6_clean_all(net, fib6_ifdown, 0, dev); 1911 struct arg_dev_net adn = {
1912 .dev = dev,
1913 .net = net,
1914 };
1915
1916 fib6_clean_all(net, fib6_ifdown, 0, &adn);
1902} 1917}
1903 1918
1904struct rt6_mtu_change_arg 1919struct rt6_mtu_change_arg
@@ -2289,6 +2304,26 @@ errout:
2289 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); 2304 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
2290} 2305}
2291 2306
2307static int ip6_route_dev_notify(struct notifier_block *this,
2308 unsigned long event, void *data)
2309{
2310 struct net_device *dev = (struct net_device *)data;
2311 struct net *net = dev->nd_net;
2312
2313 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
2314 net->ipv6.ip6_null_entry->u.dst.dev = dev;
2315 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2316#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2317 net->ipv6.ip6_prohibit_entry->u.dst.dev = dev;
2318 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
2319 net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev;
2320 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2321#endif
2322 }
2323
2324 return NOTIFY_OK;
2325}
2326
2292/* 2327/*
2293 * /proc 2328 * /proc
2294 */ 2329 */
@@ -2535,11 +2570,47 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net)
2535 2570
2536static int ip6_route_net_init(struct net *net) 2571static int ip6_route_net_init(struct net *net)
2537{ 2572{
2573 int ret = 0;
2574
2575 ret = -ENOMEM;
2576 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2577 sizeof(*net->ipv6.ip6_null_entry),
2578 GFP_KERNEL);
2579 if (!net->ipv6.ip6_null_entry)
2580 goto out;
2581 net->ipv6.ip6_null_entry->u.dst.path =
2582 (struct dst_entry *)net->ipv6.ip6_null_entry;
2583
2584#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2585 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
2586 sizeof(*net->ipv6.ip6_prohibit_entry),
2587 GFP_KERNEL);
2588 if (!net->ipv6.ip6_prohibit_entry) {
2589 kfree(net->ipv6.ip6_null_entry);
2590 goto out;
2591 }
2592 net->ipv6.ip6_prohibit_entry->u.dst.path =
2593 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
2594
2595 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2596 sizeof(*net->ipv6.ip6_blk_hole_entry),
2597 GFP_KERNEL);
2598 if (!net->ipv6.ip6_blk_hole_entry) {
2599 kfree(net->ipv6.ip6_null_entry);
2600 kfree(net->ipv6.ip6_prohibit_entry);
2601 goto out;
2602 }
2603 net->ipv6.ip6_blk_hole_entry->u.dst.path =
2604 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
2605#endif
2606
2538#ifdef CONFIG_PROC_FS 2607#ifdef CONFIG_PROC_FS
2539 proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); 2608 proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
2540 proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); 2609 proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
2541#endif 2610#endif
2542 return 0; 2611 ret = 0;
2612out:
2613 return ret;
2543} 2614}
2544 2615
2545static void ip6_route_net_exit(struct net *net) 2616static void ip6_route_net_exit(struct net *net)
@@ -2548,7 +2619,11 @@ static void ip6_route_net_exit(struct net *net)
2548 proc_net_remove(net, "ipv6_route"); 2619 proc_net_remove(net, "ipv6_route");
2549 proc_net_remove(net, "rt6_stats"); 2620 proc_net_remove(net, "rt6_stats");
2550#endif 2621#endif
2551 rt6_ifdown(net, NULL); 2622 kfree(net->ipv6.ip6_null_entry);
2623#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2624 kfree(net->ipv6.ip6_prohibit_entry);
2625 kfree(net->ipv6.ip6_blk_hole_entry);
2626#endif
2552} 2627}
2553 2628
2554static struct pernet_operations ip6_route_net_ops = { 2629static struct pernet_operations ip6_route_net_ops = {
@@ -2556,6 +2631,11 @@ static struct pernet_operations ip6_route_net_ops = {
2556 .exit = ip6_route_net_exit, 2631 .exit = ip6_route_net_exit,
2557}; 2632};
2558 2633
2634static struct notifier_block ip6_route_dev_notifier = {
2635 .notifier_call = ip6_route_dev_notify,
2636 .priority = 0,
2637};
2638
2559int __init ip6_route_init(void) 2639int __init ip6_route_init(void)
2560{ 2640{
2561 int ret; 2641 int ret;
@@ -2568,30 +2648,24 @@ int __init ip6_route_init(void)
2568 2648
2569 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; 2649 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
2570 2650
2571 ret = -ENOMEM; 2651 ret = register_pernet_subsys(&ip6_route_net_ops);
2572 ip6_null_entry = kmemdup(&ip6_null_entry_template, 2652 if (ret)
2573 sizeof(*ip6_null_entry), GFP_KERNEL);
2574 if (!ip6_null_entry)
2575 goto out_kmem_cache; 2653 goto out_kmem_cache;
2576 ip6_null_entry->u.dst.path = (struct dst_entry *)ip6_null_entry;
2577
2578#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2579 ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
2580 sizeof(*ip6_prohibit_entry), GFP_KERNEL);
2581 if (!ip6_prohibit_entry)
2582 goto out_ip6_null_entry;
2583 ip6_prohibit_entry->u.dst.path = (struct dst_entry *)ip6_prohibit_entry;
2584
2585 ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2586 sizeof(*ip6_blk_hole_entry), GFP_KERNEL);
2587 if (!ip6_blk_hole_entry)
2588 goto out_ip6_prohibit_entry;
2589 ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)ip6_blk_hole_entry;
2590#endif
2591 2654
2655 /* Registering of the loopback is done before this portion of code,
2656 * the loopback reference in rt6_info will not be taken, do it
2657 * manually for init_net */
2658 init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev;
2659 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
2660 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
2661 init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
2662 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
2663 init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
2664 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
2665 #endif
2592 ret = fib6_init(); 2666 ret = fib6_init();
2593 if (ret) 2667 if (ret)
2594 goto out_ip6_blk_hole_entry; 2668 goto out_register_subsys;
2595 2669
2596 ret = xfrm6_init(); 2670 ret = xfrm6_init();
2597 if (ret) 2671 if (ret)
@@ -2607,9 +2681,10 @@ int __init ip6_route_init(void)
2607 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) 2681 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
2608 goto fib6_rules_init; 2682 goto fib6_rules_init;
2609 2683
2610 ret = register_pernet_subsys(&ip6_route_net_ops); 2684 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
2611 if (ret) 2685 if (ret)
2612 goto fib6_rules_init; 2686 goto fib6_rules_init;
2687
2613out: 2688out:
2614 return ret; 2689 return ret;
2615 2690
@@ -2619,14 +2694,8 @@ xfrm6_init:
2619 xfrm6_fini(); 2694 xfrm6_fini();
2620out_fib6_init: 2695out_fib6_init:
2621 fib6_gc_cleanup(); 2696 fib6_gc_cleanup();
2622out_ip6_blk_hole_entry: 2697out_register_subsys:
2623#ifdef CONFIG_IPV6_MULTIPLE_TABLES 2698 unregister_pernet_subsys(&ip6_route_net_ops);
2624 kfree(ip6_blk_hole_entry);
2625out_ip6_prohibit_entry:
2626 kfree(ip6_prohibit_entry);
2627out_ip6_null_entry:
2628#endif
2629 kfree(ip6_null_entry);
2630out_kmem_cache: 2699out_kmem_cache:
2631 kmem_cache_destroy(ip6_dst_ops.kmem_cachep); 2700 kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
2632 goto out; 2701 goto out;
@@ -2634,15 +2703,10 @@ out_kmem_cache:
2634 2703
2635void ip6_route_cleanup(void) 2704void ip6_route_cleanup(void)
2636{ 2705{
2637 unregister_pernet_subsys(&ip6_route_net_ops); 2706 unregister_netdevice_notifier(&ip6_route_dev_notifier);
2638 fib6_rules_cleanup(); 2707 fib6_rules_cleanup();
2639 xfrm6_fini(); 2708 xfrm6_fini();
2640 fib6_gc_cleanup(); 2709 fib6_gc_cleanup();
2710 unregister_pernet_subsys(&ip6_route_net_ops);
2641 kmem_cache_destroy(ip6_dst_ops.kmem_cachep); 2711 kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
2642
2643 kfree(ip6_null_entry);
2644#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2645 kfree(ip6_prohibit_entry);
2646 kfree(ip6_blk_hole_entry);
2647#endif
2648} 2712}