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.c294
1 files changed, 188 insertions, 106 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index bab72b6f1444..b3f6e03c454c 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:
@@ -789,11 +773,11 @@ out:
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 */
791 if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { 775 if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
792 pn->leaf = fib6_find_prefix(pn); 776 pn->leaf = fib6_find_prefix(info->nl_net, pn);
793#if RT6_DEBUG >= 2 777#if RT6_DEBUG >= 2
794 if (!pn->leaf) { 778 if (!pn->leaf) {
795 BUG_TRAP(pn->leaf != NULL); 779 BUG_TRAP(pn->leaf != NULL);
796 pn->leaf = &ip6_null_entry; 780 pn->leaf = info->nl_net->ipv6.ip6_null_entry;
797 } 781 }
798#endif 782#endif
799 atomic_inc(&pn->leaf->rt6i_ref); 783 atomic_inc(&pn->leaf->rt6i_ref);
@@ -809,7 +793,7 @@ out:
809 */ 793 */
810st_failure: 794st_failure:
811 if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) 795 if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
812 fib6_repair_tree(fn); 796 fib6_repair_tree(info->nl_net, fn);
813 dst_free(&rt->u.dst); 797 dst_free(&rt->u.dst);
814 return err; 798 return err;
815#endif 799#endif
@@ -975,10 +959,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
975 * 959 *
976 */ 960 */
977 961
978static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) 962static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
979{ 963{
980 if (fn->fn_flags&RTN_ROOT) 964 if (fn->fn_flags&RTN_ROOT)
981 return &ip6_null_entry; 965 return net->ipv6.ip6_null_entry;
982 966
983 while(fn) { 967 while(fn) {
984 if(fn->left) 968 if(fn->left)
@@ -997,7 +981,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
997 * is the node we want to try and remove. 981 * is the node we want to try and remove.
998 */ 982 */
999 983
1000static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) 984static struct fib6_node *fib6_repair_tree(struct net *net,
985 struct fib6_node *fn)
1001{ 986{
1002 int children; 987 int children;
1003 int nstate; 988 int nstate;
@@ -1024,11 +1009,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
1024 || (children && fn->fn_flags&RTN_ROOT) 1009 || (children && fn->fn_flags&RTN_ROOT)
1025#endif 1010#endif
1026 ) { 1011 ) {
1027 fn->leaf = fib6_find_prefix(fn); 1012 fn->leaf = fib6_find_prefix(net, fn);
1028#if RT6_DEBUG >= 2 1013#if RT6_DEBUG >= 2
1029 if (fn->leaf==NULL) { 1014 if (fn->leaf==NULL) {
1030 BUG_TRAP(fn->leaf); 1015 BUG_TRAP(fn->leaf);
1031 fn->leaf = &ip6_null_entry; 1016 fn->leaf = net->ipv6.ip6_null_entry;
1032 } 1017 }
1033#endif 1018#endif
1034 atomic_inc(&fn->leaf->rt6i_ref); 1019 atomic_inc(&fn->leaf->rt6i_ref);
@@ -1101,14 +1086,15 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1101{ 1086{
1102 struct fib6_walker_t *w; 1087 struct fib6_walker_t *w;
1103 struct rt6_info *rt = *rtp; 1088 struct rt6_info *rt = *rtp;
1089 struct net *net = info->nl_net;
1104 1090
1105 RT6_TRACE("fib6_del_route\n"); 1091 RT6_TRACE("fib6_del_route\n");
1106 1092
1107 /* Unlink it */ 1093 /* Unlink it */
1108 *rtp = rt->u.dst.rt6_next; 1094 *rtp = rt->u.dst.rt6_next;
1109 rt->rt6i_node = NULL; 1095 rt->rt6i_node = NULL;
1110 rt6_stats.fib_rt_entries--; 1096 net->ipv6.rt6_stats->fib_rt_entries--;
1111 rt6_stats.fib_discarded_routes++; 1097 net->ipv6.rt6_stats->fib_discarded_routes++;
1112 1098
1113 /* Reset round-robin state, if necessary */ 1099 /* Reset round-robin state, if necessary */
1114 if (fn->rr_ptr == rt) 1100 if (fn->rr_ptr == rt)
@@ -1131,8 +1117,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 */ 1117 /* If it was last route, expunge its radix tree node */
1132 if (fn->leaf == NULL) { 1118 if (fn->leaf == NULL) {
1133 fn->fn_flags &= ~RTN_RTINFO; 1119 fn->fn_flags &= ~RTN_RTINFO;
1134 rt6_stats.fib_route_nodes--; 1120 net->ipv6.rt6_stats->fib_route_nodes--;
1135 fn = fib6_repair_tree(fn); 1121 fn = fib6_repair_tree(net, fn);
1136 } 1122 }
1137 1123
1138 if (atomic_read(&rt->rt6i_ref) != 1) { 1124 if (atomic_read(&rt->rt6i_ref) != 1) {
@@ -1144,7 +1130,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1144 */ 1130 */
1145 while (fn) { 1131 while (fn) {
1146 if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { 1132 if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
1147 fn->leaf = fib6_find_prefix(fn); 1133 fn->leaf = fib6_find_prefix(net, fn);
1148 atomic_inc(&fn->leaf->rt6i_ref); 1134 atomic_inc(&fn->leaf->rt6i_ref);
1149 rt6_release(rt); 1135 rt6_release(rt);
1150 } 1136 }
@@ -1160,6 +1146,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
1160 1146
1161int fib6_del(struct rt6_info *rt, struct nl_info *info) 1147int fib6_del(struct rt6_info *rt, struct nl_info *info)
1162{ 1148{
1149 struct net *net = info->nl_net;
1163 struct fib6_node *fn = rt->rt6i_node; 1150 struct fib6_node *fn = rt->rt6i_node;
1164 struct rt6_info **rtp; 1151 struct rt6_info **rtp;
1165 1152
@@ -1169,7 +1156,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
1169 return -ENOENT; 1156 return -ENOENT;
1170 } 1157 }
1171#endif 1158#endif
1172 if (fn == NULL || rt == &ip6_null_entry) 1159 if (fn == NULL || rt == net->ipv6.ip6_null_entry)
1173 return -ENOENT; 1160 return -ENOENT;
1174 1161
1175 BUG_TRAP(fn->fn_flags&RTN_RTINFO); 1162 BUG_TRAP(fn->fn_flags&RTN_RTINFO);
@@ -1184,7 +1171,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
1184 pn = pn->parent; 1171 pn = pn->parent;
1185 } 1172 }
1186#endif 1173#endif
1187 fib6_prune_clones(pn, rt); 1174 fib6_prune_clones(info->nl_net, pn, rt);
1188 } 1175 }
1189 1176
1190 /* 1177 /*
@@ -1314,12 +1301,12 @@ static int fib6_walk(struct fib6_walker_t *w)
1314 1301
1315static int fib6_clean_node(struct fib6_walker_t *w) 1302static int fib6_clean_node(struct fib6_walker_t *w)
1316{ 1303{
1317 struct nl_info info = {
1318 .nl_net = &init_net,
1319 };
1320 int res; 1304 int res;
1321 struct rt6_info *rt; 1305 struct rt6_info *rt;
1322 struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w); 1306 struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w);
1307 struct nl_info info = {
1308 .nl_net = c->net,
1309 };
1323 1310
1324 for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) { 1311 for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
1325 res = c->func(rt, c->arg); 1312 res = c->func(rt, c->arg);
@@ -1351,7 +1338,7 @@ static int fib6_clean_node(struct fib6_walker_t *w)
1351 * ignoring pure split nodes) will be scanned. 1338 * ignoring pure split nodes) will be scanned.
1352 */ 1339 */
1353 1340
1354static void fib6_clean_tree(struct fib6_node *root, 1341static void fib6_clean_tree(struct net *net, struct fib6_node *root,
1355 int (*func)(struct rt6_info *, void *arg), 1342 int (*func)(struct rt6_info *, void *arg),
1356 int prune, void *arg) 1343 int prune, void *arg)
1357{ 1344{
@@ -1362,23 +1349,26 @@ static void fib6_clean_tree(struct fib6_node *root,
1362 c.w.prune = prune; 1349 c.w.prune = prune;
1363 c.func = func; 1350 c.func = func;
1364 c.arg = arg; 1351 c.arg = arg;
1352 c.net = net;
1365 1353
1366 fib6_walk(&c.w); 1354 fib6_walk(&c.w);
1367} 1355}
1368 1356
1369void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), 1357void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
1370 int prune, void *arg) 1358 int prune, void *arg)
1371{ 1359{
1372 struct fib6_table *table; 1360 struct fib6_table *table;
1373 struct hlist_node *node; 1361 struct hlist_node *node;
1362 struct hlist_head *head;
1374 unsigned int h; 1363 unsigned int h;
1375 1364
1376 rcu_read_lock(); 1365 rcu_read_lock();
1377 for (h = 0; h < FIB_TABLE_HASHSZ; h++) { 1366 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
1378 hlist_for_each_entry_rcu(table, node, &fib_table_hash[h], 1367 head = &net->ipv6.fib_table_hash[h];
1379 tb6_hlist) { 1368 hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
1380 write_lock_bh(&table->tb6_lock); 1369 write_lock_bh(&table->tb6_lock);
1381 fib6_clean_tree(&table->tb6_root, func, prune, arg); 1370 fib6_clean_tree(net, &table->tb6_root,
1371 func, prune, arg);
1382 write_unlock_bh(&table->tb6_lock); 1372 write_unlock_bh(&table->tb6_lock);
1383 } 1373 }
1384 } 1374 }
@@ -1395,9 +1385,10 @@ static int fib6_prune_clone(struct rt6_info *rt, void *arg)
1395 return 0; 1385 return 0;
1396} 1386}
1397 1387
1398static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt) 1388static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
1389 struct rt6_info *rt)
1399{ 1390{
1400 fib6_clean_tree(fn, fib6_prune_clone, 1, rt); 1391 fib6_clean_tree(net, fn, fib6_prune_clone, 1, rt);
1401} 1392}
1402 1393
1403/* 1394/*
@@ -1447,54 +1438,145 @@ static int fib6_age(struct rt6_info *rt, void *arg)
1447 1438
1448static DEFINE_SPINLOCK(fib6_gc_lock); 1439static DEFINE_SPINLOCK(fib6_gc_lock);
1449 1440
1450void fib6_run_gc(unsigned long dummy) 1441void fib6_run_gc(unsigned long expires, struct net *net)
1451{ 1442{
1452 if (dummy != ~0UL) { 1443 if (expires != ~0UL) {
1453 spin_lock_bh(&fib6_gc_lock); 1444 spin_lock_bh(&fib6_gc_lock);
1454 gc_args.timeout = dummy ? (int)dummy : 1445 gc_args.timeout = expires ? (int)expires :
1455 init_net.ipv6.sysctl.ip6_rt_gc_interval; 1446 net->ipv6.sysctl.ip6_rt_gc_interval;
1456 } else { 1447 } else {
1457 local_bh_disable(); 1448 local_bh_disable();
1458 if (!spin_trylock(&fib6_gc_lock)) { 1449 if (!spin_trylock(&fib6_gc_lock)) {
1459 mod_timer(&ip6_fib_timer, jiffies + HZ); 1450 mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ);
1460 local_bh_enable(); 1451 local_bh_enable();
1461 return; 1452 return;
1462 } 1453 }
1463 gc_args.timeout = init_net.ipv6.sysctl.ip6_rt_gc_interval; 1454 gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
1464 } 1455 }
1465 gc_args.more = 0; 1456 gc_args.more = 0;
1466 1457
1467 ndisc_dst_gc(&gc_args.more); 1458 icmp6_dst_gc(&gc_args.more);
1468 fib6_clean_all(fib6_age, 0, NULL); 1459
1460 fib6_clean_all(net, fib6_age, 0, NULL);
1469 1461
1470 if (gc_args.more) 1462 if (gc_args.more)
1471 mod_timer(&ip6_fib_timer, jiffies + 1463 mod_timer(net->ipv6.ip6_fib_timer, jiffies +
1472 init_net.ipv6.sysctl.ip6_rt_gc_interval); 1464 net->ipv6.sysctl.ip6_rt_gc_interval);
1473 else { 1465 else {
1474 del_timer(&ip6_fib_timer); 1466 del_timer(net->ipv6.ip6_fib_timer);
1475 ip6_fib_timer.expires = 0; 1467 net->ipv6.ip6_fib_timer->expires = 0;
1476 } 1468 }
1477 spin_unlock_bh(&fib6_gc_lock); 1469 spin_unlock_bh(&fib6_gc_lock);
1478} 1470}
1479 1471
1480int __init fib6_init(void) 1472static void fib6_gc_timer_cb(unsigned long arg)
1473{
1474 fib6_run_gc(0, (struct net *)arg);
1475}
1476
1477static int fib6_net_init(struct net *net)
1481{ 1478{
1482 int ret; 1479 int ret;
1480 struct timer_list *timer;
1481
1482 ret = -ENOMEM;
1483 timer = kzalloc(sizeof(*timer), GFP_KERNEL);
1484 if (!timer)
1485 goto out;
1486
1487 setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net);
1488 net->ipv6.ip6_fib_timer = timer;
1489
1490 net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
1491 if (!net->ipv6.rt6_stats)
1492 goto out_timer;
1493
1494 net->ipv6.fib_table_hash =
1495 kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
1496 GFP_KERNEL);
1497 if (!net->ipv6.fib_table_hash)
1498 goto out_rt6_stats;
1499
1500 net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
1501 GFP_KERNEL);
1502 if (!net->ipv6.fib6_main_tbl)
1503 goto out_fib_table_hash;
1504
1505 net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
1506 net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
1507 net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
1508 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1509
1510#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1511 net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
1512 GFP_KERNEL);
1513 if (!net->ipv6.fib6_local_tbl)
1514 goto out_fib6_main_tbl;
1515 net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
1516 net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
1517 net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
1518 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
1519#endif
1520 fib6_tables_init(net);
1521
1522 ret = 0;
1523out:
1524 return ret;
1525
1526#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1527out_fib6_main_tbl:
1528 kfree(net->ipv6.fib6_main_tbl);
1529#endif
1530out_fib_table_hash:
1531 kfree(net->ipv6.fib_table_hash);
1532out_rt6_stats:
1533 kfree(net->ipv6.rt6_stats);
1534out_timer:
1535 kfree(timer);
1536 goto out;
1537 }
1538
1539static void fib6_net_exit(struct net *net)
1540{
1541 rt6_ifdown(net, NULL);
1542 del_timer(net->ipv6.ip6_fib_timer);
1543 kfree(net->ipv6.ip6_fib_timer);
1544#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1545 kfree(net->ipv6.fib6_local_tbl);
1546#endif
1547 kfree(net->ipv6.fib6_main_tbl);
1548 kfree(net->ipv6.fib_table_hash);
1549 kfree(net->ipv6.rt6_stats);
1550}
1551
1552static struct pernet_operations fib6_net_ops = {
1553 .init = fib6_net_init,
1554 .exit = fib6_net_exit,
1555};
1556
1557int __init fib6_init(void)
1558{
1559 int ret = -ENOMEM;
1560
1483 fib6_node_kmem = kmem_cache_create("fib6_nodes", 1561 fib6_node_kmem = kmem_cache_create("fib6_nodes",
1484 sizeof(struct fib6_node), 1562 sizeof(struct fib6_node),
1485 0, SLAB_HWCACHE_ALIGN, 1563 0, SLAB_HWCACHE_ALIGN,
1486 NULL); 1564 NULL);
1487 if (!fib6_node_kmem) 1565 if (!fib6_node_kmem)
1488 return -ENOMEM; 1566 goto out;
1489 1567
1490 fib6_tables_init(); 1568 ret = register_pernet_subsys(&fib6_net_ops);
1569 if (ret)
1570 goto out_kmem_cache_create;
1491 1571
1492 ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); 1572 ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
1493 if (ret) 1573 if (ret)
1494 goto out_kmem_cache_create; 1574 goto out_unregister_subsys;
1495out: 1575out:
1496 return ret; 1576 return ret;
1497 1577
1578out_unregister_subsys:
1579 unregister_pernet_subsys(&fib6_net_ops);
1498out_kmem_cache_create: 1580out_kmem_cache_create:
1499 kmem_cache_destroy(fib6_node_kmem); 1581 kmem_cache_destroy(fib6_node_kmem);
1500 goto out; 1582 goto out;
@@ -1502,6 +1584,6 @@ out_kmem_cache_create:
1502 1584
1503void fib6_gc_cleanup(void) 1585void fib6_gc_cleanup(void)
1504{ 1586{
1505 del_timer(&ip6_fib_timer); 1587 unregister_pernet_subsys(&fib6_net_ops);
1506 kmem_cache_destroy(fib6_node_kmem); 1588 kmem_cache_destroy(fib6_node_kmem);
1507} 1589}