aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_fib.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r--net/ipv6/ip6_fib.c298
1 files changed, 192 insertions, 106 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index bab72b6f1444..50f3f8f8a59b 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -48,8 +48,6 @@
48#define RT6_TRACE(x...) do { ; } while (0) 48#define RT6_TRACE(x...) do { ; } while (0)
49#endif 49#endif
50 50
51struct rt6_statistics rt6_stats;
52
53static struct kmem_cache * fib6_node_kmem __read_mostly; 51static struct kmem_cache * fib6_node_kmem __read_mostly;
54 52
55enum fib_walk_state_t 53enum fib_walk_state_t
@@ -66,6 +64,7 @@ enum fib_walk_state_t
66struct fib6_cleaner_t 64struct fib6_cleaner_t
67{ 65{
68 struct fib6_walker_t w; 66 struct fib6_walker_t w;
67 struct net *net;
69 int (*func)(struct rt6_info *, void *arg); 68 int (*func)(struct rt6_info *, void *arg);
70 void *arg; 69 void *arg;
71}; 70};
@@ -78,9 +77,10 @@ static DEFINE_RWLOCK(fib6_walker_lock);
78#define FWS_INIT FWS_L 77#define FWS_INIT FWS_L
79#endif 78#endif
80 79
81static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); 80static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
82static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); 81 struct rt6_info *rt);
83static struct fib6_node * fib6_repair_tree(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 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
@@ -93,7 +93,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w);
93 93
94static __u32 rt_sernum; 94static __u32 rt_sernum;
95 95
96static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); 96static void fib6_gc_timer_cb(unsigned long arg);
97 97
98static struct fib6_walker_t fib6_walker_list = { 98static struct fib6_walker_t fib6_walker_list = {
99 .prev = &fib6_walker_list, 99 .prev = &fib6_walker_list,
@@ -166,22 +166,13 @@ static __inline__ void rt6_release(struct rt6_info *rt)
166 dst_free(&rt->u.dst); 166 dst_free(&rt->u.dst);
167} 167}
168 168
169static struct fib6_table fib6_main_tbl = {
170 .tb6_id = RT6_TABLE_MAIN,
171 .tb6_root = {
172 .leaf = &ip6_null_entry,
173 .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
174 },
175};
176
177#ifdef CONFIG_IPV6_MULTIPLE_TABLES 169#ifdef CONFIG_IPV6_MULTIPLE_TABLES
178#define FIB_TABLE_HASHSZ 256 170#define FIB_TABLE_HASHSZ 256
179#else 171#else
180#define FIB_TABLE_HASHSZ 1 172#define FIB_TABLE_HASHSZ 1
181#endif 173#endif
182static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
183 174
184static void fib6_link_table(struct fib6_table *tb) 175static void fib6_link_table(struct net *net, struct fib6_table *tb)
185{ 176{
186 unsigned int h; 177 unsigned int h;
187 178
@@ -197,52 +188,46 @@ static void fib6_link_table(struct fib6_table *tb)
197 * No protection necessary, this is the only list mutatation 188 * No protection necessary, this is the only list mutatation
198 * operation, tables never disappear once they exist. 189 * operation, tables never disappear once they exist.
199 */ 190 */
200 hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]); 191 hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]);
201} 192}
202 193
203#ifdef CONFIG_IPV6_MULTIPLE_TABLES 194#ifdef CONFIG_IPV6_MULTIPLE_TABLES
204static struct fib6_table fib6_local_tbl = {
205 .tb6_id = RT6_TABLE_LOCAL,
206 .tb6_root = {
207 .leaf = &ip6_null_entry,
208 .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
209 },
210};
211 195
212static struct fib6_table *fib6_alloc_table(u32 id) 196static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
213{ 197{
214 struct fib6_table *table; 198 struct fib6_table *table;
215 199
216 table = kzalloc(sizeof(*table), GFP_ATOMIC); 200 table = kzalloc(sizeof(*table), GFP_ATOMIC);
217 if (table != NULL) { 201 if (table != NULL) {
218 table->tb6_id = id; 202 table->tb6_id = id;
219 table->tb6_root.leaf = &ip6_null_entry; 203 table->tb6_root.leaf = net->ipv6.ip6_null_entry;
220 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;
221 } 205 }
222 206
223 return table; 207 return table;
224} 208}
225 209
226struct fib6_table *fib6_new_table(u32 id) 210struct fib6_table *fib6_new_table(struct net *net, u32 id)
227{ 211{
228 struct fib6_table *tb; 212 struct fib6_table *tb;
229 213
230 if (id == 0) 214 if (id == 0)
231 id = RT6_TABLE_MAIN; 215 id = RT6_TABLE_MAIN;
232 tb = fib6_get_table(id); 216 tb = fib6_get_table(net, id);
233 if (tb) 217 if (tb)
234 return tb; 218 return tb;
235 219
236 tb = fib6_alloc_table(id); 220 tb = fib6_alloc_table(net, id);
237 if (tb != NULL) 221 if (tb != NULL)
238 fib6_link_table(tb); 222 fib6_link_table(net, tb);
239 223
240 return tb; 224 return tb;
241} 225}
242 226
243struct fib6_table *fib6_get_table(u32 id) 227struct fib6_table *fib6_get_table(struct net *net, u32 id)
244{ 228{
245 struct fib6_table *tb; 229 struct fib6_table *tb;
230 struct hlist_head *head;
246 struct hlist_node *node; 231 struct hlist_node *node;
247 unsigned int h; 232 unsigned int h;
248 233
@@ -250,7 +235,8 @@ struct fib6_table *fib6_get_table(u32 id)
250 id = RT6_TABLE_MAIN; 235 id = RT6_TABLE_MAIN;
251 h = id & (FIB_TABLE_HASHSZ - 1); 236 h = id & (FIB_TABLE_HASHSZ - 1);
252 rcu_read_lock(); 237 rcu_read_lock();
253 hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) { 238 head = &net->ipv6.fib_table_hash[h];
239 hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
254 if (tb->tb6_id == id) { 240 if (tb->tb6_id == id) {
255 rcu_read_unlock(); 241 rcu_read_unlock();
256 return tb; 242 return tb;
@@ -261,33 +247,32 @@ struct fib6_table *fib6_get_table(u32 id)
261 return NULL; 247 return NULL;
262} 248}
263 249
264static void __init fib6_tables_init(void) 250static void fib6_tables_init(struct net *net)
265{ 251{
266 fib6_link_table(&fib6_main_tbl); 252 fib6_link_table(net, net->ipv6.fib6_main_tbl);
267 fib6_link_table(&fib6_local_tbl); 253 fib6_link_table(net, net->ipv6.fib6_local_tbl);
268} 254}
269
270#else 255#else
271 256
272struct fib6_table *fib6_new_table(u32 id) 257struct fib6_table *fib6_new_table(struct net *net, u32 id)
273{ 258{
274 return fib6_get_table(id); 259 return fib6_get_table(net, id);
275} 260}
276 261
277struct fib6_table *fib6_get_table(u32 id) 262struct fib6_table *fib6_get_table(struct net *net, u32 id)
278{ 263{
279 return &fib6_main_tbl; 264 return net->ipv6.fib6_main_tbl;
280} 265}
281 266
282struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, 267struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
283 pol_lookup_t lookup) 268 int flags, pol_lookup_t lookup)
284{ 269{
285 return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags); 270 return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
286} 271}
287 272
288static void __init fib6_tables_init(void) 273static void fib6_tables_init(struct net *net)
289{ 274{
290 fib6_link_table(&fib6_main_tbl); 275 fib6_link_table(net, net->ipv6.fib6_main_tbl);
291} 276}
292 277
293#endif 278#endif
@@ -361,18 +346,16 @@ end:
361 346
362static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) 347static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
363{ 348{
364 struct net *net = skb->sk->sk_net; 349 struct net *net = sock_net(skb->sk);
365 unsigned int h, s_h; 350 unsigned int h, s_h;
366 unsigned int e = 0, s_e; 351 unsigned int e = 0, s_e;
367 struct rt6_rtnl_dump_arg arg; 352 struct rt6_rtnl_dump_arg arg;
368 struct fib6_walker_t *w; 353 struct fib6_walker_t *w;
369 struct fib6_table *tb; 354 struct fib6_table *tb;
370 struct hlist_node *node; 355 struct hlist_node *node;
356 struct hlist_head *head;
371 int res = 0; 357 int res = 0;
372 358
373 if (net != &init_net)
374 return 0;
375
376 s_h = cb->args[0]; 359 s_h = cb->args[0];
377 s_e = cb->args[1]; 360 s_e = cb->args[1];
378 361
@@ -401,7 +384,8 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
401 384
402 for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { 385 for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
403 e = 0; 386 e = 0;
404 hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) { 387 head = &net->ipv6.fib_table_hash[h];
388 hlist_for_each_entry(tb, node, head, tb6_hlist) {
405 if (e < s_e) 389 if (e < s_e)
406 goto next; 390 goto next;
407 res = fib6_dump_table(tb, skb, cb); 391 res = fib6_dump_table(tb, skb, cb);
@@ -667,29 +651,29 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
667 rt->rt6i_node = fn; 651 rt->rt6i_node = fn;
668 atomic_inc(&rt->rt6i_ref); 652 atomic_inc(&rt->rt6i_ref);
669 inet6_rt_notify(RTM_NEWROUTE, rt, info); 653 inet6_rt_notify(RTM_NEWROUTE, rt, info);
670 rt6_stats.fib_rt_entries++; 654 info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
671 655
672 if ((fn->fn_flags & RTN_RTINFO) == 0) { 656 if ((fn->fn_flags & RTN_RTINFO) == 0) {
673 rt6_stats.fib_route_nodes++; 657 info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
674 fn->fn_flags |= RTN_RTINFO; 658 fn->fn_flags |= RTN_RTINFO;
675 } 659 }
676 660
677 return 0; 661 return 0;
678} 662}
679 663
680static __inline__ void fib6_start_gc(struct rt6_info *rt) 664static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt)
681{ 665{
682 if (ip6_fib_timer.expires == 0 && 666 if (net->ipv6.ip6_fib_timer->expires == 0 &&
683 (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) 667 (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE)))
684 mod_timer(&ip6_fib_timer, jiffies + 668 mod_timer(net->ipv6.ip6_fib_timer, jiffies +
685 init_net.ipv6.sysctl.ip6_rt_gc_interval); 669 net->ipv6.sysctl.ip6_rt_gc_interval);
686} 670}
687 671
688void fib6_force_start_gc(void) 672void fib6_force_start_gc(struct net *net)
689{ 673{
690 if (ip6_fib_timer.expires == 0) 674 if (net->ipv6.ip6_fib_timer->expires == 0)
691 mod_timer(&ip6_fib_timer, jiffies + 675 mod_timer(net->ipv6.ip6_fib_timer, jiffies +
692 init_net.ipv6.sysctl.ip6_rt_gc_interval); 676 net->ipv6.sysctl.ip6_rt_gc_interval);
693} 677}
694 678
695/* 679/*
@@ -733,8 +717,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
733 if (sfn == NULL) 717 if (sfn == NULL)
734 goto st_failure; 718 goto st_failure;
735 719
736 sfn->leaf = &ip6_null_entry; 720 sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
737 atomic_inc(&ip6_null_entry.rt6i_ref); 721 atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
738 sfn->fn_flags = RTN_ROOT; 722 sfn->fn_flags = RTN_ROOT;
739 sfn->fn_sernum = fib6_new_sernum(); 723 sfn->fn_sernum = fib6_new_sernum();
740 724
@@ -776,9 +760,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
776 err = fib6_add_rt2node(fn, rt, info); 760 err = fib6_add_rt2node(fn, rt, info);
777 761
778 if (err == 0) { 762 if (err == 0) {
779 fib6_start_gc(rt); 763 fib6_start_gc(info->nl_net, rt);
780 if (!(rt->rt6i_flags&RTF_CACHE)) 764 if (!(rt->rt6i_flags&RTF_CACHE))
781 fib6_prune_clones(pn, rt); 765 fib6_prune_clones(info->nl_net, pn, rt);
782 } 766 }
783 767
784out: 768out:
@@ -788,12 +772,16 @@ out:
788 * If fib6_add_1 has cleared the old leaf pointer in the 772 * If fib6_add_1 has cleared the old leaf pointer in the
789 * 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.
790 */ 774 */
775 if (pn != fn && pn->leaf == rt) {
776 pn->leaf = NULL;
777 atomic_dec(&rt->rt6i_ref);
778 }
791 if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { 779 if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
792 pn->leaf = fib6_find_prefix(pn); 780 pn->leaf = fib6_find_prefix(info->nl_net, pn);
793#if RT6_DEBUG >= 2 781#if RT6_DEBUG >= 2
794 if (!pn->leaf) { 782 if (!pn->leaf) {
795 BUG_TRAP(pn->leaf != NULL); 783 BUG_TRAP(pn->leaf != NULL);
796 pn->leaf = &ip6_null_entry; 784 pn->leaf = info->nl_net->ipv6.ip6_null_entry;
797 } 785 }
798#endif 786#endif
799 atomic_inc(&pn->leaf->rt6i_ref); 787 atomic_inc(&pn->leaf->rt6i_ref);
@@ -809,7 +797,7 @@ out:
809 */ 797 */
810st_failure: 798st_failure:
811 if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) 799 if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
812 fib6_repair_tree(fn); 800 fib6_repair_tree(info->nl_net, fn);
813 dst_free(&rt->u.dst); 801 dst_free(&rt->u.dst);
814 return err; 802 return err;
815#endif 803#endif
@@ -975,10 +963,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
975 * 963 *
976 */ 964 */
977 965
978static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) 966static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
979{ 967{
980 if (fn->fn_flags&RTN_ROOT) 968 if (fn->fn_flags&RTN_ROOT)
981 return &ip6_null_entry; 969 return net->ipv6.ip6_null_entry;
982 970
983 while(fn) { 971 while(fn) {
984 if(fn->left) 972 if(fn->left)
@@ -997,7 +985,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
997 * is the node we want to try and remove. 985 * is the node we want to try and remove.
998 */ 986 */
999 987
1000static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) 988static struct fib6_node *fib6_repair_tree(struct net *net,
989 struct fib6_node *fn)
1001{ 990{
1002 int children; 991 int children;
1003 int nstate; 992 int nstate;
@@ -1024,11 +1013,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
1024 || (children && fn->fn_flags&RTN_ROOT) 1013 || (children && fn->fn_flags&RTN_ROOT)
1025#endif 1014#endif
1026 ) { 1015 ) {
1027 fn->leaf = fib6_find_prefix(fn); 1016 fn->leaf = fib6_find_prefix(net, fn);
1028#if RT6_DEBUG >= 2 1017#if RT6_DEBUG >= 2
1029 if (fn->leaf==NULL) { 1018 if (fn->leaf==NULL) {
1030 BUG_TRAP(fn->leaf); 1019 BUG_TRAP(fn->leaf);
1031 fn->leaf = &ip6_null_entry; 1020 fn->leaf = net->ipv6.ip6_null_entry;
1032 } 1021 }
1033#endif 1022#endif
1034 atomic_inc(&fn->leaf->rt6i_ref); 1023 atomic_inc(&fn->leaf->rt6i_ref);
@@ -1101,14 +1090,15 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1101{ 1090{
1102 struct fib6_walker_t *w; 1091 struct fib6_walker_t *w;
1103 struct rt6_info *rt = *rtp; 1092 struct rt6_info *rt = *rtp;
1093 struct net *net = info->nl_net;
1104 1094
1105 RT6_TRACE("fib6_del_route\n"); 1095 RT6_TRACE("fib6_del_route\n");
1106 1096
1107 /* Unlink it */ 1097 /* Unlink it */
1108 *rtp = rt->u.dst.rt6_next; 1098 *rtp = rt->u.dst.rt6_next;
1109 rt->rt6i_node = NULL; 1099 rt->rt6i_node = NULL;
1110 rt6_stats.fib_rt_entries--; 1100 net->ipv6.rt6_stats->fib_rt_entries--;
1111 rt6_stats.fib_discarded_routes++; 1101 net->ipv6.rt6_stats->fib_discarded_routes++;
1112 1102
1113 /* Reset round-robin state, if necessary */ 1103 /* Reset round-robin state, if necessary */
1114 if (fn->rr_ptr == rt) 1104 if (fn->rr_ptr == rt)
@@ -1131,8 +1121,8 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1131 /* If it was last route, expunge its radix tree node */ 1121 /* If it was last route, expunge its radix tree node */
1132 if (fn->leaf == NULL) { 1122 if (fn->leaf == NULL) {
1133 fn->fn_flags &= ~RTN_RTINFO; 1123 fn->fn_flags &= ~RTN_RTINFO;
1134 rt6_stats.fib_route_nodes--; 1124 net->ipv6.rt6_stats->fib_route_nodes--;
1135 fn = fib6_repair_tree(fn); 1125 fn = fib6_repair_tree(net, fn);
1136 } 1126 }
1137 1127
1138 if (atomic_read(&rt->rt6i_ref) != 1) { 1128 if (atomic_read(&rt->rt6i_ref) != 1) {
@@ -1144,7 +1134,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1144 */ 1134 */
1145 while (fn) { 1135 while (fn) {
1146 if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { 1136 if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
1147 fn->leaf = fib6_find_prefix(fn); 1137 fn->leaf = fib6_find_prefix(net, fn);
1148 atomic_inc(&fn->leaf->rt6i_ref); 1138 atomic_inc(&fn->leaf->rt6i_ref);
1149 rt6_release(rt); 1139 rt6_release(rt);
1150 } 1140 }
@@ -1160,6 +1150,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1160 1150
1161int fib6_del(struct rt6_info *rt, struct nl_info *info) 1151int fib6_del(struct rt6_info *rt, struct nl_info *info)
1162{ 1152{
1153 struct net *net = info->nl_net;
1163 struct fib6_node *fn = rt->rt6i_node; 1154 struct fib6_node *fn = rt->rt6i_node;
1164 struct rt6_info **rtp; 1155 struct rt6_info **rtp;
1165 1156
@@ -1169,7 +1160,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
1169 return -ENOENT; 1160 return -ENOENT;
1170 } 1161 }
1171#endif 1162#endif
1172 if (fn == NULL || rt == &ip6_null_entry) 1163 if (fn == NULL || rt == net->ipv6.ip6_null_entry)
1173 return -ENOENT; 1164 return -ENOENT;
1174 1165
1175 BUG_TRAP(fn->fn_flags&RTN_RTINFO); 1166 BUG_TRAP(fn->fn_flags&RTN_RTINFO);
@@ -1184,7 +1175,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
1184 pn = pn->parent; 1175 pn = pn->parent;
1185 } 1176 }
1186#endif 1177#endif
1187 fib6_prune_clones(pn, rt); 1178 fib6_prune_clones(info->nl_net, pn, rt);
1188 } 1179 }
1189 1180
1190 /* 1181 /*
@@ -1314,12 +1305,12 @@ static int fib6_walk(struct fib6_walker_t *w)
1314 1305
1315static int fib6_clean_node(struct fib6_walker_t *w) 1306static int fib6_clean_node(struct fib6_walker_t *w)
1316{ 1307{
1317 struct nl_info info = {
1318 .nl_net = &init_net,
1319 };
1320 int res; 1308 int res;
1321 struct rt6_info *rt; 1309 struct rt6_info *rt;
1322 struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w); 1310 struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w);
1311 struct nl_info info = {
1312 .nl_net = c->net,
1313 };
1323 1314
1324 for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) { 1315 for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
1325 res = c->func(rt, c->arg); 1316 res = c->func(rt, c->arg);
@@ -1351,7 +1342,7 @@ static int fib6_clean_node(struct fib6_walker_t *w)
1351 * ignoring pure split nodes) will be scanned. 1342 * ignoring pure split nodes) will be scanned.
1352 */ 1343 */
1353 1344
1354static void fib6_clean_tree(struct fib6_node *root, 1345static void fib6_clean_tree(struct net *net, struct fib6_node *root,
1355 int (*func)(struct rt6_info *, void *arg), 1346 int (*func)(struct rt6_info *, void *arg),
1356 int prune, void *arg) 1347 int prune, void *arg)
1357{ 1348{
@@ -1362,23 +1353,26 @@ static void fib6_clean_tree(struct fib6_node *root,
1362 c.w.prune = prune; 1353 c.w.prune = prune;
1363 c.func = func; 1354 c.func = func;
1364 c.arg = arg; 1355 c.arg = arg;
1356 c.net = net;
1365 1357
1366 fib6_walk(&c.w); 1358 fib6_walk(&c.w);
1367} 1359}
1368 1360
1369void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), 1361void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
1370 int prune, void *arg) 1362 int prune, void *arg)
1371{ 1363{
1372 struct fib6_table *table; 1364 struct fib6_table *table;
1373 struct hlist_node *node; 1365 struct hlist_node *node;
1366 struct hlist_head *head;
1374 unsigned int h; 1367 unsigned int h;
1375 1368
1376 rcu_read_lock(); 1369 rcu_read_lock();
1377 for (h = 0; h < FIB_TABLE_HASHSZ; h++) { 1370 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
1378 hlist_for_each_entry_rcu(table, node, &fib_table_hash[h], 1371 head = &net->ipv6.fib_table_hash[h];
1379 tb6_hlist) { 1372 hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
1380 write_lock_bh(&table->tb6_lock); 1373 write_lock_bh(&table->tb6_lock);
1381 fib6_clean_tree(&table->tb6_root, func, prune, arg); 1374 fib6_clean_tree(net, &table->tb6_root,
1375 func, prune, arg);
1382 write_unlock_bh(&table->tb6_lock); 1376 write_unlock_bh(&table->tb6_lock);
1383 } 1377 }
1384 } 1378 }
@@ -1395,9 +1389,10 @@ static int fib6_prune_clone(struct rt6_info *rt, void *arg)
1395 return 0; 1389 return 0;
1396} 1390}
1397 1391
1398static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt) 1392static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
1393 struct rt6_info *rt)
1399{ 1394{
1400 fib6_clean_tree(fn, fib6_prune_clone, 1, rt); 1395 fib6_clean_tree(net, fn, fib6_prune_clone, 1, rt);
1401} 1396}
1402 1397
1403/* 1398/*
@@ -1447,54 +1442,145 @@ static int fib6_age(struct rt6_info *rt, void *arg)
1447 1442
1448static DEFINE_SPINLOCK(fib6_gc_lock); 1443static DEFINE_SPINLOCK(fib6_gc_lock);
1449 1444
1450void fib6_run_gc(unsigned long dummy) 1445void fib6_run_gc(unsigned long expires, struct net *net)
1451{ 1446{
1452 if (dummy != ~0UL) { 1447 if (expires != ~0UL) {
1453 spin_lock_bh(&fib6_gc_lock); 1448 spin_lock_bh(&fib6_gc_lock);
1454 gc_args.timeout = dummy ? (int)dummy : 1449 gc_args.timeout = expires ? (int)expires :
1455 init_net.ipv6.sysctl.ip6_rt_gc_interval; 1450 net->ipv6.sysctl.ip6_rt_gc_interval;
1456 } else { 1451 } else {
1457 local_bh_disable(); 1452 local_bh_disable();
1458 if (!spin_trylock(&fib6_gc_lock)) { 1453 if (!spin_trylock(&fib6_gc_lock)) {
1459 mod_timer(&ip6_fib_timer, jiffies + HZ); 1454 mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ);
1460 local_bh_enable(); 1455 local_bh_enable();
1461 return; 1456 return;
1462 } 1457 }
1463 gc_args.timeout = init_net.ipv6.sysctl.ip6_rt_gc_interval; 1458 gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
1464 } 1459 }
1465 gc_args.more = 0; 1460 gc_args.more = 0;
1466 1461
1467 ndisc_dst_gc(&gc_args.more); 1462 icmp6_dst_gc(&gc_args.more);
1468 fib6_clean_all(fib6_age, 0, NULL); 1463
1464 fib6_clean_all(net, fib6_age, 0, NULL);
1469 1465
1470 if (gc_args.more) 1466 if (gc_args.more)
1471 mod_timer(&ip6_fib_timer, jiffies + 1467 mod_timer(net->ipv6.ip6_fib_timer, jiffies +
1472 init_net.ipv6.sysctl.ip6_rt_gc_interval); 1468 net->ipv6.sysctl.ip6_rt_gc_interval);
1473 else { 1469 else {
1474 del_timer(&ip6_fib_timer); 1470 del_timer(net->ipv6.ip6_fib_timer);
1475 ip6_fib_timer.expires = 0; 1471 net->ipv6.ip6_fib_timer->expires = 0;
1476 } 1472 }
1477 spin_unlock_bh(&fib6_gc_lock); 1473 spin_unlock_bh(&fib6_gc_lock);
1478} 1474}
1479 1475
1480int __init fib6_init(void) 1476static void fib6_gc_timer_cb(unsigned long arg)
1477{
1478 fib6_run_gc(0, (struct net *)arg);
1479}
1480
1481static int fib6_net_init(struct net *net)
1481{ 1482{
1482 int ret; 1483 int ret;
1484 struct timer_list *timer;
1485
1486 ret = -ENOMEM;
1487 timer = kzalloc(sizeof(*timer), GFP_KERNEL);
1488 if (!timer)
1489 goto out;
1490
1491 setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net);
1492 net->ipv6.ip6_fib_timer = timer;
1493
1494 net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
1495 if (!net->ipv6.rt6_stats)
1496 goto out_timer;
1497
1498 net->ipv6.fib_table_hash =
1499 kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
1500 GFP_KERNEL);
1501 if (!net->ipv6.fib_table_hash)
1502 goto out_rt6_stats;
1503
1504 net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
1505 GFP_KERNEL);
1506 if (!net->ipv6.fib6_main_tbl)
1507 goto out_fib_table_hash;
1508
1509 net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
1510 net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
1511 net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
1512 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1513
1514#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1515 net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
1516 GFP_KERNEL);
1517 if (!net->ipv6.fib6_local_tbl)
1518 goto out_fib6_main_tbl;
1519 net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
1520 net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
1521 net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
1522 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1523#endif
1524 fib6_tables_init(net);
1525
1526 ret = 0;
1527out:
1528 return ret;
1529
1530#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1531out_fib6_main_tbl:
1532 kfree(net->ipv6.fib6_main_tbl);
1533#endif
1534out_fib_table_hash:
1535 kfree(net->ipv6.fib_table_hash);
1536out_rt6_stats:
1537 kfree(net->ipv6.rt6_stats);
1538out_timer:
1539 kfree(timer);
1540 goto out;
1541 }
1542
1543static void fib6_net_exit(struct net *net)
1544{
1545 rt6_ifdown(net, NULL);
1546 del_timer(net->ipv6.ip6_fib_timer);
1547 kfree(net->ipv6.ip6_fib_timer);
1548#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1549 kfree(net->ipv6.fib6_local_tbl);
1550#endif
1551 kfree(net->ipv6.fib6_main_tbl);
1552 kfree(net->ipv6.fib_table_hash);
1553 kfree(net->ipv6.rt6_stats);
1554}
1555
1556static struct pernet_operations fib6_net_ops = {
1557 .init = fib6_net_init,
1558 .exit = fib6_net_exit,
1559};
1560
1561int __init fib6_init(void)
1562{
1563 int ret = -ENOMEM;
1564
1483 fib6_node_kmem = kmem_cache_create("fib6_nodes", 1565 fib6_node_kmem = kmem_cache_create("fib6_nodes",
1484 sizeof(struct fib6_node), 1566 sizeof(struct fib6_node),
1485 0, SLAB_HWCACHE_ALIGN, 1567 0, SLAB_HWCACHE_ALIGN,
1486 NULL); 1568 NULL);
1487 if (!fib6_node_kmem) 1569 if (!fib6_node_kmem)
1488 return -ENOMEM; 1570 goto out;
1489 1571
1490 fib6_tables_init(); 1572 ret = register_pernet_subsys(&fib6_net_ops);
1573 if (ret)
1574 goto out_kmem_cache_create;
1491 1575
1492 ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); 1576 ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
1493 if (ret) 1577 if (ret)
1494 goto out_kmem_cache_create; 1578 goto out_unregister_subsys;
1495out: 1579out:
1496 return ret; 1580 return ret;
1497 1581
1582out_unregister_subsys:
1583 unregister_pernet_subsys(&fib6_net_ops);
1498out_kmem_cache_create: 1584out_kmem_cache_create:
1499 kmem_cache_destroy(fib6_node_kmem); 1585 kmem_cache_destroy(fib6_node_kmem);
1500 goto out; 1586 goto out;
@@ -1502,6 +1588,6 @@ out_kmem_cache_create:
1502 1588
1503void fib6_gc_cleanup(void) 1589void fib6_gc_cleanup(void)
1504{ 1590{
1505 del_timer(&ip6_fib_timer); 1591 unregister_pernet_subsys(&fib6_net_ops);
1506 kmem_cache_destroy(fib6_node_kmem); 1592 kmem_cache_destroy(fib6_node_kmem);
1507} 1593}