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.c463
1 files changed, 387 insertions, 76 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 764221220afd..8fcae7a6510b 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -18,6 +18,7 @@
18 * Yuji SEKIYA @USAGI: Support default route on router node; 18 * Yuji SEKIYA @USAGI: Support default route on router node;
19 * remove ip6_null_entry from the top of 19 * remove ip6_null_entry from the top of
20 * routing table. 20 * routing table.
21 * Ville Nuorvala: Fixed routing subtrees.
21 */ 22 */
22#include <linux/errno.h> 23#include <linux/errno.h>
23#include <linux/types.h> 24#include <linux/types.h>
@@ -26,6 +27,7 @@
26#include <linux/netdevice.h> 27#include <linux/netdevice.h>
27#include <linux/in6.h> 28#include <linux/in6.h>
28#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/list.h>
29 31
30#ifdef CONFIG_PROC_FS 32#ifdef CONFIG_PROC_FS
31#include <linux/proc_fs.h> 33#include <linux/proc_fs.h>
@@ -68,19 +70,19 @@ struct fib6_cleaner_t
68 void *arg; 70 void *arg;
69}; 71};
70 72
71DEFINE_RWLOCK(fib6_walker_lock); 73static DEFINE_RWLOCK(fib6_walker_lock);
72
73 74
74#ifdef CONFIG_IPV6_SUBTREES 75#ifdef CONFIG_IPV6_SUBTREES
75#define FWS_INIT FWS_S 76#define FWS_INIT FWS_S
76#define SUBTREE(fn) ((fn)->subtree)
77#else 77#else
78#define FWS_INIT FWS_L 78#define FWS_INIT FWS_L
79#define SUBTREE(fn) NULL
80#endif 79#endif
81 80
82static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); 81static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
82static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
83static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); 83static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
84static int fib6_walk(struct fib6_walker_t *w);
85static int fib6_walk_continue(struct fib6_walker_t *w);
84 86
85/* 87/*
86 * A routing update causes an increase of the serial number on the 88 * A routing update causes an increase of the serial number on the
@@ -93,13 +95,31 @@ static __u32 rt_sernum;
93 95
94static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); 96static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0);
95 97
96struct fib6_walker_t fib6_walker_list = { 98static struct fib6_walker_t fib6_walker_list = {
97 .prev = &fib6_walker_list, 99 .prev = &fib6_walker_list,
98 .next = &fib6_walker_list, 100 .next = &fib6_walker_list,
99}; 101};
100 102
101#define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) 103#define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next)
102 104
105static inline void fib6_walker_link(struct fib6_walker_t *w)
106{
107 write_lock_bh(&fib6_walker_lock);
108 w->next = fib6_walker_list.next;
109 w->prev = &fib6_walker_list;
110 w->next->prev = w;
111 w->prev->next = w;
112 write_unlock_bh(&fib6_walker_lock);
113}
114
115static inline void fib6_walker_unlink(struct fib6_walker_t *w)
116{
117 write_lock_bh(&fib6_walker_lock);
118 w->next->prev = w->prev;
119 w->prev->next = w->next;
120 w->prev = w->next = w;
121 write_unlock_bh(&fib6_walker_lock);
122}
103static __inline__ u32 fib6_new_sernum(void) 123static __inline__ u32 fib6_new_sernum(void)
104{ 124{
105 u32 n = ++rt_sernum; 125 u32 n = ++rt_sernum;
@@ -147,6 +167,253 @@ static __inline__ void rt6_release(struct rt6_info *rt)
147 dst_free(&rt->u.dst); 167 dst_free(&rt->u.dst);
148} 168}
149 169
170static struct fib6_table fib6_main_tbl = {
171 .tb6_id = RT6_TABLE_MAIN,
172 .tb6_lock = RW_LOCK_UNLOCKED,
173 .tb6_root = {
174 .leaf = &ip6_null_entry,
175 .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
176 },
177};
178
179#ifdef CONFIG_IPV6_MULTIPLE_TABLES
180#define FIB_TABLE_HASHSZ 256
181#else
182#define FIB_TABLE_HASHSZ 1
183#endif
184static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
185
186static void fib6_link_table(struct fib6_table *tb)
187{
188 unsigned int h;
189
190 h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);
191
192 /*
193 * No protection necessary, this is the only list mutatation
194 * operation, tables never disappear once they exist.
195 */
196 hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
197}
198
199#ifdef CONFIG_IPV6_MULTIPLE_TABLES
200static struct fib6_table fib6_local_tbl = {
201 .tb6_id = RT6_TABLE_LOCAL,
202 .tb6_lock = RW_LOCK_UNLOCKED,
203 .tb6_root = {
204 .leaf = &ip6_null_entry,
205 .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
206 },
207};
208
209static struct fib6_table *fib6_alloc_table(u32 id)
210{
211 struct fib6_table *table;
212
213 table = kzalloc(sizeof(*table), GFP_ATOMIC);
214 if (table != NULL) {
215 table->tb6_id = id;
216 table->tb6_lock = RW_LOCK_UNLOCKED;
217 table->tb6_root.leaf = &ip6_null_entry;
218 table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
219 }
220
221 return table;
222}
223
224struct fib6_table *fib6_new_table(u32 id)
225{
226 struct fib6_table *tb;
227
228 if (id == 0)
229 id = RT6_TABLE_MAIN;
230 tb = fib6_get_table(id);
231 if (tb)
232 return tb;
233
234 tb = fib6_alloc_table(id);
235 if (tb != NULL)
236 fib6_link_table(tb);
237
238 return tb;
239}
240
241struct fib6_table *fib6_get_table(u32 id)
242{
243 struct fib6_table *tb;
244 struct hlist_node *node;
245 unsigned int h;
246
247 if (id == 0)
248 id = RT6_TABLE_MAIN;
249 h = id & (FIB_TABLE_HASHSZ - 1);
250 rcu_read_lock();
251 hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
252 if (tb->tb6_id == id) {
253 rcu_read_unlock();
254 return tb;
255 }
256 }
257 rcu_read_unlock();
258
259 return NULL;
260}
261
262static void __init fib6_tables_init(void)
263{
264 fib6_link_table(&fib6_main_tbl);
265 fib6_link_table(&fib6_local_tbl);
266}
267
268#else
269
270struct fib6_table *fib6_new_table(u32 id)
271{
272 return fib6_get_table(id);
273}
274
275struct fib6_table *fib6_get_table(u32 id)
276{
277 return &fib6_main_tbl;
278}
279
280struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
281 pol_lookup_t lookup)
282{
283 return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags);
284}
285
286static void __init fib6_tables_init(void)
287{
288 fib6_link_table(&fib6_main_tbl);
289}
290
291#endif
292
293static int fib6_dump_node(struct fib6_walker_t *w)
294{
295 int res;
296 struct rt6_info *rt;
297
298 for (rt = w->leaf; rt; rt = rt->u.next) {
299 res = rt6_dump_route(rt, w->args);
300 if (res < 0) {
301 /* Frame is full, suspend walking */
302 w->leaf = rt;
303 return 1;
304 }
305 BUG_TRAP(res!=0);
306 }
307 w->leaf = NULL;
308 return 0;
309}
310
311static void fib6_dump_end(struct netlink_callback *cb)
312{
313 struct fib6_walker_t *w = (void*)cb->args[2];
314
315 if (w) {
316 cb->args[2] = 0;
317 kfree(w);
318 }
319 cb->done = (void*)cb->args[3];
320 cb->args[1] = 3;
321}
322
323static int fib6_dump_done(struct netlink_callback *cb)
324{
325 fib6_dump_end(cb);
326 return cb->done ? cb->done(cb) : 0;
327}
328
329static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
330 struct netlink_callback *cb)
331{
332 struct fib6_walker_t *w;
333 int res;
334
335 w = (void *)cb->args[2];
336 w->root = &table->tb6_root;
337
338 if (cb->args[4] == 0) {
339 read_lock_bh(&table->tb6_lock);
340 res = fib6_walk(w);
341 read_unlock_bh(&table->tb6_lock);
342 if (res > 0)
343 cb->args[4] = 1;
344 } else {
345 read_lock_bh(&table->tb6_lock);
346 res = fib6_walk_continue(w);
347 read_unlock_bh(&table->tb6_lock);
348 if (res != 0) {
349 if (res < 0)
350 fib6_walker_unlink(w);
351 goto end;
352 }
353 fib6_walker_unlink(w);
354 cb->args[4] = 0;
355 }
356end:
357 return res;
358}
359
360int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
361{
362 unsigned int h, s_h;
363 unsigned int e = 0, s_e;
364 struct rt6_rtnl_dump_arg arg;
365 struct fib6_walker_t *w;
366 struct fib6_table *tb;
367 struct hlist_node *node;
368 int res = 0;
369
370 s_h = cb->args[0];
371 s_e = cb->args[1];
372
373 w = (void *)cb->args[2];
374 if (w == NULL) {
375 /* New dump:
376 *
377 * 1. hook callback destructor.
378 */
379 cb->args[3] = (long)cb->done;
380 cb->done = fib6_dump_done;
381
382 /*
383 * 2. allocate and initialize walker.
384 */
385 w = kzalloc(sizeof(*w), GFP_ATOMIC);
386 if (w == NULL)
387 return -ENOMEM;
388 w->func = fib6_dump_node;
389 cb->args[2] = (long)w;
390 }
391
392 arg.skb = skb;
393 arg.cb = cb;
394 w->args = &arg;
395
396 for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
397 e = 0;
398 hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) {
399 if (e < s_e)
400 goto next;
401 res = fib6_dump_table(tb, skb, cb);
402 if (res != 0)
403 goto out;
404next:
405 e++;
406 }
407 }
408out:
409 cb->args[1] = e;
410 cb->args[0] = h;
411
412 res = res < 0 ? res : skb->len;
413 if (res <= 0)
414 fib6_dump_end(cb);
415 return res;
416}
150 417
151/* 418/*
152 * Routing Table 419 * Routing Table
@@ -343,7 +610,7 @@ insert_above:
343 */ 610 */
344 611
345static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, 612static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
346 struct nlmsghdr *nlh, struct netlink_skb_parms *req) 613 struct nl_info *info)
347{ 614{
348 struct rt6_info *iter = NULL; 615 struct rt6_info *iter = NULL;
349 struct rt6_info **ins; 616 struct rt6_info **ins;
@@ -398,7 +665,7 @@ out:
398 *ins = rt; 665 *ins = rt;
399 rt->rt6i_node = fn; 666 rt->rt6i_node = fn;
400 atomic_inc(&rt->rt6i_ref); 667 atomic_inc(&rt->rt6i_ref);
401 inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); 668 inet6_rt_notify(RTM_NEWROUTE, rt, info);
402 rt6_stats.fib_rt_entries++; 669 rt6_stats.fib_rt_entries++;
403 670
404 if ((fn->fn_flags & RTN_RTINFO) == 0) { 671 if ((fn->fn_flags & RTN_RTINFO) == 0) {
@@ -428,10 +695,9 @@ void fib6_force_start_gc(void)
428 * with source addr info in sub-trees 695 * with source addr info in sub-trees
429 */ 696 */
430 697
431int fib6_add(struct fib6_node *root, struct rt6_info *rt, 698int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
432 struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req)
433{ 699{
434 struct fib6_node *fn; 700 struct fib6_node *fn, *pn = NULL;
435 int err = -ENOMEM; 701 int err = -ENOMEM;
436 702
437 fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), 703 fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
@@ -440,6 +706,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
440 if (fn == NULL) 706 if (fn == NULL)
441 goto out; 707 goto out;
442 708
709 pn = fn;
710
443#ifdef CONFIG_IPV6_SUBTREES 711#ifdef CONFIG_IPV6_SUBTREES
444 if (rt->rt6i_src.plen) { 712 if (rt->rt6i_src.plen) {
445 struct fib6_node *sn; 713 struct fib6_node *sn;
@@ -485,10 +753,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
485 /* Now link new subtree to main tree */ 753 /* Now link new subtree to main tree */
486 sfn->parent = fn; 754 sfn->parent = fn;
487 fn->subtree = sfn; 755 fn->subtree = sfn;
488 if (fn->leaf == NULL) {
489 fn->leaf = rt;
490 atomic_inc(&rt->rt6i_ref);
491 }
492 } else { 756 } else {
493 sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, 757 sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
494 sizeof(struct in6_addr), rt->rt6i_src.plen, 758 sizeof(struct in6_addr), rt->rt6i_src.plen,
@@ -498,21 +762,42 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
498 goto st_failure; 762 goto st_failure;
499 } 763 }
500 764
765 if (fn->leaf == NULL) {
766 fn->leaf = rt;
767 atomic_inc(&rt->rt6i_ref);
768 }
501 fn = sn; 769 fn = sn;
502 } 770 }
503#endif 771#endif
504 772
505 err = fib6_add_rt2node(fn, rt, nlh, req); 773 err = fib6_add_rt2node(fn, rt, info);
506 774
507 if (err == 0) { 775 if (err == 0) {
508 fib6_start_gc(rt); 776 fib6_start_gc(rt);
509 if (!(rt->rt6i_flags&RTF_CACHE)) 777 if (!(rt->rt6i_flags&RTF_CACHE))
510 fib6_prune_clones(fn, rt); 778 fib6_prune_clones(pn, rt);
511 } 779 }
512 780
513out: 781out:
514 if (err) 782 if (err) {
783#ifdef CONFIG_IPV6_SUBTREES
784 /*
785 * If fib6_add_1 has cleared the old leaf pointer in the
786 * super-tree leaf node we have to find a new one for it.
787 */
788 if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
789 pn->leaf = fib6_find_prefix(pn);
790#if RT6_DEBUG >= 2
791 if (!pn->leaf) {
792 BUG_TRAP(pn->leaf != NULL);
793 pn->leaf = &ip6_null_entry;
794 }
795#endif
796 atomic_inc(&pn->leaf->rt6i_ref);
797 }
798#endif
515 dst_free(&rt->u.dst); 799 dst_free(&rt->u.dst);
800 }
516 return err; 801 return err;
517 802
518#ifdef CONFIG_IPV6_SUBTREES 803#ifdef CONFIG_IPV6_SUBTREES
@@ -543,6 +828,9 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
543 struct fib6_node *fn; 828 struct fib6_node *fn;
544 int dir; 829 int dir;
545 830
831 if (unlikely(args->offset == 0))
832 return NULL;
833
546 /* 834 /*
547 * Descend on a tree 835 * Descend on a tree
548 */ 836 */
@@ -564,33 +852,26 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
564 break; 852 break;
565 } 853 }
566 854
567 while ((fn->fn_flags & RTN_ROOT) == 0) { 855 while(fn) {
568#ifdef CONFIG_IPV6_SUBTREES 856 if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) {
569 if (fn->subtree) {
570 struct fib6_node *st;
571 struct lookup_args *narg;
572
573 narg = args + 1;
574
575 if (narg->addr) {
576 st = fib6_lookup_1(fn->subtree, narg);
577
578 if (st && !(st->fn_flags & RTN_ROOT))
579 return st;
580 }
581 }
582#endif
583
584 if (fn->fn_flags & RTN_RTINFO) {
585 struct rt6key *key; 857 struct rt6key *key;
586 858
587 key = (struct rt6key *) ((u8 *) fn->leaf + 859 key = (struct rt6key *) ((u8 *) fn->leaf +
588 args->offset); 860 args->offset);
589 861
590 if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) 862 if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) {
591 return fn; 863#ifdef CONFIG_IPV6_SUBTREES
864 if (fn->subtree)
865 fn = fib6_lookup_1(fn->subtree, args + 1);
866#endif
867 if (!fn || fn->fn_flags & RTN_RTINFO)
868 return fn;
869 }
592 } 870 }
593 871
872 if (fn->fn_flags & RTN_ROOT)
873 break;
874
594 fn = fn->parent; 875 fn = fn->parent;
595 } 876 }
596 877
@@ -600,18 +881,24 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
600struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, 881struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr,
601 struct in6_addr *saddr) 882 struct in6_addr *saddr)
602{ 883{
603 struct lookup_args args[2];
604 struct fib6_node *fn; 884 struct fib6_node *fn;
605 885 struct lookup_args args[] = {
606 args[0].offset = offsetof(struct rt6_info, rt6i_dst); 886 {
607 args[0].addr = daddr; 887 .offset = offsetof(struct rt6_info, rt6i_dst),
608 888 .addr = daddr,
889 },
609#ifdef CONFIG_IPV6_SUBTREES 890#ifdef CONFIG_IPV6_SUBTREES
610 args[1].offset = offsetof(struct rt6_info, rt6i_src); 891 {
611 args[1].addr = saddr; 892 .offset = offsetof(struct rt6_info, rt6i_src),
893 .addr = saddr,
894 },
612#endif 895#endif
896 {
897 .offset = 0, /* sentinel */
898 }
899 };
613 900
614 fn = fib6_lookup_1(root, args); 901 fn = fib6_lookup_1(root, daddr ? args : args + 1);
615 902
616 if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) 903 if (fn == NULL || fn->fn_flags & RTN_TL_ROOT)
617 fn = root; 904 fn = root;
@@ -667,10 +954,8 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
667#ifdef CONFIG_IPV6_SUBTREES 954#ifdef CONFIG_IPV6_SUBTREES
668 if (src_len) { 955 if (src_len) {
669 BUG_TRAP(saddr!=NULL); 956 BUG_TRAP(saddr!=NULL);
670 if (fn == NULL) 957 if (fn && fn->subtree)
671 fn = fn->subtree; 958 fn = fib6_locate_1(fn->subtree, saddr, src_len,
672 if (fn)
673 fn = fib6_locate_1(fn, saddr, src_len,
674 offsetof(struct rt6_info, rt6i_src)); 959 offsetof(struct rt6_info, rt6i_src));
675 } 960 }
676#endif 961#endif
@@ -699,7 +984,7 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
699 if(fn->right) 984 if(fn->right)
700 return fn->right->leaf; 985 return fn->right->leaf;
701 986
702 fn = SUBTREE(fn); 987 fn = FIB6_SUBTREE(fn);
703 } 988 }
704 return NULL; 989 return NULL;
705} 990}
@@ -730,7 +1015,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
730 if (fn->right) child = fn->right, children |= 1; 1015 if (fn->right) child = fn->right, children |= 1;
731 if (fn->left) child = fn->left, children |= 2; 1016 if (fn->left) child = fn->left, children |= 2;
732 1017
733 if (children == 3 || SUBTREE(fn) 1018 if (children == 3 || FIB6_SUBTREE(fn)
734#ifdef CONFIG_IPV6_SUBTREES 1019#ifdef CONFIG_IPV6_SUBTREES
735 /* Subtree root (i.e. fn) may have one child */ 1020 /* Subtree root (i.e. fn) may have one child */
736 || (children && fn->fn_flags&RTN_ROOT) 1021 || (children && fn->fn_flags&RTN_ROOT)
@@ -749,9 +1034,9 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
749 1034
750 pn = fn->parent; 1035 pn = fn->parent;
751#ifdef CONFIG_IPV6_SUBTREES 1036#ifdef CONFIG_IPV6_SUBTREES
752 if (SUBTREE(pn) == fn) { 1037 if (FIB6_SUBTREE(pn) == fn) {
753 BUG_TRAP(fn->fn_flags&RTN_ROOT); 1038 BUG_TRAP(fn->fn_flags&RTN_ROOT);
754 SUBTREE(pn) = NULL; 1039 FIB6_SUBTREE(pn) = NULL;
755 nstate = FWS_L; 1040 nstate = FWS_L;
756 } else { 1041 } else {
757 BUG_TRAP(!(fn->fn_flags&RTN_ROOT)); 1042 BUG_TRAP(!(fn->fn_flags&RTN_ROOT));
@@ -799,7 +1084,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
799 read_unlock(&fib6_walker_lock); 1084 read_unlock(&fib6_walker_lock);
800 1085
801 node_free(fn); 1086 node_free(fn);
802 if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn)) 1087 if (pn->fn_flags&RTN_RTINFO || FIB6_SUBTREE(pn))
803 return pn; 1088 return pn;
804 1089
805 rt6_release(pn->leaf); 1090 rt6_release(pn->leaf);
@@ -809,7 +1094,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
809} 1094}
810 1095
811static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, 1096static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
812 struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) 1097 struct nl_info *info)
813{ 1098{
814 struct fib6_walker_t *w; 1099 struct fib6_walker_t *w;
815 struct rt6_info *rt = *rtp; 1100 struct rt6_info *rt = *rtp;
@@ -865,11 +1150,11 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
865 if (atomic_read(&rt->rt6i_ref) != 1) BUG(); 1150 if (atomic_read(&rt->rt6i_ref) != 1) BUG();
866 } 1151 }
867 1152
868 inet6_rt_notify(RTM_DELROUTE, rt, nlh, req); 1153 inet6_rt_notify(RTM_DELROUTE, rt, info);
869 rt6_release(rt); 1154 rt6_release(rt);
870} 1155}
871 1156
872int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) 1157int fib6_del(struct rt6_info *rt, struct nl_info *info)
873{ 1158{
874 struct fib6_node *fn = rt->rt6i_node; 1159 struct fib6_node *fn = rt->rt6i_node;
875 struct rt6_info **rtp; 1160 struct rt6_info **rtp;
@@ -885,8 +1170,18 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne
885 1170
886 BUG_TRAP(fn->fn_flags&RTN_RTINFO); 1171 BUG_TRAP(fn->fn_flags&RTN_RTINFO);
887 1172
888 if (!(rt->rt6i_flags&RTF_CACHE)) 1173 if (!(rt->rt6i_flags&RTF_CACHE)) {
889 fib6_prune_clones(fn, rt); 1174 struct fib6_node *pn = fn;
1175#ifdef CONFIG_IPV6_SUBTREES
1176 /* clones of this route might be in another subtree */
1177 if (rt->rt6i_src.plen) {
1178 while (!(pn->fn_flags&RTN_ROOT))
1179 pn = pn->parent;
1180 pn = pn->parent;
1181 }
1182#endif
1183 fib6_prune_clones(pn, rt);
1184 }
890 1185
891 /* 1186 /*
892 * Walk the leaf entries looking for ourself 1187 * Walk the leaf entries looking for ourself
@@ -894,7 +1189,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne
894 1189
895 for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { 1190 for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) {
896 if (*rtp == rt) { 1191 if (*rtp == rt) {
897 fib6_del_route(fn, rtp, nlh, _rtattr, req); 1192 fib6_del_route(fn, rtp, info);
898 return 0; 1193 return 0;
899 } 1194 }
900 } 1195 }
@@ -925,7 +1220,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne
925 * <0 -> walk is terminated by an error. 1220 * <0 -> walk is terminated by an error.
926 */ 1221 */
927 1222
928int fib6_walk_continue(struct fib6_walker_t *w) 1223static int fib6_walk_continue(struct fib6_walker_t *w)
929{ 1224{
930 struct fib6_node *fn, *pn; 1225 struct fib6_node *fn, *pn;
931 1226
@@ -942,8 +1237,8 @@ int fib6_walk_continue(struct fib6_walker_t *w)
942 switch (w->state) { 1237 switch (w->state) {
943#ifdef CONFIG_IPV6_SUBTREES 1238#ifdef CONFIG_IPV6_SUBTREES
944 case FWS_S: 1239 case FWS_S:
945 if (SUBTREE(fn)) { 1240 if (FIB6_SUBTREE(fn)) {
946 w->node = SUBTREE(fn); 1241 w->node = FIB6_SUBTREE(fn);
947 continue; 1242 continue;
948 } 1243 }
949 w->state = FWS_L; 1244 w->state = FWS_L;
@@ -977,7 +1272,7 @@ int fib6_walk_continue(struct fib6_walker_t *w)
977 pn = fn->parent; 1272 pn = fn->parent;
978 w->node = pn; 1273 w->node = pn;
979#ifdef CONFIG_IPV6_SUBTREES 1274#ifdef CONFIG_IPV6_SUBTREES
980 if (SUBTREE(pn) == fn) { 1275 if (FIB6_SUBTREE(pn) == fn) {
981 BUG_TRAP(fn->fn_flags&RTN_ROOT); 1276 BUG_TRAP(fn->fn_flags&RTN_ROOT);
982 w->state = FWS_L; 1277 w->state = FWS_L;
983 continue; 1278 continue;
@@ -999,7 +1294,7 @@ int fib6_walk_continue(struct fib6_walker_t *w)
999 } 1294 }
1000} 1295}
1001 1296
1002int fib6_walk(struct fib6_walker_t *w) 1297static int fib6_walk(struct fib6_walker_t *w)
1003{ 1298{
1004 int res; 1299 int res;
1005 1300
@@ -1023,7 +1318,7 @@ static int fib6_clean_node(struct fib6_walker_t *w)
1023 res = c->func(rt, c->arg); 1318 res = c->func(rt, c->arg);
1024 if (res < 0) { 1319 if (res < 0) {
1025 w->leaf = rt; 1320 w->leaf = rt;
1026 res = fib6_del(rt, NULL, NULL, NULL); 1321 res = fib6_del(rt, NULL);
1027 if (res) { 1322 if (res) {
1028#if RT6_DEBUG >= 2 1323#if RT6_DEBUG >= 2
1029 printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); 1324 printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
@@ -1049,9 +1344,9 @@ static int fib6_clean_node(struct fib6_walker_t *w)
1049 * ignoring pure split nodes) will be scanned. 1344 * ignoring pure split nodes) will be scanned.
1050 */ 1345 */
1051 1346
1052void fib6_clean_tree(struct fib6_node *root, 1347static void fib6_clean_tree(struct fib6_node *root,
1053 int (*func)(struct rt6_info *, void *arg), 1348 int (*func)(struct rt6_info *, void *arg),
1054 int prune, void *arg) 1349 int prune, void *arg)
1055{ 1350{
1056 struct fib6_cleaner_t c; 1351 struct fib6_cleaner_t c;
1057 1352
@@ -1064,6 +1359,25 @@ void fib6_clean_tree(struct fib6_node *root,
1064 fib6_walk(&c.w); 1359 fib6_walk(&c.w);
1065} 1360}
1066 1361
1362void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
1363 int prune, void *arg)
1364{
1365 struct fib6_table *table;
1366 struct hlist_node *node;
1367 unsigned int h;
1368
1369 rcu_read_lock();
1370 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
1371 hlist_for_each_entry_rcu(table, node, &fib_table_hash[h],
1372 tb6_hlist) {
1373 write_lock_bh(&table->tb6_lock);
1374 fib6_clean_tree(&table->tb6_root, func, prune, arg);
1375 write_unlock_bh(&table->tb6_lock);
1376 }
1377 }
1378 rcu_read_unlock();
1379}
1380
1067static int fib6_prune_clone(struct rt6_info *rt, void *arg) 1381static int fib6_prune_clone(struct rt6_info *rt, void *arg)
1068{ 1382{
1069 if (rt->rt6i_flags & RTF_CACHE) { 1383 if (rt->rt6i_flags & RTF_CACHE) {
@@ -1142,11 +1456,8 @@ void fib6_run_gc(unsigned long dummy)
1142 } 1456 }
1143 gc_args.more = 0; 1457 gc_args.more = 0;
1144 1458
1145
1146 write_lock_bh(&rt6_lock);
1147 ndisc_dst_gc(&gc_args.more); 1459 ndisc_dst_gc(&gc_args.more);
1148 fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); 1460 fib6_clean_all(fib6_age, 0, NULL);
1149 write_unlock_bh(&rt6_lock);
1150 1461
1151 if (gc_args.more) 1462 if (gc_args.more)
1152 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); 1463 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
@@ -1161,10 +1472,10 @@ void __init fib6_init(void)
1161{ 1472{
1162 fib6_node_kmem = kmem_cache_create("fib6_nodes", 1473 fib6_node_kmem = kmem_cache_create("fib6_nodes",
1163 sizeof(struct fib6_node), 1474 sizeof(struct fib6_node),
1164 0, SLAB_HWCACHE_ALIGN, 1475 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
1165 NULL, NULL); 1476 NULL, NULL);
1166 if (!fib6_node_kmem) 1477
1167 panic("cannot create fib6_nodes cache"); 1478 fib6_tables_init();
1168} 1479}
1169 1480
1170void fib6_gc_cleanup(void) 1481void fib6_gc_cleanup(void)