diff options
-rw-r--r-- | include/net/ip6_fib.h | 3 | ||||
-rw-r--r-- | include/net/netns/ipv6.h | 3 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 9 | ||||
-rw-r--r-- | net/ipv6/fib6_rules.c | 17 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 45 | ||||
-rw-r--r-- | net/ipv6/route.c | 202 |
6 files changed, 171 insertions, 108 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index fae267f65341..7c5c0f79168a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -174,7 +174,8 @@ struct fib6_table { | |||
174 | #define RT6_TABLE_LOCAL RT6_TABLE_MAIN | 174 | #define RT6_TABLE_LOCAL RT6_TABLE_MAIN |
175 | #endif | 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 | struct flowi *, int); | 179 | struct flowi *, int); |
179 | 180 | ||
180 | /* | 181 | /* |
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index c6c9afff13ef..311a942f36e9 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h | |||
@@ -36,11 +36,14 @@ struct netns_ipv6 { | |||
36 | struct xt_table *ip6table_mangle; | 36 | struct xt_table *ip6table_mangle; |
37 | struct xt_table *ip6table_raw; | 37 | struct xt_table *ip6table_raw; |
38 | #endif | 38 | #endif |
39 | struct rt6_info *ip6_null_entry; | ||
39 | struct rt6_statistics *rt6_stats; | 40 | struct rt6_statistics *rt6_stats; |
40 | struct timer_list *ip6_fib_timer; | 41 | struct timer_list *ip6_fib_timer; |
41 | struct hlist_head *fib_table_hash; | 42 | struct hlist_head *fib_table_hash; |
42 | struct fib6_table *fib6_main_tbl; | 43 | struct fib6_table *fib6_main_tbl; |
43 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 44 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
45 | struct rt6_info *ip6_prohibit_entry; | ||
46 | struct rt6_info *ip6_blk_hole_entry; | ||
44 | struct fib6_table *fib6_local_tbl; | 47 | struct fib6_table *fib6_local_tbl; |
45 | struct fib_rules_ops *fib6_rules_ops; | 48 | struct fib_rules_ops *fib6_rules_ops; |
46 | #endif | 49 | #endif |
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 | ||
50 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | 50 | 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 | { | 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 | ||
80 | static void fib6_prune_clones(struct net *net, struct fib6_node *fn, | 80 | static void fib6_prune_clones(struct net *net, struct fib6_node *fn, |
81 | struct rt6_info *rt); | 81 | struct rt6_info *rt); |
82 | static struct rt6_info * fib6_find_prefix(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 fib6_node *fn); | 83 | static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn); |
84 | static int fib6_walk(struct fib6_walker_t *w); | 84 | static int fib6_walk(struct fib6_walker_t *w); |
85 | static int fib6_walk_continue(struct fib6_walker_t *w); | 85 | static 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 | ||
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 | 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) | |||
267 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | 267 | struct 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 | ||
273 | static void fib6_tables_init(struct net *net) | 273 | 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 | 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 | */ |
794 | st_failure: | 794 | st_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 | ||
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 | 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 | ||
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 | 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 | ||
1146 | int fib6_del(struct rt6_info *rt, struct nl_info *info) | 1147 | int 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 | ||
1537 | static void fib6_net_exit(struct net *net) | 1539 | static 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 | ||
148 | struct rt6_info *ip6_null_entry; | ||
149 | |||
150 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 148 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
151 | 149 | ||
152 | static int ip6_pkt_prohibit(struct sk_buff *skb); | 150 | static 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 | ||
173 | struct rt6_info *ip6_prohibit_entry; | ||
174 | |||
175 | static struct rt6_info ip6_blk_hole_entry_template = { | 171 | static 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 | ||
193 | struct 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 | ||
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 | 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, | |||
415 | static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) | 410 | static 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) \ |
527 | do { \ | 524 | do { \ |
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 | ||
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 | 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); |
552 | restart: | 550 | restart: |
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); |
556 | out: | 554 | out: |
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 | ||
671 | static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif, | 669 | static 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 | ||
689 | restart: | 687 | restart: |
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 | ||
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 | 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 | ||
749 | void ip6_route_input(struct sk_buff *skb) | 748 | void 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 | ||
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 | 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 | ||
779 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 778 | 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 | { | 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 | ||
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 | 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); |
1377 | out: | 1378 | out: |
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 | ||
1891 | struct arg_dev_net { | ||
1892 | struct net_device *dev; | ||
1893 | struct net *net; | ||
1894 | }; | ||
1895 | |||
1889 | static int fib6_ifdown(struct rt6_info *rt, void *arg) | 1896 | static 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 | ||
1899 | void rt6_ifdown(struct net *net, struct net_device *dev) | 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 | struct rt6_mtu_change_arg | 1919 | struct 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 | ||
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 | * /proc | 2328 | * /proc |
2294 | */ | 2329 | */ |
@@ -2535,11 +2570,47 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) | |||
2535 | 2570 | ||
2536 | static int ip6_route_net_init(struct net *net) | 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 | #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; |
2612 | out: | ||
2613 | return ret; | ||
2543 | } | 2614 | } |
2544 | 2615 | ||
2545 | static void ip6_route_net_exit(struct net *net) | 2616 | static 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 | ||
2554 | static struct pernet_operations ip6_route_net_ops = { | 2629 | static 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 | ||
2634 | static struct notifier_block ip6_route_dev_notifier = { | ||
2635 | .notifier_call = ip6_route_dev_notify, | ||
2636 | .priority = 0, | ||
2637 | }; | ||
2638 | |||
2559 | int __init ip6_route_init(void) | 2639 | int __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 | |||
2613 | out: | 2688 | out: |
2614 | return ret; | 2689 | return ret; |
2615 | 2690 | ||
@@ -2619,14 +2694,8 @@ xfrm6_init: | |||
2619 | xfrm6_fini(); | 2694 | xfrm6_fini(); |
2620 | out_fib6_init: | 2695 | out_fib6_init: |
2621 | fib6_gc_cleanup(); | 2696 | fib6_gc_cleanup(); |
2622 | out_ip6_blk_hole_entry: | 2697 | out_register_subsys: |
2623 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2698 | unregister_pernet_subsys(&ip6_route_net_ops); |
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); | ||
2630 | out_kmem_cache: | 2699 | out_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 | ||
2635 | void ip6_route_cleanup(void) | 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 | 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 | } |