• Home
  • Raw
  • Download

Lines Matching +full:use +full:- +full:rtm

1 // SPDX-License-Identifier: GPL-2.0-or-later
69 for (nhsel = 0, nh = (fi)->fib_nh; \
75 for (nhsel = 0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
84 int nhsel; const struct fib_nh *nh = (fi)->fib_nh; \
89 struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
123 .error = -EINVAL,
127 .error = -EHOSTUNREACH,
131 .error = -EACCES,
135 .error = -EAGAIN,
139 .error = -EINVAL,
143 .error = -EINVAL,
160 dst_dev_put(&rt->dst); in rt_fibinfo_free()
161 dst_release_immediate(&rt->dst); in rt_fibinfo_free()
169 hash = rcu_dereference_protected(nhc->nhc_exceptions, 1); in free_nh_exceptions()
179 next = rcu_dereference_protected(fnhe->fnhe_next, 1); in free_nh_exceptions()
181 rt_fibinfo_free(&fnhe->fnhe_rth_input); in free_nh_exceptions()
182 rt_fibinfo_free(&fnhe->fnhe_rth_output); in free_nh_exceptions()
204 dst_dev_put(&rt->dst); in rt_fibinfo_free_cpus()
205 dst_release_immediate(&rt->dst); in rt_fibinfo_free_cpus()
213 if (nhc->nhc_dev) in fib_nh_common_release()
214 dev_put(nhc->nhc_dev); in fib_nh_common_release()
216 lwtstate_put(nhc->nhc_lwtstate); in fib_nh_common_release()
217 rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); in fib_nh_common_release()
218 rt_fibinfo_free(&nhc->nhc_rth_input); in fib_nh_common_release()
226 if (fib_nh->nh_tclassid) in fib_nh_release()
227 atomic_dec(&net->ipv4.fib_num_tclassid_users); in fib_nh_release()
229 fib_nh_common_release(&fib_nh->nh_common); in fib_nh_release()
237 if (fi->nh) { in free_fib_info_rcu()
238 nexthop_put(fi->nh); in free_fib_info_rcu()
241 fib_nh_release(fi->fib_net, nexthop_nh); in free_fib_info_rcu()
245 ip_fib_metrics_put(fi->fib_metrics); in free_fib_info_rcu()
252 if (fi->fib_dead == 0) { in free_fib_info()
257 call_rcu(&fi->rcu, free_fib_info_rcu); in free_fib_info()
264 if (fi && --fi->fib_treeref == 0) { in fib_release_info()
265 hlist_del(&fi->fib_hash); in fib_release_info()
268 WRITE_ONCE(fib_info_cnt, fib_info_cnt - 1); in fib_release_info()
270 if (fi->fib_prefsrc) in fib_release_info()
271 hlist_del(&fi->fib_lhash); in fib_release_info()
272 if (fi->nh) { in fib_release_info()
273 list_del(&fi->nh_list); in fib_release_info()
276 if (!nexthop_nh->fib_nh_dev) in fib_release_info()
278 hlist_del(&nexthop_nh->nh_hash); in fib_release_info()
282 WRITE_ONCE(fi->fib_dead, 1); in fib_release_info()
292 if (fi->nh || ofi->nh) in nh_comp()
293 return nexthop_cmp(fi->nh, ofi->nh) ? 0 : -1; in nh_comp()
295 if (ofi->fib_nhs == 0) in nh_comp()
301 if (nh->fib_nh_oif != onh->fib_nh_oif || in nh_comp()
302 nh->fib_nh_gw_family != onh->fib_nh_gw_family || in nh_comp()
303 nh->fib_nh_scope != onh->fib_nh_scope || in nh_comp()
305 nh->fib_nh_weight != onh->fib_nh_weight || in nh_comp()
308 nh->nh_tclassid != onh->nh_tclassid || in nh_comp()
310 lwtunnel_cmp_encap(nh->fib_nh_lws, onh->fib_nh_lws) || in nh_comp()
311 ((nh->fib_nh_flags ^ onh->fib_nh_flags) & ~RTNH_COMPARE_MASK)) in nh_comp()
312 return -1; in nh_comp()
314 if (nh->fib_nh_gw_family == AF_INET && in nh_comp()
315 nh->fib_nh_gw4 != onh->fib_nh_gw4) in nh_comp()
316 return -1; in nh_comp()
318 if (nh->fib_nh_gw_family == AF_INET6 && in nh_comp()
319 ipv6_addr_cmp(&nh->fib_nh_gw6, &onh->fib_nh_gw6)) in nh_comp()
320 return -1; in nh_comp()
333 u32 val = net_hash_mix(dev_net(dev)) ^ dev->ifindex; in fib_info_devhash_bucket()
352 unsigned int mask = (fib_info_hash_size - 1); in fib_info_hashfn_result()
361 val = fib_info_hashfn_1(fi->fib_nhs, fi->fib_protocol, in fib_info_hashfn()
362 fi->fib_scope, (__force u32)fi->fib_prefsrc, in fib_info_hashfn()
363 fi->fib_priority); in fib_info_hashfn()
365 if (fi->nh) { in fib_info_hashfn()
366 val ^= fib_devindex_hashfn(fi->nh->id); in fib_info_hashfn()
369 val ^= fib_devindex_hashfn(nh->fib_nh_oif); in fib_info_hashfn()
384 hash = fib_info_hashfn_1(fib_devindex_hashfn(cfg->fc_nh_id), in fib_find_info_nh()
385 cfg->fc_protocol, cfg->fc_scope, in fib_find_info_nh()
386 (__force u32)cfg->fc_prefsrc, in fib_find_info_nh()
387 cfg->fc_priority); in fib_find_info_nh()
392 if (!net_eq(fi->fib_net, net)) in fib_find_info_nh()
394 if (!fi->nh || fi->nh->id != cfg->fc_nh_id) in fib_find_info_nh()
396 if (cfg->fc_protocol == fi->fib_protocol && in fib_find_info_nh()
397 cfg->fc_scope == fi->fib_scope && in fib_find_info_nh()
398 cfg->fc_prefsrc == fi->fib_prefsrc && in fib_find_info_nh()
399 cfg->fc_priority == fi->fib_priority && in fib_find_info_nh()
400 cfg->fc_type == fi->fib_type && in fib_find_info_nh()
401 cfg->fc_table == fi->fib_tb_id && in fib_find_info_nh()
402 !((cfg->fc_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK)) in fib_find_info_nh()
419 if (!net_eq(fi->fib_net, nfi->fib_net)) in fib_find_info()
421 if (fi->fib_nhs != nfi->fib_nhs) in fib_find_info()
423 if (nfi->fib_protocol == fi->fib_protocol && in fib_find_info()
424 nfi->fib_scope == fi->fib_scope && in fib_find_info()
425 nfi->fib_prefsrc == fi->fib_prefsrc && in fib_find_info()
426 nfi->fib_priority == fi->fib_priority && in fib_find_info()
427 nfi->fib_type == fi->fib_type && in fib_find_info()
428 nfi->fib_tb_id == fi->fib_tb_id && in fib_find_info()
429 memcmp(nfi->fib_metrics, fi->fib_metrics, in fib_find_info()
431 !((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK) && in fib_find_info()
452 if (nh->fib_nh_dev == dev && in ip_fib_check_default()
453 nh->fib_nh_gw4 == gw && in ip_fib_check_default()
454 !(nh->fib_nh_flags & RTNH_F_DEAD)) { in ip_fib_check_default()
462 return -1; in ip_fib_check_default()
478 if (fi->nh) in fib_nlmsg_size()
496 if (nhc->nhc_lwtstate) { in fib_nlmsg_size()
499 nhc->nhc_lwtstate); in fib_nlmsg_size()
519 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; in rtmsg_fib()
520 int err = -ENOBUFS; in rtmsg_fib()
522 skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); in rtmsg_fib()
526 fri.fi = fa->fa_info; in rtmsg_fib()
530 fri.tos = fa->fa_tos; in rtmsg_fib()
531 fri.type = fa->fa_type; in rtmsg_fib()
532 fri.offload = fa->offload; in rtmsg_fib()
533 fri.trap = fa->trap; in rtmsg_fib()
534 err = fib_dump_info(skb, info->portid, seq, event, &fri, nlm_flags); in rtmsg_fib()
536 /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ in rtmsg_fib()
537 WARN_ON(err == -EMSGSIZE); in rtmsg_fib()
541 rtnl_notify(skb, info->nl_net, info->portid, RTNLGRP_IPV4_ROUTE, in rtmsg_fib()
542 info->nlh, GFP_KERNEL); in rtmsg_fib()
546 rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); in rtmsg_fib()
557 if (likely(nhc->nhc_gw_family == AF_INET)) in fib_detect_death()
558 n = neigh_lookup(&arp_tbl, &nhc->nhc_gw.ipv4, nhc->nhc_dev); in fib_detect_death()
559 else if (nhc->nhc_gw_family == AF_INET6) in fib_detect_death()
560 n = neigh_lookup(ipv6_stub->nd_tbl, &nhc->nhc_gw.ipv6, in fib_detect_death()
561 nhc->nhc_dev); in fib_detect_death()
566 state = n->nud_state; in fib_detect_death()
590 nhc->nhc_pcpu_rth_output = alloc_percpu_gfp(struct rtable __rcu *, in fib_nh_common_init()
592 if (!nhc->nhc_pcpu_rth_output) in fib_nh_common_init()
593 return -ENOMEM; in fib_nh_common_init()
600 err = -EINVAL; in fib_nh_common_init()
604 nhc->nhc_family, cfg, &lwtstate, in fib_nh_common_init()
609 nhc->nhc_lwtstate = lwtstate_get(lwtstate); in fib_nh_common_init()
615 rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); in fib_nh_common_init()
616 nhc->nhc_pcpu_rth_output = NULL; in fib_nh_common_init()
627 nh->fib_nh_family = AF_INET; in fib_nh_init()
629 err = fib_nh_common_init(net, &nh->nh_common, cfg->fc_encap, in fib_nh_init()
630 cfg->fc_encap_type, cfg, GFP_KERNEL, extack); in fib_nh_init()
634 nh->fib_nh_oif = cfg->fc_oif; in fib_nh_init()
635 nh->fib_nh_gw_family = cfg->fc_gw_family; in fib_nh_init()
636 if (cfg->fc_gw_family == AF_INET) in fib_nh_init()
637 nh->fib_nh_gw4 = cfg->fc_gw4; in fib_nh_init()
638 else if (cfg->fc_gw_family == AF_INET6) in fib_nh_init()
639 nh->fib_nh_gw6 = cfg->fc_gw6; in fib_nh_init()
641 nh->fib_nh_flags = cfg->fc_flags; in fib_nh_init()
644 nh->nh_tclassid = cfg->fc_flow; in fib_nh_init()
645 if (nh->nh_tclassid) in fib_nh_init()
646 atomic_inc(&net->ipv4.fib_num_tclassid_users); in fib_nh_init()
649 nh->fib_nh_weight = nh_weight; in fib_nh_init()
669 "Invalid nexthop configuration - extra data after nexthops"); in fib_count_nexthops()
681 return -EINVAL; in fib_gw_from_attr()
694 struct net *net = fi->fib_net; in fib_get_nhs()
706 "Invalid nexthop configuration - extra data after nexthop"); in fib_get_nhs()
707 return -EINVAL; in fib_get_nhs()
710 if (rtnh->rtnh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) { in fib_get_nhs()
712 "Invalid flags for nexthop - can not contain DEAD or LINKDOWN"); in fib_get_nhs()
713 return -EINVAL; in fib_get_nhs()
716 fib_cfg.fc_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; in fib_get_nhs()
717 fib_cfg.fc_oif = rtnh->rtnh_ifindex; in fib_get_nhs()
728 return -EINVAL; in fib_get_nhs()
748 return -EINVAL; in fib_get_nhs()
763 rtnh->rtnh_hops + 1, extack); in fib_get_nhs()
770 ret = -EINVAL; in fib_get_nhs()
772 if (cfg->fc_oif && nh->fib_nh_oif != cfg->fc_oif) { in fib_get_nhs()
777 if (cfg->fc_gw_family) { in fib_get_nhs()
778 if (cfg->fc_gw_family != nh->fib_nh_gw_family || in fib_get_nhs()
779 (cfg->fc_gw_family == AF_INET && in fib_get_nhs()
780 nh->fib_nh_gw4 != cfg->fc_gw4) || in fib_get_nhs()
781 (cfg->fc_gw_family == AF_INET6 && in fib_get_nhs()
782 ipv6_addr_cmp(&nh->fib_nh_gw6, &cfg->fc_gw6))) { in fib_get_nhs()
789 if (cfg->fc_flow && nh->nh_tclassid != cfg->fc_flow) { in fib_get_nhs()
811 if (nh->fib_nh_flags & RTNH_F_DEAD) in fib_rebalance()
814 if (ip_ignore_linkdown(nh->fib_nh_dev) && in fib_rebalance()
815 nh->fib_nh_flags & RTNH_F_LINKDOWN) in fib_rebalance()
818 total += nh->fib_nh_weight; in fib_rebalance()
825 if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD) { in fib_rebalance()
826 upper_bound = -1; in fib_rebalance()
827 } else if (ip_ignore_linkdown(nexthop_nh->fib_nh_dev) && in fib_rebalance()
828 nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN) { in fib_rebalance()
829 upper_bound = -1; in fib_rebalance()
831 w += nexthop_nh->fib_nh_weight; in fib_rebalance()
833 total) - 1; in fib_rebalance()
836 atomic_set(&nexthop_nh->fib_nh_upper_bound, upper_bound); in fib_rebalance()
847 return -EINVAL; in fib_get_nhs()
869 result = lwtunnel_cmp_encap(lwtstate, nh->fib_nh_lws); in fib_encap_match()
884 if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority) in fib_nh_match()
887 if (cfg->fc_nh_id) { in fib_nh_match()
888 if (fi->nh && cfg->fc_nh_id == fi->nh->id) in fib_nh_match()
893 if (fi->nh) { in fib_nh_match()
894 if (cfg->fc_oif || cfg->fc_gw_family || cfg->fc_mp) in fib_nh_match()
899 if (cfg->fc_oif || cfg->fc_gw_family) { in fib_nh_match()
903 if (cfg->fc_encap) { in fib_nh_match()
904 if (fib_encap_match(net, cfg->fc_encap_type, in fib_nh_match()
905 cfg->fc_encap, nh, cfg, extack)) in fib_nh_match()
909 if (cfg->fc_flow && in fib_nh_match()
910 cfg->fc_flow != nh->nh_tclassid) in fib_nh_match()
913 if ((cfg->fc_oif && cfg->fc_oif != nh->fib_nh_oif) || in fib_nh_match()
914 (cfg->fc_gw_family && in fib_nh_match()
915 cfg->fc_gw_family != nh->fib_nh_gw_family)) in fib_nh_match()
918 if (cfg->fc_gw_family == AF_INET && in fib_nh_match()
919 cfg->fc_gw4 != nh->fib_nh_gw4) in fib_nh_match()
922 if (cfg->fc_gw_family == AF_INET6 && in fib_nh_match()
923 ipv6_addr_cmp(&cfg->fc_gw6, &nh->fib_nh_gw6)) in fib_nh_match()
930 if (!cfg->fc_mp) in fib_nh_match()
933 rtnh = cfg->fc_mp; in fib_nh_match()
934 remaining = cfg->fc_mp_len; in fib_nh_match()
940 return -EINVAL; in fib_nh_match()
942 if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->fib_nh_oif) in fib_nh_match()
955 return -EINVAL; in fib_nh_match()
965 if (nh->fib_nh_gw_family != AF_INET || in fib_nh_match()
966 gw != nh->fib_nh_gw4) in fib_nh_match()
975 switch (nh->fib_nh_gw_family) { in fib_nh_match()
978 cfg2.fc_gw4 != nh->fib_nh_gw4) in fib_nh_match()
984 &nh->fib_nh_gw6)) in fib_nh_match()
995 return -EINVAL; in fib_nh_match()
997 if (nla_get_u32(nla) != nh->nh_tclassid) in fib_nh_match()
1014 if (!cfg->fc_mx) in fib_metrics_match()
1017 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { in fib_metrics_match()
1032 val = tcp_ca_get_key_by_name(fi->fib_net, tmp, &ecn_ca); in fib_metrics_match()
1039 fi_val = fi->fib_metrics->metrics[type - 1]; in fib_metrics_match()
1055 .fc_flags = nh->fib_nh_flags | RTF_GATEWAY, in fib_check_nh_v6_gw()
1056 .fc_ifindex = nh->fib_nh_oif, in fib_check_nh_v6_gw()
1057 .fc_gateway = nh->fib_nh_gw6, in fib_check_nh_v6_gw()
1062 err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack); in fib_check_nh_v6_gw()
1064 nh->fib_nh_dev = fib6_nh.fib_nh_dev; in fib_check_nh_v6_gw()
1065 dev_hold(nh->fib_nh_dev); in fib_check_nh_v6_gw()
1066 nh->fib_nh_oif = nh->fib_nh_dev->ifindex; in fib_check_nh_v6_gw()
1067 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v6_gw()
1069 ipv6_stub->fib6_nh_release(&fib6_nh); in fib_check_nh_v6_gw()
1077 * -------
1083 * b) gateway must be on-link address, possibly
1087 * d) If we use tunnel routes, gateway could be not on-link.
1089 * Attempt to reconcile all of these (alas, self-contradictory) conditions
1106 * consistent and very flexible. F.e. as by-product it allows
1107 * to co-exists in peace independent exterior and interior
1112 * {universe prefix} -> (gw, oif) [scope link]
1114 * |-> {link prefix} -> (gw, oif) [scope local]
1116 * |-> {local prefix} (terminal node)
1125 if (nh->fib_nh_flags & RTNH_F_ONLINK) { in fib_check_nh_v4_gw()
1130 return -EINVAL; in fib_check_nh_v4_gw()
1132 dev = __dev_get_by_index(net, nh->fib_nh_oif); in fib_check_nh_v4_gw()
1135 return -ENODEV; in fib_check_nh_v4_gw()
1137 if (!(dev->flags & IFF_UP)) { in fib_check_nh_v4_gw()
1139 return -ENETDOWN; in fib_check_nh_v4_gw()
1141 addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4); in fib_check_nh_v4_gw()
1144 return -EINVAL; in fib_check_nh_v4_gw()
1147 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1148 nh->fib_nh_dev = dev; in fib_check_nh_v4_gw()
1150 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v4_gw()
1157 .daddr = nh->fib_nh_gw4, in fib_check_nh_v4_gw()
1159 .flowi4_oif = nh->fib_nh_oif, in fib_check_nh_v4_gw()
1190 err = -EINVAL; in fib_check_nh_v4_gw()
1195 nh->fib_nh_scope = res.scope; in fib_check_nh_v4_gw()
1196 nh->fib_nh_oif = FIB_RES_OIF(res); in fib_check_nh_v4_gw()
1197 nh->fib_nh_dev = dev = FIB_RES_DEV(res); in fib_check_nh_v4_gw()
1205 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1206 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; in fib_check_nh_v4_gw()
1218 if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) { in fib_check_nh_nongw()
1220 "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set"); in fib_check_nh_nongw()
1221 return -EINVAL; in fib_check_nh_nongw()
1226 err = -ENODEV; in fib_check_nh_nongw()
1227 in_dev = inetdev_by_index(net, nh->fib_nh_oif); in fib_check_nh_nongw()
1230 err = -ENETDOWN; in fib_check_nh_nongw()
1231 if (!(in_dev->dev->flags & IFF_UP)) { in fib_check_nh_nongw()
1236 nh->fib_nh_dev = in_dev->dev; in fib_check_nh_nongw()
1237 dev_hold(nh->fib_nh_dev); in fib_check_nh_nongw()
1238 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_nongw()
1239 if (!netif_carrier_ok(nh->fib_nh_dev)) in fib_check_nh_nongw()
1240 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_nongw()
1252 if (nh->fib_nh_gw_family == AF_INET) in fib_check_nh()
1254 else if (nh->fib_nh_gw_family == AF_INET6) in fib_check_nh()
1264 unsigned int mask = (fib_info_hash_size - 1); in fib_laddr_hashfn()
1316 hlist_add_head(&fi->fib_hash, dest); in fib_info_hash_move()
1330 new_hash = fib_laddr_hashfn(fi->fib_prefsrc); in fib_info_hash_move()
1332 hlist_add_head(&fi->fib_lhash, ldest); in fib_info_hash_move()
1350 if (nhc->nhc_family != AF_INET) in fib_info_update_nhc_saddr()
1351 return inet_select_addr(nhc->nhc_dev, 0, scope); in fib_info_update_nhc_saddr()
1354 saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope); in fib_info_update_nhc_saddr()
1356 WRITE_ONCE(nh->nh_saddr, saddr); in fib_info_update_nhc_saddr()
1357 WRITE_ONCE(nh->nh_saddr_genid, atomic_read(&net->ipv4.dev_addr_genid)); in fib_info_update_nhc_saddr()
1364 struct fib_nh_common *nhc = res->nhc; in fib_result_prefsrc()
1366 if (res->fi->fib_prefsrc) in fib_result_prefsrc()
1367 return res->fi->fib_prefsrc; in fib_result_prefsrc()
1369 if (nhc->nhc_family == AF_INET) { in fib_result_prefsrc()
1373 if (READ_ONCE(nh->nh_saddr_genid) == in fib_result_prefsrc()
1374 atomic_read(&net->ipv4.dev_addr_genid)) in fib_result_prefsrc()
1375 return READ_ONCE(nh->nh_saddr); in fib_result_prefsrc()
1378 return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope); in fib_result_prefsrc()
1383 if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || in fib_valid_prefsrc()
1384 fib_prefsrc != cfg->fc_dst) { in fib_valid_prefsrc()
1385 u32 tb_id = cfg->fc_table; in fib_valid_prefsrc()
1391 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1395 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1413 struct net *net = cfg->fc_nlinfo.nl_net; in fib_create_info()
1415 if (cfg->fc_type > RTN_MAX) in fib_create_info()
1419 if (fib_props[cfg->fc_type].scope > cfg->fc_scope) { in fib_create_info()
1424 if (cfg->fc_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) { in fib_create_info()
1426 "Invalid rtm_flags - can not contain DEAD or LINKDOWN"); in fib_create_info()
1430 if (cfg->fc_nh_id) { in fib_create_info()
1431 if (!cfg->fc_mx) { in fib_create_info()
1434 fi->fib_treeref++; in fib_create_info()
1439 nh = nexthop_find_by_id(net, cfg->fc_nh_id); in fib_create_info()
1448 if (cfg->fc_mp) { in fib_create_info()
1449 nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len, extack); in fib_create_info()
1455 err = -ENOBUFS; in fib_create_info()
1482 fi->fib_metrics = ip_fib_metrics_init(fi->fib_net, cfg->fc_mx, in fib_create_info()
1483 cfg->fc_mx_len, extack); in fib_create_info()
1484 if (IS_ERR(fi->fib_metrics)) { in fib_create_info()
1485 err = PTR_ERR(fi->fib_metrics); in fib_create_info()
1490 fi->fib_net = net; in fib_create_info()
1491 fi->fib_protocol = cfg->fc_protocol; in fib_create_info()
1492 fi->fib_scope = cfg->fc_scope; in fib_create_info()
1493 fi->fib_flags = cfg->fc_flags; in fib_create_info()
1494 fi->fib_priority = cfg->fc_priority; in fib_create_info()
1495 fi->fib_prefsrc = cfg->fc_prefsrc; in fib_create_info()
1496 fi->fib_type = cfg->fc_type; in fib_create_info()
1497 fi->fib_tb_id = cfg->fc_table; in fib_create_info()
1499 fi->fib_nhs = nhs; in fib_create_info()
1503 err = -EINVAL; in fib_create_info()
1506 fi->nh = nh; in fib_create_info()
1510 nexthop_nh->nh_parent = fi; in fib_create_info()
1513 if (cfg->fc_mp) in fib_create_info()
1514 err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, in fib_create_info()
1517 err = fib_nh_init(net, fi->fib_nh, cfg, 1, extack); in fib_create_info()
1523 if (fib_props[cfg->fc_type].error) { in fib_create_info()
1524 if (cfg->fc_gw_family || cfg->fc_oif || cfg->fc_mp) { in fib_create_info()
1531 switch (cfg->fc_type) { in fib_create_info()
1544 if (cfg->fc_scope > RT_SCOPE_HOST) { in fib_create_info()
1549 if (fi->nh) { in fib_create_info()
1550 err = fib_check_nexthop(fi->nh, cfg->fc_scope, extack); in fib_create_info()
1553 } else if (cfg->fc_scope == RT_SCOPE_HOST) { in fib_create_info()
1554 struct fib_nh *nh = fi->fib_nh; in fib_create_info()
1562 if (nh->fib_nh_gw_family) { in fib_create_info()
1567 nh->fib_nh_scope = RT_SCOPE_NOWHERE; in fib_create_info()
1568 nh->fib_nh_dev = dev_get_by_index(net, nh->fib_nh_oif); in fib_create_info()
1569 err = -ENODEV; in fib_create_info()
1570 if (!nh->fib_nh_dev) in fib_create_info()
1576 err = fib_check_nh(cfg->fc_nlinfo.nl_net, nexthop_nh, in fib_create_info()
1577 cfg->fc_table, cfg->fc_scope, in fib_create_info()
1581 if (nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN) in fib_create_info()
1584 if (linkdown == fi->fib_nhs) in fib_create_info()
1585 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_create_info()
1588 if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { in fib_create_info()
1593 if (!fi->nh) { in fib_create_info()
1595 fib_info_update_nhc_saddr(net, &nexthop_nh->nh_common, in fib_create_info()
1596 fi->fib_scope); in fib_create_info()
1597 if (nexthop_nh->fib_nh_gw_family == AF_INET6) in fib_create_info()
1598 fi->fib_nh_is_v6 = true; in fib_create_info()
1608 fi->fib_dead = 1; in fib_create_info()
1610 ofi->fib_treeref++; in fib_create_info()
1614 fi->fib_treeref++; in fib_create_info()
1615 refcount_set(&fi->fib_clntref, 1); in fib_create_info()
1618 hlist_add_head(&fi->fib_hash, in fib_create_info()
1620 if (fi->fib_prefsrc) { in fib_create_info()
1623 head = &fib_info_laddrhash[fib_laddr_hashfn(fi->fib_prefsrc)]; in fib_create_info()
1624 hlist_add_head(&fi->fib_lhash, head); in fib_create_info()
1626 if (fi->nh) { in fib_create_info()
1627 list_add(&fi->nh_list, &nh->fi_list); in fib_create_info()
1632 if (!nexthop_nh->fib_nh_dev) in fib_create_info()
1634 head = fib_info_devhash_bucket(nexthop_nh->fib_nh_dev); in fib_create_info()
1635 hlist_add_head(&nexthop_nh->nh_hash, head); in fib_create_info()
1642 err = -EINVAL; in fib_create_info()
1647 fi->fib_dead = 1; in fib_create_info()
1657 if (nhc->nhc_flags & RTNH_F_DEAD) in fib_nexthop_info()
1660 if (nhc->nhc_flags & RTNH_F_LINKDOWN) { in fib_nexthop_info()
1664 switch (nhc->nhc_family) { in fib_nexthop_info()
1666 if (ip_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1670 if (ip6_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1677 switch (nhc->nhc_gw_family) { in fib_nexthop_info()
1679 if (nla_put_in_addr(skb, RTA_GATEWAY, nhc->nhc_gw.ipv4)) in fib_nexthop_info()
1686 if (rt_family != nhc->nhc_gw_family) { in fib_nexthop_info()
1696 via->rtvia_family = AF_INET6; in fib_nexthop_info()
1697 memcpy(via->rtvia_addr, &nhc->nhc_gw.ipv6, alen); in fib_nexthop_info()
1699 &nhc->nhc_gw.ipv6) < 0) { in fib_nexthop_info()
1705 *flags |= (nhc->nhc_flags & RTNH_F_ONLINK); in fib_nexthop_info()
1706 if (nhc->nhc_flags & RTNH_F_OFFLOAD) in fib_nexthop_info()
1709 if (!skip_oif && nhc->nhc_dev && in fib_nexthop_info()
1710 nla_put_u32(skb, RTA_OIF, nhc->nhc_dev->ifindex)) in fib_nexthop_info()
1713 if (nhc->nhc_lwtstate && in fib_nexthop_info()
1714 lwtunnel_fill_encap(skb, nhc->nhc_lwtstate, in fib_nexthop_info()
1721 return -EMSGSIZE; in fib_nexthop_info()
1729 const struct net_device *dev = nhc->nhc_dev; in fib_add_nexthop()
1737 rtnh->rtnh_hops = nh_weight - 1; in fib_add_nexthop()
1738 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0; in fib_add_nexthop()
1743 rtnh->rtnh_flags = flags; in fib_add_nexthop()
1749 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh; in fib_add_nexthop()
1754 return -EMSGSIZE; in fib_add_nexthop()
1768 if (unlikely(fi->nh)) { in fib_add_multipath()
1769 if (nexthop_mpath_fill_node(skb, fi->nh, AF_INET) < 0) in fib_add_multipath()
1777 nh_tclassid = nh->nh_tclassid; in fib_add_multipath()
1779 if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight, in fib_add_multipath()
1790 return -EMSGSIZE; in fib_add_multipath()
1802 unsigned int nhs = fib_info_num_path(fri->fi); in fib_dump_info()
1803 struct fib_info *fi = fri->fi; in fib_dump_info()
1804 u32 tb_id = fri->tb_id; in fib_dump_info()
1806 struct rtmsg *rtm; in fib_dump_info() local
1808 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); in fib_dump_info()
1810 return -EMSGSIZE; in fib_dump_info()
1812 rtm = nlmsg_data(nlh); in fib_dump_info()
1813 rtm->rtm_family = AF_INET; in fib_dump_info()
1814 rtm->rtm_dst_len = fri->dst_len; in fib_dump_info()
1815 rtm->rtm_src_len = 0; in fib_dump_info()
1816 rtm->rtm_tos = fri->tos; in fib_dump_info()
1818 rtm->rtm_table = tb_id; in fib_dump_info()
1820 rtm->rtm_table = RT_TABLE_COMPAT; in fib_dump_info()
1823 rtm->rtm_type = fri->type; in fib_dump_info()
1824 rtm->rtm_flags = fi->fib_flags; in fib_dump_info()
1825 rtm->rtm_scope = fi->fib_scope; in fib_dump_info()
1826 rtm->rtm_protocol = fi->fib_protocol; in fib_dump_info()
1828 if (rtm->rtm_dst_len && in fib_dump_info()
1829 nla_put_in_addr(skb, RTA_DST, fri->dst)) in fib_dump_info()
1831 if (fi->fib_priority && in fib_dump_info()
1832 nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) in fib_dump_info()
1834 if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0) in fib_dump_info()
1837 if (fi->fib_prefsrc && in fib_dump_info()
1838 nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc)) in fib_dump_info()
1841 if (fi->nh) { in fib_dump_info()
1842 if (nla_put_u32(skb, RTA_NH_ID, fi->nh->id)) in fib_dump_info()
1844 if (nexthop_is_blackhole(fi->nh)) in fib_dump_info()
1845 rtm->rtm_type = RTN_BLACKHOLE; in fib_dump_info()
1846 if (!READ_ONCE(fi->fib_net->ipv4.sysctl_nexthop_compat_mode)) in fib_dump_info()
1857 rtm->rtm_flags = flags; in fib_dump_info()
1859 if (nhc->nhc_family == AF_INET) { in fib_dump_info()
1863 if (nh->nh_tclassid && in fib_dump_info()
1864 nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) in fib_dump_info()
1874 if (fri->offload) in fib_dump_info()
1875 rtm->rtm_flags |= RTM_F_OFFLOAD; in fib_dump_info()
1876 if (fri->trap) in fib_dump_info()
1877 rtm->rtm_flags |= RTM_F_TRAP; in fib_dump_info()
1884 return -EMSGSIZE; in fib_dump_info()
1889 * - local address disappeared -> we must delete all the entries
1891 * - device went down -> we must shutdown all nexthops going via it.
1906 if (!net_eq(fi->fib_net, net) || in fib_sync_down_addr()
1907 fi->fib_tb_id != tb_id) in fib_sync_down_addr()
1909 if (fi->fib_prefsrc == local) { in fib_sync_down_addr()
1910 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_addr()
1911 fi->pfsrc_removed = true; in fib_sync_down_addr()
1921 bool ignore_link_down = ip_ignore_linkdown(nh->fib_nh_dev); in call_fib_nh_notifiers()
1928 if (nh->fib_nh_flags & RTNH_F_DEAD) in call_fib_nh_notifiers()
1930 if (ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) in call_fib_nh_notifiers()
1932 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), event_type, in call_fib_nh_notifiers()
1935 if ((ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) || in call_fib_nh_notifiers()
1936 (nh->fib_nh_flags & RTNH_F_DEAD)) in call_fib_nh_notifiers()
1937 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), in call_fib_nh_notifiers()
1947 * - the new MTU of the first hop becomes smaller than the PMTU
1948 * - the old MTU was the same as the PMTU, and it limited discovery of
1953 * - if the new MTU is greater than the PMTU, don't make any change
1954 * - otherwise, unlock and set PMTU
1961 bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1); in fib_nhc_update_mtu()
1970 fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) { in fib_nhc_update_mtu()
1971 if (fnhe->fnhe_mtu_locked) { in fib_nhc_update_mtu()
1972 if (new <= fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1973 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1974 fnhe->fnhe_mtu_locked = false; in fib_nhc_update_mtu()
1976 } else if (new < fnhe->fnhe_pmtu || in fib_nhc_update_mtu()
1977 orig == fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1978 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1990 if (nh->fib_nh_dev == dev) in fib_sync_mtu()
1991 fib_nhc_update_mtu(&nh->nh_common, dev->mtu, orig_mtu); in fib_sync_mtu()
2012 scope = -1; in fib_sync_down_dev()
2015 struct fib_info *fi = nh->nh_parent; in fib_sync_down_dev()
2018 BUG_ON(!fi->fib_nhs); in fib_sync_down_dev()
2019 if (nh->fib_nh_dev != dev || fi == prev_fi) in fib_sync_down_dev()
2024 if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD) in fib_sync_down_dev()
2026 else if (nexthop_nh->fib_nh_dev == dev && in fib_sync_down_dev()
2027 nexthop_nh->fib_nh_scope != scope) { in fib_sync_down_dev()
2031 nexthop_nh->fib_nh_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
2034 nexthop_nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2043 nexthop_nh->fib_nh_dev == dev) { in fib_sync_down_dev()
2044 dead = fi->fib_nhs; in fib_sync_down_dev()
2049 if (dead == fi->fib_nhs) { in fib_sync_down_dev()
2053 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
2056 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2072 struct hlist_head *fa_head = res->fa_head; in fib_select_default()
2073 struct fib_table *tb = res->table; in fib_select_default()
2074 u8 slen = 32 - res->prefixlen; in fib_select_default()
2075 int order = -1, last_idx = -1; in fib_select_default()
2077 u32 last_prio = res->fi->fib_priority; in fib_select_default()
2081 struct fib_info *next_fi = fa->fa_info; in fib_select_default()
2084 if (fa->fa_slen != slen) in fib_select_default()
2086 if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) in fib_select_default()
2088 if (fa->tb_id != tb->tb_id) in fib_select_default()
2090 if (next_fi->fib_priority > last_prio && in fib_select_default()
2091 fa->fa_tos == last_tos) { in fib_select_default()
2096 if (next_fi->fib_flags & RTNH_F_DEAD) in fib_select_default()
2098 last_tos = fa->fa_tos; in fib_select_default()
2099 last_prio = next_fi->fib_priority; in fib_select_default()
2101 if (next_fi->fib_scope != res->scope || in fib_select_default()
2102 fa->fa_type != RTN_UNICAST) in fib_select_default()
2106 if (!nhc->nhc_gw_family || nhc->nhc_scope != RT_SCOPE_LINK) in fib_select_default()
2112 if (next_fi != res->fi) in fib_select_default()
2116 &last_idx, fa1->fa_default)) { in fib_select_default()
2118 fa1->fa_default = order; in fib_select_default()
2127 fa1->fa_default = -1; in fib_select_default()
2132 fa1->fa_default)) { in fib_select_default()
2134 fa1->fa_default = order; in fib_select_default()
2140 fa1->fa_default = last_idx; in fib_select_default()
2158 if (!(dev->flags & IFF_UP)) in fib_sync_up()
2173 struct fib_info *fi = nh->nh_parent; in fib_sync_up()
2176 BUG_ON(!fi->fib_nhs); in fib_sync_up()
2177 if (nh->fib_nh_dev != dev || fi == prev_fi) in fib_sync_up()
2183 if (!(nexthop_nh->fib_nh_flags & nh_flags)) { in fib_sync_up()
2187 if (!nexthop_nh->fib_nh_dev || in fib_sync_up()
2188 !(nexthop_nh->fib_nh_dev->flags & IFF_UP)) in fib_sync_up()
2190 if (nexthop_nh->fib_nh_dev != dev || in fib_sync_up()
2194 nexthop_nh->fib_nh_flags &= ~nh_flags; in fib_sync_up()
2199 fi->fib_flags &= ~nh_flags; in fib_sync_up()
2214 if (nh->fib_nh_scope == RT_SCOPE_LINK) { in fib_good_nh()
2219 if (likely(nh->fib_nh_gw_family == AF_INET)) in fib_good_nh()
2220 n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev, in fib_good_nh()
2221 (__force u32)nh->fib_nh_gw4); in fib_good_nh()
2222 else if (nh->fib_nh_gw_family == AF_INET6) in fib_good_nh()
2223 n = __ipv6_neigh_lookup_noref_stub(nh->fib_nh_dev, in fib_good_nh()
2224 &nh->fib_nh_gw6); in fib_good_nh()
2228 state = n->nud_state; in fib_good_nh()
2238 struct fib_info *fi = res->fi; in fib_select_multipath()
2239 struct net *net = fi->fib_net; in fib_select_multipath()
2242 if (unlikely(res->fi->nh)) { in fib_select_multipath()
2248 if (READ_ONCE(net->ipv4.sysctl_fib_multipath_use_neigh)) { in fib_select_multipath()
2252 res->nh_sel = nhsel; in fib_select_multipath()
2253 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2258 if (hash > atomic_read(&nexthop_nh->fib_nh_upper_bound)) in fib_select_multipath()
2261 res->nh_sel = nhsel; in fib_select_multipath()
2262 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2271 if (fl4->flowi4_oif && !(fl4->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) in fib_select_path()
2275 if (fib_info_num_path(res->fi) > 1) { in fib_select_path()
2282 if (!res->prefixlen && in fib_select_path()
2283 res->table->tb_num_default > 1 && in fib_select_path()
2284 res->type == RTN_UNICAST) in fib_select_path()
2288 if (!fl4->saddr) in fib_select_path()
2289 fl4->saddr = fib_result_prefsrc(net, res); in fib_select_path()