Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Daniel Lezcano and committed by
David S. Miller
8ed67789 bdb3289f

+171 -108
+2 -1
include/net/ip6_fib.h
··· 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 /*
+3
include/net/netns/ipv6.h
··· 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
-9
net/ipv6/addrconf.c
··· 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);
+9 -8
net/ipv6/fib6_rules.c
··· 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, ··· 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 /*
+24 -21
net/ipv6/ip6_fib.c
··· 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 ··· 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 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 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 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 ··· 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 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 ··· 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 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; ··· 1009 1008 || (children && fn->fn_flags&RTN_ROOT) 1010 1009 #endif 1011 1010 ) { 1012 - fn->leaf = fib6_find_prefix(fn); 1011 + fn->leaf = fib6_find_prefix(net, fn); 1013 1012 #if RT6_DEBUG >= 2 1014 1013 if (fn->leaf==NULL) { 1015 1014 BUG_TRAP(fn->leaf); 1016 - fn->leaf = ip6_null_entry; 1015 + fn->leaf = net->ipv6.ip6_null_entry; 1017 1016 } 1018 1017 #endif 1019 1018 atomic_inc(&fn->leaf->rt6i_ref); ··· 1118 1117 if (fn->leaf == NULL) { 1119 1118 fn->fn_flags &= ~RTN_RTINFO; 1120 1119 net->ipv6.rt6_stats->fib_route_nodes--; 1121 - fn = fib6_repair_tree(fn); 1120 + fn = fib6_repair_tree(net, fn); 1122 1121 } 1123 1122 1124 1123 if (atomic_read(&rt->rt6i_ref) != 1) { ··· 1130 1129 */ 1131 1130 while (fn) { 1132 1131 if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { 1133 - fn->leaf = fib6_find_prefix(fn); 1132 + fn->leaf = fib6_find_prefix(net, fn); 1134 1133 atomic_inc(&fn->leaf->rt6i_ref); 1135 1134 rt6_release(rt); 1136 1135 } ··· 1146 1145 1147 1146 int fib6_del(struct rt6_info *rt, struct nl_info *info) 1148 1147 { 1148 + struct net *net = info->nl_net; 1149 1149 struct fib6_node *fn = rt->rt6i_node; 1150 1150 struct rt6_info **rtp; 1151 1151 ··· 1156 1154 return -ENOENT; 1157 1155 } 1158 1156 #endif 1159 - if (fn == NULL || rt == ip6_null_entry) 1157 + if (fn == NULL || rt == net->ipv6.ip6_null_entry) 1160 1158 return -ENOENT; 1161 1159 1162 1160 BUG_TRAP(fn->fn_flags&RTN_RTINFO); ··· 1503 1501 goto out_fib_table_hash; 1504 1502 1505 1503 net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; 1506 - net->ipv6.fib6_main_tbl->tb6_root.leaf = ip6_null_entry; 1504 + net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry; 1507 1505 net->ipv6.fib6_main_tbl->tb6_root.fn_flags = 1508 1506 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; 1509 1507 ··· 1513 1511 if (!net->ipv6.fib6_local_tbl) 1514 1512 goto out_fib6_main_tbl; 1515 1513 net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; 1516 - net->ipv6.fib6_local_tbl->tb6_root.leaf = ip6_null_entry; 1514 + net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry; 1517 1515 net->ipv6.fib6_local_tbl->tb6_root.fn_flags = 1518 1516 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; 1519 1517 #endif ··· 1538 1536 1539 1537 static void fib6_net_exit(struct net *net) 1540 1538 { 1539 + rt6_ifdown(net, NULL); 1541 1540 del_timer(net->ipv6.ip6_fib_timer); 1542 1541 kfree(net->ipv6.ip6_fib_timer); 1543 1542 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+133 -69
net/ipv6/route.c
··· 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); ··· 168 170 .rt6i_ref = ATOMIC_INIT(1), 169 171 }; 170 172 171 - struct rt6_info *ip6_prohibit_entry; 172 - 173 173 static struct rt6_info ip6_blk_hole_entry_template = { 174 174 .u = { 175 175 .dst = { ··· 185 189 .rt6i_metric = ~(u32) 0, 186 190 .rt6i_ref = ATOMIC_INIT(1), 187 191 }; 188 - 189 - struct rt6_info *ip6_blk_hole_entry; 190 192 191 193 #endif 192 194 ··· 239 245 * Route lookup. Any table->tb6_lock is implied. 240 246 */ 241 247 242 - static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, 248 + static inline struct rt6_info *rt6_device_match(struct net *net, 249 + struct rt6_info *rt, 243 250 int oif, 244 251 int strict) 245 252 { ··· 269 274 return local; 270 275 271 276 if (strict) 272 - return ip6_null_entry; 277 + return net->ipv6.ip6_null_entry; 273 278 } 274 279 return rt; 275 280 } ··· 410 415 static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) 411 416 { 412 417 struct rt6_info *match, *rt0; 418 + struct net *net; 413 419 414 420 RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", 415 421 __FUNCTION__, fn->leaf, oif); ··· 436 440 RT6_TRACE("%s() => %p\n", 437 441 __FUNCTION__, match); 438 442 439 - return (match ? match : ip6_null_entry); 443 + net = rt0->rt6i_dev->nd_net; 444 + return (match ? match : net->ipv6.ip6_null_entry); 440 445 } 441 446 442 447 #ifdef CONFIG_IPV6_ROUTE_INFO ··· 520 523 } 521 524 #endif 522 525 523 - #define BACKTRACK(saddr) \ 526 + #define BACKTRACK(__net, saddr) \ 524 527 do { \ 525 - if (rt == ip6_null_entry) { \ 528 + if (rt == __net->ipv6.ip6_null_entry) { \ 526 529 struct fib6_node *pn; \ 527 530 while (1) { \ 528 531 if (fn->fn_flags & RTN_TL_ROOT) \ ··· 538 541 } \ 539 542 } while(0) 540 543 541 - static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, 544 + static struct rt6_info *ip6_pol_route_lookup(struct net *net, 545 + struct fib6_table *table, 542 546 struct flowi *fl, int flags) 543 547 { 544 548 struct fib6_node *fn; ··· 549 551 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); 550 552 restart: 551 553 rt = fn->leaf; 552 - rt = rt6_device_match(rt, fl->oif, flags); 553 - BACKTRACK(&fl->fl6_src); 554 + rt = rt6_device_match(net, rt, fl->oif, flags); 555 + BACKTRACK(net, &fl->fl6_src); 554 556 out: 555 557 dst_use(&rt->u.dst, jiffies); 556 558 read_unlock_bh(&table->tb6_lock); ··· 666 668 return rt; 667 669 } 668 670 669 - static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif, 670 - struct flowi *fl, int flags) 671 + static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, 672 + struct flowi *fl, int flags) 671 673 { 672 674 struct fib6_node *fn; 673 675 struct rt6_info *rt, *nrt; ··· 686 688 687 689 restart: 688 690 rt = rt6_select(fn, oif, strict | reachable); 689 - BACKTRACK(&fl->fl6_src); 690 - if (rt == ip6_null_entry || 691 + 692 + BACKTRACK(net, &fl->fl6_src); 693 + if (rt == net->ipv6.ip6_null_entry || 691 694 rt->rt6i_flags & RTF_CACHE) 692 695 goto out; 693 696 ··· 706 707 } 707 708 708 709 dst_release(&rt->u.dst); 709 - rt = nrt ? : ip6_null_entry; 710 + rt = nrt ? : net->ipv6.ip6_null_entry; 710 711 711 712 dst_hold(&rt->u.dst); 712 713 if (nrt) { ··· 739 740 return rt; 740 741 } 741 742 742 - static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, 743 + static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, 743 744 struct flowi *fl, int flags) 744 745 { 745 - return ip6_pol_route(table, fl->iif, fl, flags); 746 + return ip6_pol_route(net, table, fl->iif, fl, flags); 746 747 } 747 748 748 749 void ip6_route_input(struct sk_buff *skb) ··· 769 770 skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); 770 771 } 771 772 772 - static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, 773 + static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, 773 774 struct flowi *fl, int flags) 774 775 { 775 - return ip6_pol_route(table, fl->oif, fl, flags); 776 + return ip6_pol_route(net, table, fl->oif, fl, flags); 776 777 } 777 778 778 779 struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) ··· 1258 1259 { 1259 1260 int err; 1260 1261 struct fib6_table *table; 1262 + struct net *net = rt->rt6i_dev->nd_net; 1261 1263 1262 - if (rt == ip6_null_entry) 1264 + if (rt == net->ipv6.ip6_null_entry) 1263 1265 return -ENOENT; 1264 1266 1265 1267 table = rt->rt6i_table; ··· 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 { ··· 1373 1372 } 1374 1373 1375 1374 if (!rt) 1376 - rt = ip6_null_entry; 1377 - BACKTRACK(&fl->fl6_src); 1375 + rt = net->ipv6.ip6_null_entry; 1376 + BACKTRACK(net, &fl->fl6_src); 1378 1377 out: 1379 1378 dst_hold(&rt->u.dst); 1380 1379 ··· 1416 1415 { 1417 1416 struct rt6_info *rt, *nrt = NULL; 1418 1417 struct netevent_redirect netevent; 1418 + struct net *net = neigh->dev->nd_net; 1419 1419 1420 1420 rt = ip6_route_redirect(dest, src, saddr, neigh->dev); 1421 1421 1422 - if (rt == ip6_null_entry) { 1422 + if (rt == net->ipv6.ip6_null_entry) { 1423 1423 if (net_ratelimit()) 1424 1424 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " 1425 1425 "for redirect target\n"); ··· 1888 1886 return rt; 1889 1887 } 1890 1888 1889 + struct arg_dev_net { 1890 + struct net_device *dev; 1891 + struct net *net; 1892 + }; 1893 + 1891 1894 static int fib6_ifdown(struct rt6_info *rt, void *arg) 1892 1895 { 1893 - if (((void*)rt->rt6i_dev == arg || arg == NULL) && 1894 - rt != ip6_null_entry) { 1896 + struct net_device *dev = ((struct arg_dev_net *)arg)->dev; 1897 + struct net *net = ((struct arg_dev_net *)arg)->net; 1898 + 1899 + if (((void *)rt->rt6i_dev == dev || dev == NULL) && 1900 + rt != net->ipv6.ip6_null_entry) { 1895 1901 RT6_TRACE("deleted by ifdown %p\n", rt); 1896 1902 return -1; 1897 1903 } ··· 1908 1898 1909 1899 void rt6_ifdown(struct net *net, struct net_device *dev) 1910 1900 { 1911 - fib6_clean_all(net, fib6_ifdown, 0, dev); 1901 + struct arg_dev_net adn = { 1902 + .dev = dev, 1903 + .net = net, 1904 + }; 1905 + 1906 + fib6_clean_all(net, fib6_ifdown, 0, &adn); 1912 1907 } 1913 1908 1914 1909 struct rt6_mtu_change_arg ··· 2304 2289 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); 2305 2290 } 2306 2291 2292 + static int ip6_route_dev_notify(struct notifier_block *this, 2293 + unsigned long event, void *data) 2294 + { 2295 + struct net_device *dev = (struct net_device *)data; 2296 + struct net *net = dev->nd_net; 2297 + 2298 + if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { 2299 + net->ipv6.ip6_null_entry->u.dst.dev = dev; 2300 + net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); 2301 + #ifdef CONFIG_IPV6_MULTIPLE_TABLES 2302 + net->ipv6.ip6_prohibit_entry->u.dst.dev = dev; 2303 + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); 2304 + net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev; 2305 + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); 2306 + #endif 2307 + } 2308 + 2309 + return NOTIFY_OK; 2310 + } 2311 + 2307 2312 /* 2308 2313 * /proc 2309 2314 */ ··· 2570 2535 2571 2536 static int ip6_route_net_init(struct net *net) 2572 2537 { 2538 + int ret = 0; 2539 + 2540 + ret = -ENOMEM; 2541 + net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, 2542 + sizeof(*net->ipv6.ip6_null_entry), 2543 + GFP_KERNEL); 2544 + if (!net->ipv6.ip6_null_entry) 2545 + goto out; 2546 + net->ipv6.ip6_null_entry->u.dst.path = 2547 + (struct dst_entry *)net->ipv6.ip6_null_entry; 2548 + 2549 + #ifdef CONFIG_IPV6_MULTIPLE_TABLES 2550 + net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, 2551 + sizeof(*net->ipv6.ip6_prohibit_entry), 2552 + GFP_KERNEL); 2553 + if (!net->ipv6.ip6_prohibit_entry) { 2554 + kfree(net->ipv6.ip6_null_entry); 2555 + goto out; 2556 + } 2557 + net->ipv6.ip6_prohibit_entry->u.dst.path = 2558 + (struct dst_entry *)net->ipv6.ip6_prohibit_entry; 2559 + 2560 + net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, 2561 + sizeof(*net->ipv6.ip6_blk_hole_entry), 2562 + GFP_KERNEL); 2563 + if (!net->ipv6.ip6_blk_hole_entry) { 2564 + kfree(net->ipv6.ip6_null_entry); 2565 + kfree(net->ipv6.ip6_prohibit_entry); 2566 + goto out; 2567 + } 2568 + net->ipv6.ip6_blk_hole_entry->u.dst.path = 2569 + (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; 2570 + #endif 2571 + 2573 2572 #ifdef CONFIG_PROC_FS 2574 2573 proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); 2575 2574 proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); 2576 2575 #endif 2577 - return 0; 2576 + ret = 0; 2577 + out: 2578 + return ret; 2578 2579 } 2579 2580 2580 2581 static void ip6_route_net_exit(struct net *net) ··· 2619 2548 proc_net_remove(net, "ipv6_route"); 2620 2549 proc_net_remove(net, "rt6_stats"); 2621 2550 #endif 2622 - rt6_ifdown(net, NULL); 2551 + kfree(net->ipv6.ip6_null_entry); 2552 + #ifdef CONFIG_IPV6_MULTIPLE_TABLES 2553 + kfree(net->ipv6.ip6_prohibit_entry); 2554 + kfree(net->ipv6.ip6_blk_hole_entry); 2555 + #endif 2623 2556 } 2624 2557 2625 2558 static struct pernet_operations ip6_route_net_ops = { 2626 2559 .init = ip6_route_net_init, 2627 2560 .exit = ip6_route_net_exit, 2561 + }; 2562 + 2563 + static struct notifier_block ip6_route_dev_notifier = { 2564 + .notifier_call = ip6_route_dev_notify, 2565 + .priority = 0, 2628 2566 }; 2629 2567 2630 2568 int __init ip6_route_init(void) ··· 2648 2568 2649 2569 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; 2650 2570 2651 - ret = -ENOMEM; 2652 - ip6_null_entry = kmemdup(&ip6_null_entry_template, 2653 - sizeof(*ip6_null_entry), GFP_KERNEL); 2654 - if (!ip6_null_entry) 2571 + ret = register_pernet_subsys(&ip6_route_net_ops); 2572 + if (ret) 2655 2573 goto out_kmem_cache; 2656 - ip6_null_entry->u.dst.path = (struct dst_entry *)ip6_null_entry; 2657 2574 2658 - #ifdef CONFIG_IPV6_MULTIPLE_TABLES 2659 - ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, 2660 - sizeof(*ip6_prohibit_entry), GFP_KERNEL); 2661 - if (!ip6_prohibit_entry) 2662 - goto out_ip6_null_entry; 2663 - ip6_prohibit_entry->u.dst.path = (struct dst_entry *)ip6_prohibit_entry; 2664 - 2665 - ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, 2666 - sizeof(*ip6_blk_hole_entry), GFP_KERNEL); 2667 - if (!ip6_blk_hole_entry) 2668 - goto out_ip6_prohibit_entry; 2669 - ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)ip6_blk_hole_entry; 2670 - #endif 2671 - 2575 + /* Registering of the loopback is done before this portion of code, 2576 + * the loopback reference in rt6_info will not be taken, do it 2577 + * manually for init_net */ 2578 + init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev; 2579 + init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); 2580 + #ifdef CONFIG_IPV6_MULTIPLE_TABLES 2581 + init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev; 2582 + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); 2583 + init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev; 2584 + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); 2585 + #endif 2672 2586 ret = fib6_init(); 2673 2587 if (ret) 2674 - goto out_ip6_blk_hole_entry; 2588 + goto out_register_subsys; 2675 2589 2676 2590 ret = xfrm6_init(); 2677 2591 if (ret) ··· 2681 2607 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) 2682 2608 goto fib6_rules_init; 2683 2609 2684 - ret = register_pernet_subsys(&ip6_route_net_ops); 2610 + ret = register_netdevice_notifier(&ip6_route_dev_notifier); 2685 2611 if (ret) 2686 2612 goto fib6_rules_init; 2613 + 2687 2614 out: 2688 2615 return ret; 2689 2616 ··· 2694 2619 xfrm6_fini(); 2695 2620 out_fib6_init: 2696 2621 fib6_gc_cleanup(); 2697 - out_ip6_blk_hole_entry: 2698 - #ifdef CONFIG_IPV6_MULTIPLE_TABLES 2699 - kfree(ip6_blk_hole_entry); 2700 - out_ip6_prohibit_entry: 2701 - kfree(ip6_prohibit_entry); 2702 - out_ip6_null_entry: 2703 - #endif 2704 - kfree(ip6_null_entry); 2622 + out_register_subsys: 2623 + unregister_pernet_subsys(&ip6_route_net_ops); 2705 2624 out_kmem_cache: 2706 2625 kmem_cache_destroy(ip6_dst_ops.kmem_cachep); 2707 2626 goto out; ··· 2703 2634 2704 2635 void ip6_route_cleanup(void) 2705 2636 { 2706 - unregister_pernet_subsys(&ip6_route_net_ops); 2637 + unregister_netdevice_notifier(&ip6_route_dev_notifier); 2707 2638 fib6_rules_cleanup(); 2708 2639 xfrm6_fini(); 2709 2640 fib6_gc_cleanup(); 2641 + unregister_pernet_subsys(&ip6_route_net_ops); 2710 2642 kmem_cache_destroy(ip6_dst_ops.kmem_cachep); 2711 - 2712 - kfree(ip6_null_entry); 2713 - #ifdef CONFIG_IPV6_MULTIPLE_TABLES 2714 - kfree(ip6_prohibit_entry); 2715 - kfree(ip6_blk_hole_entry); 2716 - #endif 2717 2643 }