Lines Matching +full:route +full:- +full:ptp
1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * FIB front-end.
14 * - respect outgoing interface
15 * - select from (probably) reachable routers (i.e.
17 * - always select the same router if it is (probably)
18 * reachable. otherwise, round-robin the list.
33 #include <linux/route.h>
79 RT6_NUD_FAIL_HARD = -3,
80 RT6_NUD_FAIL_PROBE = -2,
81 RT6_NUD_FAIL_DO_RR = -1,
142 rt->dst.rt_uncached_list = ul; in rt6_uncached_list_add()
144 spin_lock_bh(&ul->lock); in rt6_uncached_list_add()
145 list_add_tail(&rt->dst.rt_uncached, &ul->head); in rt6_uncached_list_add()
146 spin_unlock_bh(&ul->lock); in rt6_uncached_list_add()
151 if (!list_empty(&rt->dst.rt_uncached)) { in rt6_uncached_list_del()
152 struct uncached_list *ul = rt->dst.rt_uncached_list; in rt6_uncached_list_del()
154 spin_lock_bh(&ul->lock); in rt6_uncached_list_del()
155 list_del_init(&rt->dst.rt_uncached); in rt6_uncached_list_del()
156 spin_unlock_bh(&ul->lock); in rt6_uncached_list_del()
168 if (list_empty(&ul->head)) in rt6_uncached_list_flush_dev()
171 spin_lock_bh(&ul->lock); in rt6_uncached_list_flush_dev()
172 list_for_each_entry_safe(rt, safe, &ul->head, dst.rt_uncached) { in rt6_uncached_list_flush_dev()
173 struct inet6_dev *rt_idev = rt->rt6i_idev; in rt6_uncached_list_flush_dev()
174 struct net_device *rt_dev = rt->dst.dev; in rt6_uncached_list_flush_dev()
177 if (rt_idev && rt_idev->dev == dev) { in rt6_uncached_list_flush_dev()
178 rt->rt6i_idev = in6_dev_get(blackhole_netdev); in rt6_uncached_list_flush_dev()
184 rt->dst.dev = blackhole_netdev; in rt6_uncached_list_flush_dev()
186 &rt->dst.dev_tracker, in rt6_uncached_list_flush_dev()
191 list_del_init(&rt->dst.rt_uncached); in rt6_uncached_list_flush_dev()
193 spin_unlock_bh(&ul->lock); in rt6_uncached_list_flush_dev()
204 return &ipv6_hdr(skb)->daddr; in choose_neigh_daddr()
231 dst->dev, skb, daddr); in ip6_dst_neigh_lookup()
237 struct net_device *dev = dst->dev; in ip6_confirm_neigh()
242 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) in ip6_confirm_neigh()
281 [RTAX_HOPLIMIT - 1] = 0,
298 .error = -ENETUNREACH,
312 .error = -EACCES,
324 .error = -EINVAL,
342 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, in ip6_dst_alloc()
347 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc); in ip6_dst_alloc()
363 idev = rt->rt6i_idev; in ip6_dst_destroy()
365 rt->rt6i_idev = NULL; in ip6_dst_destroy()
369 from = unrcu_pointer(xchg(&rt->from, NULL)); in ip6_dst_destroy()
376 struct inet6_dev *idev = rt->rt6i_idev; in ip6_dst_ifdown()
379 if (idev && idev->dev != blackhole_netdev) { in ip6_dst_ifdown()
383 rt->rt6i_idev = blackhole_idev; in ip6_dst_ifdown()
387 from = unrcu_pointer(xchg(&rt->from, NULL)); in ip6_dst_ifdown()
393 if (rt->rt6i_flags & RTF_EXPIRES) in __rt6_check_expired()
394 return time_after(jiffies, rt->dst.expires); in __rt6_check_expired()
403 from = rcu_dereference(rt->from); in rt6_check_expired()
405 if (rt->rt6i_flags & RTF_EXPIRES) { in rt6_check_expired()
406 if (time_after(jiffies, rt->dst.expires)) in rt6_check_expired()
409 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK || in rt6_check_expired()
421 fn = rcu_dereference(rt->fib6_node); in rt6_multipath_first_sibling_rcu()
424 iter = rcu_dereference(fn->leaf); in rt6_multipath_first_sibling_rcu()
429 if (iter->fib6_metric == rt->fib6_metric && in rt6_multipath_first_sibling_rcu()
432 iter = rcu_dereference(iter->fib6_next); in rt6_multipath_first_sibling_rcu()
443 struct fib6_info *first, *match = res->f6i; in fib6_select_path()
447 if (!match->nh && (!match->fib6_nsiblings || have_oif_match)) in fib6_select_path()
450 if (match->nh && have_oif_match && res->nh) in fib6_select_path()
454 IP6CB(skb)->flags |= IP6SKB_MULTIPATH; in fib6_select_path()
457 * case it will always be non-zero. Otherwise now is the time to do it. in fib6_select_path()
459 if (!fl6->mp_hash && in fib6_select_path()
460 (!match->nh || nexthop_is_multipath(match->nh))) in fib6_select_path()
461 fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL); in fib6_select_path()
463 if (unlikely(match->nh)) { in fib6_select_path()
464 nexthop_path_fib6_result(res, fl6->mp_hash); in fib6_select_path()
472 hash = fl6->mp_hash; in fib6_select_path()
473 if (hash <= atomic_read(&first->fib6_nh->fib_nh_upper_bound)) { in fib6_select_path()
474 if (rt6_score_route(first->fib6_nh, first->fib6_flags, oif, in fib6_select_path()
480 list_for_each_entry_rcu(sibling, &first->fib6_siblings, in fib6_select_path()
482 const struct fib6_nh *nh = sibling->fib6_nh; in fib6_select_path()
485 nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); in fib6_select_path()
488 if (rt6_score_route(nh, sibling->fib6_flags, oif, strict) < 0) in fib6_select_path()
495 res->f6i = match; in fib6_select_path()
496 res->nh = match->fib6_nh; in fib6_select_path()
500 * Route lookup. rcu_read_lock() should be held.
508 if (nh->fib_nh_flags & RTNH_F_DEAD) in __rt6_device_match()
511 dev = nh->fib_nh_dev; in __rt6_device_match()
513 if (dev->ifindex == oif) in __rt6_device_match()
536 arg->nh = nh; in __rt6_nh_dev_match()
537 return __rt6_device_match(arg->net, nh, arg->saddr, arg->oif, in __rt6_nh_dev_match()
538 arg->flags); in __rt6_nh_dev_match()
566 struct fib6_info *f6i = res->f6i; in rt6_device_match()
571 if (unlikely(f6i->nh)) { in rt6_device_match()
572 nh = nexthop_fib6_nh(f6i->nh); in rt6_device_match()
573 if (nexthop_is_blackhole(f6i->nh)) in rt6_device_match()
576 nh = f6i->fib6_nh; in rt6_device_match()
578 if (!(nh->fib_nh_flags & RTNH_F_DEAD)) in rt6_device_match()
582 for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) { in rt6_device_match()
585 if (unlikely(spf6i->nh)) { in rt6_device_match()
586 nh = rt6_nh_dev_match(net, spf6i->nh, res, saddr, in rt6_device_match()
591 nh = spf6i->fib6_nh; in rt6_device_match()
596 res->f6i = spf6i; in rt6_device_match()
602 res->f6i = net->ipv6.fib6_null_entry; in rt6_device_match()
603 nh = res->f6i->fib6_nh; in rt6_device_match()
607 if (unlikely(f6i->nh)) { in rt6_device_match()
608 nh = nexthop_fib6_nh(f6i->nh); in rt6_device_match()
609 if (nexthop_is_blackhole(f6i->nh)) in rt6_device_match()
612 nh = f6i->fib6_nh; in rt6_device_match()
615 if (nh->fib_nh_flags & RTNH_F_DEAD) { in rt6_device_match()
616 res->f6i = net->ipv6.fib6_null_entry; in rt6_device_match()
617 nh = res->f6i->fib6_nh; in rt6_device_match()
620 res->nh = nh; in rt6_device_match()
621 res->fib6_type = res->f6i->fib6_type; in rt6_device_match()
622 res->fib6_flags = res->f6i->fib6_flags; in rt6_device_match()
626 res->fib6_flags |= RTF_REJECT; in rt6_device_match()
627 res->fib6_type = RTN_BLACKHOLE; in rt6_device_match()
628 res->nh = nh; in rt6_device_match()
645 addrconf_addr_solict_mult(&work->target, &mcaddr); in rt6_probe_deferred()
646 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0); in rt6_probe_deferred()
647 netdev_put(work->dev, &work->dev_tracker); in rt6_probe_deferred()
665 * Router Reachability Probe MUST be rate-limited in rt6_probe()
668 if (!fib6_nh->fib_nh_gw_family) in rt6_probe()
671 nh_gw = &fib6_nh->fib_nh_gw6; in rt6_probe()
672 dev = fib6_nh->fib_nh_dev; in rt6_probe()
674 last_probe = READ_ONCE(fib6_nh->last_probe); in rt6_probe()
680 if (READ_ONCE(neigh->nud_state) & NUD_VALID) in rt6_probe()
683 write_lock_bh(&neigh->lock); in rt6_probe()
684 if (!(neigh->nud_state & NUD_VALID) && in rt6_probe()
686 neigh->updated + in rt6_probe()
687 READ_ONCE(idev->cnf.rtr_probe_interval))) { in rt6_probe()
692 write_unlock_bh(&neigh->lock); in rt6_probe()
694 READ_ONCE(idev->cnf.rtr_probe_interval))) { in rt6_probe()
698 if (!work || cmpxchg(&fib6_nh->last_probe, in rt6_probe()
702 INIT_WORK(&work->work, rt6_probe_deferred); in rt6_probe()
703 work->target = *nh_gw; in rt6_probe()
704 netdev_hold(dev, &work->dev_tracker, GFP_ATOMIC); in rt6_probe()
705 work->dev = dev; in rt6_probe()
706 schedule_work(&work->work); in rt6_probe()
727 neigh = __ipv6_neigh_lookup_noref(fib6_nh->fib_nh_dev, in rt6_check_neigh()
728 &fib6_nh->fib_nh_gw6); in rt6_check_neigh()
730 u8 nud_state = READ_ONCE(neigh->nud_state); in rt6_check_neigh()
754 if (!oif || nh->fib_nh_dev->ifindex == oif) in rt6_score_route()
763 !(fib6_flags & RTF_NONEXTHOP) && nh->fib_nh_gw_family) { in rt6_score_route()
778 if (nh->fib_nh_flags & RTNH_F_DEAD) in find_match()
781 if (ip6_ignore_linkdown(nh->fib_nh_dev) && in find_match()
782 nh->fib_nh_flags & RTNH_F_LINKDOWN && in find_match()
820 arg->nh = nh; in rt6_nh_find_match()
821 return find_match(nh, arg->flags, arg->oif, arg->strict, in rt6_nh_find_match()
822 arg->mpri, arg->do_rr); in rt6_nh_find_match()
834 f6i = rcu_dereference(f6i->fib6_next)) { in __find_rr_leaf()
838 if (cont && f6i->fib6_metric != metric) { in __find_rr_leaf()
846 if (unlikely(f6i->nh)) { in __find_rr_leaf()
848 .flags = f6i->fib6_flags, in __find_rr_leaf()
855 if (nexthop_is_blackhole(f6i->nh)) { in __find_rr_leaf()
856 res->fib6_flags = RTF_REJECT; in __find_rr_leaf()
857 res->fib6_type = RTN_BLACKHOLE; in __find_rr_leaf()
858 res->f6i = f6i; in __find_rr_leaf()
859 res->nh = nexthop_fib6_nh(f6i->nh); in __find_rr_leaf()
862 if (nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_find_match, in __find_rr_leaf()
868 nh = f6i->fib6_nh; in __find_rr_leaf()
869 if (find_match(nh, f6i->fib6_flags, oif, strict, in __find_rr_leaf()
874 res->f6i = f6i; in __find_rr_leaf()
875 res->nh = nh; in __find_rr_leaf()
876 res->fib6_flags = f6i->fib6_flags; in __find_rr_leaf()
877 res->fib6_type = f6i->fib6_type; in __find_rr_leaf()
886 u32 metric = rr_head->fib6_metric; in find_rr_leaf()
888 int mpri = -1; in find_rr_leaf()
896 if (res->f6i || !cont) in find_rr_leaf()
906 struct fib6_info *leaf = rcu_dereference(fn->leaf); in rt6_select()
912 res->f6i = NULL; in rt6_select()
914 if (!leaf || leaf == net->ipv6.fib6_null_entry) in rt6_select()
917 rt0 = rcu_dereference(fn->rr_ptr); in rt6_select()
922 * and fn->leaf does not points to its child's leaf in rt6_select()
926 key_plen = rt0->fib6_dst.plen; in rt6_select()
928 if (rt0->fib6_src.plen) in rt6_select()
929 key_plen = rt0->fib6_src.plen; in rt6_select()
931 if (fn->fn_bit != key_plen) in rt6_select()
936 struct fib6_info *next = rcu_dereference(rt0->fib6_next); in rt6_select()
938 /* no entries matched; do round-robin */ in rt6_select()
939 if (!next || next->fib6_metric != rt0->fib6_metric) in rt6_select()
943 spin_lock_bh(&leaf->fib6_table->tb6_lock); in rt6_select()
945 if (next->fib6_node) in rt6_select()
946 rcu_assign_pointer(fn->rr_ptr, next); in rt6_select()
947 spin_unlock_bh(&leaf->fib6_table->tb6_lock); in rt6_select()
952 if (!res->f6i) { in rt6_select()
953 res->f6i = net->ipv6.fib6_null_entry; in rt6_select()
954 res->nh = res->f6i->fib6_nh; in rt6_select()
955 res->fib6_flags = res->f6i->fib6_flags; in rt6_select()
956 res->fib6_type = res->f6i->fib6_type; in rt6_select()
962 return (res->f6i->fib6_flags & RTF_NONEXTHOP) || in rt6_is_gw_or_nonexthop()
963 res->nh->fib_nh_gw_family; in rt6_is_gw_or_nonexthop()
979 return -EINVAL; in rt6_route_rcv()
983 if (rinfo->length > 3) { in rt6_route_rcv()
984 return -EINVAL; in rt6_route_rcv()
985 } else if (rinfo->prefix_len > 128) { in rt6_route_rcv()
986 return -EINVAL; in rt6_route_rcv()
987 } else if (rinfo->prefix_len > 64) { in rt6_route_rcv()
988 if (rinfo->length < 2) { in rt6_route_rcv()
989 return -EINVAL; in rt6_route_rcv()
991 } else if (rinfo->prefix_len > 0) { in rt6_route_rcv()
992 if (rinfo->length < 1) { in rt6_route_rcv()
993 return -EINVAL; in rt6_route_rcv()
997 pref = rinfo->route_pref; in rt6_route_rcv()
999 return -EINVAL; in rt6_route_rcv()
1001 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ); in rt6_route_rcv()
1003 if (rinfo->length == 3) in rt6_route_rcv()
1004 prefix = (struct in6_addr *)rinfo->prefix; in rt6_route_rcv()
1008 (struct in6_addr *)rinfo->prefix, in rt6_route_rcv()
1009 rinfo->prefix_len); in rt6_route_rcv()
1013 if (rinfo->prefix_len == 0) in rt6_route_rcv()
1016 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, in rt6_route_rcv()
1025 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, in rt6_route_rcv()
1028 rt->fib6_flags = RTF_ROUTEINFO | in rt6_route_rcv()
1029 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); in rt6_route_rcv()
1032 table = rt->fib6_table; in rt6_route_rcv()
1033 spin_lock_bh(&table->tb6_lock); in rt6_route_rcv()
1043 spin_unlock_bh(&table->tb6_lock); in rt6_route_rcv()
1058 struct net_device *dev = res->nh->fib_nh_dev; in ip6_rt_get_dev_rcu()
1060 if (res->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) { in ip6_rt_get_dev_rcu()
1061 /* for copies of local routes, dst->dev needs to be the in ip6_rt_get_dev_rcu()
1066 !rt6_need_strict(&res->f6i->fib6_dst.addr)) in ip6_rt_get_dev_rcu()
1069 dev = dev_net(dev)->loopback_dev; in ip6_rt_get_dev_rcu()
1085 [RTN_BLACKHOLE] = -EINVAL,
1086 [RTN_UNREACHABLE] = -EHOSTUNREACH,
1087 [RTN_PROHIBIT] = -EACCES,
1088 [RTN_THROW] = -EAGAIN,
1089 [RTN_NAT] = -EINVAL,
1090 [RTN_XRESOLVE] = -EINVAL,
1102 if (rt->dst_nocount) in fib6_info_dst_flags()
1104 if (rt->dst_nopolicy) in fib6_info_dst_flags()
1112 rt->dst.error = ip6_rt_type_to_error(fib6_type); in ip6_rt_init_dst_reject()
1116 rt->dst.output = dst_discard_out; in ip6_rt_init_dst_reject()
1117 rt->dst.input = dst_discard; in ip6_rt_init_dst_reject()
1120 rt->dst.output = ip6_pkt_prohibit_out; in ip6_rt_init_dst_reject()
1121 rt->dst.input = ip6_pkt_prohibit; in ip6_rt_init_dst_reject()
1126 rt->dst.output = ip6_pkt_discard_out; in ip6_rt_init_dst_reject()
1127 rt->dst.input = ip6_pkt_discard; in ip6_rt_init_dst_reject()
1134 struct fib6_info *f6i = res->f6i; in ip6_rt_init_dst()
1136 if (res->fib6_flags & RTF_REJECT) { in ip6_rt_init_dst()
1137 ip6_rt_init_dst_reject(rt, res->fib6_type); in ip6_rt_init_dst()
1141 rt->dst.error = 0; in ip6_rt_init_dst()
1142 rt->dst.output = ip6_output; in ip6_rt_init_dst()
1144 if (res->fib6_type == RTN_LOCAL || res->fib6_type == RTN_ANYCAST) { in ip6_rt_init_dst()
1145 rt->dst.input = ip6_input; in ip6_rt_init_dst()
1146 } else if (ipv6_addr_type(&f6i->fib6_dst.addr) & IPV6_ADDR_MULTICAST) { in ip6_rt_init_dst()
1147 rt->dst.input = ip6_mc_input; in ip6_rt_init_dst()
1149 rt->dst.input = ip6_forward; in ip6_rt_init_dst()
1152 if (res->nh->fib_nh_lws) { in ip6_rt_init_dst()
1153 rt->dst.lwtstate = lwtstate_get(res->nh->fib_nh_lws); in ip6_rt_init_dst()
1154 lwtunnel_set_redirect(&rt->dst); in ip6_rt_init_dst()
1157 rt->dst.lastuse = jiffies; in ip6_rt_init_dst()
1163 rt->rt6i_flags &= ~RTF_EXPIRES; in rt6_set_from()
1164 rcu_assign_pointer(rt->from, from); in rt6_set_from()
1165 ip_dst_init_metrics(&rt->dst, from->fib6_metrics); in rt6_set_from()
1171 const struct fib6_nh *nh = res->nh; in ip6_rt_copy_init()
1172 const struct net_device *dev = nh->fib_nh_dev; in ip6_rt_copy_init()
1173 struct fib6_info *f6i = res->f6i; in ip6_rt_copy_init()
1177 rt->rt6i_dst = f6i->fib6_dst; in ip6_rt_copy_init()
1178 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; in ip6_rt_copy_init()
1179 rt->rt6i_flags = res->fib6_flags; in ip6_rt_copy_init()
1180 if (nh->fib_nh_gw_family) { in ip6_rt_copy_init()
1181 rt->rt6i_gateway = nh->fib_nh_gw6; in ip6_rt_copy_init()
1182 rt->rt6i_flags |= RTF_GATEWAY; in ip6_rt_copy_init()
1186 rt->rt6i_src = f6i->fib6_src; in ip6_rt_copy_init()
1195 if (fn->fn_flags & RTN_TL_ROOT) in fib6_backtrack()
1197 pn = rcu_dereference(fn->parent); in fib6_backtrack()
1203 if (fn->fn_flags & RTN_RTINFO) in fib6_backtrack()
1212 if (dst_hold_safe(&rt->dst)) in ip6_hold_safe()
1215 rt = net->ipv6.ip6_null_entry; in ip6_hold_safe()
1216 dst_hold(&rt->dst); in ip6_hold_safe()
1227 struct net_device *dev = res->nh->fib_nh_dev; in ip6_create_rt_rcu()
1228 struct fib6_info *f6i = res->f6i; in ip6_create_rt_rcu()
1246 nrt = dev_net(dev)->ipv6.ip6_null_entry; in ip6_create_rt_rcu()
1247 dst_hold(&nrt->dst); in ip6_create_rt_rcu()
1262 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); in ip6_pol_route_lookup()
1264 res.f6i = rcu_dereference(fn->leaf); in ip6_pol_route_lookup()
1266 res.f6i = net->ipv6.fib6_null_entry; in ip6_pol_route_lookup()
1268 rt6_device_match(net, &res, &fl6->saddr, fl6->flowi6_oif, in ip6_pol_route_lookup()
1271 if (res.f6i == net->ipv6.fib6_null_entry) { in ip6_pol_route_lookup()
1272 fn = fib6_backtrack(fn, &fl6->saddr); in ip6_pol_route_lookup()
1276 rt = net->ipv6.ip6_null_entry; in ip6_pol_route_lookup()
1277 dst_hold(&rt->dst); in ip6_pol_route_lookup()
1283 fib6_select_path(net, &res, fl6, fl6->flowi6_oif, in ip6_pol_route_lookup()
1284 fl6->flowi6_oif != 0, skb, flags); in ip6_pol_route_lookup()
1287 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr); in ip6_pol_route_lookup()
1290 dst_use_noref(&rt->dst, jiffies); in ip6_pol_route_lookup()
1328 if (dst->error == 0) in rt6_lookup()
1337 /* ip6_ins_rt is called with FREE table->tb6_lock.
1338 * It takes new route entry, the addition fails by any reason the
1339 * route is released.
1349 table = rt->fib6_table; in __ip6_ins_rt()
1350 spin_lock_bh(&table->tb6_lock); in __ip6_ins_rt()
1351 err = fib6_add(&table->tb6_root, rt, info, extack); in __ip6_ins_rt()
1352 spin_unlock_bh(&table->tb6_lock); in __ip6_ins_rt()
1368 struct fib6_info *f6i = res->f6i; in ip6_rt_cache_alloc()
1373 * Clone the route. in ip6_rt_cache_alloc()
1387 rt->rt6i_flags |= RTF_CACHE; in ip6_rt_cache_alloc()
1388 rt->rt6i_dst.addr = *daddr; in ip6_rt_cache_alloc()
1389 rt->rt6i_dst.plen = 128; in ip6_rt_cache_alloc()
1392 if (f6i->fib6_dst.plen != 128 && in ip6_rt_cache_alloc()
1393 ipv6_addr_equal(&f6i->fib6_dst.addr, daddr)) in ip6_rt_cache_alloc()
1394 rt->rt6i_flags |= RTF_ANYCAST; in ip6_rt_cache_alloc()
1396 if (rt->rt6i_src.plen && saddr) { in ip6_rt_cache_alloc()
1397 rt->rt6i_src.addr = *saddr; in ip6_rt_cache_alloc()
1398 rt->rt6i_src.plen = 128; in ip6_rt_cache_alloc()
1408 struct fib6_info *f6i = res->f6i; in ip6_rt_pcpu_alloc()
1425 pcpu_rt->rt6i_flags |= RTF_PCPU; in ip6_rt_pcpu_alloc()
1427 if (f6i->nh) in ip6_rt_pcpu_alloc()
1428 pcpu_rt->sernum = rt_genid_ipv6(dev_net(dev)); in ip6_rt_pcpu_alloc()
1435 return rt6->sernum == rt_genid_ipv6(dev_net(rt6->dst.dev)); in rt6_is_valid()
1443 pcpu_rt = this_cpu_read(*res->nh->rt6i_pcpu); in rt6_get_pcpu_route()
1445 if (pcpu_rt && pcpu_rt->sernum && !rt6_is_valid(pcpu_rt)) { in rt6_get_pcpu_route()
1448 p = this_cpu_ptr(res->nh->rt6i_pcpu); in rt6_get_pcpu_route()
1452 dst_dev_put(&prev->dst); in rt6_get_pcpu_route()
1453 dst_release(&prev->dst); in rt6_get_pcpu_route()
1471 p = this_cpu_ptr(res->nh->rt6i_pcpu); in rt6_make_pcpu_route()
1475 if (res->f6i->fib6_destroying) { in rt6_make_pcpu_route()
1478 from = unrcu_pointer(xchg(&pcpu_rt->from, NULL)); in rt6_make_pcpu_route()
1500 net = dev_net(rt6_ex->rt6i->dst.dev); in rt6_remove_exception()
1501 net->ipv6.rt6_stats->fib_rt_cache--; in rt6_remove_exception()
1506 dst_dev_put(&rt6_ex->rt6i->dst); in rt6_remove_exception()
1508 hlist_del_rcu(&rt6_ex->hlist); in rt6_remove_exception()
1509 dst_release(&rt6_ex->rt6i->dst); in rt6_remove_exception()
1511 WARN_ON_ONCE(!bucket->depth); in rt6_remove_exception()
1512 bucket->depth--; in rt6_remove_exception()
1525 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) { in rt6_exception_remove_oldest()
1526 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp)) in rt6_exception_remove_oldest()
1574 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) { in __rt6_find_exception_spinlock()
1575 struct rt6_info *rt6 = rt6_ex->rt6i; in __rt6_find_exception_spinlock()
1576 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr); in __rt6_find_exception_spinlock()
1580 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr); in __rt6_find_exception_spinlock()
1609 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) { in __rt6_find_exception_rcu()
1610 struct rt6_info *rt6 = rt6_ex->rt6i; in __rt6_find_exception_rcu()
1611 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr); in __rt6_find_exception_rcu()
1615 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr); in __rt6_find_exception_rcu()
1625 const struct fib6_nh *nh = res->nh; in fib6_mtu()
1628 if (res->f6i->fib6_pmtu) { in fib6_mtu()
1629 mtu = res->f6i->fib6_pmtu; in fib6_mtu()
1631 struct net_device *dev = nh->fib_nh_dev; in fib6_mtu()
1636 mtu = READ_ONCE(idev->cnf.mtu6); in fib6_mtu()
1642 return mtu - lwtunnel_headroom(nh->fib_nh_lws, mtu); in fib6_mtu()
1659 bucket = rcu_dereference_protected(nh->rt6i_exception_bucket, in fib6_nh_get_excptn_bucket()
1662 bucket = rcu_dereference(nh->rt6i_exception_bucket); in fib6_nh_get_excptn_bucket()
1689 bucket = rcu_dereference_protected(nh->rt6i_exception_bucket, in fib6_nh_excptn_bucket_set_flushed()
1695 rcu_assign_pointer(nh->rt6i_exception_bucket, bucket); in fib6_nh_excptn_bucket_set_flushed()
1701 struct net *net = dev_net(nrt->dst.dev); in rt6_insert_exception()
1703 struct fib6_info *f6i = res->f6i; in rt6_insert_exception()
1706 struct fib6_nh *nh = res->nh; in rt6_insert_exception()
1712 bucket = rcu_dereference_protected(nh->rt6i_exception_bucket, in rt6_insert_exception()
1718 err = -ENOMEM; in rt6_insert_exception()
1721 rcu_assign_pointer(nh->rt6i_exception_bucket, bucket); in rt6_insert_exception()
1723 err = -EINVAL; in rt6_insert_exception()
1734 if (f6i->fib6_src.plen) in rt6_insert_exception()
1735 src_key = &nrt->rt6i_src.addr; in rt6_insert_exception()
1738 * Only insert this exception route if its mtu in rt6_insert_exception()
1741 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(res)) { in rt6_insert_exception()
1742 err = -EINVAL; in rt6_insert_exception()
1746 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr, in rt6_insert_exception()
1753 err = -ENOMEM; in rt6_insert_exception()
1756 rt6_ex->rt6i = nrt; in rt6_insert_exception()
1757 rt6_ex->stamp = jiffies; in rt6_insert_exception()
1758 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain); in rt6_insert_exception()
1759 bucket->depth++; in rt6_insert_exception()
1760 net->ipv6.rt6_stats->fib_rt_cache++; in rt6_insert_exception()
1764 while (bucket->depth > max_depth) in rt6_insert_exception()
1770 /* Update fn->fn_sernum to invalidate all cached dst */ in rt6_insert_exception()
1772 spin_lock_bh(&f6i->fib6_table->tb6_lock); in rt6_insert_exception()
1775 spin_unlock_bh(&f6i->fib6_table->tb6_lock); in rt6_insert_exception()
1800 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist) { in fib6_nh_flush_exceptions()
1802 rcu_access_pointer(rt6_ex->rt6i->from) == from) in fib6_nh_flush_exceptions()
1805 WARN_ON_ONCE(!from && bucket->depth); in fib6_nh_flush_exceptions()
1823 if (f6i->nh) in rt6_flush_exceptions()
1824 nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_flush_exceptions, in rt6_flush_exceptions()
1827 fib6_nh_flush_exceptions(f6i->fib6_nh, f6i); in rt6_flush_exceptions()
1849 * So we need to use f6i->fib6_src to redo lookup in rt6_find_cached_rt()
1852 * rt->rt6i_src is updated.) in rt6_find_cached_rt()
1854 if (res->f6i->fib6_src.plen) in rt6_find_cached_rt()
1858 bucket = fib6_nh_get_excptn_bucket(res->nh, NULL); in rt6_find_cached_rt()
1861 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i)) in rt6_find_cached_rt()
1862 ret = rt6_ex->rt6i; in rt6_find_cached_rt()
1866 if (!ret && src_key && src_key != &res->f6i->fib6_src.addr) { in rt6_find_cached_rt()
1867 src_key = &res->f6i->fib6_src.addr; in rt6_find_cached_rt()
1884 if (!rcu_access_pointer(nh->rt6i_exception_bucket)) in fib6_nh_remove_exception()
1885 return -ENOENT; in fib6_nh_remove_exception()
1898 src_key = &rt->rt6i_src.addr; in fib6_nh_remove_exception()
1901 &rt->rt6i_dst.addr, in fib6_nh_remove_exception()
1907 err = -ENOENT; in fib6_nh_remove_exception()
1924 err = fib6_nh_remove_exception(nh, arg->plen, arg->rt); in rt6_nh_remove_exception_rt()
1935 from = rcu_dereference(rt->from); in rt6_remove_exception_rt()
1936 if (!from || !(rt->rt6i_flags & RTF_CACHE)) in rt6_remove_exception_rt()
1937 return -EINVAL; in rt6_remove_exception_rt()
1939 if (from->nh) { in rt6_remove_exception_rt()
1942 .plen = from->fib6_src.plen in rt6_remove_exception_rt()
1947 rc = nexthop_for_each_fib6_nh(from->nh, in rt6_remove_exception_rt()
1950 return rc ? 0 : -ENOENT; in rt6_remove_exception_rt()
1953 return fib6_nh_remove_exception(from->fib6_nh, in rt6_remove_exception_rt()
1954 from->fib6_src.plen, rt); in rt6_remove_exception_rt()
1976 src_key = &rt->rt6i_src.addr; in fib6_nh_update_exception()
1978 rt6_ex = __rt6_find_exception_rcu(&bucket, &rt->rt6i_dst.addr, src_key); in fib6_nh_update_exception()
1980 rt6_ex->stamp = jiffies; in fib6_nh_update_exception()
1994 if (arg->dev != nh->fib_nh_dev || in fib6_nh_find_match()
1995 (arg->gw && !nh->fib_nh_gw_family) || in fib6_nh_find_match()
1996 (!arg->gw && nh->fib_nh_gw_family) || in fib6_nh_find_match()
1997 (arg->gw && !ipv6_addr_equal(arg->gw, &nh->fib_nh_gw6))) in fib6_nh_find_match()
2000 arg->match = nh; in fib6_nh_find_match()
2013 from = rcu_dereference(rt->from); in rt6_update_exception_stamp_rt()
2014 if (!from || !(rt->rt6i_flags & RTF_CACHE)) in rt6_update_exception_stamp_rt()
2017 if (from->nh) { in rt6_update_exception_stamp_rt()
2019 .dev = rt->dst.dev, in rt6_update_exception_stamp_rt()
2020 .gw = &rt->rt6i_gateway, in rt6_update_exception_stamp_rt()
2023 nexthop_for_each_fib6_nh(from->nh, fib6_nh_find_match, &arg); in rt6_update_exception_stamp_rt()
2029 fib6_nh = from->fib6_nh; in rt6_update_exception_stamp_rt()
2031 fib6_nh_update_exception(fib6_nh, from->fib6_src.plen, rt); in rt6_update_exception_stamp_rt()
2039 /* If the new MTU is lower than the route PMTU, this new MTU will be the in rt6_mtu_change_route_allowed()
2040 * lowest MTU in the path: always allow updating the route PMTU to in rt6_mtu_change_route_allowed()
2043 * If the new MTU is higher, and the route PMTU is equal to the local in rt6_mtu_change_route_allowed()
2049 if (dst_mtu(&rt->dst) >= mtu) in rt6_mtu_change_route_allowed()
2052 if (dst_mtu(&rt->dst) == idev->cnf.mtu6) in rt6_mtu_change_route_allowed()
2070 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) { in rt6_exceptions_update_pmtu()
2071 struct rt6_info *entry = rt6_ex->rt6i; in rt6_exceptions_update_pmtu()
2074 * route), the metrics of its rt->from have already in rt6_exceptions_update_pmtu()
2077 if (dst_metric_raw(&entry->dst, RTAX_MTU) && in rt6_exceptions_update_pmtu()
2079 dst_metric_set(&entry->dst, RTAX_MTU, mtu); in rt6_exceptions_update_pmtu()
2095 if (!rcu_access_pointer(nh->rt6i_exception_bucket)) in fib6_nh_exceptions_clean_tohost()
2103 &bucket->chain, hlist) { in fib6_nh_exceptions_clean_tohost()
2104 struct rt6_info *entry = rt6_ex->rt6i; in fib6_nh_exceptions_clean_tohost()
2106 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) == in fib6_nh_exceptions_clean_tohost()
2109 &entry->rt6i_gateway)) { in fib6_nh_exceptions_clean_tohost()
2125 struct rt6_info *rt = rt6_ex->rt6i; in rt6_age_examine_exception()
2127 /* we are pruning and obsoleting aged-out and non gateway exceptions in rt6_age_examine_exception()
2130 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when in rt6_age_examine_exception()
2133 if (!(rt->rt6i_flags & RTF_EXPIRES)) { in rt6_age_examine_exception()
2134 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) { in rt6_age_examine_exception()
2139 } else if (time_after(jiffies, rt->dst.expires)) { in rt6_age_examine_exception()
2140 pr_debug("purging expired route %p\n", rt); in rt6_age_examine_exception()
2145 if (rt->rt6i_flags & RTF_GATEWAY) { in rt6_age_examine_exception()
2148 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); in rt6_age_examine_exception()
2150 if (!(neigh && (neigh->flags & NTF_ROUTER))) { in rt6_age_examine_exception()
2151 pr_debug("purging route %p via non-router but gateway\n", in rt6_age_examine_exception()
2158 gc_args->more++; in rt6_age_examine_exception()
2170 if (!rcu_access_pointer(nh->rt6i_exception_bucket)) in fib6_nh_age_exceptions()
2179 &bucket->chain, hlist) { in fib6_nh_age_exceptions()
2199 fib6_nh_age_exceptions(nh, arg->gc_args, arg->now); in rt6_nh_age_exceptions()
2207 if (f6i->nh) { in rt6_age_exceptions()
2213 nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_age_exceptions, in rt6_age_exceptions()
2216 fib6_nh_age_exceptions(f6i->fib6_nh, gc_args, now); in rt6_age_exceptions()
2226 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); in fib6_table_lookup()
2231 if (res->f6i == net->ipv6.fib6_null_entry) { in fib6_table_lookup()
2232 fn = fib6_backtrack(fn, &fl6->saddr); in fib6_table_lookup()
2236 /* also consider unreachable route */ in fib6_table_lookup()
2261 if (READ_ONCE(net->ipv6.devconf_all->forwarding) == 0) in ip6_pol_route()
2267 if (res.f6i == net->ipv6.fib6_null_entry) in ip6_pol_route()
2273 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr); in ip6_pol_route()
2276 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) && in ip6_pol_route()
2277 !res.nh->fib_nh_gw_family)) { in ip6_pol_route()
2280 * the daddr in the skb during the neighbor look-up is different in ip6_pol_route()
2281 * from the fl6->daddr used to look-up route here. in ip6_pol_route()
2283 rt = ip6_rt_cache_alloc(&res, &fl6->daddr, NULL); in ip6_pol_route()
2308 rt = net->ipv6.ip6_null_entry; in ip6_pol_route()
2323 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags); in ip6_pol_route_input()
2332 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG) in ip6_route_input_lookup()
2351 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6)) in ip6_multipath_l3_keys()
2359 if (!icmpv6_is_err(icmph->icmp6_type)) in ip6_multipath_l3_keys()
2372 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src; in ip6_multipath_l3_keys()
2373 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst; in ip6_multipath_l3_keys()
2374 keys->tags.flow_label = _flkeys->tags.flow_label; in ip6_multipath_l3_keys()
2375 keys->basic.ip_proto = _flkeys->basic.ip_proto; in ip6_multipath_l3_keys()
2377 keys->addrs.v6addrs.src = key_iph->saddr; in ip6_multipath_l3_keys()
2378 keys->addrs.v6addrs.dst = key_iph->daddr; in ip6_multipath_l3_keys()
2379 keys->tags.flow_label = ip6_flowlabel(key_iph); in ip6_multipath_l3_keys()
2380 keys->basic.ip_proto = key_iph->nexthdr; in ip6_multipath_l3_keys()
2488 hash_keys.addrs.v6addrs.src = fl6->saddr; in rt6_multipath_custom_hash_fl6()
2490 hash_keys.addrs.v6addrs.dst = fl6->daddr; in rt6_multipath_custom_hash_fl6()
2492 hash_keys.basic.ip_proto = fl6->flowi6_proto; in rt6_multipath_custom_hash_fl6()
2496 hash_keys.ports.src = fl6->fl6_sport; in rt6_multipath_custom_hash_fl6()
2498 hash_keys.ports.dst = fl6->fl6_dport; in rt6_multipath_custom_hash_fl6()
2517 hash_keys.addrs.v6addrs.src = fl6->saddr; in rt6_multipath_hash()
2518 hash_keys.addrs.v6addrs.dst = fl6->daddr; in rt6_multipath_hash()
2520 hash_keys.basic.ip_proto = fl6->flowi6_proto; in rt6_multipath_hash()
2529 /* short-circuit if we already have L4 hash present */ in rt6_multipath_hash()
2530 if (skb->l4_hash) in rt6_multipath_hash()
2540 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src; in rt6_multipath_hash()
2541 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst; in rt6_multipath_hash()
2542 hash_keys.ports.src = flkeys->ports.src; in rt6_multipath_hash()
2543 hash_keys.ports.dst = flkeys->ports.dst; in rt6_multipath_hash()
2544 hash_keys.basic.ip_proto = flkeys->basic.ip_proto; in rt6_multipath_hash()
2548 hash_keys.addrs.v6addrs.src = fl6->saddr; in rt6_multipath_hash()
2549 hash_keys.addrs.v6addrs.dst = fl6->daddr; in rt6_multipath_hash()
2550 hash_keys.ports.src = fl6->fl6_sport; in rt6_multipath_hash()
2551 hash_keys.ports.dst = fl6->fl6_dport; in rt6_multipath_hash()
2552 hash_keys.basic.ip_proto = fl6->flowi6_proto; in rt6_multipath_hash()
2568 if (flkeys->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { in rt6_multipath_hash()
2570 hash_keys.addrs.v4addrs.src = flkeys->addrs.v4addrs.src; in rt6_multipath_hash()
2571 hash_keys.addrs.v4addrs.dst = flkeys->addrs.v4addrs.dst; in rt6_multipath_hash()
2572 } else if (flkeys->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { in rt6_multipath_hash()
2574 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src; in rt6_multipath_hash()
2575 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst; in rt6_multipath_hash()
2576 hash_keys.tags.flow_label = flkeys->tags.flow_label; in rt6_multipath_hash()
2577 hash_keys.basic.ip_proto = flkeys->basic.ip_proto; in rt6_multipath_hash()
2586 hash_keys.addrs.v6addrs.src = fl6->saddr; in rt6_multipath_hash()
2587 hash_keys.addrs.v6addrs.dst = fl6->daddr; in rt6_multipath_hash()
2589 hash_keys.basic.ip_proto = fl6->flowi6_proto; in rt6_multipath_hash()
2608 struct net *net = dev_net(skb->dev); in ip6_route_input()
2612 .flowi6_iif = skb->dev->ifindex, in ip6_route_input()
2613 .daddr = iph->daddr, in ip6_route_input()
2614 .saddr = iph->saddr, in ip6_route_input()
2616 .flowi6_mark = skb->mark, in ip6_route_input()
2617 .flowi6_proto = iph->nexthdr, in ip6_route_input()
2622 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX)) in ip6_route_input()
2623 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id; in ip6_route_input()
2631 skb_dst_set_noref(skb, ip6_route_input_lookup(net, skb->dev, in ip6_route_input()
2641 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags); in ip6_pol_route_output()
2651 if (ipv6_addr_type(&fl6->daddr) & in ip6_route_output_flags_noref()
2661 fl6->flowi6_iif = LOOPBACK_IFINDEX; in ip6_route_output_flags_noref()
2664 any_src = ipv6_addr_any(&fl6->saddr); in ip6_route_output_flags_noref()
2665 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) || in ip6_route_output_flags_noref()
2666 (fl6->flowi6_oif && any_src)) in ip6_route_output_flags_noref()
2672 flags |= rt6_srcprefs2flags(READ_ONCE(inet6_sk(sk)->srcprefs)); in ip6_route_output_flags_noref()
2689 if (list_empty(&rt6->dst.rt_uncached) && !dst_hold_safe(dst)) { in ip6_route_output_flags()
2690 dst = &net->ipv6.ip6_null_entry->dst; in ip6_route_output_flags()
2702 struct net_device *loopback_dev = net->loopback_dev; in ip6_blackhole_route()
2709 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc); in ip6_blackhole_route()
2711 new = &rt->dst; in ip6_blackhole_route()
2712 new->__use = 1; in ip6_blackhole_route()
2713 new->input = dst_discard; in ip6_blackhole_route()
2714 new->output = dst_discard_out; in ip6_blackhole_route()
2716 dst_copy_metrics(new, &ort->dst); in ip6_blackhole_route()
2718 rt->rt6i_idev = in6_dev_get(loopback_dev); in ip6_blackhole_route()
2719 rt->rt6i_gateway = ort->rt6i_gateway; in ip6_blackhole_route()
2720 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU; in ip6_blackhole_route()
2722 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); in ip6_blackhole_route()
2724 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); in ip6_blackhole_route()
2729 return new ? new : ERR_PTR(-ENOMEM); in ip6_blackhole_route()
2762 return &rt->dst; in rt6_check()
2770 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && in rt6_dst_from_check()
2772 return &rt->dst; in rt6_dst_from_check()
2786 if (rt->sernum) in ip6_dst_check()
2791 /* All IPV6 dsts are created with ->obsolete set to the value in ip6_dst_check()
2796 from = rcu_dereference(rt->from); in ip6_dst_check()
2798 if (from && (rt->rt6i_flags & RTF_PCPU || in ip6_dst_check()
2799 unlikely(!list_empty(&rt->dst.rt_uncached)))) in ip6_dst_check()
2815 if (rt->rt6i_flags & RTF_CACHE) { in ip6_negative_advice()
2839 if (rt->rt6i_flags & RTF_CACHE) { in ip6_link_failure()
2845 from = rcu_dereference(rt->from); in ip6_link_failure()
2847 fn = rcu_dereference(from->fib6_node); in ip6_link_failure()
2848 if (fn && (rt->rt6i_flags & RTF_DEFAULT)) in ip6_link_failure()
2849 WRITE_ONCE(fn->fn_sernum, -1); in ip6_link_failure()
2858 if (!(rt0->rt6i_flags & RTF_EXPIRES)) { in rt6_update_expires()
2862 from = rcu_dereference(rt0->from); in rt6_update_expires()
2864 rt0->dst.expires = from->expires; in rt6_update_expires()
2868 dst_set_expires(&rt0->dst, timeout); in rt6_update_expires()
2869 rt0->rt6i_flags |= RTF_EXPIRES; in rt6_update_expires()
2874 struct net *net = dev_net(rt->dst.dev); in rt6_do_update_pmtu()
2876 dst_metric_set(&rt->dst, RTAX_MTU, mtu); in rt6_do_update_pmtu()
2877 rt->rt6i_flags |= RTF_MODIFIED; in rt6_do_update_pmtu()
2878 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires); in rt6_do_update_pmtu()
2883 return !(rt->rt6i_flags & RTF_CACHE) && in rt6_cache_allowed_for_pmtu()
2884 (rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from)); in rt6_cache_allowed_for_pmtu()
2900 daddr = &iph->daddr; in __ip6_rt_update_pmtu()
2901 saddr = &iph->saddr; in __ip6_rt_update_pmtu()
2903 daddr = &sk->sk_v6_daddr; in __ip6_rt_update_pmtu()
2904 saddr = &inet6_sk(sk)->saddr; in __ip6_rt_update_pmtu()
2920 /* update rt6_ex->stamp for cache */ in __ip6_rt_update_pmtu()
2921 if (rt6->rt6i_flags & RTF_CACHE) in __ip6_rt_update_pmtu()
2928 res.f6i = rcu_dereference(rt6->from); in __ip6_rt_update_pmtu()
2932 res.fib6_flags = res.f6i->fib6_flags; in __ip6_rt_update_pmtu()
2933 res.fib6_type = res.f6i->fib6_type; in __ip6_rt_update_pmtu()
2935 if (res.f6i->nh) { in __ip6_rt_update_pmtu()
2937 .dev = dst->dev, in __ip6_rt_update_pmtu()
2938 .gw = &rt6->rt6i_gateway, in __ip6_rt_update_pmtu()
2941 nexthop_for_each_fib6_nh(res.f6i->nh, in __ip6_rt_update_pmtu()
2945 * using the dst->dev + gw. Should be impossible. in __ip6_rt_update_pmtu()
2952 res.nh = res.f6i->fib6_nh; in __ip6_rt_update_pmtu()
2959 dst_release_immediate(&nrt6->dst); in __ip6_rt_update_pmtu()
2977 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; in ip6_update_pmtu()
2981 .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark), in ip6_update_pmtu()
2982 .daddr = iph->daddr, in ip6_update_pmtu()
2983 .saddr = iph->saddr, in ip6_update_pmtu()
2989 if (!dst->error) in ip6_update_pmtu()
2997 int oif = sk->sk_bound_dev_if; in ip6_sk_update_pmtu()
3000 if (!oif && skb->dev) in ip6_sk_update_pmtu()
3001 oif = l3mdev_master_ifindex(skb->dev); in ip6_sk_update_pmtu()
3003 ip6_update_pmtu(skb, sock_net(sk), mtu, oif, READ_ONCE(sk->sk_mark), in ip6_sk_update_pmtu()
3004 sk->sk_uid); in ip6_sk_update_pmtu()
3007 if (!dst || !dst->obsolete || in ip6_sk_update_pmtu()
3008 dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) in ip6_sk_update_pmtu()
3012 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) in ip6_sk_update_pmtu()
3026 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ? in ip6_sk_dst_store_flow()
3027 &sk->sk_v6_daddr : NULL, in ip6_sk_dst_store_flow()
3029 ipv6_addr_equal(&fl6->saddr, &np->saddr) ? in ip6_sk_dst_store_flow()
3030 &np->saddr : in ip6_sk_dst_store_flow()
3040 const struct fib6_nh *nh = res->nh; in ip6_redirect_nh_match()
3042 if (nh->fib_nh_flags & RTNH_F_DEAD || !nh->fib_nh_gw_family || in ip6_redirect_nh_match()
3043 fl6->flowi6_oif != nh->fib_nh_dev->ifindex) in ip6_redirect_nh_match()
3051 if (!ipv6_addr_equal(gw, &nh->fib_nh_gw6)) { in ip6_redirect_nh_match()
3054 rt_cache = rt6_find_cached_rt(res, &fl6->daddr, &fl6->saddr); in ip6_redirect_nh_match()
3056 ipv6_addr_equal(gw, &rt_cache->rt6i_gateway)) { in ip6_redirect_nh_match()
3076 arg->res->nh = nh; in fib6_nh_redirect_match()
3077 return ip6_redirect_nh_match(arg->res, arg->fl6, arg->gw, arg->ret); in fib6_nh_redirect_match()
3098 .gw = &rdfl->gateway, in __ip6_route_redirect()
3104 /* Get the "current" route for this destination and in __ip6_route_redirect()
3115 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); in __ip6_route_redirect()
3121 if (rt->fib6_flags & RTF_REJECT) in __ip6_route_redirect()
3123 if (unlikely(rt->nh)) { in __ip6_route_redirect()
3124 if (nexthop_is_blackhole(rt->nh)) in __ip6_route_redirect()
3126 /* on match, res->nh is filled in and potentially ret */ in __ip6_route_redirect()
3127 if (nexthop_for_each_fib6_nh(rt->nh, in __ip6_route_redirect()
3132 res.nh = rt->fib6_nh; in __ip6_route_redirect()
3133 if (ip6_redirect_nh_match(&res, fl6, &rdfl->gateway, in __ip6_route_redirect()
3140 rt = net->ipv6.fib6_null_entry; in __ip6_route_redirect()
3141 else if (rt->fib6_flags & RTF_REJECT) { in __ip6_route_redirect()
3142 ret = net->ipv6.ip6_null_entry; in __ip6_route_redirect()
3146 if (rt == net->ipv6.fib6_null_entry) { in __ip6_route_redirect()
3147 fn = fib6_backtrack(fn, &fl6->saddr); in __ip6_route_redirect()
3153 res.nh = rt->fib6_nh; in __ip6_route_redirect()
3158 res.fib6_flags = res.f6i->fib6_flags; in __ip6_route_redirect()
3159 res.fib6_type = res.f6i->fib6_type; in __ip6_route_redirect()
3187 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; in ip6_redirect()
3193 .daddr = iph->daddr, in ip6_redirect()
3194 .saddr = iph->saddr, in ip6_redirect()
3199 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr); in ip6_redirect()
3213 .daddr = msg->dest, in ip6_redirect_no_header()
3214 .saddr = iph->daddr, in ip6_redirect_no_header()
3218 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr); in ip6_redirect_no_header()
3225 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, in ip6_sk_redirect()
3226 READ_ONCE(sk->sk_mark), sk->sk_uid); in ip6_sk_redirect()
3232 struct net_device *dev = dst->dev; in ip6_default_advmss()
3236 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); in ip6_default_advmss()
3241 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) in ip6_default_advmss()
3242 mtu = net->ipv6.sysctl.ip6_rt_min_advmss; in ip6_default_advmss()
3247 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and in ip6_default_advmss()
3248 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size. in ip6_default_advmss()
3252 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr)) in ip6_default_advmss()
3264 * 1. mtu on route is locked - use it
3275 const struct fib6_nh *nh = res->nh; in ip6_mtu_from_fib6()
3276 struct fib6_info *f6i = res->f6i; in ip6_mtu_from_fib6()
3282 mtu = f6i->fib6_pmtu; in ip6_mtu_from_fib6()
3289 mtu = dst_metric_raw(&rt->dst, RTAX_MTU); in ip6_mtu_from_fib6()
3291 struct net_device *dev = nh->fib_nh_dev; in ip6_mtu_from_fib6()
3296 mtu = max_t(u32, mtu, READ_ONCE(idev->cnf.mtu6)); in ip6_mtu_from_fib6()
3301 return mtu - lwtunnel_headroom(nh->fib_nh_lws, mtu); in ip6_mtu_from_fib6()
3313 return ERR_PTR(-ENODEV); in icmp6_dst_alloc()
3318 dst = ERR_PTR(-ENOMEM); in icmp6_dst_alloc()
3322 rt->dst.input = ip6_input; in icmp6_dst_alloc()
3323 rt->dst.output = ip6_output; in icmp6_dst_alloc()
3324 rt->rt6i_gateway = fl6->daddr; in icmp6_dst_alloc()
3325 rt->rt6i_dst.addr = fl6->daddr; in icmp6_dst_alloc()
3326 rt->rt6i_dst.plen = 128; in icmp6_dst_alloc()
3327 rt->rt6i_idev = idev; in icmp6_dst_alloc()
3328 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0); in icmp6_dst_alloc()
3335 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); in icmp6_dst_alloc()
3344 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; in ip6_dst_gc()
3345 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; in ip6_dst_gc()
3346 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; in ip6_dst_gc()
3347 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; in ip6_dst_gc()
3354 fib6_run_gc(atomic_inc_return(&net->ipv6.ip6_rt_gc_expire), net, true); in ip6_dst_gc()
3356 if (entries < ops->gc_thresh) in ip6_dst_gc()
3357 atomic_set(&net->ipv6.ip6_rt_gc_expire, rt_gc_timeout >> 1); in ip6_dst_gc()
3359 val = atomic_read(&net->ipv6.ip6_rt_gc_expire); in ip6_dst_gc()
3360 atomic_set(&net->ipv6.ip6_rt_gc_expire, val - (val >> rt_elasticity)); in ip6_dst_gc()
3368 .flowi6_oif = cfg->fc_ifindex, in ip6_nh_lookup_table()
3370 .saddr = cfg->fc_prefsrc, in ip6_nh_lookup_table()
3377 return -EINVAL; in ip6_nh_lookup_table()
3379 if (!ipv6_addr_any(&cfg->fc_prefsrc)) in ip6_nh_lookup_table()
3384 err = fib6_table_lookup(net, table, cfg->fc_ifindex, &fl6, res, flags); in ip6_nh_lookup_table()
3385 if (!err && res->f6i != net->ipv6.fib6_null_entry) in ip6_nh_lookup_table()
3386 fib6_select_path(net, res, &fl6, cfg->fc_ifindex, in ip6_nh_lookup_table()
3387 cfg->fc_ifindex != 0, NULL, flags); in ip6_nh_lookup_table()
3398 const struct in6_addr *gw_addr = &cfg->fc_gateway; in ip6_route_check_nh_onlink()
3404 /* ignore match if it is the default route */ in ip6_route_check_nh_onlink()
3405 !ipv6_addr_any(&res.f6i->fib6_dst.addr) && in ip6_route_check_nh_onlink()
3406 (res.fib6_type != RTN_UNICAST || dev != res.nh->fib_nh_dev)) { in ip6_route_check_nh_onlink()
3409 err = -EINVAL; in ip6_route_check_nh_onlink()
3421 const struct in6_addr *gw_addr = &cfg->fc_gateway; in ip6_route_check_nh()
3425 int err = -EHOSTUNREACH; in ip6_route_check_nh()
3427 if (cfg->fc_table) { in ip6_route_check_nh()
3429 cfg->fc_table, flags, &res); in ip6_route_check_nh()
3431 * route. If a device is given, it must match the result. in ip6_route_check_nh()
3434 res.nh->fib_nh_gw_family || in ip6_route_check_nh()
3435 (dev && dev != res.nh->fib_nh_dev)) in ip6_route_check_nh()
3436 err = -EHOSTUNREACH; in ip6_route_check_nh()
3441 .flowi6_oif = cfg->fc_ifindex, in ip6_route_check_nh()
3445 err = fib6_lookup(net, cfg->fc_ifindex, &fl6, &res, flags); in ip6_route_check_nh()
3447 res.nh->fib_nh_gw_family) in ip6_route_check_nh()
3448 err = -EHOSTUNREACH; in ip6_route_check_nh()
3453 fib6_select_path(net, &res, &fl6, cfg->fc_ifindex, in ip6_route_check_nh()
3454 cfg->fc_ifindex != 0, NULL, flags); in ip6_route_check_nh()
3459 if (dev != res.nh->fib_nh_dev) in ip6_route_check_nh()
3460 err = -EHOSTUNREACH; in ip6_route_check_nh()
3462 *_dev = dev = res.nh->fib_nh_dev; in ip6_route_check_nh()
3476 const struct in6_addr *gw_addr = &cfg->fc_gateway; in ip6_validate_gw()
3481 int err = -EINVAL; in ip6_validate_gw()
3485 * will return already-added prefix route via interface that in ip6_validate_gw()
3486 * prefix route was assigned to, which might be non-loopback. in ip6_validate_gw()
3495 /* IPv6 strictly inhibits using not link-local in ip6_validate_gw()
3499 * (SIT, PtP, NBMA NOARP links) it is handy to allow in ip6_validate_gw()
3500 * some exceptions. --ANK in ip6_validate_gw()
3501 * We allow IPv4-mapped nexthops to support RFC4798-type in ip6_validate_gw()
3511 if (cfg->fc_flags & RTNH_F_ONLINK) in ip6_validate_gw()
3526 err = -EINVAL; in ip6_validate_gw()
3530 } else if (dev->flags & IFF_LOOPBACK) { in ip6_validate_gw()
3532 "Egress device can not be loopback device for this route"); in ip6_validate_gw()
3553 (dev && (dev->flags & IFF_LOOPBACK) && in fib6_is_reject()
3565 netdevice_tracker *dev_tracker = &fib6_nh->fib_nh_dev_tracker; in fib6_nh_init()
3571 fib6_nh->fib_nh_family = AF_INET6; in fib6_nh_init()
3573 fib6_nh->last_probe = jiffies; in fib6_nh_init()
3575 if (cfg->fc_is_fdb) { in fib6_nh_init()
3576 fib6_nh->fib_nh_gw6 = cfg->fc_gateway; in fib6_nh_init()
3577 fib6_nh->fib_nh_gw_family = AF_INET6; in fib6_nh_init()
3581 err = -ENODEV; in fib6_nh_init()
3582 if (cfg->fc_ifindex) { in fib6_nh_init()
3583 dev = netdev_get_by_index(net, cfg->fc_ifindex, in fib6_nh_init()
3592 if (cfg->fc_flags & RTNH_F_ONLINK) { in fib6_nh_init()
3599 if (!(dev->flags & IFF_UP)) { in fib6_nh_init()
3601 err = -ENETDOWN; in fib6_nh_init()
3605 fib6_nh->fib_nh_flags |= RTNH_F_ONLINK; in fib6_nh_init()
3608 fib6_nh->fib_nh_weight = 1; in fib6_nh_init()
3613 addr_type = ipv6_addr_type(&cfg->fc_dst); in fib6_nh_init()
3614 if (fib6_is_reject(cfg->fc_flags, dev, addr_type)) { in fib6_nh_init()
3616 if (dev != net->loopback_dev) { in fib6_nh_init()
3621 dev = net->loopback_dev; in fib6_nh_init()
3625 err = -ENODEV; in fib6_nh_init()
3632 if (cfg->fc_flags & RTF_GATEWAY) { in fib6_nh_init()
3638 fib6_nh->fib_nh_gw6 = cfg->fc_gateway; in fib6_nh_init()
3639 fib6_nh->fib_nh_gw_family = AF_INET6; in fib6_nh_init()
3642 err = -ENODEV; in fib6_nh_init()
3646 if (!idev || idev->cnf.disable_ipv6) { in fib6_nh_init()
3648 err = -EACCES; in fib6_nh_init()
3652 if (!(dev->flags & IFF_UP) && !cfg->fc_ignore_dev_down) { in fib6_nh_init()
3654 err = -ENETDOWN; in fib6_nh_init()
3658 if (!(cfg->fc_flags & (RTF_LOCAL | RTF_ANYCAST)) && in fib6_nh_init()
3660 fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib6_nh_init()
3662 err = fib_nh_common_init(net, &fib6_nh->nh_common, cfg->fc_encap, in fib6_nh_init()
3663 cfg->fc_encap_type, cfg, gfp_flags, extack); in fib6_nh_init()
3668 fib6_nh->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags); in fib6_nh_init()
3669 if (!fib6_nh->rt6i_pcpu) { in fib6_nh_init()
3670 err = -ENOMEM; in fib6_nh_init()
3674 fib6_nh->fib_nh_dev = dev; in fib6_nh_init()
3675 fib6_nh->fib_nh_oif = dev->ifindex; in fib6_nh_init()
3682 fib_nh_common_release(&fib6_nh->nh_common); in fib6_nh_init()
3683 fib6_nh->nh_common.nhc_pcpu_rth_output = NULL; in fib6_nh_init()
3684 fib6_nh->fib_nh_lws = NULL; in fib6_nh_init()
3700 rcu_assign_pointer(fib6_nh->rt6i_exception_bucket, NULL); in fib6_nh_release()
3707 free_percpu(fib6_nh->rt6i_pcpu); in fib6_nh_release()
3709 fib_nh_common_release(&fib6_nh->nh_common); in fib6_nh_release()
3716 if (!fib6_nh->rt6i_pcpu) in fib6_nh_release_dsts()
3722 ppcpu_rt = per_cpu_ptr(fib6_nh->rt6i_pcpu, cpu); in fib6_nh_release_dsts()
3725 dst_dev_put(&pcpu_rt->dst); in fib6_nh_release_dsts()
3726 dst_release(&pcpu_rt->dst); in fib6_nh_release_dsts()
3735 struct net *net = cfg->fc_nlinfo.nl_net; in ip6_route_info_create()
3740 int err = -EINVAL; in ip6_route_info_create()
3744 if (cfg->fc_flags & RTF_PCPU) { in ip6_route_info_create()
3750 if (cfg->fc_flags & RTF_CACHE) { in ip6_route_info_create()
3755 if (cfg->fc_type > RTN_MAX) { in ip6_route_info_create()
3756 NL_SET_ERR_MSG(extack, "Invalid route type"); in ip6_route_info_create()
3760 if (cfg->fc_dst_len > 128) { in ip6_route_info_create()
3764 if (cfg->fc_src_len > 128) { in ip6_route_info_create()
3769 if (cfg->fc_src_len) { in ip6_route_info_create()
3775 if (cfg->fc_nh_id) { in ip6_route_info_create()
3776 nh = nexthop_find_by_id(net, cfg->fc_nh_id); in ip6_route_info_create()
3786 err = -ENOBUFS; in ip6_route_info_create()
3787 if (cfg->fc_nlinfo.nlh && in ip6_route_info_create()
3788 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { in ip6_route_info_create()
3789 table = fib6_get_table(net, cfg->fc_table); in ip6_route_info_create()
3791 pr_warn("NLM_F_CREATE should be specified when creating new route\n"); in ip6_route_info_create()
3792 table = fib6_new_table(net, cfg->fc_table); in ip6_route_info_create()
3795 table = fib6_new_table(net, cfg->fc_table); in ip6_route_info_create()
3801 err = -ENOMEM; in ip6_route_info_create()
3806 rt->fib6_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len, in ip6_route_info_create()
3808 if (IS_ERR(rt->fib6_metrics)) { in ip6_route_info_create()
3809 err = PTR_ERR(rt->fib6_metrics); in ip6_route_info_create()
3811 rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics; in ip6_route_info_create()
3815 if (cfg->fc_flags & RTF_ADDRCONF) in ip6_route_info_create()
3816 rt->dst_nocount = true; in ip6_route_info_create()
3818 if (cfg->fc_flags & RTF_EXPIRES) in ip6_route_info_create()
3820 clock_t_to_jiffies(cfg->fc_expires)); in ip6_route_info_create()
3822 if (cfg->fc_protocol == RTPROT_UNSPEC) in ip6_route_info_create()
3823 cfg->fc_protocol = RTPROT_BOOT; in ip6_route_info_create()
3824 rt->fib6_protocol = cfg->fc_protocol; in ip6_route_info_create()
3826 rt->fib6_table = table; in ip6_route_info_create()
3827 rt->fib6_metric = cfg->fc_metric; in ip6_route_info_create()
3828 rt->fib6_type = cfg->fc_type ? : RTN_UNICAST; in ip6_route_info_create()
3829 rt->fib6_flags = cfg->fc_flags & ~RTF_GATEWAY; in ip6_route_info_create()
3831 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); in ip6_route_info_create()
3832 rt->fib6_dst.plen = cfg->fc_dst_len; in ip6_route_info_create()
3835 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len); in ip6_route_info_create()
3836 rt->fib6_src.plen = cfg->fc_src_len; in ip6_route_info_create()
3839 if (rt->fib6_src.plen) { in ip6_route_info_create()
3841 err = -EINVAL; in ip6_route_info_create()
3846 err = -ENOENT; in ip6_route_info_create()
3849 rt->nh = nh; in ip6_route_info_create()
3850 fib6_nh = nexthop_fib6_nh(rt->nh); in ip6_route_info_create()
3852 err = fib6_nh_init(net, rt->fib6_nh, cfg, gfp_flags, extack); in ip6_route_info_create()
3856 fib6_nh = rt->fib6_nh; in ip6_route_info_create()
3861 addr_type = ipv6_addr_type(&cfg->fc_dst); in ip6_route_info_create()
3862 if (fib6_is_reject(cfg->fc_flags, rt->fib6_nh->fib_nh_dev, in ip6_route_info_create()
3864 rt->fib6_flags = RTF_REJECT | RTF_NONEXTHOP; in ip6_route_info_create()
3867 if (!ipv6_addr_any(&cfg->fc_prefsrc)) { in ip6_route_info_create()
3868 struct net_device *dev = fib6_nh->fib_nh_dev; in ip6_route_info_create()
3870 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { in ip6_route_info_create()
3872 err = -EINVAL; in ip6_route_info_create()
3875 rt->fib6_prefsrc.addr = cfg->fc_prefsrc; in ip6_route_info_create()
3876 rt->fib6_prefsrc.plen = 128; in ip6_route_info_create()
3878 rt->fib6_prefsrc.plen = 0; in ip6_route_info_create()
3885 ip_fib_metrics_put(rt->fib6_metrics); in ip6_route_info_create()
3900 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); in ip6_route_add()
3908 struct net *net = info->nl_net; in __ip6_del_rt()
3912 if (rt == net->ipv6.fib6_null_entry) { in __ip6_del_rt()
3913 err = -ENOENT; in __ip6_del_rt()
3917 table = rt->fib6_table; in __ip6_del_rt()
3918 spin_lock_bh(&table->tb6_lock); in __ip6_del_rt()
3920 spin_unlock_bh(&table->tb6_lock); in __ip6_del_rt()
3939 struct nl_info *info = &cfg->fc_nlinfo; in __ip6_del_rt_siblings()
3940 struct net *net = info->nl_net; in __ip6_del_rt_siblings()
3943 int err = -ENOENT; in __ip6_del_rt_siblings()
3945 if (rt == net->ipv6.fib6_null_entry) in __ip6_del_rt_siblings()
3947 table = rt->fib6_table; in __ip6_del_rt_siblings()
3948 spin_lock_bh(&table->tb6_lock); in __ip6_del_rt_siblings()
3950 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) { in __ip6_del_rt_siblings()
3957 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; in __ip6_del_rt_siblings()
3961 info->portid, seq, 0) < 0) { in __ip6_del_rt_siblings()
3965 info->skip_notify = 1; in __ip6_del_rt_siblings()
3968 /* 'rt' points to the first sibling route. If it is not the in __ip6_del_rt_siblings()
3970 * we need to check if the last sibling has a next route or not in __ip6_del_rt_siblings()
3973 info->skip_notify_kernel = 1; in __ip6_del_rt_siblings()
3974 fn = rcu_dereference_protected(rt->fib6_node, in __ip6_del_rt_siblings()
3975 lockdep_is_held(&table->tb6_lock)); in __ip6_del_rt_siblings()
3976 if (rcu_access_pointer(fn->leaf) == rt) { in __ip6_del_rt_siblings()
3979 last_sibling = list_last_entry(&rt->fib6_siblings, in __ip6_del_rt_siblings()
3983 last_sibling->fib6_next, in __ip6_del_rt_siblings()
3984 lockdep_is_held(&table->tb6_lock)); in __ip6_del_rt_siblings()
3991 rt, rt->fib6_nsiblings, in __ip6_del_rt_siblings()
3995 &rt->fib6_siblings, in __ip6_del_rt_siblings()
4005 spin_unlock_bh(&table->tb6_lock); in __ip6_del_rt_siblings()
4010 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, in __ip6_del_rt_siblings()
4011 info->nlh, gfp_any()); in __ip6_del_rt_siblings()
4018 int rc = -ESRCH; in __ip6_del_cached_rt()
4020 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex) in __ip6_del_cached_rt()
4023 if (cfg->fc_flags & RTF_GATEWAY && in __ip6_del_cached_rt()
4024 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) in __ip6_del_cached_rt()
4041 rt_cache = rt6_find_cached_rt(&res, &cfg->fc_dst, &cfg->fc_src); in ip6_del_cached_rt()
4058 rc = ip6_del_cached_rt(arg->cfg, arg->f6i, nh); in fib6_nh_del_cached_rt()
4059 return rc != -ESRCH ? rc : 0; in fib6_nh_del_cached_rt()
4069 return nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_del_cached_rt, &arg); in ip6_del_cached_rt_nh()
4078 int err = -ESRCH; in ip6_route_del()
4080 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table); in ip6_route_del()
4088 fn = fib6_locate(&table->tb6_root, in ip6_route_del()
4089 &cfg->fc_dst, cfg->fc_dst_len, in ip6_route_del()
4090 &cfg->fc_src, cfg->fc_src_len, in ip6_route_del()
4091 !(cfg->fc_flags & RTF_CACHE)); in ip6_route_del()
4097 if (rt->nh && cfg->fc_nh_id && in ip6_route_del()
4098 rt->nh->id != cfg->fc_nh_id) in ip6_route_del()
4101 if (cfg->fc_flags & RTF_CACHE) { in ip6_route_del()
4104 if (rt->nh) { in ip6_route_del()
4106 } else if (cfg->fc_nh_id) { in ip6_route_del()
4109 nh = rt->fib6_nh; in ip6_route_del()
4112 if (rc != -ESRCH) { in ip6_route_del()
4119 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric) in ip6_route_del()
4121 if (cfg->fc_protocol && in ip6_route_del()
4122 cfg->fc_protocol != rt->fib6_protocol) in ip6_route_del()
4125 if (rt->nh) { in ip6_route_del()
4130 return __ip6_del_rt(rt, &cfg->fc_nlinfo); in ip6_route_del()
4132 if (cfg->fc_nh_id) in ip6_route_del()
4135 nh = rt->fib6_nh; in ip6_route_del()
4136 if (cfg->fc_ifindex && in ip6_route_del()
4137 (!nh->fib_nh_dev || in ip6_route_del()
4138 nh->fib_nh_dev->ifindex != cfg->fc_ifindex)) in ip6_route_del()
4140 if (cfg->fc_flags & RTF_GATEWAY && in ip6_route_del()
4141 !ipv6_addr_equal(&cfg->fc_gateway, &nh->fib_nh_gw6)) in ip6_route_del()
4148 if (cfg->fc_flags & RTF_GATEWAY) in ip6_route_del()
4149 return __ip6_del_rt(rt, &cfg->fc_nlinfo); in ip6_route_del()
4171 optlen = skb_tail_pointer(skb) - skb_transport_header(skb); in rt6_do_redirect()
4172 optlen -= sizeof(*msg); in rt6_do_redirect()
4181 if (ipv6_addr_is_multicast(&msg->dest)) { in rt6_do_redirect()
4187 if (ipv6_addr_equal(&msg->dest, &msg->target)) { in rt6_do_redirect()
4189 } else if (ipv6_addr_type(&msg->target) != in rt6_do_redirect()
4191 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); in rt6_do_redirect()
4195 in6_dev = __in6_dev_get(skb->dev); in rt6_do_redirect()
4198 if (READ_ONCE(in6_dev->cnf.forwarding) || in rt6_do_redirect()
4199 !READ_ONCE(in6_dev->cnf.accept_redirects)) in rt6_do_redirect()
4204 * first-hop router for the specified ICMP Destination Address. in rt6_do_redirect()
4207 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) { in rt6_do_redirect()
4215 skb->dev); in rt6_do_redirect()
4217 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n"); in rt6_do_redirect()
4223 if (rt->rt6i_flags & RTF_REJECT) { in rt6_do_redirect()
4228 /* Redirect received -> path was valid. in rt6_do_redirect()
4230 * so that this nexthop apparently is reachable. --ANK in rt6_do_redirect()
4232 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr); in rt6_do_redirect()
4234 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1); in rt6_do_redirect()
4242 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, in rt6_do_redirect()
4250 res.f6i = rcu_dereference(rt->from); in rt6_do_redirect()
4254 if (res.f6i->nh) { in rt6_do_redirect()
4256 .dev = dst->dev, in rt6_do_redirect()
4257 .gw = &rt->rt6i_gateway, in rt6_do_redirect()
4260 nexthop_for_each_fib6_nh(res.f6i->nh, in rt6_do_redirect()
4264 * using the dst->dev. Should be impossible in rt6_do_redirect()
4270 res.nh = res.f6i->fib6_nh; in rt6_do_redirect()
4273 res.fib6_flags = res.f6i->fib6_flags; in rt6_do_redirect()
4274 res.fib6_type = res.f6i->fib6_type; in rt6_do_redirect()
4275 nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL); in rt6_do_redirect()
4279 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE; in rt6_do_redirect()
4281 nrt->rt6i_flags &= ~RTF_GATEWAY; in rt6_do_redirect()
4283 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; in rt6_do_redirect()
4287 dst_release_immediate(&nrt->dst); in rt6_do_redirect()
4291 netevent.old = &rt->dst; in rt6_do_redirect()
4292 netevent.new = &nrt->dst; in rt6_do_redirect()
4293 netevent.daddr = &msg->dest; in rt6_do_redirect()
4309 int ifindex = dev->ifindex; in rt6_get_route_info()
4319 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true); in rt6_get_route_info()
4325 if (rt->nh) in rt6_get_route_info()
4327 if (rt->fib6_nh->fib_nh_dev->ifindex != ifindex) in rt6_get_route_info()
4329 if (!(rt->fib6_flags & RTF_ROUTEINFO) || in rt6_get_route_info()
4330 !rt->fib6_nh->fib_nh_gw_family) in rt6_get_route_info()
4332 if (!ipv6_addr_equal(&rt->fib6_nh->fib_nh_gw6, gwaddr)) in rt6_get_route_info()
4351 .fc_ifindex = dev->ifindex, in rt6_add_route_info()
4366 /* We should treat it as a default route if prefix length is 0. */ in rt6_add_route_info()
4389 for_each_fib6_node_rt_rcu(&table->tb6_root) { in rt6_get_dflt_router()
4393 if (rt->nh) in rt6_get_dflt_router()
4396 nh = rt->fib6_nh; in rt6_get_dflt_router()
4397 if (dev == nh->fib_nh_dev && in rt6_get_dflt_router()
4398 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && in rt6_get_dflt_router()
4399 ipv6_addr_equal(&nh->fib_nh_gw6, addr)) in rt6_get_dflt_router()
4418 .fc_ifindex = dev->ifindex, in rt6_add_dflt_router()
4436 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER; in rt6_add_dflt_router()
4449 for_each_fib6_node_rt_rcu(&table->tb6_root) { in __rt6_purge_dflt_routers()
4453 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) && in __rt6_purge_dflt_routers()
4454 (!idev || idev->cnf.accept_ra != 2) && in __rt6_purge_dflt_routers()
4463 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER; in __rt6_purge_dflt_routers()
4475 head = &net->ipv6.fib_table_hash[h]; in rt6_purge_dflt_routers()
4477 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER) in rt6_purge_dflt_routers()
4490 .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ? in rtmsg_to_fib6_config()
4492 .fc_ifindex = rtmsg->rtmsg_ifindex, in rtmsg_to_fib6_config()
4493 .fc_metric = rtmsg->rtmsg_metric, in rtmsg_to_fib6_config()
4494 .fc_expires = rtmsg->rtmsg_info, in rtmsg_to_fib6_config()
4495 .fc_dst_len = rtmsg->rtmsg_dst_len, in rtmsg_to_fib6_config()
4496 .fc_src_len = rtmsg->rtmsg_src_len, in rtmsg_to_fib6_config()
4497 .fc_flags = rtmsg->rtmsg_flags, in rtmsg_to_fib6_config()
4498 .fc_type = rtmsg->rtmsg_type, in rtmsg_to_fib6_config()
4502 .fc_dst = rtmsg->rtmsg_dst, in rtmsg_to_fib6_config()
4503 .fc_src = rtmsg->rtmsg_src, in rtmsg_to_fib6_config()
4504 .fc_gateway = rtmsg->rtmsg_gateway, in rtmsg_to_fib6_config()
4514 return -EINVAL; in ipv6_route_ioctl()
4515 if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) in ipv6_route_ioctl()
4516 return -EPERM; in ipv6_route_ioctl()
4523 /* Only do the default setting of fc_metric in route adding */ in ipv6_route_ioctl()
4543 struct net *net = dev_net(dst->dev); in ip6_pkt_drop()
4548 if (netif_is_l3_master(skb->dev) || in ip6_pkt_drop()
4549 dst->dev == net->loopback_dev) in ip6_pkt_drop()
4550 idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif)); in ip6_pkt_drop()
4556 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); in ip6_pkt_drop()
4571 if (netif_is_l3_master(skb->dev)) in ip6_pkt_drop()
4586 skb->dev = skb_dst(skb)->dev; in ip6_pkt_discard_out()
4597 skb->dev = skb_dst(skb)->dev; in ip6_pkt_prohibit_out()
4612 .fc_table = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL, in addrconf_f6i_alloc()
4613 .fc_ifindex = idev->dev->ifindex, in addrconf_f6i_alloc()
4633 f6i->dst_nocount = true; in addrconf_f6i_alloc()
4636 (READ_ONCE(net->ipv6.devconf_all->disable_policy) || in addrconf_f6i_alloc()
4637 READ_ONCE(idev->cnf.disable_policy))) in addrconf_f6i_alloc()
4638 f6i->dst_nopolicy = true; in addrconf_f6i_alloc()
4652 struct net *net = ((struct arg_dev_net_ip *)arg)->net; in fib6_remove_prefsrc()
4653 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; in fib6_remove_prefsrc()
4655 if (!rt->nh && in fib6_remove_prefsrc()
4656 rt != net->ipv6.fib6_null_entry && in fib6_remove_prefsrc()
4657 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr) && in fib6_remove_prefsrc()
4658 !ipv6_chk_addr(net, addr, rt->fib6_nh->fib_nh_dev, 0)) { in fib6_remove_prefsrc()
4661 rt->fib6_prefsrc.plen = 0; in fib6_remove_prefsrc()
4669 struct net *net = dev_net(ifp->idev->dev); in rt6_remove_prefsrc()
4672 .addr = &ifp->addr, in rt6_remove_prefsrc()
4686 if (rt->nh) in fib6_clean_tohost()
4689 nh = rt->fib6_nh; in fib6_clean_tohost()
4690 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) && in fib6_clean_tohost()
4691 nh->fib_nh_gw_family && ipv6_addr_equal(gateway, &nh->fib_nh_gw6)) in fib6_clean_tohost()
4692 return -1; in fib6_clean_tohost()
4695 * This is needed because cached route may have a different in fib6_clean_tohost()
4721 fn = rcu_dereference_protected(rt->fib6_node, in rt6_multipath_first_sibling()
4722 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
4723 iter = rcu_dereference_protected(fn->leaf, in rt6_multipath_first_sibling()
4724 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
4726 if (iter->fib6_metric == rt->fib6_metric && in rt6_multipath_first_sibling()
4729 iter = rcu_dereference_protected(iter->fib6_next, in rt6_multipath_first_sibling()
4730 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
4739 if (rt->fib6_nh->fib_nh_flags & RTNH_F_DEAD || in rt6_is_dead()
4740 (rt->fib6_nh->fib_nh_flags & RTNH_F_LINKDOWN && in rt6_is_dead()
4741 ip6_ignore_linkdown(rt->fib6_nh->fib_nh_dev))) in rt6_is_dead()
4753 total += rt->fib6_nh->fib_nh_weight; in rt6_multipath_total_weight()
4755 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) { in rt6_multipath_total_weight()
4757 total += iter->fib6_nh->fib_nh_weight; in rt6_multipath_total_weight()
4765 int upper_bound = -1; in rt6_upper_bound_set()
4768 *weight += rt->fib6_nh->fib_nh_weight; in rt6_upper_bound_set()
4770 total) - 1; in rt6_upper_bound_set()
4772 atomic_set(&rt->fib6_nh->fib_nh_upper_bound, upper_bound); in rt6_upper_bound_set()
4782 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_upper_bound_set()
4791 /* In case the entire multipath route was marked for flushing, in rt6_multipath_rebalance()
4793 * sibling route. in rt6_multipath_rebalance()
4795 if (!rt->fib6_nsiblings || rt->should_flush) in rt6_multipath_rebalance()
4813 struct net *net = dev_net(arg->dev); in fib6_ifup()
4815 if (rt != net->ipv6.fib6_null_entry && !rt->nh && in fib6_ifup()
4816 rt->fib6_nh->fib_nh_dev == arg->dev) { in fib6_ifup()
4817 rt->fib6_nh->fib_nh_flags &= ~arg->nh_flags; in fib6_ifup()
4846 if (rt->fib6_nh->fib_nh_dev == dev) in rt6_multipath_uses_dev()
4848 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_uses_dev()
4849 if (iter->fib6_nh->fib_nh_dev == dev) in rt6_multipath_uses_dev()
4859 rt->should_flush = 1; in rt6_multipath_flush()
4860 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_flush()
4861 iter->should_flush = 1; in rt6_multipath_flush()
4870 if (rt->fib6_nh->fib_nh_dev == down_dev || in rt6_multipath_dead_count()
4871 rt->fib6_nh->fib_nh_flags & RTNH_F_DEAD) in rt6_multipath_dead_count()
4873 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_dead_count()
4874 if (iter->fib6_nh->fib_nh_dev == down_dev || in rt6_multipath_dead_count()
4875 iter->fib6_nh->fib_nh_flags & RTNH_F_DEAD) in rt6_multipath_dead_count()
4887 if (rt->fib6_nh->fib_nh_dev == dev) in rt6_multipath_nh_flags_set()
4888 rt->fib6_nh->fib_nh_flags |= nh_flags; in rt6_multipath_nh_flags_set()
4889 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_nh_flags_set()
4890 if (iter->fib6_nh->fib_nh_dev == dev) in rt6_multipath_nh_flags_set()
4891 iter->fib6_nh->fib_nh_flags |= nh_flags; in rt6_multipath_nh_flags_set()
4898 const struct net_device *dev = arg->dev; in fib6_ifdown()
4901 if (rt == net->ipv6.fib6_null_entry || rt->nh) in fib6_ifdown()
4904 switch (arg->event) { in fib6_ifdown()
4906 return rt->fib6_nh->fib_nh_dev == dev ? -1 : 0; in fib6_ifdown()
4908 if (rt->should_flush) in fib6_ifdown()
4909 return -1; in fib6_ifdown()
4910 if (!rt->fib6_nsiblings) in fib6_ifdown()
4911 return rt->fib6_nh->fib_nh_dev == dev ? -1 : 0; in fib6_ifdown()
4916 if (rt->fib6_nsiblings + 1 == count) { in fib6_ifdown()
4918 return -1; in fib6_ifdown()
4925 return -2; in fib6_ifdown()
4927 if (rt->fib6_nh->fib_nh_dev != dev || in fib6_ifdown()
4928 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) in fib6_ifdown()
4930 rt->fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib6_ifdown()
4948 if (net->ipv6.sysctl.skip_notify_on_dev_down) in rt6_sync_down_dev()
4970 struct fib6_info *f6i = arg->f6i; in fib6_nh_mtu_change()
4977 if (nh->fib_nh_dev == arg->dev) { in fib6_nh_mtu_change()
4978 struct inet6_dev *idev = __in6_dev_get(arg->dev); in fib6_nh_mtu_change()
4979 u32 mtu = f6i->fib6_pmtu; in fib6_nh_mtu_change()
4981 if (mtu >= arg->mtu || in fib6_nh_mtu_change()
4982 (mtu < arg->mtu && mtu == idev->cnf.mtu6)) in fib6_nh_mtu_change()
4983 fib6_metric_set(f6i, RTAX_MTU, arg->mtu); in fib6_nh_mtu_change()
4986 rt6_exceptions_update_pmtu(idev, nh, arg->mtu); in fib6_nh_mtu_change()
5004 idev = __in6_dev_get(arg->dev); in rt6_mtu_change_route()
5011 arg->f6i = f6i; in rt6_mtu_change_route()
5012 if (f6i->nh) { in rt6_mtu_change_route()
5014 return nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_mtu_change, in rt6_mtu_change_route()
5018 return fib6_nh_mtu_change(f6i->fib6_nh, arg); in rt6_mtu_change_route()
5068 err = -EINVAL; in rtm_to_fib6_config()
5071 if (rtm->rtm_tos) { in rtm_to_fib6_config()
5084 .fc_table = rtm->rtm_table, in rtm_to_fib6_config()
5085 .fc_dst_len = rtm->rtm_dst_len, in rtm_to_fib6_config()
5086 .fc_src_len = rtm->rtm_src_len, in rtm_to_fib6_config()
5088 .fc_protocol = rtm->rtm_protocol, in rtm_to_fib6_config()
5089 .fc_type = rtm->rtm_type, in rtm_to_fib6_config()
5093 .fc_nlinfo.nl_net = sock_net(skb->sk), in rtm_to_fib6_config()
5096 if (rtm->rtm_type == RTN_UNREACHABLE || in rtm_to_fib6_config()
5097 rtm->rtm_type == RTN_BLACKHOLE || in rtm_to_fib6_config()
5098 rtm->rtm_type == RTN_PROHIBIT || in rtm_to_fib6_config()
5099 rtm->rtm_type == RTN_THROW) in rtm_to_fib6_config()
5100 cfg->fc_flags |= RTF_REJECT; in rtm_to_fib6_config()
5102 if (rtm->rtm_type == RTN_LOCAL) in rtm_to_fib6_config()
5103 cfg->fc_flags |= RTF_LOCAL; in rtm_to_fib6_config()
5105 if (rtm->rtm_flags & RTM_F_CLONED) in rtm_to_fib6_config()
5106 cfg->fc_flags |= RTF_CACHE; in rtm_to_fib6_config()
5108 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK); in rtm_to_fib6_config()
5117 cfg->fc_nh_id = nla_get_u32(tb[RTA_NH_ID]); in rtm_to_fib6_config()
5121 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]); in rtm_to_fib6_config()
5122 cfg->fc_flags |= RTF_GATEWAY; in rtm_to_fib6_config()
5130 int plen = (rtm->rtm_dst_len + 7) >> 3; in rtm_to_fib6_config()
5135 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen); in rtm_to_fib6_config()
5139 int plen = (rtm->rtm_src_len + 7) >> 3; in rtm_to_fib6_config()
5144 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); in rtm_to_fib6_config()
5148 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]); in rtm_to_fib6_config()
5151 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); in rtm_to_fib6_config()
5154 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]); in rtm_to_fib6_config()
5157 cfg->fc_mx = nla_data(tb[RTA_METRICS]); in rtm_to_fib6_config()
5158 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]); in rtm_to_fib6_config()
5162 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); in rtm_to_fib6_config()
5165 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); in rtm_to_fib6_config()
5166 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); in rtm_to_fib6_config()
5168 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp, in rtm_to_fib6_config()
5169 cfg->fc_mp_len, extack); in rtm_to_fib6_config()
5179 cfg->fc_flags |= RTF_PREF(pref); in rtm_to_fib6_config()
5183 cfg->fc_encap = tb[RTA_ENCAP]; in rtm_to_fib6_config()
5186 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); in rtm_to_fib6_config()
5188 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack); in rtm_to_fib6_config()
5197 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ); in rtm_to_fib6_config()
5198 cfg->fc_flags |= RTF_EXPIRES; in rtm_to_fib6_config()
5219 int err = -EEXIST; in ip6_route_info_append()
5223 if (rt6_duplicate_nexthop(nh->fib6_info, rt)) in ip6_route_info_append()
5229 return -ENOMEM; in ip6_route_info_append()
5230 nh->fib6_info = rt; in ip6_route_info_append()
5231 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg)); in ip6_route_info_append()
5232 list_add_tail(&nh->next, rt6_nh_list); in ip6_route_info_append()
5242 /* if this is an APPEND route, then rt points to the first route in ip6_route_mpath_notify()
5243 * inserted and rt_last points to last route inserted. Userspace in ip6_route_mpath_notify()
5244 * wants a consistent dump of the route which starts at the first in ip6_route_mpath_notify()
5246 * the list, find the first sibling of the last route appended in ip6_route_mpath_notify()
5250 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) { in ip6_route_mpath_notify()
5251 rt = list_first_or_null_rcu(&rt_last->fib6_siblings, in ip6_route_mpath_notify()
5270 fn = rcu_dereference(rt->fib6_node); in ip6_route_mpath_should_notify()
5274 leaf = rcu_dereference(fn->leaf); in ip6_route_mpath_should_notify()
5279 (rt_can_ecmp && rt->fib6_metric == leaf->fib6_metric && in ip6_route_mpath_should_notify()
5293 return -EINVAL; in fib6_gw_from_attr()
5305 struct nl_info *info = &cfg->fc_nlinfo; in ip6_route_multipath_add()
5316 int replace = (cfg->fc_nlinfo.nlh && in ip6_route_multipath_add()
5317 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE)); in ip6_route_multipath_add()
5321 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND) in ip6_route_multipath_add()
5324 remaining = cfg->fc_mp_len; in ip6_route_multipath_add()
5325 rtnh = (struct rtnexthop *)cfg->fc_mp; in ip6_route_multipath_add()
5332 if (rtnh->rtnh_ifindex) in ip6_route_multipath_add()
5333 r_cfg.fc_ifindex = rtnh->rtnh_ifindex; in ip6_route_multipath_add()
5358 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK); in ip6_route_multipath_add()
5366 err = -EINVAL; in ip6_route_multipath_add()
5373 rt->fib6_nh->fib_nh_weight = rtnh->rtnh_hops + 1; in ip6_route_multipath_add()
5375 err = ip6_route_info_append(info->nl_net, &rt6_nh_list, in ip6_route_multipath_add()
5387 "Invalid nexthop configuration - no valid nexthops"); in ip6_route_multipath_add()
5388 return -EINVAL; in ip6_route_multipath_add()
5393 * the full route when done in ip6_route_multipath_add()
5395 info->skip_notify = 1; in ip6_route_multipath_add()
5400 info->skip_notify_kernel = 1; in ip6_route_multipath_add()
5404 err = __ip6_ins_rt(nh->fib6_info, info, extack); in ip6_route_multipath_add()
5409 "multipath route replace failed (check consistency of installed routes)"); in ip6_route_multipath_add()
5413 /* save reference to last route successfully inserted */ in ip6_route_multipath_add()
5414 rt_last = nh->fib6_info; in ip6_route_multipath_add()
5416 /* save reference to first route for notification */ in ip6_route_multipath_add()
5418 rt_notif = nh->fib6_info; in ip6_route_multipath_add()
5420 /* Because each route is added like a single route we remove in ip6_route_multipath_add()
5427 if (cfg->fc_nlinfo.nlh) { in ip6_route_multipath_add()
5428 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL | in ip6_route_multipath_add()
5430 cfg->fc_nlinfo.nlh->nlmsg_flags |= NLM_F_CREATE; in ip6_route_multipath_add()
5435 /* An in-kernel notification should only be sent in case the new in ip6_route_multipath_add()
5436 * multipath route is added as the first route in the node, or if in ip6_route_multipath_add()
5443 if (rt_notif->fib6_nsiblings != nhn - 1) in ip6_route_multipath_add()
5448 err = call_fib6_multipath_entry_notifiers(info->nl_net, in ip6_route_multipath_add()
5450 nhn - 1, extack); in ip6_route_multipath_add()
5458 /* success ... tell user about new route */ in ip6_route_multipath_add()
5474 ip6_route_del(&nh->r_cfg, extack); in ip6_route_multipath_add()
5479 fib6_info_release(nh->fib6_info); in ip6_route_multipath_add()
5480 list_del(&nh->next); in ip6_route_multipath_add()
5497 remaining = cfg->fc_mp_len; in ip6_route_multipath_del()
5498 rtnh = (struct rtnexthop *)cfg->fc_mp; in ip6_route_multipath_del()
5503 if (rtnh->rtnh_ifindex) in ip6_route_multipath_del()
5504 r_cfg.fc_ifindex = rtnh->rtnh_ifindex; in ip6_route_multipath_del()
5544 !nexthop_find_by_id(sock_net(skb->sk), cfg.fc_nh_id)) { in inet6_rtm_delroute()
5546 return -EINVAL; in inet6_rtm_delroute()
5585 if (nh->fib_nh_lws) { in rt6_nh_nlmsg_size()
5587 *nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws); in rt6_nh_nlmsg_size()
5599 if (f6i->nh) { in rt6_nlmsg_size()
5601 nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_nlmsg_size, in rt6_nlmsg_size()
5604 struct fib6_nh *nh = f6i->fib6_nh; in rt6_nlmsg_size()
5608 if (f6i->fib6_nsiblings) { in rt6_nlmsg_size()
5613 list_for_each_entry_rcu(sibling, &f6i->fib6_siblings, in rt6_nlmsg_size()
5615 rt6_nh_nlmsg_size(sibling->fib6_nh, &nexthop_len); in rt6_nlmsg_size()
5620 nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws); in rt6_nlmsg_size()
5657 if (fib_nexthop_info(skb, &fib6_nh->nh_common, AF_INET6, in rt6_fill_node_nexthop()
5665 return -EMSGSIZE; in rt6_fill_node_nexthop()
5684 return -EMSGSIZE; in rt6_fill_node()
5687 rt6_dst = &rt6->rt6i_dst; in rt6_fill_node()
5688 rt6_src = &rt6->rt6i_src; in rt6_fill_node()
5689 rt6_flags = rt6->rt6i_flags; in rt6_fill_node()
5691 rt6_dst = &rt->fib6_dst; in rt6_fill_node()
5692 rt6_src = &rt->fib6_src; in rt6_fill_node()
5693 rt6_flags = rt->fib6_flags; in rt6_fill_node()
5697 rtm->rtm_family = AF_INET6; in rt6_fill_node()
5698 rtm->rtm_dst_len = rt6_dst->plen; in rt6_fill_node()
5699 rtm->rtm_src_len = rt6_src->plen; in rt6_fill_node()
5700 rtm->rtm_tos = 0; in rt6_fill_node()
5701 if (rt->fib6_table) in rt6_fill_node()
5702 table = rt->fib6_table->tb6_id; in rt6_fill_node()
5705 rtm->rtm_table = table < 256 ? table : RT_TABLE_COMPAT; in rt6_fill_node()
5709 rtm->rtm_type = rt->fib6_type; in rt6_fill_node()
5710 rtm->rtm_flags = 0; in rt6_fill_node()
5711 rtm->rtm_scope = RT_SCOPE_UNIVERSE; in rt6_fill_node()
5712 rtm->rtm_protocol = rt->fib6_protocol; in rt6_fill_node()
5715 rtm->rtm_flags |= RTM_F_CLONED; in rt6_fill_node()
5720 rtm->rtm_dst_len = 128; in rt6_fill_node()
5721 } else if (rtm->rtm_dst_len) in rt6_fill_node()
5722 if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr)) in rt6_fill_node()
5728 rtm->rtm_src_len = 128; in rt6_fill_node()
5729 } else if (rtm->rtm_src_len && in rt6_fill_node()
5730 nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr)) in rt6_fill_node()
5735 if (ipv6_addr_is_multicast(&rt6_dst->addr)) { in rt6_fill_node()
5753 if (rt->fib6_prefsrc.plen) { in rt6_fill_node()
5755 saddr_buf = rt->fib6_prefsrc.addr; in rt6_fill_node()
5760 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics; in rt6_fill_node()
5764 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric)) in rt6_fill_node()
5772 nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway)) in rt6_fill_node()
5775 if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex)) in rt6_fill_node()
5778 if (dst->lwtstate && in rt6_fill_node()
5779 lwtunnel_fill_encap(skb, dst->lwtstate, RTA_ENCAP, RTA_ENCAP_TYPE) < 0) in rt6_fill_node()
5781 } else if (rt->fib6_nsiblings) { in rt6_fill_node()
5789 if (fib_add_nexthop(skb, &rt->fib6_nh->nh_common, in rt6_fill_node()
5790 rt->fib6_nh->fib_nh_weight, AF_INET6, in rt6_fill_node()
5796 list_for_each_entry_rcu(sibling, &rt->fib6_siblings, in rt6_fill_node()
5798 if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common, in rt6_fill_node()
5799 sibling->fib6_nh->fib_nh_weight, in rt6_fill_node()
5810 } else if (rt->nh) { in rt6_fill_node()
5811 if (nla_put_u32(skb, RTA_NH_ID, rt->nh->id)) in rt6_fill_node()
5814 if (nexthop_is_blackhole(rt->nh)) in rt6_fill_node()
5815 rtm->rtm_type = RTN_BLACKHOLE; in rt6_fill_node()
5817 if (READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode) && in rt6_fill_node()
5818 rt6_fill_node_nexthop(skb, rt->nh, &nh_flags) < 0) in rt6_fill_node()
5821 rtm->rtm_flags |= nh_flags; in rt6_fill_node()
5823 if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common, AF_INET6, in rt6_fill_node()
5827 rtm->rtm_flags |= nh_flags; in rt6_fill_node()
5831 expires = dst ? dst->expires : rt->expires; in rt6_fill_node()
5832 expires -= jiffies; in rt6_fill_node()
5836 if (READ_ONCE(rt->offload)) in rt6_fill_node()
5837 rtm->rtm_flags |= RTM_F_OFFLOAD; in rt6_fill_node()
5838 if (READ_ONCE(rt->trap)) in rt6_fill_node()
5839 rtm->rtm_flags |= RTM_F_TRAP; in rt6_fill_node()
5840 if (READ_ONCE(rt->offload_failed)) in rt6_fill_node()
5841 rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED; in rt6_fill_node()
5844 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0) in rt6_fill_node()
5856 return -EMSGSIZE; in rt6_fill_node()
5863 if (nh->fib_nh_dev == dev) in fib6_info_nh_uses_dev()
5872 if (f6i->nh) { in fib6_info_uses_dev()
5875 return !!nexthop_for_each_fib6_nh(f6i->nh, in fib6_info_uses_dev()
5880 if (f6i->fib6_nh->fib_nh_dev == dev) in fib6_info_uses_dev()
5883 if (f6i->fib6_nsiblings) { in fib6_info_uses_dev()
5887 &f6i->fib6_siblings, fib6_siblings) { in fib6_info_uses_dev()
5888 if (sibling->fib6_nh->fib_nh_dev == dev) in fib6_info_uses_dev()
5907 struct rt6_rtnl_dump_arg *dump = w->dump; in rt6_nh_dump_exceptions()
5917 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) { in rt6_nh_dump_exceptions()
5918 if (w->skip) { in rt6_nh_dump_exceptions()
5919 w->skip--; in rt6_nh_dump_exceptions()
5934 if (rt6_check_expired(rt6_ex->rt6i)) { in rt6_nh_dump_exceptions()
5935 w->count++; in rt6_nh_dump_exceptions()
5939 err = rt6_fill_node(dump->net, dump->skb, w->rt, in rt6_nh_dump_exceptions()
5940 &rt6_ex->rt6i->dst, NULL, NULL, 0, in rt6_nh_dump_exceptions()
5942 NETLINK_CB(dump->cb->skb).portid, in rt6_nh_dump_exceptions()
5943 dump->cb->nlh->nlmsg_seq, w->flags); in rt6_nh_dump_exceptions()
5947 w->count++; in rt6_nh_dump_exceptions()
5955 /* Return -1 if done with node, number of handled routes on partial dump */
5959 struct fib_dump_filter *filter = &arg->filter; in rt6_dump_route()
5961 struct net *net = arg->net; in rt6_dump_route()
5964 if (rt == net->ipv6.fib6_null_entry) in rt6_dump_route()
5965 return -1; in rt6_dump_route()
5967 if ((filter->flags & RTM_F_PREFIX) && in rt6_dump_route()
5968 !(rt->fib6_flags & RTF_PREFIX_RT)) { in rt6_dump_route()
5969 /* success since this is not a prefix route */ in rt6_dump_route()
5970 return -1; in rt6_dump_route()
5972 if (filter->filter_set && in rt6_dump_route()
5973 ((filter->rt_type && rt->fib6_type != filter->rt_type) || in rt6_dump_route()
5974 (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) || in rt6_dump_route()
5975 (filter->protocol && rt->fib6_protocol != filter->protocol))) { in rt6_dump_route()
5976 return -1; in rt6_dump_route()
5979 if (filter->filter_set || in rt6_dump_route()
5980 !filter->dump_routes || !filter->dump_exceptions) { in rt6_dump_route()
5984 if (filter->dump_routes) { in rt6_dump_route()
5986 skip--; in rt6_dump_route()
5988 if (rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, in rt6_dump_route()
5990 NETLINK_CB(arg->cb->skb).portid, in rt6_dump_route()
5991 arg->cb->nlh->nlmsg_seq, flags)) { in rt6_dump_route()
5998 if (filter->dump_exceptions) { in rt6_dump_route()
6007 if (rt->nh) { in rt6_dump_route()
6008 err = nexthop_for_each_fib6_nh(rt->nh, in rt6_dump_route()
6012 err = rt6_nh_dump_exceptions(rt->fib6_nh, &w); in rt6_dump_route()
6020 return -1; in rt6_dump_route()
6031 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { in inet6_rtm_valid_getroute_req()
6033 "Invalid header for get route request"); in inet6_rtm_valid_getroute_req()
6034 return -EINVAL; in inet6_rtm_valid_getroute_req()
6042 if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) || in inet6_rtm_valid_getroute_req()
6043 (rtm->rtm_dst_len && rtm->rtm_dst_len != 128) || in inet6_rtm_valid_getroute_req()
6044 rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope || in inet6_rtm_valid_getroute_req()
6045 rtm->rtm_type) { in inet6_rtm_valid_getroute_req()
6046 NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request"); in inet6_rtm_valid_getroute_req()
6047 return -EINVAL; in inet6_rtm_valid_getroute_req()
6049 if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) { in inet6_rtm_valid_getroute_req()
6051 "Invalid flags for get route request"); in inet6_rtm_valid_getroute_req()
6052 return -EINVAL; in inet6_rtm_valid_getroute_req()
6060 if ((tb[RTA_SRC] && !rtm->rtm_src_len) || in inet6_rtm_valid_getroute_req()
6061 (tb[RTA_DST] && !rtm->rtm_dst_len)) { in inet6_rtm_valid_getroute_req()
6063 return -EINVAL; in inet6_rtm_valid_getroute_req()
6070 return -EINVAL; in inet6_rtm_valid_getroute_req()
6090 NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request"); in inet6_rtm_valid_getroute_req()
6091 return -EINVAL; in inet6_rtm_valid_getroute_req()
6101 struct net *net = sock_net(in_skb->sk); in inet6_rtm_getroute()
6117 err = -EINVAL; in inet6_rtm_getroute()
6119 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH); in inet6_rtm_getroute()
6165 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, flowlabel); in inet6_rtm_getroute()
6176 err = -ENODEV; in inet6_rtm_getroute()
6196 if (rt->dst.error) { in inet6_rtm_getroute()
6197 err = rt->dst.error; in inet6_rtm_getroute()
6202 if (rt == net->ipv6.ip6_null_entry) { in inet6_rtm_getroute()
6203 err = rt->dst.error; in inet6_rtm_getroute()
6211 err = -ENOBUFS; in inet6_rtm_getroute()
6215 skb_dst_set(skb, &rt->dst); in inet6_rtm_getroute()
6218 from = rcu_dereference(rt->from); in inet6_rtm_getroute()
6224 nlh->nlmsg_seq, 0); in inet6_rtm_getroute()
6229 nlh->nlmsg_seq, 0); in inet6_rtm_getroute()
6231 err = -ENETUNREACH; in inet6_rtm_getroute()
6249 struct net *net = info->nl_net; in inet6_rt_notify()
6253 err = -ENOBUFS; in inet6_rt_notify()
6254 seq = info->nlh ? info->nlh->nlmsg_seq : 0; in inet6_rt_notify()
6261 event, info->portid, seq, nlm_flags); in inet6_rt_notify()
6263 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ in inet6_rt_notify()
6264 WARN_ON(err == -EMSGSIZE); in inet6_rt_notify()
6268 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, in inet6_rt_notify()
6269 info->nlh, GFP_ATOMIC); in inet6_rt_notify()
6278 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; in fib6_rt_update()
6280 int err = -ENOBUFS; in fib6_rt_update()
6287 RTM_NEWROUTE, info->portid, seq, NLM_F_REPLACE); in fib6_rt_update()
6289 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ in fib6_rt_update()
6290 WARN_ON(err == -EMSGSIZE); in fib6_rt_update()
6294 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, in fib6_rt_update()
6295 info->nlh, gfp_any()); in fib6_rt_update()
6307 if (READ_ONCE(f6i->offload) == offload && in fib6_info_hw_flags_set()
6308 READ_ONCE(f6i->trap) == trap && in fib6_info_hw_flags_set()
6309 READ_ONCE(f6i->offload_failed) == offload_failed) in fib6_info_hw_flags_set()
6312 WRITE_ONCE(f6i->offload, offload); in fib6_info_hw_flags_set()
6313 WRITE_ONCE(f6i->trap, trap); in fib6_info_hw_flags_set()
6316 if (net->ipv6.sysctl.fib_notify_on_flag_change == 2 && in fib6_info_hw_flags_set()
6317 READ_ONCE(f6i->offload_failed) == offload_failed) in fib6_info_hw_flags_set()
6320 WRITE_ONCE(f6i->offload_failed, offload_failed); in fib6_info_hw_flags_set()
6322 if (!rcu_access_pointer(f6i->fib6_node)) in fib6_info_hw_flags_set()
6323 /* The route was removed from the tree, do not send in fib6_info_hw_flags_set()
6328 if (!net->ipv6.sysctl.fib_notify_on_flag_change) in fib6_info_hw_flags_set()
6333 err = -ENOBUFS; in fib6_info_hw_flags_set()
6340 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ in fib6_info_hw_flags_set()
6341 WARN_ON(err == -EMSGSIZE); in fib6_info_hw_flags_set()
6360 if (!(dev->flags & IFF_LOOPBACK)) in ip6_route_dev_notify()
6364 net->ipv6.fib6_null_entry->fib6_nh->fib_nh_dev = dev; in ip6_route_dev_notify()
6365 net->ipv6.ip6_null_entry->dst.dev = dev; in ip6_route_dev_notify()
6366 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); in ip6_route_dev_notify()
6368 net->ipv6.ip6_prohibit_entry->dst.dev = dev; in ip6_route_dev_notify()
6369 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); in ip6_route_dev_notify()
6370 net->ipv6.ip6_blk_hole_entry->dst.dev = dev; in ip6_route_dev_notify()
6371 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); in ip6_route_dev_notify()
6374 dev->reg_state != NETREG_UNREGISTERED) { in ip6_route_dev_notify()
6378 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); in ip6_route_dev_notify()
6380 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); in ip6_route_dev_notify()
6381 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); in ip6_route_dev_notify()
6395 struct net *net = (struct net *)seq->private; in rt6_stats_seq_show()
6397 net->ipv6.rt6_stats->fib_nodes, in rt6_stats_seq_show()
6398 net->ipv6.rt6_stats->fib_route_nodes, in rt6_stats_seq_show()
6399 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc), in rt6_stats_seq_show()
6400 net->ipv6.rt6_stats->fib_rt_entries, in rt6_stats_seq_show()
6401 net->ipv6.rt6_stats->fib_rt_cache, in rt6_stats_seq_show()
6402 dst_entries_get_slow(&net->ipv6.ip6_dst_ops), in rt6_stats_seq_show()
6403 net->ipv6.rt6_stats->fib_discarded_routes); in rt6_stats_seq_show()
6418 return -EINVAL; in ipv6_sysctl_rtcache_flush()
6424 net = (struct net *)ctl->extra1; in ipv6_sysctl_rtcache_flush()
6425 delay = net->ipv6.sysctl.flush_delay; in ipv6_sysctl_rtcache_flush()
6521 table[0].data = &net->ipv6.sysctl.ip6_rt_max_size; in ipv6_route_sysctl_init()
6522 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; in ipv6_route_sysctl_init()
6523 table[2].data = &net->ipv6.sysctl.flush_delay; in ipv6_route_sysctl_init()
6525 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; in ipv6_route_sysctl_init()
6526 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; in ipv6_route_sysctl_init()
6527 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval; in ipv6_route_sysctl_init()
6528 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity; in ipv6_route_sysctl_init()
6529 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; in ipv6_route_sysctl_init()
6530 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; in ipv6_route_sysctl_init()
6531 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; in ipv6_route_sysctl_init()
6532 table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down; in ipv6_route_sysctl_init()
6541 if (net->user_ns != &init_user_ns) in ipv6_route_sysctl_table_size()
6550 int ret = -ENOMEM; in ip6_route_net_init()
6552 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, in ip6_route_net_init()
6553 sizeof(net->ipv6.ip6_dst_ops)); in ip6_route_net_init()
6555 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) in ip6_route_net_init()
6558 net->ipv6.fib6_null_entry = fib6_info_alloc(GFP_KERNEL, true); in ip6_route_net_init()
6559 if (!net->ipv6.fib6_null_entry) in ip6_route_net_init()
6561 memcpy(net->ipv6.fib6_null_entry, &fib6_null_entry_template, in ip6_route_net_init()
6562 sizeof(*net->ipv6.fib6_null_entry)); in ip6_route_net_init()
6564 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, in ip6_route_net_init()
6565 sizeof(*net->ipv6.ip6_null_entry), in ip6_route_net_init()
6567 if (!net->ipv6.ip6_null_entry) in ip6_route_net_init()
6569 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; in ip6_route_net_init()
6570 dst_init_metrics(&net->ipv6.ip6_null_entry->dst, in ip6_route_net_init()
6572 INIT_LIST_HEAD(&net->ipv6.ip6_null_entry->dst.rt_uncached); in ip6_route_net_init()
6575 net->ipv6.fib6_has_custom_rules = false; in ip6_route_net_init()
6576 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, in ip6_route_net_init()
6577 sizeof(*net->ipv6.ip6_prohibit_entry), in ip6_route_net_init()
6579 if (!net->ipv6.ip6_prohibit_entry) in ip6_route_net_init()
6581 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; in ip6_route_net_init()
6582 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst, in ip6_route_net_init()
6584 INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached); in ip6_route_net_init()
6586 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, in ip6_route_net_init()
6587 sizeof(*net->ipv6.ip6_blk_hole_entry), in ip6_route_net_init()
6589 if (!net->ipv6.ip6_blk_hole_entry) in ip6_route_net_init()
6591 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; in ip6_route_net_init()
6592 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, in ip6_route_net_init()
6594 INIT_LIST_HEAD(&net->ipv6.ip6_blk_hole_entry->dst.rt_uncached); in ip6_route_net_init()
6596 net->ipv6.fib6_routes_require_src = 0; in ip6_route_net_init()
6600 net->ipv6.sysctl.flush_delay = 0; in ip6_route_net_init()
6601 net->ipv6.sysctl.ip6_rt_max_size = INT_MAX; in ip6_route_net_init()
6602 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; in ip6_route_net_init()
6603 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ; in ip6_route_net_init()
6604 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ; in ip6_route_net_init()
6605 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9; in ip6_route_net_init()
6606 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; in ip6_route_net_init()
6607 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; in ip6_route_net_init()
6608 net->ipv6.sysctl.skip_notify_on_dev_down = 0; in ip6_route_net_init()
6610 atomic_set(&net->ipv6.ip6_rt_gc_expire, 30*HZ); in ip6_route_net_init()
6618 kfree(net->ipv6.ip6_prohibit_entry); in ip6_route_net_init()
6620 kfree(net->ipv6.ip6_null_entry); in ip6_route_net_init()
6623 kfree(net->ipv6.fib6_null_entry); in ip6_route_net_init()
6625 dst_entries_destroy(&net->ipv6.ip6_dst_ops); in ip6_route_net_init()
6632 kfree(net->ipv6.fib6_null_entry); in ip6_route_net_exit()
6633 kfree(net->ipv6.ip6_null_entry); in ip6_route_net_exit()
6635 kfree(net->ipv6.ip6_prohibit_entry); in ip6_route_net_exit()
6636 kfree(net->ipv6.ip6_blk_hole_entry); in ip6_route_net_exit()
6638 dst_entries_destroy(&net->ipv6.ip6_dst_ops); in ip6_route_net_exit()
6644 if (!proc_create_net("ipv6_route", 0, net->proc_net, in ip6_route_net_init_late()
6647 return -ENOMEM; in ip6_route_net_init_late()
6649 if (!proc_create_net_single("rt6_stats", 0444, net->proc_net, in ip6_route_net_init_late()
6651 remove_proc_entry("ipv6_route", net->proc_net); in ip6_route_net_init_late()
6652 return -ENOMEM; in ip6_route_net_init_late()
6661 remove_proc_entry("ipv6_route", net->proc_net); in ip6_route_net_exit_late()
6662 remove_proc_entry("rt6_stats", net->proc_net); in ip6_route_net_exit_late()
6676 return -ENOMEM; in ipv6_inetpeer_init()
6678 net->ipv6.peers = bp; in ipv6_inetpeer_init()
6684 struct inet_peer_base *bp = net->ipv6.peers; in ipv6_inetpeer_exit()
6686 net->ipv6.peers = NULL; in ipv6_inetpeer_exit()
6703 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
6711 init_net.ipv6.fib6_null_entry->fib6_nh->fib_nh_dev = init_net.loopback_dev; in ip6_route_init_special_entries()
6712 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; in ip6_route_init_special_entries()
6713 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); in ip6_route_init_special_entries()
6715 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; in ip6_route_init_special_entries()
6716 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); in ip6_route_init_special_entries()
6717 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; in ip6_route_init_special_entries()
6718 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); in ip6_route_init_special_entries()
6773 ret = -ENOMEM; in ip6_route_init()
6829 INIT_LIST_HEAD(&ul->head); in ip6_route_init()
6830 spin_lock_init(&ul->lock); in ip6_route_init()