diff options
| -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 |
