static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt) { struct rt6_info *iter = NULL; struct rt6_info **ins; ins = &fn->leaf; for (iter = fn->leaf; iter; iter=iter->u.next) { /* * Search for duplicates */ if (iter->rt6i_metric == rt->rt6i_metric) { /* * Same priority level */ if ((iter->rt6i_dev == rt->rt6i_dev) && (iter->rt6i_flowr == rt->rt6i_flowr) && (ipv6_addr_cmp(&iter->rt6i_gateway, &rt->rt6i_gateway) == 0)) { if (!(iter->rt6i_flags&RTF_EXPIRES)) return -EEXIST; iter->rt6i_expires = rt->rt6i_expires; if (!(rt->rt6i_flags&RTF_EXPIRES)) { iter->rt6i_flags &= ~RTF_EXPIRES; iter->rt6i_expires = 0; } return -EEXIST; } } if (iter->rt6i_metric > rt->rt6i_metric) break; ins = &iter->u.next; } /* * insert node */ rt->u.next = iter; *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); #ifdef CONFIG_RTNETLINK inet6_rt_notify(RTM_NEWROUTE, rt); #endif rt6_stats.fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { rt6_stats.fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } return 0; }
static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp) { struct fib6_walker_t *w; struct rt6_info *rt = *rtp; RT6_TRACE("fib6_del_route\n"); /* Unlink it */ *rtp = rt->u.next; rt->rt6i_node = NULL; rt6_stats.fib_rt_entries--; /* Adjust walkers */ FOR_WALKERS(w) { if (w->state == FWS_C && w->leaf == rt) { RT6_TRACE("walker %p adjusted by delroute\n", w); w->leaf = rt->u.next; if (w->leaf == NULL) w->state = FWS_U; } } rt->u.next = NULL; /* If it was last route, expunge its radix tree node */ if (fn->leaf == NULL) { fn->fn_flags &= ~RTN_RTINFO; rt6_stats.fib_route_nodes--; fib6_repair_tree(fn); } #ifdef CONFIG_RTNETLINK inet6_rt_notify(RTM_DELROUTE, rt); #endif rt6_release(rt); }
static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, struct nl_info *info) { struct rt6_info *iter = NULL; struct rt6_info **ins; int replace = (info->nlh && (info->nlh->nlmsg_flags & NLM_F_REPLACE)); int add = (!info->nlh || (info->nlh->nlmsg_flags & NLM_F_CREATE)); int found = 0; ins = &fn->leaf; for (iter = fn->leaf; iter; iter = iter->dst.rt6_next) { /* * Search for duplicates */ if (iter->rt6i_metric == rt->rt6i_metric) { /* * Same priority level */ if (info->nlh && (info->nlh->nlmsg_flags & NLM_F_EXCL)) return -EEXIST; if (replace) { found++; break; } if (iter->dst.dev == rt->dst.dev && iter->rt6i_idev == rt->rt6i_idev && ipv6_addr_equal(&iter->rt6i_gateway, &rt->rt6i_gateway)) { if (!(iter->rt6i_flags & RTF_EXPIRES)) return -EEXIST; if (!(rt->rt6i_flags & RTF_EXPIRES)) rt6_clean_expires(iter); else rt6_set_expires(iter, rt->dst.expires); return -EEXIST; } } if (iter->rt6i_metric > rt->rt6i_metric) break; ins = &iter->dst.rt6_next; } /* Reset round-robin state, if necessary */ if (ins == &fn->leaf) fn->rr_ptr = NULL; /* * insert node */ if (!replace) { if (!add) pr_warn("NLM_F_CREATE should be set when creating new route\n"); add: rt->dst.rt6_next = iter; *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, info); info->nl_net->ipv6.rt6_stats->fib_rt_entries++; if (!(fn->fn_flags & RTN_RTINFO)) { info->nl_net->ipv6.rt6_stats->fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } } else { if (!found) { if (add) goto add; pr_warn("NLM_F_REPLACE set, but no existing node found!\n"); return -ENOENT; } *ins = rt; rt->rt6i_node = fn; rt->dst.rt6_next = iter->dst.rt6_next; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, info); rt6_release(iter); if (!(fn->fn_flags & RTN_RTINFO)) { info->nl_net->ipv6.rt6_stats->fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } } return 0; }
static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, struct nlmsghdr *nlh, struct netlink_skb_parms *req) { struct rt6_info *iter = NULL; struct rt6_info **ins; ins = &fn->leaf; if (fn->fn_flags&RTN_TL_ROOT && fn->leaf == &ip6_null_entry && !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ){ fn->leaf = rt; rt->u.next = NULL; goto out; } for (iter = fn->leaf; iter; iter=iter->u.next) { /* * Search for duplicates */ if (iter->rt6i_metric == rt->rt6i_metric) { /* * Same priority level */ if (iter->rt6i_dev == rt->rt6i_dev && iter->rt6i_idev == rt->rt6i_idev && ipv6_addr_equal(&iter->rt6i_gateway, &rt->rt6i_gateway)) { if (!(iter->rt6i_flags&RTF_EXPIRES)) return -EEXIST; iter->rt6i_expires = rt->rt6i_expires; if (!(rt->rt6i_flags&RTF_EXPIRES)) { iter->rt6i_flags &= ~RTF_EXPIRES; iter->rt6i_expires = 0; } return -EEXIST; } } if (iter->rt6i_metric > rt->rt6i_metric) break; ins = &iter->u.next; } /* * insert node */ out: rt->u.next = iter; *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); rt6_stats.fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { rt6_stats.fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } return 0; }
static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, struct nl_info *info) { struct rt6_info *iter = NULL; struct rt6_info **ins; ins = &fn->leaf; for (iter = fn->leaf; iter; iter=iter->dst.rt6_next) { /* * Search for duplicates */ if (iter->rt6i_metric == rt->rt6i_metric) { /* * Same priority level */ if (iter->rt6i_dev == rt->rt6i_dev && iter->rt6i_idev == rt->rt6i_idev && ipv6_addr_equal(&iter->rt6i_gateway, &rt->rt6i_gateway)) { if (!(iter->rt6i_flags&RTF_EXPIRES)) return -EEXIST; iter->rt6i_expires = rt->rt6i_expires; if (!(rt->rt6i_flags&RTF_EXPIRES)) { iter->rt6i_flags &= ~RTF_EXPIRES; iter->rt6i_expires = 0; } return -EEXIST; } } if (iter->rt6i_metric > rt->rt6i_metric) break; ins = &iter->dst.rt6_next; } /* Reset round-robin state, if necessary */ if (ins == &fn->leaf) fn->rr_ptr = NULL; /* * insert node */ rt->dst.rt6_next = iter; *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, info); info->nl_net->ipv6.rt6_stats->fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { info->nl_net->ipv6.rt6_stats->fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } return 0; }
static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, struct nlmsghdr *nlh, struct netlink_skb_parms *req) { struct rt6_info *iter = NULL; struct rt6_info **ins; ins = &fn->leaf; if (fn->fn_flags&RTN_TL_ROOT && fn->leaf == &ip6_null_entry && !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ){ fn->leaf = rt; rt->u.next = NULL; goto out; } for (iter = fn->leaf; iter; iter=iter->u.next) { /* * Search for duplicates */ if (iter->rt6i_metric == rt->rt6i_metric) { /* * Same priority level */ if (iter->rt6i_dev == rt->rt6i_dev && iter->rt6i_idev == rt->rt6i_idev && ipv6_addr_equal(&iter->rt6i_gateway, &rt->rt6i_gateway)) { if (!(iter->rt6i_flags&RTF_EXPIRES)) return -EEXIST; iter->rt6i_expires = rt->rt6i_expires; if (!(rt->rt6i_flags&RTF_EXPIRES)) { iter->rt6i_flags &= ~RTF_EXPIRES; iter->rt6i_expires = 0; } return -EEXIST; } } if (iter->rt6i_metric > rt->rt6i_metric) break; ins = &iter->u.next; } /* * insert node */ out: rt->u.next = iter; *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); rt6_stats.fib_rt_entries++; #ifdef CONFIG_NK_IPV6_LOADBALANCE /*purpose : ipv6 author : paul date : 2011-06-21 */ /*description : support ipv6 loadbalance */ if(rt->rt6i_metric == NK_EQUALIZERV6_METRIC){ fn->weight += rt->weight; fn->power += rt->weight; rt->power = rt->weight; } #endif if ((fn->fn_flags & RTN_RTINFO) == 0) { rt6_stats.fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } return 0; }