atomic_inc(&rt->rt6i_ref); } } else { sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, sizeof(struct in6_addr), rt->rt6i_src.plen, offsetof(struct rt6_info, rt6i_src)); if (sn == NULL) goto st_failure; } fn = sn; } #endif err = fib6_add_rt2node(fn, rt, nlh, req); if (err == 0) { fib6_start_gc(rt); if (!(rt->rt6i_flags&RTF_CACHE)) fib6_prune_clones(fn, rt); } out: if (err) dst_free(&rt->u.dst); return err; #ifdef CONFIG_IPV6_SUBTREES /* Subtree creation failed, probably main tree node is orphan. If it is, shoot it.
err = PTR_ERR(sn); sn = NULL; } if (!sn) goto st_failure; } if (!fn->leaf) { fn->leaf = rt; atomic_inc(&rt->rt6i_ref); } fn = sn; } #endif err = fib6_add_rt2node(fn, rt, info); if (!err) { fib6_start_gc(info->nl_net, rt); if (!(rt->rt6i_flags & RTF_CACHE)) fib6_prune_clones(info->nl_net, pn, rt); } out: if (err) { #ifdef CONFIG_IPV6_SUBTREES /* * If fib6_add_1 has cleared the old leaf pointer in the * super-tree leaf node we have to find a new one for it. */ if (pn != fn && pn->leaf == rt) { pn->leaf = NULL;
int fib6_add(struct fib6_node *root, struct rt6_info *rt) { struct fib6_node *fn; int err = -ENOMEM; fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt); if (fn == NULL) return -ENOMEM; #ifdef CONFIG_IPV6_SUBTREES if (rt->rt6i_src.plen) { struct fib6_node *sn; if (fn->subtree == NULL) { struct fib6_node *sfn; /* * Create subtree. * * fn[main tree] * | * sfn[subtree root] * \ * sn[new leaf node] */ /* Create subtree root node */ sfn = node_alloc(); if (sfn == NULL) goto st_failure; sfn->leaf = &ip6_null_entry; atomic_inc(&ip6_null_entry.rt6i_ref); sfn->fn_flags = RTN_ROOT; sfn->fn_sernum = fib6_new_sernum(); /* Now add the first leaf node to new subtree */ sn = fib6_add_1(sfn, &rt->rt6i_src.addr, sizeof(struct in6_addr), rt->rt6i_src.plen, (u8*) &rt->rt6i_src - (u8*) rt); if (sn == NULL) { /* If it is failed, discard just allocated root, and then (in st_failure) stale node in main tree. */ node_free(sfn); goto st_failure; } /* Now link new subtree to main tree */ sfn->parent = fn; fn->subtree = sfn; if (fn->leaf == NULL) { fn->leaf = rt; atomic_inc(&rt->rt6i_ref); } } else { sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, sizeof(struct in6_addr), rt->rt6i_src.plen, (u8*) &rt->rt6i_src - (u8*) rt); if (sn == NULL) goto st_failure; } fn = sn; } #endif err = fib6_add_rt2node(fn, rt); if (err == 0) { fib6_start_gc(rt); if (!(rt->rt6i_flags&RTF_CACHE)) fib6_prune_clones(fn, rt); } if (err) dst_free(&rt->u.dst); return err; #ifdef CONFIG_IPV6_SUBTREES /* Subtree creation failed, probably main tree node is orphan. If it is, shot it. */ st_failure: if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT)) fib_repair_tree(fn); dst_free(&rt->u.dst); return err; #endif }