diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2006-08-23 20:20:34 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:55:46 -0400 |
commit | 66729e18df08ee20a9824148236b89f56371659e (patch) | |
tree | 6f974289880a6a3d6df0e30c9d9c4a067f65c5d0 /net/ipv6 | |
parent | 8e1ef0a95b87e8b4292b2ba733e8cb854ea2d2fe (diff) |
[IPV6] ROUTE: Make sure we have fn->leaf when adding a node on subtree.
Based on MIPL2 kernel patch.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Ville Nuorvala <vnuorval@tcs.hut.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/ip6_fib.c | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 667b1b1ea25d..11f9660a4796 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -80,6 +80,7 @@ static DEFINE_RWLOCK(fib6_walker_lock); | |||
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); | 82 | static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); |
83 | static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); | ||
83 | static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); | 84 | static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); |
84 | static int fib6_walk(struct fib6_walker_t *w); | 85 | static int fib6_walk(struct fib6_walker_t *w); |
85 | static int fib6_walk_continue(struct fib6_walker_t *w); | 86 | static int fib6_walk_continue(struct fib6_walker_t *w); |
@@ -697,7 +698,7 @@ void fib6_force_start_gc(void) | |||
697 | 698 | ||
698 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) | 699 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) |
699 | { | 700 | { |
700 | struct fib6_node *fn; | 701 | struct fib6_node *fn, *pn = NULL; |
701 | int err = -ENOMEM; | 702 | int err = -ENOMEM; |
702 | 703 | ||
703 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), | 704 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), |
@@ -706,6 +707,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) | |||
706 | if (fn == NULL) | 707 | if (fn == NULL) |
707 | goto out; | 708 | goto out; |
708 | 709 | ||
710 | pn = fn; | ||
711 | |||
709 | #ifdef CONFIG_IPV6_SUBTREES | 712 | #ifdef CONFIG_IPV6_SUBTREES |
710 | if (rt->rt6i_src.plen) { | 713 | if (rt->rt6i_src.plen) { |
711 | struct fib6_node *sn; | 714 | struct fib6_node *sn; |
@@ -751,10 +754,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) | |||
751 | /* Now link new subtree to main tree */ | 754 | /* Now link new subtree to main tree */ |
752 | sfn->parent = fn; | 755 | sfn->parent = fn; |
753 | fn->subtree = sfn; | 756 | fn->subtree = sfn; |
754 | if (fn->leaf == NULL) { | ||
755 | fn->leaf = rt; | ||
756 | atomic_inc(&rt->rt6i_ref); | ||
757 | } | ||
758 | } else { | 757 | } else { |
759 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, | 758 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, |
760 | sizeof(struct in6_addr), rt->rt6i_src.plen, | 759 | sizeof(struct in6_addr), rt->rt6i_src.plen, |
@@ -764,6 +763,10 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) | |||
764 | goto st_failure; | 763 | goto st_failure; |
765 | } | 764 | } |
766 | 765 | ||
766 | if (fn->leaf == NULL) { | ||
767 | fn->leaf = rt; | ||
768 | atomic_inc(&rt->rt6i_ref); | ||
769 | } | ||
767 | fn = sn; | 770 | fn = sn; |
768 | } | 771 | } |
769 | #endif | 772 | #endif |
@@ -777,8 +780,25 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) | |||
777 | } | 780 | } |
778 | 781 | ||
779 | out: | 782 | out: |
780 | if (err) | 783 | if (err) { |
784 | #ifdef CONFIG_IPV6_SUBTREES | ||
785 | /* | ||
786 | * If fib6_add_1 has cleared the old leaf pointer in the | ||
787 | * super-tree leaf node we have to find a new one for it. | ||
788 | */ | ||
789 | if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { | ||
790 | pn->leaf = fib6_find_prefix(pn); | ||
791 | #if RT6_DEBUG >= 2 | ||
792 | if (!pn->leaf) { | ||
793 | BUG_TRAP(pn->leaf != NULL); | ||
794 | pn->leaf = &ip6_null_entry; | ||
795 | } | ||
796 | #endif | ||
797 | atomic_inc(&pn->leaf->rt6i_ref); | ||
798 | } | ||
799 | #endif | ||
781 | dst_free(&rt->u.dst); | 800 | dst_free(&rt->u.dst); |
801 | } | ||
782 | return err; | 802 | return err; |
783 | 803 | ||
784 | #ifdef CONFIG_IPV6_SUBTREES | 804 | #ifdef CONFIG_IPV6_SUBTREES |