• Home
  • Raw
  • Download

Lines Matching full:rt

106 static int rt6_score_route(struct fib6_info *rt, int oif, int strict);
107 static size_t rt6_nlmsg_size(struct fib6_info *rt);
109 struct fib6_info *rt, struct dst_entry *dst,
113 static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
136 void rt6_uncached_list_add(struct rt6_info *rt) in rt6_uncached_list_add() argument
140 rt->rt6i_uncached_list = ul; in rt6_uncached_list_add()
143 list_add_tail(&rt->rt6i_uncached, &ul->head); in rt6_uncached_list_add()
147 void rt6_uncached_list_del(struct rt6_info *rt) in rt6_uncached_list_del() argument
149 if (!list_empty(&rt->rt6i_uncached)) { in rt6_uncached_list_del()
150 struct uncached_list *ul = rt->rt6i_uncached_list; in rt6_uncached_list_del()
151 struct net *net = dev_net(rt->dst.dev); in rt6_uncached_list_del()
154 list_del(&rt->rt6i_uncached); in rt6_uncached_list_del()
170 struct rt6_info *rt; in rt6_uncached_list_flush_dev() local
173 list_for_each_entry(rt, &ul->head, rt6i_uncached) { in rt6_uncached_list_flush_dev()
174 struct inet6_dev *rt_idev = rt->rt6i_idev; in rt6_uncached_list_flush_dev()
175 struct net_device *rt_dev = rt->dst.dev; in rt6_uncached_list_flush_dev()
178 rt->rt6i_idev = in6_dev_get(loopback_dev); in rt6_uncached_list_flush_dev()
183 rt->dst.dev = loopback_dev; in rt6_uncached_list_flush_dev()
184 dev_hold(rt->dst.dev); in rt6_uncached_list_flush_dev()
223 const struct rt6_info *rt = container_of(dst, struct rt6_info, dst); in ip6_dst_neigh_lookup() local
225 return ip6_neigh_lookup(&rt->rt6i_gateway, dst->dev, skb, daddr); in ip6_dst_neigh_lookup()
231 struct rt6_info *rt = (struct rt6_info *)dst; in ip6_confirm_neigh() local
233 daddr = choose_neigh_daddr(&rt->rt6i_gateway, NULL, daddr); in ip6_confirm_neigh()
345 static void rt6_info_init(struct rt6_info *rt) in rt6_info_init() argument
347 struct dst_entry *dst = &rt->dst; in rt6_info_init()
349 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); in rt6_info_init()
350 INIT_LIST_HEAD(&rt->rt6i_uncached); in rt6_info_init()
357 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, in ip6_dst_alloc() local
360 if (rt) { in ip6_dst_alloc()
361 rt6_info_init(rt); in ip6_dst_alloc()
365 return rt; in ip6_dst_alloc()
372 struct rt6_info *rt = (struct rt6_info *)dst; in ip6_dst_destroy() local
379 rt6_uncached_list_del(rt); in ip6_dst_destroy()
381 idev = rt->rt6i_idev; in ip6_dst_destroy()
383 rt->rt6i_idev = NULL; in ip6_dst_destroy()
387 from = xchg((__force struct fib6_info **)&rt->from, NULL); in ip6_dst_destroy()
394 struct rt6_info *rt = (struct rt6_info *)dst; in ip6_dst_ifdown() local
395 struct inet6_dev *idev = rt->rt6i_idev; in ip6_dst_ifdown()
402 rt->rt6i_idev = loopback_idev; in ip6_dst_ifdown()
408 static bool __rt6_check_expired(const struct rt6_info *rt) in __rt6_check_expired() argument
410 if (rt->rt6i_flags & RTF_EXPIRES) in __rt6_check_expired()
411 return time_after(jiffies, rt->dst.expires); in __rt6_check_expired()
416 static bool rt6_check_expired(const struct rt6_info *rt) in rt6_check_expired() argument
420 from = rcu_dereference(rt->from); in rt6_check_expired()
422 if (rt->rt6i_flags & RTF_EXPIRES) { in rt6_check_expired()
423 if (time_after(jiffies, rt->dst.expires)) in rt6_check_expired()
426 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK || in rt6_check_expired()
470 struct fib6_info *rt, in rt6_device_match()
478 !(rt->fib6_nh.nh_flags & RTNH_F_DEAD)) in rt6_device_match()
479 return rt; in rt6_device_match()
481 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->fib6_next)) { in rt6_device_match()
500 return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt; in rt6_device_match()
522 static void rt6_probe(struct fib6_info *rt) in rt6_probe() argument
539 if (!rt || !(rt->fib6_flags & RTF_GATEWAY)) in rt6_probe()
542 nh_gw = &rt->fib6_nh.nh_gw; in rt6_probe()
543 dev = rt->fib6_nh.nh_dev; in rt6_probe()
545 last_probe = READ_ONCE(rt->last_probe); in rt6_probe()
566 if (!work || cmpxchg(&rt->last_probe, in rt6_probe()
581 static inline void rt6_probe(struct fib6_info *rt) in rt6_probe() argument
589 static inline int rt6_check_dev(struct fib6_info *rt, int oif) in rt6_check_dev() argument
591 const struct net_device *dev = rt->fib6_nh.nh_dev; in rt6_check_dev()
598 static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt) in rt6_check_neigh() argument
603 if (rt->fib6_flags & RTF_NONEXTHOP || in rt6_check_neigh()
604 !(rt->fib6_flags & RTF_GATEWAY)) in rt6_check_neigh()
608 neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh.nh_dev, in rt6_check_neigh()
609 &rt->fib6_nh.nh_gw); in rt6_check_neigh()
630 static int rt6_score_route(struct fib6_info *rt, int oif, int strict) in rt6_score_route() argument
634 m = rt6_check_dev(rt, oif); in rt6_score_route()
638 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->fib6_flags)) << 2; in rt6_score_route()
641 int n = rt6_check_neigh(rt); in rt6_score_route()
663 static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict, in find_match() argument
670 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) in find_match()
673 if (fib6_ignore_linkdown(rt) && in find_match()
674 rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && in find_match()
678 if (fib6_check_expired(rt)) in find_match()
681 m = rt6_score_route(rt, oif, strict); in find_match()
690 rt6_probe(rt); in find_match()
696 match = rt; in find_match()
708 struct fib6_info *rt, *match, *cont; in find_rr_leaf() local
713 for (rt = rr_head; rt; rt = rcu_dereference(rt->fib6_next)) { in find_rr_leaf()
714 if (rt->fib6_metric != metric) { in find_rr_leaf()
715 cont = rt; in find_rr_leaf()
719 match = find_match(rt, oif, strict, &mpri, match, do_rr); in find_rr_leaf()
722 for (rt = leaf; rt && rt != rr_head; in find_rr_leaf()
723 rt = rcu_dereference(rt->fib6_next)) { in find_rr_leaf()
724 if (rt->fib6_metric != metric) { in find_rr_leaf()
725 cont = rt; in find_rr_leaf()
729 match = find_match(rt, oif, strict, &mpri, match, do_rr); in find_rr_leaf()
735 for (rt = cont; rt; rt = rcu_dereference(rt->fib6_next)) in find_rr_leaf()
736 match = find_match(rt, oif, strict, &mpri, match, do_rr); in find_rr_leaf()
791 static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt) in rt6_is_gw_or_nonexthop() argument
793 return (rt->fib6_flags & (RTF_NONEXTHOP | RTF_GATEWAY)); in rt6_is_gw_or_nonexthop()
805 struct fib6_info *rt; in rt6_route_rcv() local
843 rt = rt6_get_dflt_router(net, gwaddr, dev); in rt6_route_rcv()
845 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, in rt6_route_rcv()
848 if (rt && !lifetime) { in rt6_route_rcv()
849 ip6_del_rt(net, rt); in rt6_route_rcv()
850 rt = NULL; in rt6_route_rcv()
853 if (!rt && lifetime) in rt6_route_rcv()
854 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, in rt6_route_rcv()
856 else if (rt) in rt6_route_rcv()
857 rt->fib6_flags = RTF_ROUTEINFO | in rt6_route_rcv()
858 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); in rt6_route_rcv()
860 if (rt) { in rt6_route_rcv()
862 fib6_clean_expires(rt); in rt6_route_rcv()
864 fib6_set_expires(rt, jiffies + HZ * lifetime); in rt6_route_rcv()
866 fib6_info_release(rt); in rt6_route_rcv()
877 static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt) in ip6_rt_get_dev_rcu() argument
879 struct net_device *dev = rt->fib6_nh.nh_dev; in ip6_rt_get_dev_rcu()
881 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) { in ip6_rt_get_dev_rcu()
887 !rt6_need_strict(&rt->fib6_dst.addr)) in ip6_rt_get_dev_rcu()
919 static unsigned short fib6_info_dst_flags(struct fib6_info *rt) in fib6_info_dst_flags() argument
923 if (rt->dst_nocount) in fib6_info_dst_flags()
925 if (rt->dst_nopolicy) in fib6_info_dst_flags()
927 if (rt->dst_host) in fib6_info_dst_flags()
933 static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort) in ip6_rt_init_dst_reject() argument
935 rt->dst.error = ip6_rt_type_to_error(ort->fib6_type); in ip6_rt_init_dst_reject()
939 rt->dst.output = dst_discard_out; in ip6_rt_init_dst_reject()
940 rt->dst.input = dst_discard; in ip6_rt_init_dst_reject()
943 rt->dst.output = ip6_pkt_prohibit_out; in ip6_rt_init_dst_reject()
944 rt->dst.input = ip6_pkt_prohibit; in ip6_rt_init_dst_reject()
949 rt->dst.output = ip6_pkt_discard_out; in ip6_rt_init_dst_reject()
950 rt->dst.input = ip6_pkt_discard; in ip6_rt_init_dst_reject()
955 static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort) in ip6_rt_init_dst() argument
958 ip6_rt_init_dst_reject(rt, ort); in ip6_rt_init_dst()
962 rt->dst.error = 0; in ip6_rt_init_dst()
963 rt->dst.output = ip6_output; in ip6_rt_init_dst()
966 rt->dst.input = ip6_input; in ip6_rt_init_dst()
968 rt->dst.input = ip6_mc_input; in ip6_rt_init_dst()
970 rt->dst.input = ip6_forward; in ip6_rt_init_dst()
974 rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate); in ip6_rt_init_dst()
975 lwtunnel_set_redirect(&rt->dst); in ip6_rt_init_dst()
978 rt->dst.lastuse = jiffies; in ip6_rt_init_dst()
982 static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from) in rt6_set_from() argument
984 rt->rt6i_flags &= ~RTF_EXPIRES; in rt6_set_from()
985 rcu_assign_pointer(rt->from, from); in rt6_set_from()
986 dst_init_metrics(&rt->dst, from->fib6_metrics->metrics, true); in rt6_set_from()
988 rt->dst._metrics |= DST_METRICS_REFCOUNTED; in rt6_set_from()
994 static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort) in ip6_rt_copy_init() argument
998 ip6_rt_init_dst(rt, ort); in ip6_rt_copy_init()
1000 rt->rt6i_dst = ort->fib6_dst; in ip6_rt_copy_init()
1001 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; in ip6_rt_copy_init()
1002 rt->rt6i_gateway = ort->fib6_nh.nh_gw; in ip6_rt_copy_init()
1003 rt->rt6i_flags = ort->fib6_flags; in ip6_rt_copy_init()
1004 rt6_set_from(rt, ort); in ip6_rt_copy_init()
1006 rt->rt6i_src = ort->fib6_src; in ip6_rt_copy_init()
1008 rt->rt6i_prefsrc = ort->fib6_prefsrc; in ip6_rt_copy_init()
1032 struct rt6_info *rt = *prt; in ip6_hold_safe() local
1034 if (dst_hold_safe(&rt->dst)) in ip6_hold_safe()
1037 rt = net->ipv6.ip6_null_entry; in ip6_hold_safe()
1038 dst_hold(&rt->dst); in ip6_hold_safe()
1040 rt = NULL; in ip6_hold_safe()
1042 *prt = rt; in ip6_hold_safe()
1047 static struct rt6_info *ip6_create_rt_rcu(struct fib6_info *rt) in ip6_create_rt_rcu() argument
1049 unsigned short flags = fib6_info_dst_flags(rt); in ip6_create_rt_rcu()
1050 struct net_device *dev = rt->fib6_nh.nh_dev; in ip6_create_rt_rcu()
1053 if (!fib6_info_hold_safe(rt)) in ip6_create_rt_rcu()
1058 fib6_info_release(rt); in ip6_create_rt_rcu()
1062 ip6_rt_copy_init(nrt, rt); in ip6_create_rt_rcu()
1079 struct rt6_info *rt; in ip6_pol_route_lookup() local
1107 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr); in ip6_pol_route_lookup()
1108 if (rt) { in ip6_pol_route_lookup()
1109 if (ip6_hold_safe(net, &rt, true)) in ip6_pol_route_lookup()
1110 dst_use_noref(&rt->dst, jiffies); in ip6_pol_route_lookup()
1112 rt = net->ipv6.ip6_null_entry; in ip6_pol_route_lookup()
1113 dst_hold(&rt->dst); in ip6_pol_route_lookup()
1115 rt = ip6_create_rt_rcu(f6i); in ip6_pol_route_lookup()
1120 return rt; in ip6_pol_route_lookup()
1162 static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info, in __ip6_ins_rt() argument
1168 table = rt->fib6_table; in __ip6_ins_rt()
1170 err = fib6_add(&table->tb6_root, rt, info, extack); in __ip6_ins_rt()
1176 int ip6_ins_rt(struct net *net, struct fib6_info *rt) in ip6_ins_rt() argument
1180 return __ip6_ins_rt(rt, &info, NULL); in ip6_ins_rt()
1188 struct rt6_info *rt; in ip6_rt_cache_alloc() local
1198 rt = ip6_dst_alloc(dev_net(dev), dev, 0); in ip6_rt_cache_alloc()
1199 if (!rt) { in ip6_rt_cache_alloc()
1204 ip6_rt_copy_init(rt, ort); in ip6_rt_cache_alloc()
1205 rt->rt6i_flags |= RTF_CACHE; in ip6_rt_cache_alloc()
1206 rt->dst.flags |= DST_HOST; in ip6_rt_cache_alloc()
1207 rt->rt6i_dst.addr = *daddr; in ip6_rt_cache_alloc()
1208 rt->rt6i_dst.plen = 128; in ip6_rt_cache_alloc()
1213 rt->rt6i_flags |= RTF_ANYCAST; in ip6_rt_cache_alloc()
1215 if (rt->rt6i_src.plen && saddr) { in ip6_rt_cache_alloc()
1216 rt->rt6i_src.addr = *saddr; in ip6_rt_cache_alloc()
1217 rt->rt6i_src.plen = 128; in ip6_rt_cache_alloc()
1222 return rt; in ip6_rt_cache_alloc()
1225 static struct rt6_info *ip6_rt_pcpu_alloc(struct fib6_info *rt) in ip6_rt_pcpu_alloc() argument
1227 unsigned short flags = fib6_info_dst_flags(rt); in ip6_rt_pcpu_alloc()
1231 if (!fib6_info_hold_safe(rt)) in ip6_rt_pcpu_alloc()
1235 dev = ip6_rt_get_dev_rcu(rt); in ip6_rt_pcpu_alloc()
1239 fib6_info_release(rt); in ip6_rt_pcpu_alloc()
1242 ip6_rt_copy_init(pcpu_rt, rt); in ip6_rt_pcpu_alloc()
1248 static struct rt6_info *rt6_get_pcpu_route(struct fib6_info *rt) in rt6_get_pcpu_route() argument
1252 p = this_cpu_ptr(rt->rt6i_pcpu); in rt6_get_pcpu_route()
1262 struct fib6_info *rt) in rt6_make_pcpu_route() argument
1266 pcpu_rt = ip6_rt_pcpu_alloc(rt); in rt6_make_pcpu_route()
1273 p = this_cpu_ptr(rt->rt6i_pcpu); in rt6_make_pcpu_route()
1277 if (rt->fib6_destroying) { in rt6_make_pcpu_route()
1353 /* Helper function to find the cached rt in the hash table
1386 /* Helper function to find the cached rt in the hash table
1421 static unsigned int fib6_mtu(const struct fib6_info *rt) in fib6_mtu() argument
1425 if (rt->fib6_pmtu) { in fib6_mtu()
1426 mtu = rt->fib6_pmtu; in fib6_mtu()
1428 struct net_device *dev = fib6_info_nh_dev(rt); in fib6_mtu()
1439 return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu); in fib6_mtu()
1527 void rt6_flush_exceptions(struct fib6_info *rt) in rt6_flush_exceptions() argument
1536 rt->exception_bucket_flushed = 1; in rt6_flush_exceptions()
1538 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, in rt6_flush_exceptions()
1554 /* Find cached rt in the hash table inside passed in rt
1557 static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt, in rt6_find_cached_rt() argument
1567 /* rt6i_src.plen != 0 indicates rt is in subtree in rt6_find_cached_rt()
1576 * rt->rt6i_src is updated.) in rt6_find_cached_rt()
1578 if (rt->fib6_src.plen) in rt6_find_cached_rt()
1582 bucket = rcu_dereference(rt->rt6i_exception_bucket); in rt6_find_cached_rt()
1590 if (!res && src_key && src_key != &rt->fib6_src.addr) { in rt6_find_cached_rt()
1591 src_key = &rt->fib6_src.addr; in rt6_find_cached_rt()
1599 /* Remove the passed in cached rt from the hash table that contains it */
1600 static int rt6_remove_exception_rt(struct rt6_info *rt) in rt6_remove_exception_rt() argument
1608 from = rcu_dereference(rt->from); in rt6_remove_exception_rt()
1610 !(rt->rt6i_flags & RTF_CACHE)) in rt6_remove_exception_rt()
1627 src_key = &rt->rt6i_src.addr; in rt6_remove_exception_rt()
1630 &rt->rt6i_dst.addr, in rt6_remove_exception_rt()
1643 /* Find rt6_ex which contains the passed in rt cache and
1646 static void rt6_update_exception_stamp_rt(struct rt6_info *rt) in rt6_update_exception_stamp_rt() argument
1654 from = rcu_dereference(rt->from); in rt6_update_exception_stamp_rt()
1655 if (!from || !(rt->rt6i_flags & RTF_CACHE)) in rt6_update_exception_stamp_rt()
1668 src_key = &rt->rt6i_src.addr; in rt6_update_exception_stamp_rt()
1671 &rt->rt6i_dst.addr, in rt6_update_exception_stamp_rt()
1680 static void rt6_exceptions_remove_prefsrc(struct fib6_info *rt) in rt6_exceptions_remove_prefsrc() argument
1686 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, in rt6_exceptions_remove_prefsrc()
1700 struct rt6_info *rt, int mtu) in rt6_mtu_change_route_allowed() argument
1712 if (dst_mtu(&rt->dst) >= mtu) in rt6_mtu_change_route_allowed()
1715 if (dst_mtu(&rt->dst) == idev->cnf.mtu6) in rt6_mtu_change_route_allowed()
1722 struct fib6_info *rt, int mtu) in rt6_exceptions_update_pmtu() argument
1728 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, in rt6_exceptions_update_pmtu()
1739 * route), the metrics of its rt->from have already in rt6_exceptions_update_pmtu()
1752 static void rt6_exceptions_clean_tohost(struct fib6_info *rt, in rt6_exceptions_clean_tohost() argument
1760 if (!rcu_access_pointer(rt->rt6i_exception_bucket)) in rt6_exceptions_clean_tohost()
1764 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, in rt6_exceptions_clean_tohost()
1792 struct rt6_info *rt = rt6_ex->rt6i; in rt6_age_examine_exception() local
1800 if (!(rt->rt6i_flags & RTF_EXPIRES)) { in rt6_age_examine_exception()
1801 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) { in rt6_age_examine_exception()
1802 RT6_TRACE("aging clone %p\n", rt); in rt6_age_examine_exception()
1806 } else if (time_after(jiffies, rt->dst.expires)) { in rt6_age_examine_exception()
1807 RT6_TRACE("purging expired route %p\n", rt); in rt6_age_examine_exception()
1812 if (rt->rt6i_flags & RTF_GATEWAY) { in rt6_age_examine_exception()
1816 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); in rt6_age_examine_exception()
1822 rt); in rt6_age_examine_exception()
1831 void rt6_age_exceptions(struct fib6_info *rt, in rt6_age_exceptions() argument
1840 if (!rcu_access_pointer(rt->rt6i_exception_bucket)) in rt6_age_exceptions()
1845 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, in rt6_age_exceptions()
1899 struct rt6_info *rt; in ip6_pol_route() local
1914 rt = net->ipv6.ip6_null_entry; in ip6_pol_route()
1916 dst_hold(&rt->dst); in ip6_pol_route()
1917 return rt; in ip6_pol_route()
1921 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr); in ip6_pol_route()
1922 if (rt) { in ip6_pol_route()
1923 if (ip6_hold_safe(net, &rt, true)) in ip6_pol_route()
1924 dst_use_noref(&rt->dst, jiffies); in ip6_pol_route()
1927 return rt; in ip6_pol_route()
2169 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig; in ip6_blackhole_route() local
2173 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1, in ip6_blackhole_route()
2175 if (rt) { in ip6_blackhole_route()
2176 rt6_info_init(rt); in ip6_blackhole_route()
2179 new = &rt->dst; in ip6_blackhole_route()
2186 rt->rt6i_idev = in6_dev_get(loopback_dev); in ip6_blackhole_route()
2187 rt->rt6i_gateway = ort->rt6i_gateway; in ip6_blackhole_route()
2188 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU; in ip6_blackhole_route()
2190 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); in ip6_blackhole_route()
2192 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); in ip6_blackhole_route()
2217 static struct dst_entry *rt6_check(struct rt6_info *rt, in rt6_check() argument
2227 if (rt6_check_expired(rt)) in rt6_check()
2230 return &rt->dst; in rt6_check()
2233 static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, in rt6_dst_from_check() argument
2237 if (!__rt6_check_expired(rt) && in rt6_dst_from_check()
2238 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && in rt6_dst_from_check()
2240 return &rt->dst; in rt6_dst_from_check()
2249 struct rt6_info *rt; in ip6_dst_check() local
2251 rt = container_of(dst, struct rt6_info, dst); in ip6_dst_check()
2260 from = rcu_dereference(rt->from); in ip6_dst_check()
2262 if (from && (rt->rt6i_flags & RTF_PCPU || in ip6_dst_check()
2263 unlikely(!list_empty(&rt->rt6i_uncached)))) in ip6_dst_check()
2264 dst_ret = rt6_dst_from_check(rt, from, cookie); in ip6_dst_check()
2266 dst_ret = rt6_check(rt, from, cookie); in ip6_dst_check()
2275 struct rt6_info *rt = (struct rt6_info *) dst; in ip6_negative_advice() local
2277 if (rt) { in ip6_negative_advice()
2278 if (rt->rt6i_flags & RTF_CACHE) { in ip6_negative_advice()
2280 if (rt6_check_expired(rt)) { in ip6_negative_advice()
2281 rt6_remove_exception_rt(rt); in ip6_negative_advice()
2295 struct rt6_info *rt; in ip6_link_failure() local
2299 rt = (struct rt6_info *) skb_dst(skb); in ip6_link_failure()
2300 if (rt) { in ip6_link_failure()
2302 if (rt->rt6i_flags & RTF_CACHE) { in ip6_link_failure()
2303 rt6_remove_exception_rt(rt); in ip6_link_failure()
2308 from = rcu_dereference(rt->from); in ip6_link_failure()
2311 if (fn && (rt->rt6i_flags & RTF_DEFAULT)) in ip6_link_failure()
2335 static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu) in rt6_do_update_pmtu() argument
2337 struct net *net = dev_net(rt->dst.dev); in rt6_do_update_pmtu()
2339 dst_metric_set(&rt->dst, RTAX_MTU, mtu); in rt6_do_update_pmtu()
2340 rt->rt6i_flags |= RTF_MODIFIED; in rt6_do_update_pmtu()
2341 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires); in rt6_do_update_pmtu()
2344 static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) in rt6_cache_allowed_for_pmtu() argument
2349 from_set = !!rcu_dereference(rt->from); in rt6_cache_allowed_for_pmtu()
2352 return !(rt->rt6i_flags & RTF_CACHE) && in rt6_cache_allowed_for_pmtu()
2353 (rt->rt6i_flags & RTF_PCPU || from_set); in rt6_cache_allowed_for_pmtu()
2494 struct fib6_info *rt; in __ip6_route_redirect() local
2517 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) in __ip6_route_redirect()
2519 if (fib6_check_expired(rt)) in __ip6_route_redirect()
2521 if (rt->fib6_flags & RTF_REJECT) in __ip6_route_redirect()
2523 if (!(rt->fib6_flags & RTF_GATEWAY)) in __ip6_route_redirect()
2525 if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex) in __ip6_route_redirect()
2532 if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) { in __ip6_route_redirect()
2533 rt_cache = rt6_find_cached_rt(rt, in __ip6_route_redirect()
2547 if (!rt) in __ip6_route_redirect()
2548 rt = net->ipv6.fib6_null_entry; in __ip6_route_redirect()
2549 else if (rt->fib6_flags & RTF_REJECT) { in __ip6_route_redirect()
2554 if (rt == net->ipv6.fib6_null_entry) { in __ip6_route_redirect()
2564 ret = ip6_create_rt_rcu(rt); in __ip6_route_redirect()
2568 trace_fib6_table_lookup(net, rt, table, fl6); in __ip6_route_redirect()
2694 struct rt6_info *rt; in ip6_mtu_from_fib6() local
2703 rt = rt6_find_cached_rt(f6i, daddr, saddr); in ip6_mtu_from_fib6()
2704 if (unlikely(rt)) { in ip6_mtu_from_fib6()
2705 mtu = dst_metric_raw(&rt->dst, RTAX_MTU); in ip6_mtu_from_fib6()
2724 struct rt6_info *rt; in icmp6_dst_alloc() local
2731 rt = ip6_dst_alloc(net, dev, 0); in icmp6_dst_alloc()
2732 if (unlikely(!rt)) { in icmp6_dst_alloc()
2738 rt->dst.flags |= DST_HOST; in icmp6_dst_alloc()
2739 rt->dst.input = ip6_input; in icmp6_dst_alloc()
2740 rt->dst.output = ip6_output; in icmp6_dst_alloc()
2741 rt->rt6i_gateway = fl6->daddr; in icmp6_dst_alloc()
2742 rt->rt6i_dst.addr = fl6->daddr; in icmp6_dst_alloc()
2743 rt->rt6i_dst.plen = 128; in icmp6_dst_alloc()
2744 rt->rt6i_idev = idev; in icmp6_dst_alloc()
2745 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0); in icmp6_dst_alloc()
2750 rt6_uncached_list_add(rt); in icmp6_dst_alloc()
2753 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); in icmp6_dst_alloc()
2784 static int ip6_convert_metrics(struct net *net, struct fib6_info *rt, in ip6_convert_metrics() argument
2792 p = kzalloc(sizeof(*rt->fib6_metrics), GFP_KERNEL); in ip6_convert_metrics()
2797 rt->fib6_metrics = p; in ip6_convert_metrics()
2813 struct rt6_info *rt; in ip6_nh_lookup_table() local
2823 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags); in ip6_nh_lookup_table()
2826 if (rt == net->ipv6.ip6_null_entry) { in ip6_nh_lookup_table()
2827 ip6_rt_put(rt); in ip6_nh_lookup_table()
2828 rt = NULL; in ip6_nh_lookup_table()
2831 return rt; in ip6_nh_lookup_table()
2996 struct fib6_info *rt = NULL; in ip6_route_info_create() local
3079 rt = fib6_info_alloc(gfp_flags); in ip6_route_info_create()
3080 if (!rt) in ip6_route_info_create()
3084 rt->last_probe = jiffies; in ip6_route_info_create()
3087 rt->dst_nocount = true; in ip6_route_info_create()
3089 err = ip6_convert_metrics(net, rt, cfg); in ip6_route_info_create()
3094 fib6_set_expires(rt, jiffies + in ip6_route_info_create()
3097 fib6_clean_expires(rt); in ip6_route_info_create()
3101 rt->fib6_protocol = cfg->fc_protocol; in ip6_route_info_create()
3113 rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate); in ip6_route_info_create()
3116 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); in ip6_route_info_create()
3117 rt->fib6_dst.plen = cfg->fc_dst_len; in ip6_route_info_create()
3118 if (rt->fib6_dst.plen == 128) in ip6_route_info_create()
3119 rt->dst_host = true; in ip6_route_info_create()
3122 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len); in ip6_route_info_create()
3123 rt->fib6_src.plen = cfg->fc_src_len; in ip6_route_info_create()
3126 rt->fib6_metric = cfg->fc_metric; in ip6_route_info_create()
3127 rt->fib6_nh.nh_weight = 1; in ip6_route_info_create()
3129 rt->fib6_type = cfg->fc_type ? : RTN_UNICAST; in ip6_route_info_create()
3152 rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP; in ip6_route_info_create()
3161 rt->fib6_nh.nh_gw = cfg->fc_gateway; in ip6_route_info_create()
3186 rt->fib6_prefsrc.addr = cfg->fc_prefsrc; in ip6_route_info_create()
3187 rt->fib6_prefsrc.plen = 128; in ip6_route_info_create()
3189 rt->fib6_prefsrc.plen = 0; in ip6_route_info_create()
3191 rt->fib6_flags = cfg->fc_flags; in ip6_route_info_create()
3194 if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) && in ip6_route_info_create()
3196 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; in ip6_route_info_create()
3197 rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); in ip6_route_info_create()
3198 rt->fib6_nh.nh_dev = dev; in ip6_route_info_create()
3199 rt->fib6_table = table; in ip6_route_info_create()
3206 return rt; in ip6_route_info_create()
3213 fib6_info_release(rt); in ip6_route_info_create()
3220 struct fib6_info *rt; in ip6_route_add() local
3223 rt = ip6_route_info_create(cfg, gfp_flags, extack); in ip6_route_add()
3224 if (IS_ERR(rt)) in ip6_route_add()
3225 return PTR_ERR(rt); in ip6_route_add()
3227 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); in ip6_route_add()
3228 fib6_info_release(rt); in ip6_route_add()
3233 static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info) in __ip6_del_rt() argument
3239 if (rt == net->ipv6.fib6_null_entry) { in __ip6_del_rt()
3244 table = rt->fib6_table; in __ip6_del_rt()
3246 err = fib6_del(rt, info); in __ip6_del_rt()
3250 fib6_info_release(rt); in __ip6_del_rt()
3254 int ip6_del_rt(struct net *net, struct fib6_info *rt) in ip6_del_rt() argument
3258 return __ip6_del_rt(rt, &info); in ip6_del_rt()
3261 static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg) in __ip6_del_rt_siblings() argument
3269 if (rt == net->ipv6.fib6_null_entry) in __ip6_del_rt_siblings()
3271 table = rt->fib6_table; in __ip6_del_rt_siblings()
3274 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) { in __ip6_del_rt_siblings()
3278 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); in __ip6_del_rt_siblings()
3282 if (rt6_fill_node(net, skb, rt, NULL, in __ip6_del_rt_siblings()
3292 &rt->fib6_siblings, in __ip6_del_rt_siblings()
3300 err = fib6_del(rt, info); in __ip6_del_rt_siblings()
3304 fib6_info_release(rt); in __ip6_del_rt_siblings()
3313 static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg) in ip6_del_cached_rt() argument
3317 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex) in ip6_del_cached_rt()
3321 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) in ip6_del_cached_rt()
3324 rc = rt6_remove_exception_rt(rt); in ip6_del_cached_rt()
3334 struct fib6_info *rt; in ip6_route_del() local
3356 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst, in ip6_route_del()
3368 (!rt->fib6_nh.nh_dev || in ip6_route_del()
3369 rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex)) in ip6_route_del()
3372 !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw)) in ip6_route_del()
3374 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric) in ip6_route_del()
3376 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol) in ip6_route_del()
3378 if (!fib6_info_hold_safe(rt)) in ip6_route_del()
3384 return __ip6_del_rt(rt, &cfg->fc_nlinfo); in ip6_route_del()
3386 return __ip6_del_rt_siblings(rt, cfg); in ip6_route_del()
3397 struct rt6_info *rt, *nrt = NULL; in rt6_do_redirect() local
3456 rt = (struct rt6_info *) dst; in rt6_do_redirect()
3457 if (rt->rt6i_flags & RTF_REJECT) { in rt6_do_redirect()
3466 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr); in rt6_do_redirect()
3484 from = rcu_dereference(rt->from); in rt6_do_redirect()
3504 netevent.old = &rt->dst; in rt6_do_redirect()
3524 struct fib6_info *rt = NULL; in rt6_get_route_info() local
3537 if (rt->fib6_nh.nh_dev->ifindex != ifindex) in rt6_get_route_info()
3539 if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) in rt6_get_route_info()
3541 if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr)) in rt6_get_route_info()
3543 if (!fib6_info_hold_safe(rt)) in rt6_get_route_info()
3549 return rt; in rt6_get_route_info()
3590 struct fib6_info *rt; in rt6_get_dflt_router() local
3599 if (dev == rt->fib6_nh.nh_dev && in rt6_get_dflt_router()
3600 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && in rt6_get_dflt_router()
3601 ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr)) in rt6_get_dflt_router()
3604 if (rt && !fib6_info_hold_safe(rt)) in rt6_get_dflt_router()
3605 rt = NULL; in rt6_get_dflt_router()
3607 return rt; in rt6_get_dflt_router()
3644 struct fib6_info *rt; in __rt6_purge_dflt_routers() local
3649 struct net_device *dev = fib6_info_nh_dev(rt); in __rt6_purge_dflt_routers()
3652 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) && in __rt6_purge_dflt_routers()
3654 fib6_info_hold_safe(rt)) { in __rt6_purge_dflt_routers()
3656 ip6_del_rt(net, rt); in __rt6_purge_dflt_routers()
3841 static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg) in fib6_remove_prefsrc() argument
3847 if (((void *)rt->fib6_nh.nh_dev == dev || !dev) && in fib6_remove_prefsrc()
3848 rt != net->ipv6.fib6_null_entry && in fib6_remove_prefsrc()
3849 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) { in fib6_remove_prefsrc()
3852 rt->fib6_prefsrc.plen = 0; in fib6_remove_prefsrc()
3854 rt6_exceptions_remove_prefsrc(rt); in fib6_remove_prefsrc()
3874 static int fib6_clean_tohost(struct fib6_info *rt, void *arg) in fib6_clean_tohost() argument
3878 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) && in fib6_clean_tohost()
3879 ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) { in fib6_clean_tohost()
3887 rt6_exceptions_clean_tohost(rt, gateway); in fib6_clean_tohost()
3905 static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt) in rt6_multipath_first_sibling() argument
3910 fn = rcu_dereference_protected(rt->fib6_node, in rt6_multipath_first_sibling()
3911 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
3913 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
3915 if (iter->fib6_metric == rt->fib6_metric && in rt6_multipath_first_sibling()
3919 lockdep_is_held(&rt->fib6_table->tb6_lock)); in rt6_multipath_first_sibling()
3925 static bool rt6_is_dead(const struct fib6_info *rt) in rt6_is_dead() argument
3927 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD || in rt6_is_dead()
3928 (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && in rt6_is_dead()
3929 fib6_ignore_linkdown(rt))) in rt6_is_dead()
3935 static int rt6_multipath_total_weight(const struct fib6_info *rt) in rt6_multipath_total_weight() argument
3940 if (!rt6_is_dead(rt)) in rt6_multipath_total_weight()
3941 total += rt->fib6_nh.nh_weight; in rt6_multipath_total_weight()
3943 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) { in rt6_multipath_total_weight()
3951 static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total) in rt6_upper_bound_set() argument
3955 if (!rt6_is_dead(rt)) { in rt6_upper_bound_set()
3956 *weight += rt->fib6_nh.nh_weight; in rt6_upper_bound_set()
3960 atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound); in rt6_upper_bound_set()
3963 static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total) in rt6_multipath_upper_bound_set() argument
3968 rt6_upper_bound_set(rt, &weight, total); in rt6_multipath_upper_bound_set()
3970 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_upper_bound_set()
3974 void rt6_multipath_rebalance(struct fib6_info *rt) in rt6_multipath_rebalance() argument
3983 if (!rt->fib6_nsiblings || rt->should_flush) in rt6_multipath_rebalance()
3990 first = rt6_multipath_first_sibling(rt); in rt6_multipath_rebalance()
3998 static int fib6_ifup(struct fib6_info *rt, void *p_arg) in fib6_ifup() argument
4003 if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) { in fib6_ifup()
4004 rt->fib6_nh.nh_flags &= ~arg->nh_flags; in fib6_ifup()
4005 fib6_update_sernum_upto_root(net, rt); in fib6_ifup()
4006 rt6_multipath_rebalance(rt); in fib6_ifup()
4027 static bool rt6_multipath_uses_dev(const struct fib6_info *rt, in rt6_multipath_uses_dev() argument
4032 if (rt->fib6_nh.nh_dev == dev) in rt6_multipath_uses_dev()
4034 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_uses_dev()
4041 static void rt6_multipath_flush(struct fib6_info *rt) in rt6_multipath_flush() argument
4045 rt->should_flush = 1; in rt6_multipath_flush()
4046 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_flush()
4050 static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt, in rt6_multipath_dead_count() argument
4056 if (rt->fib6_nh.nh_dev == down_dev || in rt6_multipath_dead_count()
4057 rt->fib6_nh.nh_flags & RTNH_F_DEAD) in rt6_multipath_dead_count()
4059 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_dead_count()
4067 static void rt6_multipath_nh_flags_set(struct fib6_info *rt, in rt6_multipath_nh_flags_set() argument
4073 if (rt->fib6_nh.nh_dev == dev) in rt6_multipath_nh_flags_set()
4074 rt->fib6_nh.nh_flags |= nh_flags; in rt6_multipath_nh_flags_set()
4075 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) in rt6_multipath_nh_flags_set()
4080 /* called with write lock held for table with rt */
4081 static int fib6_ifdown(struct fib6_info *rt, void *p_arg) in fib6_ifdown() argument
4087 if (rt == net->ipv6.fib6_null_entry) in fib6_ifdown()
4092 return rt->fib6_nh.nh_dev == dev ? -1 : 0; in fib6_ifdown()
4094 if (rt->should_flush) in fib6_ifdown()
4096 if (!rt->fib6_nsiblings) in fib6_ifdown()
4097 return rt->fib6_nh.nh_dev == dev ? -1 : 0; in fib6_ifdown()
4098 if (rt6_multipath_uses_dev(rt, dev)) { in fib6_ifdown()
4101 count = rt6_multipath_dead_count(rt, dev); in fib6_ifdown()
4102 if (rt->fib6_nsiblings + 1 == count) { in fib6_ifdown()
4103 rt6_multipath_flush(rt); in fib6_ifdown()
4106 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD | in fib6_ifdown()
4108 fib6_update_sernum(net, rt); in fib6_ifdown()
4109 rt6_multipath_rebalance(rt); in fib6_ifdown()
4113 if (rt->fib6_nh.nh_dev != dev || in fib6_ifdown()
4114 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) in fib6_ifdown()
4116 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; in fib6_ifdown()
4117 rt6_multipath_rebalance(rt); in fib6_ifdown()
4148 static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg) in rt6_mtu_change_route() argument
4168 if (rt->fib6_nh.nh_dev == arg->dev && in rt6_mtu_change_route()
4169 !fib6_metric_locked(rt, RTAX_MTU)) { in rt6_mtu_change_route()
4170 u32 mtu = rt->fib6_pmtu; in rt6_mtu_change_route()
4174 fib6_metric_set(rt, RTAX_MTU, arg->mtu); in rt6_mtu_change_route()
4177 rt6_exceptions_update_pmtu(idev, rt, arg->mtu); in rt6_mtu_change_route()
4362 struct fib6_info *rt, in ip6_route_info_append() argument
4370 if (rt6_duplicate_nexthop(nh->fib6_info, rt)) in ip6_route_info_append()
4377 nh->fib6_info = rt; in ip6_route_info_append()
4384 static void ip6_route_mpath_notify(struct fib6_info *rt, in ip6_route_mpath_notify() argument
4389 /* if this is an APPEND route, then rt points to the first route in ip6_route_mpath_notify()
4396 rt = list_first_entry(&rt_last->fib6_siblings, in ip6_route_mpath_notify()
4401 if (rt) in ip6_route_mpath_notify()
4402 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags); in ip6_route_mpath_notify()
4412 struct fib6_info *rt; in ip6_route_multipath_add() local
4455 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack); in ip6_route_multipath_add()
4456 if (IS_ERR(rt)) { in ip6_route_multipath_add()
4457 err = PTR_ERR(rt); in ip6_route_multipath_add()
4458 rt = NULL; in ip6_route_multipath_add()
4461 if (!rt6_qualify_for_ecmp(rt)) { in ip6_route_multipath_add()
4465 fib6_info_release(rt); in ip6_route_multipath_add()
4469 rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1; in ip6_route_multipath_add()
4472 rt, &r_cfg); in ip6_route_multipath_add()
4474 fib6_info_release(rt); in ip6_route_multipath_add()
4625 static size_t rt6_nlmsg_size(struct fib6_info *rt) in rt6_nlmsg_size() argument
4629 if (rt->fib6_nsiblings) { in rt6_nlmsg_size()
4633 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate); in rt6_nlmsg_size()
4635 nexthop_len *= rt->fib6_nsiblings; in rt6_nlmsg_size()
4651 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate) in rt6_nlmsg_size()
4655 static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt, in rt6_nexthop_info() argument
4658 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) in rt6_nexthop_info()
4661 if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) { in rt6_nexthop_info()
4665 if (fib6_ignore_linkdown(rt)) in rt6_nexthop_info()
4670 if (rt->fib6_flags & RTF_GATEWAY) { in rt6_nexthop_info()
4671 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0) in rt6_nexthop_info()
4675 *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK); in rt6_nexthop_info()
4676 if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD) in rt6_nexthop_info()
4680 if (!skip_oif && rt->fib6_nh.nh_dev && in rt6_nexthop_info()
4681 nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex)) in rt6_nexthop_info()
4684 if (rt->fib6_nh.nh_lwtstate && in rt6_nexthop_info()
4685 lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0) in rt6_nexthop_info()
4695 static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt) in rt6_add_nexthop() argument
4697 const struct net_device *dev = rt->fib6_nh.nh_dev; in rt6_add_nexthop()
4705 rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1; in rt6_add_nexthop()
4708 if (rt6_nexthop_info(skb, rt, &flags, true) < 0) in rt6_add_nexthop()
4723 struct fib6_info *rt, struct dst_entry *dst, in rt6_fill_node() argument
4744 rt6_dst = &rt->fib6_dst; in rt6_fill_node()
4745 rt6_src = &rt->fib6_src; in rt6_fill_node()
4746 rt6_flags = rt->fib6_flags; in rt6_fill_node()
4754 if (rt->fib6_table) in rt6_fill_node()
4755 table = rt->fib6_table->tb6_id; in rt6_fill_node()
4762 rtm->rtm_type = rt->fib6_type; in rt6_fill_node()
4765 rtm->rtm_protocol = rt->fib6_protocol; in rt6_fill_node()
4801 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 && in rt6_fill_node()
4806 if (rt->fib6_prefsrc.plen) { in rt6_fill_node()
4808 saddr_buf = rt->fib6_prefsrc.addr; in rt6_fill_node()
4813 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics; in rt6_fill_node()
4817 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric)) in rt6_fill_node()
4830 } else if (rt->fib6_nsiblings) { in rt6_fill_node()
4838 if (rt6_add_nexthop(skb, rt) < 0) in rt6_fill_node()
4842 &rt->fib6_siblings, fib6_siblings) { in rt6_fill_node()
4849 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0) in rt6_fill_node()
4854 expires = dst ? dst->expires : rt->expires; in rt6_fill_node()
4873 int rt6_dump_route(struct fib6_info *rt, void *p_arg) in rt6_dump_route() argument
4878 if (rt == net->ipv6.fib6_null_entry) in rt6_dump_route()
4886 !(rt->fib6_flags & RTF_PREFIX_RT)) { in rt6_dump_route()
4892 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0, in rt6_dump_route()
4905 struct rt6_info *rt; in inet6_rtm_getroute() local
4993 rt = container_of(dst, struct rt6_info, dst); in inet6_rtm_getroute()
4994 if (rt->dst.error) { in inet6_rtm_getroute()
4995 err = rt->dst.error; in inet6_rtm_getroute()
4996 ip6_rt_put(rt); in inet6_rtm_getroute()
5000 if (rt == net->ipv6.ip6_null_entry) { in inet6_rtm_getroute()
5001 err = rt->dst.error; in inet6_rtm_getroute()
5002 ip6_rt_put(rt); in inet6_rtm_getroute()
5008 ip6_rt_put(rt); in inet6_rtm_getroute()
5013 skb_dst_set(skb, &rt->dst); in inet6_rtm_getroute()
5016 from = rcu_dereference(rt->from); in inet6_rtm_getroute()
5043 void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, in inet6_rt_notify() argument
5054 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); in inet6_rt_notify()
5058 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0, in inet6_rt_notify()