Commit 8ed677896752fff056f6cf3d7ce462adc6c464f0

Authored by Daniel Lezcano
Committed by David S. Miller
1 parent bdb3289f73

[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: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 6 changed files with 171 additions and 108 deletions Side-by-side Diff

include/net/ip6_fib.h
... ... @@ -174,7 +174,8 @@
174 174 #define RT6_TABLE_LOCAL RT6_TABLE_MAIN
175 175 #endif
176 176  
177   -typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *,
  177 +typedef struct rt6_info *(*pol_lookup_t)(struct net *,
  178 + struct fib6_table *,
178 179 struct flowi *, int);
179 180  
180 181 /*
include/net/netns/ipv6.h
... ... @@ -36,11 +36,14 @@
36 36 struct xt_table *ip6table_mangle;
37 37 struct xt_table *ip6table_raw;
38 38 #endif
  39 + struct rt6_info *ip6_null_entry;
39 40 struct rt6_statistics *rt6_stats;
40 41 struct timer_list *ip6_fib_timer;
41 42 struct hlist_head *fib_table_hash;
42 43 struct fib6_table *fib6_main_tbl;
43 44 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  45 + struct rt6_info *ip6_prohibit_entry;
  46 + struct rt6_info *ip6_blk_hole_entry;
44 47 struct fib6_table *fib6_local_tbl;
45 48 struct fib_rules_ops *fib6_rules_ops;
46 49 #endif
... ... @@ -4301,15 +4301,6 @@
4301 4301 if (err)
4302 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 4304 register_netdevice_notifier(&ipv6_dev_notf);
4314 4305  
4315 4306 addrconf_verify(0);
net/ipv6/fib6_rules.c
... ... @@ -43,8 +43,8 @@
43 43 if (arg.result)
44 44 return arg.result;
45 45  
46   - dst_hold(&ip6_null_entry->u.dst);
47   - return &ip6_null_entry->u.dst;
  46 + dst_hold(&net->ipv6.ip6_null_entry->u.dst);
  47 + return &net->ipv6.ip6_null_entry->u.dst;
48 48 }
49 49  
50 50 static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
51 51  
52 52  
53 53  
54 54  
55 55  
56 56  
... ... @@ -52,28 +52,29 @@
52 52 {
53 53 struct rt6_info *rt = NULL;
54 54 struct fib6_table *table;
  55 + struct net *net = rule->fr_net;
55 56 pol_lookup_t lookup = arg->lookup_ptr;
56 57  
57 58 switch (rule->action) {
58 59 case FR_ACT_TO_TBL:
59 60 break;
60 61 case FR_ACT_UNREACHABLE:
61   - rt = ip6_null_entry;
  62 + rt = net->ipv6.ip6_null_entry;
62 63 goto discard_pkt;
63 64 default:
64 65 case FR_ACT_BLACKHOLE:
65   - rt = ip6_blk_hole_entry;
  66 + rt = net->ipv6.ip6_blk_hole_entry;
66 67 goto discard_pkt;
67 68 case FR_ACT_PROHIBIT:
68   - rt = ip6_prohibit_entry;
  69 + rt = net->ipv6.ip6_prohibit_entry;
69 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 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 78 struct fib6_rule *r = (struct fib6_rule *)rule;
78 79  
79 80 /*
... ... @@ -79,8 +79,8 @@
79 79  
80 80 static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
81 81 struct rt6_info *rt);
82   -static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
83   -static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
  82 +static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
  83 +static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
84 84 static int fib6_walk(struct fib6_walker_t *w);
85 85 static int fib6_walk_continue(struct fib6_walker_t *w);
86 86  
87 87  
... ... @@ -193,14 +193,14 @@
193 193  
194 194 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
195 195  
196   -static struct fib6_table *fib6_alloc_table(u32 id)
  196 +static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
197 197 {
198 198 struct fib6_table *table;
199 199  
200 200 table = kzalloc(sizeof(*table), GFP_ATOMIC);
201 201 if (table != NULL) {
202 202 table->tb6_id = id;
203   - table->tb6_root.leaf = ip6_null_entry;
  203 + table->tb6_root.leaf = net->ipv6.ip6_null_entry;
204 204 table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
205 205 }
206 206  
... ... @@ -217,7 +217,7 @@
217 217 if (tb)
218 218 return tb;
219 219  
220   - tb = fib6_alloc_table(id);
  220 + tb = fib6_alloc_table(net, id);
221 221 if (tb != NULL)
222 222 fib6_link_table(net, tb);
223 223  
... ... @@ -267,7 +267,7 @@
267 267 struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
268 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  
273 273 static void fib6_tables_init(struct net *net)
... ... @@ -717,8 +717,8 @@
717 717 if (sfn == NULL)
718 718 goto st_failure;
719 719  
720   - sfn->leaf = ip6_null_entry;
721   - atomic_inc(&ip6_null_entry->rt6i_ref);
  720 + sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
  721 + atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
722 722 sfn->fn_flags = RTN_ROOT;
723 723 sfn->fn_sernum = fib6_new_sernum();
724 724  
725 725  
... ... @@ -773,11 +773,11 @@
773 773 * super-tree leaf node we have to find a new one for it.
774 774 */
775 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 777 #if RT6_DEBUG >= 2
778 778 if (!pn->leaf) {
779 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 782 #endif
783 783 atomic_inc(&pn->leaf->rt6i_ref);
... ... @@ -793,7 +793,7 @@
793 793 */
794 794 st_failure:
795 795 if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
796   - fib6_repair_tree(fn);
  796 + fib6_repair_tree(info->nl_net, fn);
797 797 dst_free(&rt->u.dst);
798 798 return err;
799 799 #endif
800 800  
... ... @@ -959,10 +959,10 @@
959 959 *
960 960 */
961 961  
962   -static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
  962 +static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
963 963 {
964 964 if (fn->fn_flags&RTN_ROOT)
965   - return ip6_null_entry;
  965 + return net->ipv6.ip6_null_entry;
966 966  
967 967 while(fn) {
968 968 if(fn->left)
... ... @@ -981,7 +981,8 @@
981 981 * is the node we want to try and remove.
982 982 */
983 983  
984   -static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
  984 +static struct fib6_node *fib6_repair_tree(struct net *net,
  985 + struct fib6_node *fn)
985 986 {
986 987 int children;
987 988 int nstate;
988 989  
... ... @@ -1008,11 +1009,11 @@
1008 1009 || (children && fn->fn_flags&RTN_ROOT)
1009 1010 #endif
1010 1011 ) {
1011   - fn->leaf = fib6_find_prefix(fn);
  1012 + fn->leaf = fib6_find_prefix(net, fn);
1012 1013 #if RT6_DEBUG >= 2
1013 1014 if (fn->leaf==NULL) {
1014 1015 BUG_TRAP(fn->leaf);
1015   - fn->leaf = ip6_null_entry;
  1016 + fn->leaf = net->ipv6.ip6_null_entry;
1016 1017 }
1017 1018 #endif
1018 1019 atomic_inc(&fn->leaf->rt6i_ref);
... ... @@ -1117,7 +1118,7 @@
1117 1118 if (fn->leaf == NULL) {
1118 1119 fn->fn_flags &= ~RTN_RTINFO;
1119 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 1124 if (atomic_read(&rt->rt6i_ref) != 1) {
... ... @@ -1129,7 +1130,7 @@
1129 1130 */
1130 1131 while (fn) {
1131 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 1134 atomic_inc(&fn->leaf->rt6i_ref);
1134 1135 rt6_release(rt);
1135 1136 }
... ... @@ -1145,6 +1146,7 @@
1145 1146  
1146 1147 int fib6_del(struct rt6_info *rt, struct nl_info *info)
1147 1148 {
  1149 + struct net *net = info->nl_net;
1148 1150 struct fib6_node *fn = rt->rt6i_node;
1149 1151 struct rt6_info **rtp;
1150 1152  
... ... @@ -1154,7 +1156,7 @@
1154 1156 return -ENOENT;
1155 1157 }
1156 1158 #endif
1157   - if (fn == NULL || rt == ip6_null_entry)
  1159 + if (fn == NULL || rt == net->ipv6.ip6_null_entry)
1158 1160 return -ENOENT;
1159 1161  
1160 1162 BUG_TRAP(fn->fn_flags&RTN_RTINFO);
... ... @@ -1501,7 +1503,7 @@
1501 1503 goto out_fib_table_hash;
1502 1504  
1503 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 1507 net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
1506 1508 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1507 1509  
... ... @@ -1511,7 +1513,7 @@
1511 1513 if (!net->ipv6.fib6_local_tbl)
1512 1514 goto out_fib6_main_tbl;
1513 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 1517 net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
1516 1518 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1517 1519 #endif
... ... @@ -1536,6 +1538,7 @@
1536 1538  
1537 1539 static void fib6_net_exit(struct net *net)
1538 1540 {
  1541 + rt6_ifdown(net, NULL);
1539 1542 del_timer(net->ipv6.ip6_fib_timer);
1540 1543 kfree(net->ipv6.ip6_fib_timer);
1541 1544 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
... ... @@ -145,8 +145,6 @@
145 145 .rt6i_ref = ATOMIC_INIT(1),
146 146 };
147 147  
148   -struct rt6_info *ip6_null_entry;
149   -
150 148 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
151 149  
152 150 static int ip6_pkt_prohibit(struct sk_buff *skb);
... ... @@ -170,8 +168,6 @@
170 168 .rt6i_ref = ATOMIC_INIT(1),
171 169 };
172 170  
173   -struct rt6_info *ip6_prohibit_entry;
174   -
175 171 static struct rt6_info ip6_blk_hole_entry_template = {
176 172 .u = {
177 173 .dst = {
... ... @@ -190,8 +186,6 @@
190 186 .rt6i_ref = ATOMIC_INIT(1),
191 187 };
192 188  
193   -struct rt6_info *ip6_blk_hole_entry;
194   -
195 189 #endif
196 190  
197 191 /* allocate dst with ip6_dst_ops */
... ... @@ -245,7 +239,8 @@
245 239 * Route lookup. Any table->tb6_lock is implied.
246 240 */
247 241  
248   -static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
  242 +static inline struct rt6_info *rt6_device_match(struct net *net,
  243 + struct rt6_info *rt,
249 244 int oif,
250 245 int strict)
251 246 {
... ... @@ -274,7 +269,7 @@
274 269 return local;
275 270  
276 271 if (strict)
277   - return ip6_null_entry;
  272 + return net->ipv6.ip6_null_entry;
278 273 }
279 274 return rt;
280 275 }
... ... @@ -415,6 +410,7 @@
415 410 static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
416 411 {
417 412 struct rt6_info *match, *rt0;
  413 + struct net *net;
418 414  
419 415 RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
420 416 __FUNCTION__, fn->leaf, oif);
... ... @@ -440,7 +436,8 @@
440 436 RT6_TRACE("%s() => %p\n",
441 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 443 #ifdef CONFIG_IPV6_ROUTE_INFO
447 444  
... ... @@ -523,9 +520,9 @@
523 520 }
524 521 #endif
525 522  
526   -#define BACKTRACK(saddr) \
  523 +#define BACKTRACK(__net, saddr) \
527 524 do { \
528   - if (rt == ip6_null_entry) { \
  525 + if (rt == __net->ipv6.ip6_null_entry) { \
529 526 struct fib6_node *pn; \
530 527 while (1) { \
531 528 if (fn->fn_flags & RTN_TL_ROOT) \
... ... @@ -541,7 +538,8 @@
541 538 } \
542 539 } while(0)
543 540  
544   -static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
  541 +static struct rt6_info *ip6_pol_route_lookup(struct net *net,
  542 + struct fib6_table *table,
545 543 struct flowi *fl, int flags)
546 544 {
547 545 struct fib6_node *fn;
... ... @@ -551,8 +549,8 @@
551 549 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
552 550 restart:
553 551 rt = fn->leaf;
554   - rt = rt6_device_match(rt, fl->oif, flags);
555   - BACKTRACK(&fl->fl6_src);
  552 + rt = rt6_device_match(net, rt, fl->oif, flags);
  553 + BACKTRACK(net, &fl->fl6_src);
556 554 out:
557 555 dst_use(&rt->u.dst, jiffies);
558 556 read_unlock_bh(&table->tb6_lock);
... ... @@ -668,8 +666,8 @@
668 666 return rt;
669 667 }
670 668  
671   -static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif,
672   - struct flowi *fl, int flags)
  669 +static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
  670 + struct flowi *fl, int flags)
673 671 {
674 672 struct fib6_node *fn;
675 673 struct rt6_info *rt, *nrt;
... ... @@ -688,8 +686,9 @@
688 686  
689 687 restart:
690 688 rt = rt6_select(fn, oif, strict | reachable);
691   - BACKTRACK(&fl->fl6_src);
692   - if (rt == ip6_null_entry ||
  689 +
  690 + BACKTRACK(net, &fl->fl6_src);
  691 + if (rt == net->ipv6.ip6_null_entry ||
693 692 rt->rt6i_flags & RTF_CACHE)
694 693 goto out;
695 694  
... ... @@ -707,7 +706,7 @@
707 706 }
708 707  
709 708 dst_release(&rt->u.dst);
710   - rt = nrt ? : ip6_null_entry;
  709 + rt = nrt ? : net->ipv6.ip6_null_entry;
711 710  
712 711 dst_hold(&rt->u.dst);
713 712 if (nrt) {
714 713  
... ... @@ -740,10 +739,10 @@
740 739 return rt;
741 740 }
742 741  
743   -static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
  742 +static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
744 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  
749 748 void ip6_route_input(struct sk_buff *skb)
750 749  
... ... @@ -770,10 +769,10 @@
770 769 skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
771 770 }
772 771  
773   -static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
  772 +static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
774 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  
779 778 struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
780 779  
... ... @@ -1259,8 +1258,9 @@
1259 1258 {
1260 1259 int err;
1261 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 1264 return -ENOENT;
1265 1265  
1266 1266 table = rt->rt6i_table;
... ... @@ -1329,7 +1329,8 @@
1329 1329 struct in6_addr gateway;
1330 1330 };
1331 1331  
1332   -static struct rt6_info *__ip6_route_redirect(struct fib6_table *table,
  1332 +static struct rt6_info *__ip6_route_redirect(struct net *net,
  1333 + struct fib6_table *table,
1333 1334 struct flowi *fl,
1334 1335 int flags)
1335 1336 {
... ... @@ -1372,8 +1373,8 @@
1372 1373 }
1373 1374  
1374 1375 if (!rt)
1375   - rt = ip6_null_entry;
1376   - BACKTRACK(&fl->fl6_src);
  1376 + rt = net->ipv6.ip6_null_entry;
  1377 + BACKTRACK(net, &fl->fl6_src);
1377 1378 out:
1378 1379 dst_hold(&rt->u.dst);
1379 1380  
1380 1381  
... ... @@ -1415,10 +1416,11 @@
1415 1416 {
1416 1417 struct rt6_info *rt, *nrt = NULL;
1417 1418 struct netevent_redirect netevent;
  1419 + struct net *net = neigh->dev->nd_net;
1418 1420  
1419 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 1424 if (net_ratelimit())
1423 1425 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
1424 1426 "for redirect target\n");
1425 1427  
... ... @@ -1886,10 +1888,18 @@
1886 1888 return rt;
1887 1889 }
1888 1890  
  1891 +struct arg_dev_net {
  1892 + struct net_device *dev;
  1893 + struct net *net;
  1894 +};
  1895 +
1889 1896 static int fib6_ifdown(struct rt6_info *rt, void *arg)
1890 1897 {
1891   - if (((void*)rt->rt6i_dev == arg || arg == NULL) &&
1892   - rt != ip6_null_entry) {
  1898 + struct net_device *dev = ((struct arg_dev_net *)arg)->dev;
  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 1903 RT6_TRACE("deleted by ifdown %p\n", rt);
1894 1904 return -1;
1895 1905 }
... ... @@ -1898,7 +1908,12 @@
1898 1908  
1899 1909 void 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  
1904 1919 struct rt6_mtu_change_arg
... ... @@ -2289,6 +2304,26 @@
2289 2304 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
2290 2305 }
2291 2306  
  2307 +static 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 2328 * /proc
2294 2329 */
2295 2330  
... ... @@ -2535,11 +2570,47 @@
2535 2570  
2536 2571 static 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 2607 #ifdef CONFIG_PROC_FS
2539 2608 proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
2540 2609 proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
2541 2610 #endif
2542   - return 0;
  2611 + ret = 0;
  2612 +out:
  2613 + return ret;
2543 2614 }
2544 2615  
2545 2616 static void ip6_route_net_exit(struct net *net)
... ... @@ -2548,7 +2619,11 @@
2548 2619 proc_net_remove(net, "ipv6_route");
2549 2620 proc_net_remove(net, "rt6_stats");
2550 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  
2554 2629 static struct pernet_operations ip6_route_net_ops = {
... ... @@ -2556,6 +2631,11 @@
2556 2631 .exit = ip6_route_net_exit,
2557 2632 };
2558 2633  
  2634 +static struct notifier_block ip6_route_dev_notifier = {
  2635 + .notifier_call = ip6_route_dev_notify,
  2636 + .priority = 0,
  2637 +};
  2638 +
2559 2639 int __init ip6_route_init(void)
2560 2640 {
2561 2641 int ret;
2562 2642  
2563 2643  
2564 2644  
... ... @@ -2568,30 +2648,24 @@
2568 2648  
2569 2649 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
2570 2650  
2571   - ret = -ENOMEM;
2572   - ip6_null_entry = kmemdup(&ip6_null_entry_template,
2573   - sizeof(*ip6_null_entry), GFP_KERNEL);
2574   - if (!ip6_null_entry)
  2651 + ret = register_pernet_subsys(&ip6_route_net_ops);
  2652 + if (ret)
2575 2653 goto out_kmem_cache;
2576   - ip6_null_entry->u.dst.path = (struct dst_entry *)ip6_null_entry;
2577 2654  
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   -
  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 2666 ret = fib6_init();
2593 2667 if (ret)
2594   - goto out_ip6_blk_hole_entry;
  2668 + goto out_register_subsys;
2595 2669  
2596 2670 ret = xfrm6_init();
2597 2671 if (ret)
2598 2672  
... ... @@ -2607,9 +2681,10 @@
2607 2681 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
2608 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 2685 if (ret)
2612 2686 goto fib6_rules_init;
  2687 +
2613 2688 out:
2614 2689 return ret;
2615 2690  
... ... @@ -2619,14 +2694,8 @@
2619 2694 xfrm6_fini();
2620 2695 out_fib6_init:
2621 2696 fib6_gc_cleanup();
2622   -out_ip6_blk_hole_entry:
2623   -#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2624   - kfree(ip6_blk_hole_entry);
2625   -out_ip6_prohibit_entry:
2626   - kfree(ip6_prohibit_entry);
2627   -out_ip6_null_entry:
2628   -#endif
2629   - kfree(ip6_null_entry);
  2697 +out_register_subsys:
  2698 + unregister_pernet_subsys(&ip6_route_net_ops);
2630 2699 out_kmem_cache:
2631 2700 kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
2632 2701 goto out;
2633 2702  
2634 2703  
... ... @@ -2634,16 +2703,11 @@
2634 2703  
2635 2704 void ip6_route_cleanup(void)
2636 2705 {
2637   - unregister_pernet_subsys(&ip6_route_net_ops);
  2706 + unregister_netdevice_notifier(&ip6_route_dev_notifier);
2638 2707 fib6_rules_cleanup();
2639 2708 xfrm6_fini();
2640 2709 fib6_gc_cleanup();
  2710 + unregister_pernet_subsys(&ip6_route_net_ops);
2641 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 }