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

1 // SPDX-License-Identifier: GPL-2.0-or-later
71 for (nhsel = 0, nh = (fi)->fib_nh; \
77 for (nhsel = 0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
86 int nhsel; const struct fib_nh *nh = (fi)->fib_nh; \
91 struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
125 .error = -EINVAL,
129 .error = -EHOSTUNREACH,
133 .error = -EACCES,
137 .error = -EAGAIN,
141 .error = -EINVAL,
145 .error = -EINVAL,
162 dst_dev_put(&rt->dst); in rt_fibinfo_free()
163 dst_release_immediate(&rt->dst); in rt_fibinfo_free()
171 hash = rcu_dereference_protected(nhc->nhc_exceptions, 1); in free_nh_exceptions()
181 next = rcu_dereference_protected(fnhe->fnhe_next, 1); in free_nh_exceptions()
183 rt_fibinfo_free(&fnhe->fnhe_rth_input); in free_nh_exceptions()
184 rt_fibinfo_free(&fnhe->fnhe_rth_output); in free_nh_exceptions()
206 dst_dev_put(&rt->dst); in rt_fibinfo_free_cpus()
207 dst_release_immediate(&rt->dst); in rt_fibinfo_free_cpus()
215 netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker); 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_hurry(&fi->rcu, free_fib_info_rcu); in free_fib_info()
264 if (fi && refcount_dec_and_test(&fi->fib_treeref)) { 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.dscp = fa->fa_dscp; in rtmsg_fib()
531 fri.type = fa->fa_type; in rtmsg_fib()
532 fri.offload = READ_ONCE(fa->offload); in rtmsg_fib()
533 fri.trap = READ_ONCE(fa->trap); in rtmsg_fib()
534 fri.offload_failed = READ_ONCE(fa->offload_failed); in rtmsg_fib()
535 err = fib_dump_info(skb, info->portid, seq, event, &fri, nlm_flags); in rtmsg_fib()
537 /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ in rtmsg_fib()
538 WARN_ON(err == -EMSGSIZE); in rtmsg_fib()
542 rtnl_notify(skb, info->nl_net, info->portid, RTNLGRP_IPV4_ROUTE, in rtmsg_fib()
543 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 = READ_ONCE(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()
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 netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, in fib_check_nh_v6_gw()
1067 nh->fib_nh_oif = nh->fib_nh_dev->ifindex; in fib_check_nh_v6_gw()
1068 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v6_gw()
1070 ipv6_stub->fib6_nh_release(&fib6_nh); in fib_check_nh_v6_gw()
1078 * -------
1084 * b) gateway must be on-link address, possibly
1088 * d) If we use tunnel routes, gateway could be not on-link.
1090 * Attempt to reconcile all of these (alas, self-contradictory) conditions
1107 * consistent and very flexible. F.e. as by-product it allows
1108 * to co-exists in peace independent exterior and interior
1113 * {universe prefix} -> (gw, oif) [scope link]
1115 * |-> {link prefix} -> (gw, oif) [scope local]
1117 * |-> {local prefix} (terminal node)
1126 if (nh->fib_nh_flags & RTNH_F_ONLINK) { in fib_check_nh_v4_gw()
1131 return -EINVAL; in fib_check_nh_v4_gw()
1133 dev = __dev_get_by_index(net, nh->fib_nh_oif); in fib_check_nh_v4_gw()
1136 return -ENODEV; in fib_check_nh_v4_gw()
1138 if (!(dev->flags & IFF_UP)) { in fib_check_nh_v4_gw()
1140 return -ENETDOWN; in fib_check_nh_v4_gw()
1142 addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4); in fib_check_nh_v4_gw()
1145 return -EINVAL; in fib_check_nh_v4_gw()
1148 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1149 nh->fib_nh_dev = dev; in fib_check_nh_v4_gw()
1150 netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_v4_gw()
1151 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v4_gw()
1158 .daddr = nh->fib_nh_gw4, in fib_check_nh_v4_gw()
1160 .flowi4_oif = nh->fib_nh_oif, in fib_check_nh_v4_gw()
1191 err = -EINVAL; in fib_check_nh_v4_gw()
1196 nh->fib_nh_scope = res.scope; in fib_check_nh_v4_gw()
1197 nh->fib_nh_oif = FIB_RES_OIF(res); in fib_check_nh_v4_gw()
1198 nh->fib_nh_dev = dev = FIB_RES_DEV(res); in fib_check_nh_v4_gw()
1204 netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_v4_gw()
1206 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1207 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; in fib_check_nh_v4_gw()
1219 if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) { in fib_check_nh_nongw()
1221 "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set"); in fib_check_nh_nongw()
1222 return -EINVAL; in fib_check_nh_nongw()
1227 err = -ENODEV; in fib_check_nh_nongw()
1228 in_dev = inetdev_by_index(net, nh->fib_nh_oif); in fib_check_nh_nongw()
1231 err = -ENETDOWN; in fib_check_nh_nongw()
1232 if (!(in_dev->dev->flags & IFF_UP)) { in fib_check_nh_nongw()
1237 nh->fib_nh_dev = in_dev->dev; in fib_check_nh_nongw()
1238 netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_nongw()
1239 nh->fib_nh_scope = RT_SCOPE_HOST; in fib_check_nh_nongw()
1240 if (!netif_carrier_ok(nh->fib_nh_dev)) in fib_check_nh_nongw()
1241 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_nongw()
1253 if (nh->fib_nh_gw_family == AF_INET) in fib_check_nh()
1255 else if (nh->fib_nh_gw_family == AF_INET6) in fib_check_nh()
1297 hlist_add_head(&fi->fib_hash, dest); in fib_info_hash_move()
1311 ldest = fib_info_laddrhash_bucket(fi->fib_net, in fib_info_hash_move()
1312 fi->fib_prefsrc); in fib_info_hash_move()
1313 hlist_add_head(&fi->fib_lhash, ldest); in fib_info_hash_move()
1329 if (nhc->nhc_family != AF_INET) in fib_info_update_nhc_saddr()
1330 return inet_select_addr(nhc->nhc_dev, 0, scope); in fib_info_update_nhc_saddr()
1333 saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope); in fib_info_update_nhc_saddr()
1335 WRITE_ONCE(nh->nh_saddr, saddr); in fib_info_update_nhc_saddr()
1336 WRITE_ONCE(nh->nh_saddr_genid, atomic_read(&net->ipv4.dev_addr_genid)); in fib_info_update_nhc_saddr()
1343 struct fib_nh_common *nhc = res->nhc; in fib_result_prefsrc()
1345 if (res->fi->fib_prefsrc) in fib_result_prefsrc()
1346 return res->fi->fib_prefsrc; in fib_result_prefsrc()
1348 if (nhc->nhc_family == AF_INET) { in fib_result_prefsrc()
1352 if (READ_ONCE(nh->nh_saddr_genid) == in fib_result_prefsrc()
1353 atomic_read(&net->ipv4.dev_addr_genid)) in fib_result_prefsrc()
1354 return READ_ONCE(nh->nh_saddr); in fib_result_prefsrc()
1357 return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope); in fib_result_prefsrc()
1362 if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || in fib_valid_prefsrc()
1363 fib_prefsrc != cfg->fc_dst) { in fib_valid_prefsrc()
1364 u32 tb_id = cfg->fc_table; in fib_valid_prefsrc()
1370 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1374 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1392 struct net *net = cfg->fc_nlinfo.nl_net; in fib_create_info()
1394 if (cfg->fc_type > RTN_MAX) in fib_create_info()
1398 if (fib_props[cfg->fc_type].scope > cfg->fc_scope) { in fib_create_info()
1403 if (cfg->fc_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) { in fib_create_info()
1405 "Invalid rtm_flags - can not contain DEAD or LINKDOWN"); in fib_create_info()
1409 if (cfg->fc_nh_id) { in fib_create_info()
1410 if (!cfg->fc_mx) { in fib_create_info()
1413 refcount_inc(&fi->fib_treeref); in fib_create_info()
1418 nh = nexthop_find_by_id(net, cfg->fc_nh_id); in fib_create_info()
1427 if (cfg->fc_mp) { in fib_create_info()
1428 nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len, extack); in fib_create_info()
1434 err = -ENOBUFS; in fib_create_info()
1461 fi->fib_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len, extack); in fib_create_info()
1462 if (IS_ERR(fi->fib_metrics)) { in fib_create_info()
1463 err = PTR_ERR(fi->fib_metrics); in fib_create_info()
1468 fi->fib_net = net; in fib_create_info()
1469 fi->fib_protocol = cfg->fc_protocol; in fib_create_info()
1470 fi->fib_scope = cfg->fc_scope; in fib_create_info()
1471 fi->fib_flags = cfg->fc_flags; in fib_create_info()
1472 fi->fib_priority = cfg->fc_priority; in fib_create_info()
1473 fi->fib_prefsrc = cfg->fc_prefsrc; in fib_create_info()
1474 fi->fib_type = cfg->fc_type; in fib_create_info()
1475 fi->fib_tb_id = cfg->fc_table; in fib_create_info()
1477 fi->fib_nhs = nhs; in fib_create_info()
1481 err = -EINVAL; in fib_create_info()
1484 fi->nh = nh; in fib_create_info()
1488 nexthop_nh->nh_parent = fi; in fib_create_info()
1491 if (cfg->fc_mp) in fib_create_info()
1492 err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, in fib_create_info()
1495 err = fib_nh_init(net, fi->fib_nh, cfg, 1, extack); in fib_create_info()
1501 if (fib_props[cfg->fc_type].error) { in fib_create_info()
1502 if (cfg->fc_gw_family || cfg->fc_oif || cfg->fc_mp) { in fib_create_info()
1509 switch (cfg->fc_type) { in fib_create_info()
1522 if (cfg->fc_scope > RT_SCOPE_HOST) { in fib_create_info()
1527 if (fi->nh) { in fib_create_info()
1528 err = fib_check_nexthop(fi->nh, cfg->fc_scope, extack); in fib_create_info()
1531 } else if (cfg->fc_scope == RT_SCOPE_HOST) { in fib_create_info()
1532 struct fib_nh *nh = fi->fib_nh; in fib_create_info()
1540 if (nh->fib_nh_gw_family) { in fib_create_info()
1545 nh->fib_nh_scope = RT_SCOPE_NOWHERE; in fib_create_info()
1546 nh->fib_nh_dev = dev_get_by_index(net, nh->fib_nh_oif); in fib_create_info()
1547 err = -ENODEV; in fib_create_info()
1548 if (!nh->fib_nh_dev) in fib_create_info()
1550 netdev_tracker_alloc(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, in fib_create_info()
1556 err = fib_check_nh(cfg->fc_nlinfo.nl_net, nexthop_nh, in fib_create_info()
1557 cfg->fc_table, cfg->fc_scope, in fib_create_info()
1561 if (nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN) in fib_create_info()
1564 if (linkdown == fi->fib_nhs) in fib_create_info()
1565 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_create_info()
1568 if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { in fib_create_info()
1573 if (!fi->nh) { in fib_create_info()
1575 fib_info_update_nhc_saddr(net, &nexthop_nh->nh_common, in fib_create_info()
1576 fi->fib_scope); in fib_create_info()
1577 if (nexthop_nh->fib_nh_gw_family == AF_INET6) in fib_create_info()
1578 fi->fib_nh_is_v6 = true; in fib_create_info()
1588 fi->fib_dead = 1; in fib_create_info()
1590 refcount_inc(&ofi->fib_treeref); in fib_create_info()
1594 refcount_set(&fi->fib_treeref, 1); in fib_create_info()
1595 refcount_set(&fi->fib_clntref, 1); in fib_create_info()
1598 hlist_add_head(&fi->fib_hash, in fib_create_info()
1600 if (fi->fib_prefsrc) { in fib_create_info()
1603 head = fib_info_laddrhash_bucket(net, fi->fib_prefsrc); in fib_create_info()
1604 hlist_add_head(&fi->fib_lhash, head); in fib_create_info()
1606 if (fi->nh) { in fib_create_info()
1607 list_add(&fi->nh_list, &nh->fi_list); in fib_create_info()
1612 if (!nexthop_nh->fib_nh_dev) in fib_create_info()
1614 head = fib_info_devhash_bucket(nexthop_nh->fib_nh_dev); in fib_create_info()
1615 hlist_add_head(&nexthop_nh->nh_hash, head); in fib_create_info()
1622 err = -EINVAL; in fib_create_info()
1627 fi->fib_dead = 1; in fib_create_info()
1637 if (nhc->nhc_flags & RTNH_F_DEAD) in fib_nexthop_info()
1640 if (nhc->nhc_flags & RTNH_F_LINKDOWN) { in fib_nexthop_info()
1644 switch (nhc->nhc_family) { in fib_nexthop_info()
1646 if (ip_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1650 if (ip6_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1657 switch (nhc->nhc_gw_family) { in fib_nexthop_info()
1659 if (nla_put_in_addr(skb, RTA_GATEWAY, nhc->nhc_gw.ipv4)) in fib_nexthop_info()
1666 if (rt_family != nhc->nhc_gw_family) { in fib_nexthop_info()
1676 via->rtvia_family = AF_INET6; in fib_nexthop_info()
1677 memcpy(via->rtvia_addr, &nhc->nhc_gw.ipv6, alen); in fib_nexthop_info()
1679 &nhc->nhc_gw.ipv6) < 0) { in fib_nexthop_info()
1685 *flags |= (nhc->nhc_flags & in fib_nexthop_info()
1688 if (!skip_oif && nhc->nhc_dev && in fib_nexthop_info()
1689 nla_put_u32(skb, RTA_OIF, nhc->nhc_dev->ifindex)) in fib_nexthop_info()
1692 if (nhc->nhc_lwtstate && in fib_nexthop_info()
1693 lwtunnel_fill_encap(skb, nhc->nhc_lwtstate, in fib_nexthop_info()
1700 return -EMSGSIZE; in fib_nexthop_info()
1708 const struct net_device *dev = nhc->nhc_dev; in fib_add_nexthop()
1716 rtnh->rtnh_hops = nh_weight - 1; in fib_add_nexthop()
1717 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0; in fib_add_nexthop()
1722 rtnh->rtnh_flags = flags; in fib_add_nexthop()
1728 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh; in fib_add_nexthop()
1733 return -EMSGSIZE; in fib_add_nexthop()
1747 if (unlikely(fi->nh)) { in fib_add_multipath()
1748 if (nexthop_mpath_fill_node(skb, fi->nh, AF_INET) < 0) in fib_add_multipath()
1756 nh_tclassid = nh->nh_tclassid; in fib_add_multipath()
1758 if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight, in fib_add_multipath()
1769 return -EMSGSIZE; in fib_add_multipath()
1781 unsigned int nhs = fib_info_num_path(fri->fi); in fib_dump_info()
1782 struct fib_info *fi = fri->fi; in fib_dump_info()
1783 u32 tb_id = fri->tb_id; in fib_dump_info()
1785 struct rtmsg *rtm; in fib_dump_info() local
1787 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); in fib_dump_info()
1789 return -EMSGSIZE; in fib_dump_info()
1791 rtm = nlmsg_data(nlh); in fib_dump_info()
1792 rtm->rtm_family = AF_INET; in fib_dump_info()
1793 rtm->rtm_dst_len = fri->dst_len; in fib_dump_info()
1794 rtm->rtm_src_len = 0; in fib_dump_info()
1795 rtm->rtm_tos = inet_dscp_to_dsfield(fri->dscp); in fib_dump_info()
1797 rtm->rtm_table = tb_id; in fib_dump_info()
1799 rtm->rtm_table = RT_TABLE_COMPAT; in fib_dump_info()
1802 rtm->rtm_type = fri->type; in fib_dump_info()
1803 rtm->rtm_flags = fi->fib_flags; in fib_dump_info()
1804 rtm->rtm_scope = fi->fib_scope; in fib_dump_info()
1805 rtm->rtm_protocol = fi->fib_protocol; in fib_dump_info()
1807 if (rtm->rtm_dst_len && in fib_dump_info()
1808 nla_put_in_addr(skb, RTA_DST, fri->dst)) in fib_dump_info()
1810 if (fi->fib_priority && in fib_dump_info()
1811 nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) in fib_dump_info()
1813 if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0) in fib_dump_info()
1816 if (fi->fib_prefsrc && in fib_dump_info()
1817 nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc)) in fib_dump_info()
1820 if (fi->nh) { in fib_dump_info()
1821 if (nla_put_u32(skb, RTA_NH_ID, fi->nh->id)) in fib_dump_info()
1823 if (nexthop_is_blackhole(fi->nh)) in fib_dump_info()
1824 rtm->rtm_type = RTN_BLACKHOLE; in fib_dump_info()
1825 if (!READ_ONCE(fi->fib_net->ipv4.sysctl_nexthop_compat_mode)) in fib_dump_info()
1836 rtm->rtm_flags = flags; in fib_dump_info()
1838 if (nhc->nhc_family == AF_INET) { in fib_dump_info()
1842 if (nh->nh_tclassid && in fib_dump_info()
1843 nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) in fib_dump_info()
1853 if (fri->offload) in fib_dump_info()
1854 rtm->rtm_flags |= RTM_F_OFFLOAD; in fib_dump_info()
1855 if (fri->trap) in fib_dump_info()
1856 rtm->rtm_flags |= RTM_F_TRAP; in fib_dump_info()
1857 if (fri->offload_failed) in fib_dump_info()
1858 rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED; in fib_dump_info()
1865 return -EMSGSIZE; in fib_dump_info()
1870 * - local address disappeared -> we must delete all the entries
1872 * - device went down -> we must shutdown all nexthops going via it.
1887 if (!net_eq(fi->fib_net, net) || in fib_sync_down_addr()
1888 fi->fib_tb_id != tb_id) in fib_sync_down_addr()
1890 if (fi->fib_prefsrc == local) { in fib_sync_down_addr()
1891 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_addr()
1892 fi->pfsrc_removed = true; in fib_sync_down_addr()
1902 bool ignore_link_down = ip_ignore_linkdown(nh->fib_nh_dev); in call_fib_nh_notifiers()
1909 if (nh->fib_nh_flags & RTNH_F_DEAD) in call_fib_nh_notifiers()
1911 if (ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) in call_fib_nh_notifiers()
1913 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), event_type, in call_fib_nh_notifiers()
1916 if ((ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) || in call_fib_nh_notifiers()
1917 (nh->fib_nh_flags & RTNH_F_DEAD)) in call_fib_nh_notifiers()
1918 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), in call_fib_nh_notifiers()
1929 * - the new MTU of the first hop becomes smaller than the PMTU
1930 * - the old MTU was the same as the PMTU, and it limited discovery of
1935 * - if the new MTU is greater than the PMTU, don't make any change
1936 * - otherwise, unlock and set PMTU
1943 bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1); in fib_nhc_update_mtu()
1952 fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) { in fib_nhc_update_mtu()
1953 if (fnhe->fnhe_mtu_locked) { in fib_nhc_update_mtu()
1954 if (new <= fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1955 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1956 fnhe->fnhe_mtu_locked = false; in fib_nhc_update_mtu()
1958 } else if (new < fnhe->fnhe_pmtu || in fib_nhc_update_mtu()
1959 orig == fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1960 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1972 if (nh->fib_nh_dev == dev) in fib_sync_mtu()
1973 fib_nhc_update_mtu(&nh->nh_common, dev->mtu, orig_mtu); in fib_sync_mtu()
1994 scope = -1; in fib_sync_down_dev()
1997 struct fib_info *fi = nh->nh_parent; in fib_sync_down_dev()
2000 BUG_ON(!fi->fib_nhs); in fib_sync_down_dev()
2001 if (nh->fib_nh_dev != dev || fi == prev_fi) in fib_sync_down_dev()
2006 if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD) in fib_sync_down_dev()
2008 else if (nexthop_nh->fib_nh_dev == dev && in fib_sync_down_dev()
2009 nexthop_nh->fib_nh_scope != scope) { in fib_sync_down_dev()
2013 nexthop_nh->fib_nh_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
2016 nexthop_nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2025 nexthop_nh->fib_nh_dev == dev) { in fib_sync_down_dev()
2026 dead = fi->fib_nhs; in fib_sync_down_dev()
2031 if (dead == fi->fib_nhs) { in fib_sync_down_dev()
2035 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
2038 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2054 struct hlist_head *fa_head = res->fa_head; in fib_select_default()
2055 struct fib_table *tb = res->table; in fib_select_default()
2056 u8 slen = 32 - res->prefixlen; in fib_select_default()
2057 int order = -1, last_idx = -1; in fib_select_default()
2059 u32 last_prio = res->fi->fib_priority; in fib_select_default()
2063 struct fib_info *next_fi = fa->fa_info; in fib_select_default()
2066 if (fa->fa_slen != slen) in fib_select_default()
2068 if (fa->fa_dscp && !fib_dscp_masked_match(fa->fa_dscp, flp)) in fib_select_default()
2070 if (fa->tb_id != tb->tb_id) in fib_select_default()
2072 if (next_fi->fib_priority > last_prio && in fib_select_default()
2073 fa->fa_dscp == last_dscp) { in fib_select_default()
2078 if (next_fi->fib_flags & RTNH_F_DEAD) in fib_select_default()
2080 last_dscp = fa->fa_dscp; in fib_select_default()
2081 last_prio = next_fi->fib_priority; in fib_select_default()
2083 if (next_fi->fib_scope != res->scope || in fib_select_default()
2084 fa->fa_type != RTN_UNICAST) in fib_select_default()
2088 if (!nhc->nhc_gw_family || nhc->nhc_scope != RT_SCOPE_LINK) in fib_select_default()
2094 if (next_fi != res->fi) in fib_select_default()
2098 &last_idx, fa1->fa_default)) { in fib_select_default()
2100 fa1->fa_default = order; in fib_select_default()
2109 fa1->fa_default = -1; in fib_select_default()
2114 fa1->fa_default)) { in fib_select_default()
2116 fa1->fa_default = order; in fib_select_default()
2122 fa1->fa_default = last_idx; in fib_select_default()
2140 if (!(dev->flags & IFF_UP)) in fib_sync_up()
2155 struct fib_info *fi = nh->nh_parent; in fib_sync_up()
2158 BUG_ON(!fi->fib_nhs); in fib_sync_up()
2159 if (nh->fib_nh_dev != dev || fi == prev_fi) in fib_sync_up()
2165 if (!(nexthop_nh->fib_nh_flags & nh_flags)) { in fib_sync_up()
2169 if (!nexthop_nh->fib_nh_dev || in fib_sync_up()
2170 !(nexthop_nh->fib_nh_dev->flags & IFF_UP)) in fib_sync_up()
2172 if (nexthop_nh->fib_nh_dev != dev || in fib_sync_up()
2176 nexthop_nh->fib_nh_flags &= ~nh_flags; in fib_sync_up()
2181 fi->fib_flags &= ~nh_flags; in fib_sync_up()
2196 if (nh->fib_nh_scope == RT_SCOPE_LINK) { in fib_good_nh()
2201 if (likely(nh->fib_nh_gw_family == AF_INET)) in fib_good_nh()
2202 n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev, in fib_good_nh()
2203 (__force u32)nh->fib_nh_gw4); in fib_good_nh()
2204 else if (nh->fib_nh_gw_family == AF_INET6) in fib_good_nh()
2205 n = __ipv6_neigh_lookup_noref_stub(nh->fib_nh_dev, in fib_good_nh()
2206 &nh->fib_nh_gw6); in fib_good_nh()
2210 state = READ_ONCE(n->nud_state); in fib_good_nh()
2220 struct fib_info *fi = res->fi; in fib_select_multipath()
2221 struct net *net = fi->fib_net; in fib_select_multipath()
2224 if (unlikely(res->fi->nh)) { in fib_select_multipath()
2230 if (READ_ONCE(net->ipv4.sysctl_fib_multipath_use_neigh)) { in fib_select_multipath()
2234 res->nh_sel = nhsel; in fib_select_multipath()
2235 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2240 if (hash > atomic_read(&nexthop_nh->fib_nh_upper_bound)) in fib_select_multipath()
2243 res->nh_sel = nhsel; in fib_select_multipath()
2244 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2253 if (fl4->flowi4_oif) in fib_select_path()
2257 if (fib_info_num_path(res->fi) > 1) { in fib_select_path()
2264 if (!res->prefixlen && in fib_select_path()
2265 res->table->tb_num_default > 1 && in fib_select_path()
2266 res->type == RTN_UNICAST) in fib_select_path()
2270 if (!fl4->saddr) { in fib_select_path()
2273 l3mdev = dev_get_by_index_rcu(net, fl4->flowi4_l3mdev); in fib_select_path()
2277 fl4->saddr = fib_result_prefsrc(net, res); in fib_select_path()
2279 fl4->saddr = inet_select_addr(l3mdev, 0, RT_SCOPE_LINK); in fib_select_path()