Lines Matching full:rt
111 struct fib6_info *rt, struct dst_entry *dst,
138 void rt6_uncached_list_add(struct rt6_info *rt) in rt6_uncached_list_add() argument
142 rt->dst.rt_uncached_list = ul; in rt6_uncached_list_add()
145 list_add_tail(&rt->dst.rt_uncached, &ul->head); in rt6_uncached_list_add()
149 void rt6_uncached_list_del(struct rt6_info *rt) in rt6_uncached_list_del() argument
151 struct uncached_list *ul = rt->dst.rt_uncached_list; in rt6_uncached_list_del()
155 list_del_init(&rt->dst.rt_uncached); in rt6_uncached_list_del()
166 struct rt6_info *rt, *safe; in rt6_uncached_list_flush_dev() local
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()
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()
228 const struct rt6_info *rt = dst_rt6_info(dst); in ip6_dst_neigh_lookup() local
230 return ip6_neigh_lookup(rt6_nexthop(rt, &in6addr_any), in ip6_dst_neigh_lookup()
236 const struct rt6_info *rt = dst_rt6_info(dst); in ip6_confirm_neigh() local
239 daddr = choose_neigh_daddr(rt6_nexthop(rt, &in6addr_any), NULL, daddr); in ip6_confirm_neigh()
333 static void rt6_info_init(struct rt6_info *rt) in rt6_info_init() argument
335 memset_after(rt, 0, dst); in rt6_info_init()
342 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, in ip6_dst_alloc() local
345 if (rt) { in ip6_dst_alloc()
346 rt6_info_init(rt); in ip6_dst_alloc()
350 return rt; in ip6_dst_alloc()
356 struct rt6_info *rt = dst_rt6_info(dst); in ip6_dst_destroy() local
361 rt6_uncached_list_del(rt); in ip6_dst_destroy()
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()
375 struct rt6_info *rt = dst_rt6_info(dst); in ip6_dst_ifdown() local
376 struct inet6_dev *idev = rt->rt6i_idev; 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()
391 static bool __rt6_check_expired(const struct rt6_info *rt) in __rt6_check_expired() argument
393 if (rt->rt6i_flags & RTF_EXPIRES) in __rt6_check_expired()
394 return time_after(jiffies, READ_ONCE(rt->dst.expires)); in __rt6_check_expired()
398 static bool rt6_check_expired(const struct rt6_info *rt) in rt6_check_expired() argument
402 from = rcu_dereference(rt->from); in rt6_check_expired()
404 if (rt->rt6i_flags & RTF_EXPIRES) { in rt6_check_expired()
405 if (time_after(jiffies, READ_ONCE(rt->dst.expires))) in rt6_check_expired()
408 return READ_ONCE(rt->dst.obsolete) != DST_OBSOLETE_FORCE_CHK || in rt6_check_expired()
415 rt6_multipath_first_sibling_rcu(const struct fib6_info *rt) in rt6_multipath_first_sibling_rcu() argument
420 fn = rcu_dereference(rt->fib6_node); in rt6_multipath_first_sibling_rcu()
428 if (iter->fib6_metric == rt->fib6_metric && in rt6_multipath_first_sibling_rcu()
978 struct fib6_info *rt; in rt6_route_rcv() local
1016 rt = rt6_get_dflt_router(net, gwaddr, dev); in rt6_route_rcv()
1018 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, in rt6_route_rcv()
1021 if (rt && !lifetime) { in rt6_route_rcv()
1022 ip6_del_rt(net, rt, false); in rt6_route_rcv()
1023 rt = NULL; in rt6_route_rcv()
1026 if (!rt && lifetime) in rt6_route_rcv()
1027 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, in rt6_route_rcv()
1029 else if (rt) in rt6_route_rcv()
1030 rt->fib6_flags = RTF_ROUTEINFO | in rt6_route_rcv()
1031 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); in rt6_route_rcv()
1033 if (rt) { in rt6_route_rcv()
1034 table = rt->fib6_table; in rt6_route_rcv()
1038 fib6_clean_expires(rt); in rt6_route_rcv()
1039 fib6_may_remove_gc_list(net, rt); in rt6_route_rcv()
1041 fib6_set_expires(rt, jiffies + HZ * lifetime); in rt6_route_rcv()
1042 fib6_add_gc_list(rt); in rt6_route_rcv()
1047 fib6_info_release(rt); in rt6_route_rcv()
1101 static unsigned short fib6_info_dst_flags(struct fib6_info *rt) in fib6_info_dst_flags() argument
1105 if (rt->dst_nocount) in fib6_info_dst_flags()
1107 if (rt->dst_nopolicy) in fib6_info_dst_flags()
1113 static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type) in ip6_rt_init_dst_reject() argument
1115 rt->dst.error = ip6_rt_type_to_error(fib6_type); in ip6_rt_init_dst_reject()
1119 rt->dst.output = dst_discard_out; in ip6_rt_init_dst_reject()
1120 rt->dst.input = dst_discard; in ip6_rt_init_dst_reject()
1123 rt->dst.output = ip6_pkt_prohibit_out; in ip6_rt_init_dst_reject()
1124 rt->dst.input = ip6_pkt_prohibit; in ip6_rt_init_dst_reject()
1129 rt->dst.output = ip6_pkt_discard_out; in ip6_rt_init_dst_reject()
1130 rt->dst.input = ip6_pkt_discard; in ip6_rt_init_dst_reject()
1135 static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res) in ip6_rt_init_dst() argument
1140 ip6_rt_init_dst_reject(rt, res->fib6_type); in ip6_rt_init_dst()
1144 rt->dst.error = 0; in ip6_rt_init_dst()
1145 rt->dst.output = ip6_output; in ip6_rt_init_dst()
1148 rt->dst.input = ip6_input; in ip6_rt_init_dst()
1150 rt->dst.input = ip6_mc_input; in ip6_rt_init_dst()
1151 rt->dst.output = ip6_mr_output; in ip6_rt_init_dst()
1153 rt->dst.input = ip6_forward; in ip6_rt_init_dst()
1157 rt->dst.lwtstate = lwtstate_get(res->nh->fib_nh_lws); in ip6_rt_init_dst()
1158 lwtunnel_set_redirect(&rt->dst); in ip6_rt_init_dst()
1161 rt->dst.lastuse = jiffies; in ip6_rt_init_dst()
1165 static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from) in rt6_set_from() argument
1167 rt->rt6i_flags &= ~RTF_EXPIRES; in rt6_set_from()
1168 rcu_assign_pointer(rt->from, from); in rt6_set_from()
1169 ip_dst_init_metrics(&rt->dst, from->fib6_metrics); in rt6_set_from()
1173 static void ip6_rt_copy_init(struct rt6_info *rt, const struct fib6_result *res) in ip6_rt_copy_init() argument
1179 ip6_rt_init_dst(rt, res); in ip6_rt_copy_init()
1181 rt->rt6i_dst = f6i->fib6_dst; in ip6_rt_copy_init()
1182 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; in ip6_rt_copy_init()
1183 rt->rt6i_flags = res->fib6_flags; in ip6_rt_copy_init()
1185 rt->rt6i_gateway = nh->fib_nh_gw6; in ip6_rt_copy_init()
1186 rt->rt6i_flags |= RTF_GATEWAY; in ip6_rt_copy_init()
1188 rt6_set_from(rt, f6i); in ip6_rt_copy_init()
1190 rt->rt6i_src = f6i->fib6_src; in ip6_rt_copy_init()
1214 struct rt6_info *rt = *prt; in ip6_hold_safe() local
1216 if (dst_hold_safe(&rt->dst)) in ip6_hold_safe()
1219 rt = net->ipv6.ip6_null_entry; in ip6_hold_safe()
1220 dst_hold(&rt->dst); in ip6_hold_safe()
1222 rt = NULL; in ip6_hold_safe()
1224 *prt = rt; in ip6_hold_safe()
1263 struct rt6_info *rt; in ip6_pol_route_lookup() local
1280 rt = net->ipv6.ip6_null_entry; in ip6_pol_route_lookup()
1281 dst_hold(&rt->dst); in ip6_pol_route_lookup()
1291 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr); in ip6_pol_route_lookup()
1292 if (rt) { in ip6_pol_route_lookup()
1293 if (ip6_hold_safe(net, &rt)) in ip6_pol_route_lookup()
1294 dst_use_noref(&rt->dst, jiffies); in ip6_pol_route_lookup()
1297 rt = ip6_create_rt_rcu(&res); in ip6_pol_route_lookup()
1305 return rt; in ip6_pol_route_lookup()
1347 static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info, in __ip6_ins_rt() argument
1353 table = rt->fib6_table; in __ip6_ins_rt()
1355 err = fib6_add(&table->tb6_root, rt, info, extack); in __ip6_ins_rt()
1361 int ip6_ins_rt(struct net *net, struct fib6_info *rt) in ip6_ins_rt() argument
1365 return __ip6_ins_rt(rt, &info, NULL); in ip6_ins_rt()
1374 struct rt6_info *rt; in ip6_rt_cache_alloc() local
1384 rt = ip6_dst_alloc(dev_net(dev), dev, 0); in ip6_rt_cache_alloc()
1385 if (!rt) { in ip6_rt_cache_alloc()
1390 ip6_rt_copy_init(rt, res); in ip6_rt_cache_alloc()
1391 rt->rt6i_flags |= RTF_CACHE; in ip6_rt_cache_alloc()
1392 rt->rt6i_dst.addr = *daddr; in ip6_rt_cache_alloc()
1393 rt->rt6i_dst.plen = 128; in ip6_rt_cache_alloc()
1398 rt->rt6i_flags |= RTF_ANYCAST; in ip6_rt_cache_alloc()
1400 if (rt->rt6i_src.plen && saddr) { in ip6_rt_cache_alloc()
1401 rt->rt6i_src.addr = *saddr; in ip6_rt_cache_alloc()
1402 rt->rt6i_src.plen = 128; in ip6_rt_cache_alloc()
1407 return rt; in ip6_rt_cache_alloc()
1570 /* Helper function to find the cached rt in the hash table
1603 /* Helper function to find the cached rt in the hash table
1851 /* Find cached rt in the hash table inside passed in rt
1873 * rt->rt6i_src is updated.) in rt6_find_cached_rt()
1896 /* Remove the passed in cached rt from the hash table that contains it */
1898 const struct rt6_info *rt) in fib6_nh_remove_exception() argument
1919 src_key = &rt->rt6i_src.addr; in fib6_nh_remove_exception()
1922 &rt->rt6i_dst.addr, in fib6_nh_remove_exception()
1936 struct rt6_info *rt; member
1945 err = fib6_nh_remove_exception(nh, arg->plen, arg->rt); in rt6_nh_remove_exception_rt()
1952 static int rt6_remove_exception_rt(struct rt6_info *rt) in rt6_remove_exception_rt() argument
1956 from = rcu_dereference(rt->from); in rt6_remove_exception_rt()
1957 if (!from || !(rt->rt6i_flags & RTF_CACHE)) in rt6_remove_exception_rt()
1962 .rt = rt, in rt6_remove_exception_rt()
1975 from->fib6_src.plen, rt); in rt6_remove_exception_rt()
1978 /* Find rt6_ex which contains the passed in rt cache and
1982 const struct rt6_info *rt) in fib6_nh_update_exception() argument
1997 src_key = &rt->rt6i_src.addr; in fib6_nh_update_exception()
1999 rt6_ex = __rt6_find_exception_rcu(&bucket, &rt->rt6i_dst.addr, src_key); in fib6_nh_update_exception()
2027 static void rt6_update_exception_stamp_rt(struct rt6_info *rt) in rt6_update_exception_stamp_rt() argument
2034 from = rcu_dereference(rt->from); in rt6_update_exception_stamp_rt()
2035 if (!from || !(rt->rt6i_flags & RTF_CACHE)) in rt6_update_exception_stamp_rt()
2040 .dev = rt->dst.dev, in rt6_update_exception_stamp_rt()
2041 .gw = &rt->rt6i_gateway, in rt6_update_exception_stamp_rt()
2052 fib6_nh_update_exception(fib6_nh, from->fib6_src.plen, rt); in rt6_update_exception_stamp_rt()
2058 struct rt6_info *rt, int mtu) in rt6_mtu_change_route_allowed() argument
2060 u32 dmtu = dst6_mtu(&rt->dst); in rt6_mtu_change_route_allowed()
2097 * route), the metrics of its rt->from have already in rt6_exceptions_update_pmtu()
2148 struct rt6_info *rt = rt6_ex->rt6i; in rt6_age_examine_exception() local
2156 if (!(rt->rt6i_flags & RTF_EXPIRES)) { in rt6_age_examine_exception()
2157 if (time_after_eq(now, READ_ONCE(rt->dst.lastuse) + in rt6_age_examine_exception()
2159 pr_debug("aging clone %p\n", rt); in rt6_age_examine_exception()
2163 } else if (time_after(jiffies, READ_ONCE(rt->dst.expires))) { in rt6_age_examine_exception()
2164 pr_debug("purging expired route %p\n", rt); in rt6_age_examine_exception()
2169 if (rt->rt6i_flags & RTF_GATEWAY) { in rt6_age_examine_exception()
2172 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); in rt6_age_examine_exception()
2176 rt); in rt6_age_examine_exception()
2277 struct rt6_info *rt = NULL; in ip6_pol_route() local
2297 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr); in ip6_pol_route()
2298 if (rt) { in ip6_pol_route()
2307 rt = ip6_rt_cache_alloc(&res, &fl6->daddr, NULL); in ip6_pol_route()
2309 if (rt) { in ip6_pol_route()
2315 rt6_uncached_list_add(rt); in ip6_pol_route()
2318 return rt; in ip6_pol_route()
2323 rt = rt6_get_pcpu_route(&res); in ip6_pol_route()
2325 if (!rt) in ip6_pol_route()
2326 rt = rt6_make_pcpu_route(net, &res); in ip6_pol_route()
2331 if (!rt) in ip6_pol_route()
2332 rt = net->ipv6.ip6_null_entry; in ip6_pol_route()
2334 ip6_hold_safe(net, &rt); in ip6_pol_route()
2337 return rt; in ip6_pol_route()
2733 struct rt6_info *rt, *ort = dst_rt6_info(dst_orig); in ip6_blackhole_route() local
2737 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, in ip6_blackhole_route()
2739 if (rt) { in ip6_blackhole_route()
2740 rt6_info_init(rt); in ip6_blackhole_route()
2743 new = &rt->dst; in ip6_blackhole_route()
2750 rt->rt6i_idev = in6_dev_get(loopback_dev); in ip6_blackhole_route()
2751 rt->rt6i_gateway = ort->rt6i_gateway; in ip6_blackhole_route()
2752 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU; in ip6_blackhole_route()
2754 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); in ip6_blackhole_route()
2756 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); in ip6_blackhole_route()
2781 static struct dst_entry *rt6_check(struct rt6_info *rt, in rt6_check() argument
2791 if (rt6_check_expired(rt)) in rt6_check()
2794 return &rt->dst; in rt6_check()
2797 static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, in rt6_dst_from_check() argument
2801 if (!__rt6_check_expired(rt) && in rt6_dst_from_check()
2802 READ_ONCE(rt->dst.obsolete) == DST_OBSOLETE_FORCE_CHK && in rt6_dst_from_check()
2804 return &rt->dst; in rt6_dst_from_check()
2813 struct rt6_info *rt; in ip6_dst_check() local
2815 rt = dst_rt6_info(dst); in ip6_dst_check()
2817 if (rt->sernum) in ip6_dst_check()
2818 return rt6_is_valid(rt) ? dst : NULL; in ip6_dst_check()
2827 from = rcu_dereference(rt->from); in ip6_dst_check()
2829 if (from && (rt->rt6i_flags & RTF_PCPU || in ip6_dst_check()
2830 unlikely(!list_empty(&rt->dst.rt_uncached)))) in ip6_dst_check()
2831 dst_ret = rt6_dst_from_check(rt, from, cookie); in ip6_dst_check()
2833 dst_ret = rt6_check(rt, from, cookie); in ip6_dst_check()
2844 struct rt6_info *rt = dst_rt6_info(dst); in ip6_negative_advice() local
2846 if (rt->rt6i_flags & RTF_CACHE) { in ip6_negative_advice()
2848 if (rt6_check_expired(rt)) { in ip6_negative_advice()
2849 /* rt/dst can not be destroyed yet, in ip6_negative_advice()
2853 rt6_remove_exception_rt(rt); in ip6_negative_advice()
2863 struct rt6_info *rt; in ip6_link_failure() local
2867 rt = dst_rt6_info(skb_dst(skb)); in ip6_link_failure()
2868 if (rt) { in ip6_link_failure()
2870 if (rt->rt6i_flags & RTF_CACHE) { in ip6_link_failure()
2871 rt6_remove_exception_rt(rt); in ip6_link_failure()
2876 from = rcu_dereference(rt->from); in ip6_link_failure()
2879 if (fn && (rt->rt6i_flags & RTF_DEFAULT)) in ip6_link_failure()
2903 static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu) in rt6_do_update_pmtu() argument
2905 struct net *net = dev_net(rt->dst.dev); in rt6_do_update_pmtu()
2907 dst_metric_set(&rt->dst, RTAX_MTU, mtu); in rt6_do_update_pmtu()
2908 rt->rt6i_flags |= RTF_MODIFIED; in rt6_do_update_pmtu()
2909 rt6_update_expires(rt, READ_ONCE(net->ipv6.sysctl.ip6_rt_mtu_expires)); in rt6_do_update_pmtu()
2912 static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) in rt6_cache_allowed_for_pmtu() argument
2914 return !(rt->rt6i_flags & RTF_CACHE) && in rt6_cache_allowed_for_pmtu()
2915 (rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from)); in rt6_cache_allowed_for_pmtu()
3131 struct fib6_info *rt; in __ip6_route_redirect() local
3148 res.f6i = rt; in __ip6_route_redirect()
3149 if (fib6_check_expired(rt)) in __ip6_route_redirect()
3151 if (rt->fib6_flags & RTF_REJECT) in __ip6_route_redirect()
3153 if (unlikely(rt->nh)) { in __ip6_route_redirect()
3154 if (nexthop_is_blackhole(rt->nh)) in __ip6_route_redirect()
3157 if (nexthop_for_each_fib6_nh(rt->nh, in __ip6_route_redirect()
3162 res.nh = rt->fib6_nh; in __ip6_route_redirect()
3169 if (!rt) in __ip6_route_redirect()
3170 rt = net->ipv6.fib6_null_entry; in __ip6_route_redirect()
3171 else if (rt->fib6_flags & RTF_REJECT) { in __ip6_route_redirect()
3176 if (rt == net->ipv6.fib6_null_entry) { in __ip6_route_redirect()
3182 res.f6i = rt; in __ip6_route_redirect()
3183 res.nh = rt->fib6_nh; in __ip6_route_redirect()
3307 struct rt6_info *rt; in ip6_mtu_from_fib6() local
3316 rt = rt6_find_cached_rt(res, daddr, saddr); in ip6_mtu_from_fib6()
3317 if (unlikely(rt)) { in ip6_mtu_from_fib6()
3318 mtu = dst_metric_raw(&rt->dst, RTAX_MTU); in ip6_mtu_from_fib6()
3337 struct rt6_info *rt; in icmp6_dst_alloc() local
3344 rt = ip6_dst_alloc(net, dev, 0); in icmp6_dst_alloc()
3345 if (unlikely(!rt)) { in icmp6_dst_alloc()
3351 rt->dst.input = ip6_input; in icmp6_dst_alloc()
3352 rt->dst.output = ip6_output; in icmp6_dst_alloc()
3353 rt->rt6i_gateway = fl6->daddr; in icmp6_dst_alloc()
3354 rt->rt6i_dst.addr = fl6->daddr; in icmp6_dst_alloc()
3355 rt->rt6i_dst.plen = 128; in icmp6_dst_alloc()
3356 rt->rt6i_idev = idev; in icmp6_dst_alloc()
3357 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0); in icmp6_dst_alloc()
3362 rt6_uncached_list_add(rt); in icmp6_dst_alloc()
3364 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); in icmp6_dst_alloc()
3813 struct fib6_info *rt; in ip6_route_info_create() local
3831 rt = fib6_info_alloc(gfp_flags, !cfg->fc_nh_id); in ip6_route_info_create()
3832 if (!rt) { in ip6_route_info_create()
3837 rt->fib6_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len, in ip6_route_info_create()
3839 if (IS_ERR(rt->fib6_metrics)) { in ip6_route_info_create()
3840 err = PTR_ERR(rt->fib6_metrics); in ip6_route_info_create()
3845 rt->dst_nocount = true; in ip6_route_info_create()
3848 fib6_set_expires(rt, jiffies + in ip6_route_info_create()
3854 rt->fib6_protocol = cfg->fc_protocol; in ip6_route_info_create()
3855 rt->fib6_table = table; in ip6_route_info_create()
3856 rt->fib6_metric = cfg->fc_metric; in ip6_route_info_create()
3857 rt->fib6_type = cfg->fc_type ? : RTN_UNICAST; in ip6_route_info_create()
3858 rt->fib6_flags = cfg->fc_flags & ~RTF_GATEWAY; in ip6_route_info_create()
3860 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); in ip6_route_info_create()
3861 rt->fib6_dst.plen = cfg->fc_dst_len; in ip6_route_info_create()
3864 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len); in ip6_route_info_create()
3865 rt->fib6_src.plen = cfg->fc_src_len; in ip6_route_info_create()
3867 return rt; in ip6_route_info_create()
3869 kfree(rt); in ip6_route_info_create()
3874 static int ip6_route_info_create_nh(struct fib6_info *rt, in ip6_route_info_create_nh() argument
3905 rt->nh = nh; in ip6_route_info_create_nh()
3906 fib6_nh = nexthop_fib6_nh(rt->nh); in ip6_route_info_create_nh()
3912 err = fib6_nh_init(net, rt->fib6_nh, cfg, gfp_flags, extack); in ip6_route_info_create_nh()
3916 fib6_nh = rt->fib6_nh; in ip6_route_info_create_nh()
3922 if (fib6_is_reject(cfg->fc_flags, rt->fib6_nh->fib_nh_dev, in ip6_route_info_create_nh()
3924 rt->fib6_flags = RTF_REJECT | RTF_NONEXTHOP; in ip6_route_info_create_nh()
3935 rt->fib6_prefsrc.addr = cfg->fc_prefsrc; in ip6_route_info_create_nh()
3936 rt->fib6_prefsrc.plen = 128; in ip6_route_info_create_nh()
3941 fib6_info_release(rt); in ip6_route_info_create_nh()
3945 ip_fib_metrics_put(rt->fib6_metrics); in ip6_route_info_create_nh()
3946 kfree(rt); in ip6_route_info_create_nh()
3953 struct fib6_info *rt; in ip6_route_add() local
3960 rt = ip6_route_info_create(cfg, gfp_flags, extack); in ip6_route_add()
3961 if (IS_ERR(rt)) in ip6_route_add()
3962 return PTR_ERR(rt); in ip6_route_add()
3964 err = ip6_route_info_create_nh(rt, cfg, gfp_flags, extack); in ip6_route_add()
3968 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); in ip6_route_add()
3969 fib6_info_release(rt); in ip6_route_add()
3974 static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info) in __ip6_del_rt() argument
3980 if (rt == net->ipv6.fib6_null_entry) { in __ip6_del_rt()
3985 table = rt->fib6_table; in __ip6_del_rt()
3987 err = fib6_del(rt, info); in __ip6_del_rt()
3991 fib6_info_release(rt); in __ip6_del_rt()
3995 int ip6_del_rt(struct net *net, struct fib6_info *rt, bool skip_notify) in ip6_del_rt() argument
4002 return __ip6_del_rt(rt, &info); in ip6_del_rt()
4005 static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg) in __ip6_del_rt_siblings() argument
4013 if (rt == net->ipv6.fib6_null_entry) in __ip6_del_rt_siblings()
4015 table = rt->fib6_table; in __ip6_del_rt_siblings()
4018 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) { in __ip6_del_rt_siblings()
4023 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); in __ip6_del_rt_siblings()
4027 if (rt6_fill_node(net, skb, rt, NULL, in __ip6_del_rt_siblings()
4036 /* 'rt' points to the first sibling route. If it is not the in __ip6_del_rt_siblings()
4042 fn = rcu_dereference_protected(rt->fib6_node, in __ip6_del_rt_siblings()
4044 if (rcu_access_pointer(fn->leaf) == rt) { in __ip6_del_rt_siblings()
4047 last_sibling = list_last_entry(&rt->fib6_siblings, in __ip6_del_rt_siblings()
4059 rt, rt->fib6_nsiblings, in __ip6_del_rt_siblings()
4063 &rt->fib6_siblings, in __ip6_del_rt_siblings()
4071 err = fib6_del(rt, info); in __ip6_del_rt_siblings()
4075 fib6_info_release(rt); in __ip6_del_rt_siblings()
4084 static int __ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg) in __ip6_del_cached_rt() argument
4088 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex) in __ip6_del_cached_rt()
4092 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) in __ip6_del_cached_rt()
4095 rc = rt6_remove_exception_rt(rt); in __ip6_del_cached_rt()
4100 static int ip6_del_cached_rt(struct fib6_config *cfg, struct fib6_info *rt, in ip6_del_cached_rt() argument
4104 .f6i = rt, in ip6_del_cached_rt()
4144 struct fib6_info *rt; in ip6_route_del() local
4165 if (rt->nh && cfg->fc_nh_id && in ip6_route_del()
4166 rt->nh->id != cfg->fc_nh_id) in ip6_route_del()
4172 if (rt->nh) { in ip6_route_del()
4173 rc = ip6_del_cached_rt_nh(cfg, rt); in ip6_route_del()
4177 nh = rt->fib6_nh; in ip6_route_del()
4178 rc = ip6_del_cached_rt(cfg, rt, nh); in ip6_route_del()
4187 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric) in ip6_route_del()
4190 cfg->fc_protocol != rt->fib6_protocol) in ip6_route_del()
4193 if (rt->nh) { in ip6_route_del()
4194 if (!fib6_info_hold_safe(rt)) in ip6_route_del()
4197 err = __ip6_del_rt(rt, &cfg->fc_nlinfo); in ip6_route_del()
4203 nh = rt->fib6_nh; in ip6_route_del()
4211 if (!fib6_info_hold_safe(rt)) in ip6_route_del()
4216 err = __ip6_del_rt(rt, &cfg->fc_nlinfo); in ip6_route_del()
4218 err = __ip6_del_rt_siblings(rt, cfg); in ip6_route_del()
4230 struct rt6_info *rt, *nrt = NULL; in rt6_do_redirect() local
4290 rt = dst_rt6_info(dst); in rt6_do_redirect()
4291 if (rt->rt6i_flags & RTF_REJECT) { in rt6_do_redirect()
4300 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr); in rt6_do_redirect()
4318 res.f6i = rcu_dereference(rt->from); in rt6_do_redirect()
4325 .gw = &rt->rt6i_gateway, in rt6_do_redirect()
4359 netevent.old = &rt->dst; in rt6_do_redirect()
4379 struct fib6_info *rt = NULL; in rt6_get_route_info() local
4393 if (rt->nh) in rt6_get_route_info()
4395 if (rt->fib6_nh->fib_nh_dev->ifindex != ifindex) in rt6_get_route_info()
4397 if (!(rt->fib6_flags & RTF_ROUTEINFO) || in rt6_get_route_info()
4398 !rt->fib6_nh->fib_nh_gw_family) in rt6_get_route_info()
4400 if (!ipv6_addr_equal(&rt->fib6_nh->fib_nh_gw6, gwaddr)) in rt6_get_route_info()
4402 if (!fib6_info_hold_safe(rt)) in rt6_get_route_info()
4408 return rt; in rt6_get_route_info()
4449 struct fib6_info *rt; in rt6_get_dflt_router() local
4461 if (rt->nh) in rt6_get_dflt_router()
4464 nh = rt->fib6_nh; in rt6_get_dflt_router()
4466 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && in rt6_get_dflt_router()
4470 if (rt && !fib6_info_hold_safe(rt)) in rt6_get_dflt_router()
4471 rt = NULL; in rt6_get_dflt_router()
4473 return rt; in rt6_get_dflt_router()
4513 struct fib6_info *rt; in __rt6_purge_dflt_routers() local
4518 struct net_device *dev = fib6_info_nh_dev(rt); in __rt6_purge_dflt_routers()
4521 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) && in __rt6_purge_dflt_routers()
4523 fib6_info_hold_safe(rt)) { in __rt6_purge_dflt_routers()
4525 ip6_del_rt(net, rt, false); in __rt6_purge_dflt_routers()
4724 static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg) in fib6_remove_prefsrc() argument
4729 if (!rt->nh && in fib6_remove_prefsrc()
4730 rt != net->ipv6.fib6_null_entry && in fib6_remove_prefsrc()
4731 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr) && in fib6_remove_prefsrc()
4732 !ipv6_chk_addr(net, addr, rt->fib6_nh->fib_nh_dev, 0)) { in fib6_remove_prefsrc()
4735 rt->fib6_prefsrc.plen = 0; in fib6_remove_prefsrc()
4754 static int fib6_clean_tohost(struct fib6_info *rt, void *arg) in fib6_clean_tohost() argument
4760 if (rt->nh) in fib6_clean_tohost()
4763 nh = rt->fib6_nh; in fib6_clean_tohost()
4764 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) && in fib6_clean_tohost()
4790 static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt) in rt6_multipath_first_sibling() argument
4795 fn = rcu_dereference_protected(rt->fib6_node, in rt6_multipath_first_sibling()
4796 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
4798 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
4800 if (iter->fib6_metric == rt->fib6_metric && in rt6_multipath_first_sibling()
4804 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
4811 static bool rt6_is_dead(const struct fib6_info *rt) in rt6_is_dead() argument
4813 if (rt->fib6_nh->fib_nh_flags & RTNH_F_DEAD || in rt6_is_dead()
4814 (rt->fib6_nh->fib_nh_flags & RTNH_F_LINKDOWN && in rt6_is_dead()
4815 ip6_ignore_linkdown(rt->fib6_nh->fib_nh_dev))) in rt6_is_dead()
4821 static int rt6_multipath_total_weight(const struct fib6_info *rt) in rt6_multipath_total_weight() argument
4826 if (!rt6_is_dead(rt)) in rt6_multipath_total_weight()
4827 total += rt->fib6_nh->fib_nh_weight; in rt6_multipath_total_weight()
4829 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) { in rt6_multipath_total_weight()
4837 static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total) in rt6_upper_bound_set() argument
4841 if (!rt6_is_dead(rt)) { in rt6_upper_bound_set()
4842 *weight += rt->fib6_nh->fib_nh_weight; in rt6_upper_bound_set()
4846 atomic_set(&rt->fib6_nh->fib_nh_upper_bound, upper_bound); in rt6_upper_bound_set()
4849 static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total) in rt6_multipath_upper_bound_set() argument
4854 rt6_upper_bound_set(rt, &weight, total); in rt6_multipath_upper_bound_set()
4856 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_upper_bound_set()
4860 void rt6_multipath_rebalance(struct fib6_info *rt) in rt6_multipath_rebalance() argument
4869 if (!rt->fib6_nsiblings || rt->should_flush) in rt6_multipath_rebalance()
4876 first = rt6_multipath_first_sibling(rt); in rt6_multipath_rebalance()
4884 static int fib6_ifup(struct fib6_info *rt, void *p_arg) in fib6_ifup() argument
4889 if (rt != net->ipv6.fib6_null_entry && !rt->nh && in fib6_ifup()
4890 rt->fib6_nh->fib_nh_dev == arg->dev) { in fib6_ifup()
4891 rt->fib6_nh->fib_nh_flags &= ~arg->nh_flags; in fib6_ifup()
4892 fib6_update_sernum_upto_root(net, rt); in fib6_ifup()
4893 rt6_multipath_rebalance(rt); in fib6_ifup()
4915 static bool rt6_multipath_uses_dev(const struct fib6_info *rt, in rt6_multipath_uses_dev() argument
4920 if (rt->fib6_nh->fib_nh_dev == dev) in rt6_multipath_uses_dev()
4922 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_uses_dev()
4929 static void rt6_multipath_flush(struct fib6_info *rt) in rt6_multipath_flush() argument
4933 rt->should_flush = 1; in rt6_multipath_flush()
4934 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_flush()
4938 static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt, in rt6_multipath_dead_count() argument
4944 if (rt->fib6_nh->fib_nh_dev == down_dev || in rt6_multipath_dead_count()
4945 rt->fib6_nh->fib_nh_flags & RTNH_F_DEAD) in rt6_multipath_dead_count()
4947 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_dead_count()
4955 static void rt6_multipath_nh_flags_set(struct fib6_info *rt, in rt6_multipath_nh_flags_set() argument
4961 if (rt->fib6_nh->fib_nh_dev == dev) in rt6_multipath_nh_flags_set()
4962 rt->fib6_nh->fib_nh_flags |= nh_flags; in rt6_multipath_nh_flags_set()
4963 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_nh_flags_set()
4968 /* called with write lock held for table with rt */
4969 static int fib6_ifdown(struct fib6_info *rt, void *p_arg) in fib6_ifdown() argument
4975 if (rt == net->ipv6.fib6_null_entry || rt->nh) in fib6_ifdown()
4980 return rt->fib6_nh->fib_nh_dev == dev ? -1 : 0; in fib6_ifdown()
4982 if (rt->should_flush) in fib6_ifdown()
4984 if (!rt->fib6_nsiblings) in fib6_ifdown()
4985 return rt->fib6_nh->fib_nh_dev == dev ? -1 : 0; in fib6_ifdown()
4986 if (rt6_multipath_uses_dev(rt, dev)) { in fib6_ifdown()
4989 count = rt6_multipath_dead_count(rt, dev); in fib6_ifdown()
4990 if (rt->fib6_nsiblings + 1 == count) { in fib6_ifdown()
4991 rt6_multipath_flush(rt); in fib6_ifdown()
4994 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD | in fib6_ifdown()
4996 fib6_update_sernum(net, rt); in fib6_ifdown()
4997 rt6_multipath_rebalance(rt); in fib6_ifdown()
5001 if (rt->fib6_nh->fib_nh_dev != dev || in fib6_ifdown()
5002 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) in fib6_ifdown()
5004 rt->fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib6_ifdown()
5005 fib6_update_sernum(net, rt); in fib6_ifdown()
5006 rt6_multipath_rebalance(rt); in fib6_ifdown()
5336 struct fib6_info *rt, in ip6_route_info_append() argument
5343 if (rt6_duplicate_nexthop(nh->fib6_info, rt)) in ip6_route_info_append()
5351 nh->fib6_info = rt; in ip6_route_info_append()
5358 static void ip6_route_mpath_notify(struct fib6_info *rt, in ip6_route_mpath_notify() argument
5363 /* if this is an APPEND route, then rt points to the first route in ip6_route_mpath_notify()
5373 rt = list_first_or_null_rcu(&rt_last->fib6_siblings, in ip6_route_mpath_notify()
5378 if (rt) in ip6_route_mpath_notify()
5379 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags); in ip6_route_mpath_notify()
5384 static bool ip6_route_mpath_should_notify(const struct fib6_info *rt) in ip6_route_mpath_should_notify() argument
5386 bool rt_can_ecmp = rt6_qualify_for_ecmp(rt); in ip6_route_mpath_should_notify()
5392 fn = rcu_dereference(rt->fib6_node); in ip6_route_mpath_should_notify()
5400 if (rt == leaf || in ip6_route_mpath_should_notify()
5401 (rt_can_ecmp && rt->fib6_metric == leaf->fib6_metric && in ip6_route_mpath_should_notify()
5420 struct fib6_info *rt; in ip6_route_multipath_add() local
5467 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack); in ip6_route_multipath_add()
5468 if (IS_ERR(rt)) { in ip6_route_multipath_add()
5469 err = PTR_ERR(rt); in ip6_route_multipath_add()
5470 rt = NULL; in ip6_route_multipath_add()
5474 err = ip6_route_info_create_nh(rt, &r_cfg, GFP_KERNEL, extack); in ip6_route_multipath_add()
5476 rt = NULL; in ip6_route_multipath_add()
5480 rt->fib6_nh->fib_nh_weight = rtnh->rtnh_hops + 1; in ip6_route_multipath_add()
5482 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); in ip6_route_multipath_add()
5484 fib6_info_release(rt); in ip6_route_multipath_add()
5770 struct fib6_info *rt, struct dst_entry *dst, in rt6_fill_node() argument
5792 rt6_dst = &rt->fib6_dst; in rt6_fill_node()
5793 rt6_src = &rt->fib6_src; in rt6_fill_node()
5794 rt6_flags = rt->fib6_flags; in rt6_fill_node()
5802 if (rt->fib6_table) in rt6_fill_node()
5803 table = rt->fib6_table->tb6_id; in rt6_fill_node()
5810 rtm->rtm_type = rt->fib6_type; in rt6_fill_node()
5813 rtm->rtm_protocol = rt->fib6_protocol; in rt6_fill_node()
5849 if (ip6_route_get_saddr(net, rt, dest, 0, 0, &saddr_buf) == 0 && in rt6_fill_node()
5854 if (rt->fib6_prefsrc.plen) { in rt6_fill_node()
5856 saddr_buf = rt->fib6_prefsrc.addr; in rt6_fill_node()
5861 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics; in rt6_fill_node()
5865 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric)) in rt6_fill_node()
5884 } else if (READ_ONCE(rt->fib6_nsiblings)) { in rt6_fill_node()
5892 if (fib_add_nexthop(skb, &rt->fib6_nh->nh_common, in rt6_fill_node()
5893 rt->fib6_nh->fib_nh_weight, AF_INET6, in rt6_fill_node()
5899 list_for_each_entry_rcu(sibling, &rt->fib6_siblings, in rt6_fill_node()
5908 if (!READ_ONCE(rt->fib6_nsiblings)) in rt6_fill_node()
5915 } else if (rt->nh) { in rt6_fill_node()
5916 if (nla_put_u32(skb, RTA_NH_ID, rt->nh->id)) in rt6_fill_node()
5919 if (nexthop_is_blackhole(rt->nh)) in rt6_fill_node()
5923 rt6_fill_node_nexthop(skb, rt->nh, &nh_flags) < 0) in rt6_fill_node()
5928 if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common, AF_INET6, in rt6_fill_node()
5936 expires = dst ? READ_ONCE(dst->expires) : rt->expires; in rt6_fill_node()
5941 if (READ_ONCE(rt->offload)) in rt6_fill_node()
5943 if (READ_ONCE(rt->trap)) in rt6_fill_node()
5945 if (READ_ONCE(rt->offload_failed)) in rt6_fill_node()
6008 struct fib6_info *rt; member
6049 err = rt6_fill_node(dump->net, dump->skb, w->rt, in rt6_nh_dump_exceptions()
6066 int rt6_dump_route(struct fib6_info *rt, void *p_arg, unsigned int skip) in rt6_dump_route() argument
6074 if (rt == net->ipv6.fib6_null_entry) in rt6_dump_route()
6078 !(rt->fib6_flags & RTF_PREFIX_RT)) { in rt6_dump_route()
6083 ((filter->rt_type && rt->fib6_type != filter->rt_type) || in rt6_dump_route()
6084 (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) || in rt6_dump_route()
6085 (filter->protocol && rt->fib6_protocol != filter->protocol))) { in rt6_dump_route()
6098 if (rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, in rt6_dump_route()
6110 .rt = rt, in rt6_dump_route()
6117 if (rt->nh) { in rt6_dump_route()
6118 err = nexthop_for_each_fib6_nh(rt->nh, in rt6_dump_route()
6122 err = rt6_nh_dump_exceptions(rt->fib6_nh, &w); in rt6_dump_route()
6216 struct rt6_info *rt; in inet6_rtm_getroute() local
6305 rt = dst_rt6_info(dst); in inet6_rtm_getroute()
6306 if (rt->dst.error) { in inet6_rtm_getroute()
6307 err = rt->dst.error; in inet6_rtm_getroute()
6308 ip6_rt_put(rt); in inet6_rtm_getroute()
6312 if (rt == net->ipv6.ip6_null_entry) { in inet6_rtm_getroute()
6313 err = rt->dst.error; in inet6_rtm_getroute()
6314 ip6_rt_put(rt); in inet6_rtm_getroute()
6320 ip6_rt_put(rt); in inet6_rtm_getroute()
6325 skb_dst_set(skb, &rt->dst); in inet6_rtm_getroute()
6328 from = rcu_dereference(rt->from); in inet6_rtm_getroute()
6355 void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, in inet6_rt_notify() argument
6368 sz = rt6_nlmsg_size(rt); in inet6_rt_notify()
6374 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0, in inet6_rt_notify()
6380 sz = max(rt6_nlmsg_size(rt), sz << 1); in inet6_rt_notify()
6396 void fib6_rt_update(struct net *net, struct fib6_info *rt, in fib6_rt_update() argument
6403 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); in fib6_rt_update()
6407 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0, in fib6_rt_update()
6846 DEFINE_BPF_ITER_FUNC(ipv6_route, struct bpf_iter_meta *meta, struct fib6_info *rt)
6861 { offsetof(struct bpf_iter__ipv6_route, rt),