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(&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()
547 rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); in rtmsg_fib()
558 if (likely(nhc->nhc_gw_family == AF_INET)) in fib_detect_death()
559 n = neigh_lookup(&arp_tbl, &nhc->nhc_gw.ipv4, nhc->nhc_dev); in fib_detect_death()
560 else if (nhc->nhc_gw_family == AF_INET6) in fib_detect_death()
561 n = neigh_lookup(ipv6_stub->nd_tbl, &nhc->nhc_gw.ipv6, in fib_detect_death()
562 nhc->nhc_dev); in fib_detect_death()
567 state = READ_ONCE(n->nud_state); in fib_detect_death()
591 nhc->nhc_pcpu_rth_output = alloc_percpu_gfp(struct rtable __rcu *, in fib_nh_common_init()
593 if (!nhc->nhc_pcpu_rth_output) in fib_nh_common_init()
594 return -ENOMEM; in fib_nh_common_init()
601 err = -EINVAL; in fib_nh_common_init()
605 nhc->nhc_family, cfg, &lwtstate, in fib_nh_common_init()
610 nhc->nhc_lwtstate = lwtstate_get(lwtstate); in fib_nh_common_init()
616 rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); in fib_nh_common_init()
617 nhc->nhc_pcpu_rth_output = NULL; in fib_nh_common_init()
628 nh->fib_nh_family = AF_INET; in fib_nh_init()
630 err = fib_nh_common_init(net, &nh->nh_common, cfg->fc_encap, in fib_nh_init()
631 cfg->fc_encap_type, cfg, GFP_KERNEL, extack); in fib_nh_init()
635 nh->fib_nh_oif = cfg->fc_oif; in fib_nh_init()
636 nh->fib_nh_gw_family = cfg->fc_gw_family; in fib_nh_init()
637 if (cfg->fc_gw_family == AF_INET) in fib_nh_init()
638 nh->fib_nh_gw4 = cfg->fc_gw4; in fib_nh_init()
639 else if (cfg->fc_gw_family == AF_INET6) in fib_nh_init()
640 nh->fib_nh_gw6 = cfg->fc_gw6; in fib_nh_init()
642 nh->fib_nh_flags = cfg->fc_flags; in fib_nh_init()
645 nh->nh_tclassid = cfg->fc_flow; in fib_nh_init()
646 if (nh->nh_tclassid) in fib_nh_init()
647 atomic_inc(&net->ipv4.fib_num_tclassid_users); in fib_nh_init()
650 nh->fib_nh_weight = nh_weight; in fib_nh_init()
670 "Invalid nexthop configuration - extra data after nexthops"); in fib_count_nexthops()
682 return -EINVAL; in fib_gw_from_attr()
695 struct net *net = fi->fib_net; in fib_get_nhs()
707 "Invalid nexthop configuration - extra data after nexthop"); in fib_get_nhs()
708 return -EINVAL; in fib_get_nhs()
711 if (rtnh->rtnh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) { in fib_get_nhs()
713 "Invalid flags for nexthop - can not contain DEAD or LINKDOWN"); in fib_get_nhs()
714 return -EINVAL; in fib_get_nhs()
717 fib_cfg.fc_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; in fib_get_nhs()
718 fib_cfg.fc_oif = rtnh->rtnh_ifindex; in fib_get_nhs()
729 return -EINVAL; in fib_get_nhs()
749 return -EINVAL; in fib_get_nhs()
764 rtnh->rtnh_hops + 1, extack); in fib_get_nhs()
771 ret = -EINVAL; in fib_get_nhs()
773 if (cfg->fc_oif && nh->fib_nh_oif != cfg->fc_oif) { in fib_get_nhs()
778 if (cfg->fc_gw_family) { in fib_get_nhs()
779 if (cfg->fc_gw_family != nh->fib_nh_gw_family || in fib_get_nhs()
780 (cfg->fc_gw_family == AF_INET && in fib_get_nhs()
781 nh->fib_nh_gw4 != cfg->fc_gw4) || in fib_get_nhs()
782 (cfg->fc_gw_family == AF_INET6 && in fib_get_nhs()
783 ipv6_addr_cmp(&nh->fib_nh_gw6, &cfg->fc_gw6))) { in fib_get_nhs()
790 if (cfg->fc_flow && nh->nh_tclassid != cfg->fc_flow) { in fib_get_nhs()
812 if (nh->fib_nh_flags & RTNH_F_DEAD) in fib_rebalance()
815 if (ip_ignore_linkdown(nh->fib_nh_dev) && in fib_rebalance()
816 nh->fib_nh_flags & RTNH_F_LINKDOWN) in fib_rebalance()
819 total += nh->fib_nh_weight; in fib_rebalance()
826 if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD) { in fib_rebalance()
827 upper_bound = -1; in fib_rebalance()
828 } else if (ip_ignore_linkdown(nexthop_nh->fib_nh_dev) && in fib_rebalance()
829 nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN) { in fib_rebalance()
830 upper_bound = -1; in fib_rebalance()
832 w += nexthop_nh->fib_nh_weight; in fib_rebalance()
834 total) - 1; in fib_rebalance()
837 atomic_set(&nexthop_nh->fib_nh_upper_bound, upper_bound); in fib_rebalance()
848 return -EINVAL; in fib_get_nhs()
870 result = lwtunnel_cmp_encap(lwtstate, nh->fib_nh_lws); in fib_encap_match()
885 if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority) in fib_nh_match()
888 if (cfg->fc_nh_id) { in fib_nh_match()
889 if (fi->nh && cfg->fc_nh_id == fi->nh->id) in fib_nh_match()
894 if (fi->nh) { in fib_nh_match()
895 if (cfg->fc_oif || cfg->fc_gw_family || cfg->fc_mp) in fib_nh_match()
900 if (cfg->fc_oif || cfg->fc_gw_family) { in fib_nh_match()
904 if (cfg->fc_encap) { in fib_nh_match()
905 if (fib_encap_match(net, cfg->fc_encap_type, in fib_nh_match()
906 cfg->fc_encap, nh, cfg, extack)) in fib_nh_match()
910 if (cfg->fc_flow && in fib_nh_match()
911 cfg->fc_flow != nh->nh_tclassid) in fib_nh_match()
914 if ((cfg->fc_oif && cfg->fc_oif != nh->fib_nh_oif) || in fib_nh_match()
915 (cfg->fc_gw_family && in fib_nh_match()
916 cfg->fc_gw_family != nh->fib_nh_gw_family)) in fib_nh_match()
919 if (cfg->fc_gw_family == AF_INET && in fib_nh_match()
920 cfg->fc_gw4 != nh->fib_nh_gw4) in fib_nh_match()
923 if (cfg->fc_gw_family == AF_INET6 && in fib_nh_match()
924 ipv6_addr_cmp(&cfg->fc_gw6, &nh->fib_nh_gw6)) in fib_nh_match()
931 if (!cfg->fc_mp) in fib_nh_match()
934 rtnh = cfg->fc_mp; in fib_nh_match()
935 remaining = cfg->fc_mp_len; in fib_nh_match()
941 return -EINVAL; in fib_nh_match()
943 if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->fib_nh_oif) in fib_nh_match()
956 return -EINVAL; in fib_nh_match()
966 if (nh->fib_nh_gw_family != AF_INET || in fib_nh_match()
967 gw != nh->fib_nh_gw4) in fib_nh_match()
976 switch (nh->fib_nh_gw_family) { in fib_nh_match()
979 cfg2.fc_gw4 != nh->fib_nh_gw4) in fib_nh_match()
985 &nh->fib_nh_gw6)) in fib_nh_match()
996 return -EINVAL; in fib_nh_match()
998 if (nla_get_u32(nla) != nh->nh_tclassid) in fib_nh_match()
1015 if (!cfg->fc_mx) in fib_metrics_match()
1018 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { in fib_metrics_match()
1040 fi_val = fi->fib_metrics->metrics[type - 1]; in fib_metrics_match()
1056 .fc_flags = nh->fib_nh_flags | RTF_GATEWAY, in fib_check_nh_v6_gw()
1057 .fc_ifindex = nh->fib_nh_oif, in fib_check_nh_v6_gw()
1058 .fc_gateway = nh->fib_nh_gw6, in fib_check_nh_v6_gw()
1063 err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack); in fib_check_nh_v6_gw()
1065 nh->fib_nh_dev = fib6_nh.fib_nh_dev; in fib_check_nh_v6_gw()
1066 netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, in fib_check_nh_v6_gw()
1068 nh->fib_nh_oif = nh->fib_nh_dev->ifindex; in fib_check_nh_v6_gw()
1069 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v6_gw()
1071 ipv6_stub->fib6_nh_release(&fib6_nh); in fib_check_nh_v6_gw()
1079 * -------
1085 * b) gateway must be on-link address, possibly
1089 * d) If we use tunnel routes, gateway could be not on-link.
1091 * Attempt to reconcile all of these (alas, self-contradictory) conditions
1108 * consistent and very flexible. F.e. as by-product it allows
1109 * to co-exists in peace independent exterior and interior
1114 * {universe prefix} -> (gw, oif) [scope link]
1116 * |-> {link prefix} -> (gw, oif) [scope local]
1118 * |-> {local prefix} (terminal node)
1127 if (nh->fib_nh_flags & RTNH_F_ONLINK) { in fib_check_nh_v4_gw()
1132 return -EINVAL; in fib_check_nh_v4_gw()
1134 dev = __dev_get_by_index(net, nh->fib_nh_oif); in fib_check_nh_v4_gw()
1137 return -ENODEV; in fib_check_nh_v4_gw()
1139 if (!(dev->flags & IFF_UP)) { in fib_check_nh_v4_gw()
1141 return -ENETDOWN; in fib_check_nh_v4_gw()
1143 addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4); in fib_check_nh_v4_gw()
1146 return -EINVAL; in fib_check_nh_v4_gw()
1149 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1150 nh->fib_nh_dev = dev; in fib_check_nh_v4_gw()
1151 netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_v4_gw()
1152 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v4_gw()
1159 .daddr = nh->fib_nh_gw4, in fib_check_nh_v4_gw()
1161 .flowi4_oif = nh->fib_nh_oif, in fib_check_nh_v4_gw()
1192 err = -EINVAL; in fib_check_nh_v4_gw()
1197 nh->fib_nh_scope = res.scope; in fib_check_nh_v4_gw()
1198 nh->fib_nh_oif = FIB_RES_OIF(res); in fib_check_nh_v4_gw()
1199 nh->fib_nh_dev = dev = FIB_RES_DEV(res); in fib_check_nh_v4_gw()
1205 netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_v4_gw()
1207 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1208 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; in fib_check_nh_v4_gw()
1220 if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) { in fib_check_nh_nongw()
1222 "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set"); in fib_check_nh_nongw()
1223 return -EINVAL; in fib_check_nh_nongw()
1228 err = -ENODEV; in fib_check_nh_nongw()
1229 in_dev = inetdev_by_index(net, nh->fib_nh_oif); in fib_check_nh_nongw()
1232 err = -ENETDOWN; in fib_check_nh_nongw()
1233 if (!(in_dev->dev->flags & IFF_UP)) { in fib_check_nh_nongw()
1238 nh->fib_nh_dev = in_dev->dev; in fib_check_nh_nongw()
1239 netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_nongw()
1240 nh->fib_nh_scope = RT_SCOPE_HOST; in fib_check_nh_nongw()
1241 if (!netif_carrier_ok(nh->fib_nh_dev)) in fib_check_nh_nongw()
1242 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_nongw()
1254 if (nh->fib_nh_gw_family == AF_INET) in fib_check_nh()
1256 else if (nh->fib_nh_gw_family == AF_INET6) in fib_check_nh()
1298 hlist_add_head(&fi->fib_hash, dest); in fib_info_hash_move()
1312 ldest = fib_info_laddrhash_bucket(fi->fib_net, in fib_info_hash_move()
1313 fi->fib_prefsrc); in fib_info_hash_move()
1314 hlist_add_head(&fi->fib_lhash, ldest); in fib_info_hash_move()
1330 if (nhc->nhc_family != AF_INET) in fib_info_update_nhc_saddr()
1331 return inet_select_addr(nhc->nhc_dev, 0, scope); in fib_info_update_nhc_saddr()
1334 saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope); in fib_info_update_nhc_saddr()
1336 WRITE_ONCE(nh->nh_saddr, saddr); in fib_info_update_nhc_saddr()
1337 WRITE_ONCE(nh->nh_saddr_genid, atomic_read(&net->ipv4.dev_addr_genid)); in fib_info_update_nhc_saddr()
1344 struct fib_nh_common *nhc = res->nhc; in fib_result_prefsrc()
1346 if (res->fi->fib_prefsrc) in fib_result_prefsrc()
1347 return res->fi->fib_prefsrc; in fib_result_prefsrc()
1349 if (nhc->nhc_family == AF_INET) { in fib_result_prefsrc()
1353 if (READ_ONCE(nh->nh_saddr_genid) == in fib_result_prefsrc()
1354 atomic_read(&net->ipv4.dev_addr_genid)) in fib_result_prefsrc()
1355 return READ_ONCE(nh->nh_saddr); in fib_result_prefsrc()
1358 return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope); in fib_result_prefsrc()
1363 if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || in fib_valid_prefsrc()
1364 fib_prefsrc != cfg->fc_dst) { in fib_valid_prefsrc()
1365 u32 tb_id = cfg->fc_table; in fib_valid_prefsrc()
1371 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1375 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1393 struct net *net = cfg->fc_nlinfo.nl_net; in fib_create_info()
1395 if (cfg->fc_type > RTN_MAX) in fib_create_info()
1399 if (fib_props[cfg->fc_type].scope > cfg->fc_scope) { in fib_create_info()
1404 if (cfg->fc_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) { in fib_create_info()
1406 "Invalid rtm_flags - can not contain DEAD or LINKDOWN"); in fib_create_info()
1410 if (cfg->fc_nh_id) { in fib_create_info()
1411 if (!cfg->fc_mx) { in fib_create_info()
1414 refcount_inc(&fi->fib_treeref); in fib_create_info()
1419 nh = nexthop_find_by_id(net, cfg->fc_nh_id); in fib_create_info()
1428 if (cfg->fc_mp) { in fib_create_info()
1429 nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len, extack); in fib_create_info()
1435 err = -ENOBUFS; in fib_create_info()
1462 fi->fib_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len, extack); in fib_create_info()
1463 if (IS_ERR(fi->fib_metrics)) { in fib_create_info()
1464 err = PTR_ERR(fi->fib_metrics); in fib_create_info()
1469 fi->fib_net = net; in fib_create_info()
1470 fi->fib_protocol = cfg->fc_protocol; in fib_create_info()
1471 fi->fib_scope = cfg->fc_scope; in fib_create_info()
1472 fi->fib_flags = cfg->fc_flags; in fib_create_info()
1473 fi->fib_priority = cfg->fc_priority; in fib_create_info()
1474 fi->fib_prefsrc = cfg->fc_prefsrc; in fib_create_info()
1475 fi->fib_type = cfg->fc_type; in fib_create_info()
1476 fi->fib_tb_id = cfg->fc_table; in fib_create_info()
1478 fi->fib_nhs = nhs; in fib_create_info()
1482 err = -EINVAL; in fib_create_info()
1485 fi->nh = nh; in fib_create_info()
1489 nexthop_nh->nh_parent = fi; in fib_create_info()
1492 if (cfg->fc_mp) in fib_create_info()
1493 err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, in fib_create_info()
1496 err = fib_nh_init(net, fi->fib_nh, cfg, 1, extack); in fib_create_info()
1502 if (fib_props[cfg->fc_type].error) { in fib_create_info()
1503 if (cfg->fc_gw_family || cfg->fc_oif || cfg->fc_mp) { in fib_create_info()
1510 switch (cfg->fc_type) { in fib_create_info()
1523 if (cfg->fc_scope > RT_SCOPE_HOST) { in fib_create_info()
1528 if (fi->nh) { in fib_create_info()
1529 err = fib_check_nexthop(fi->nh, cfg->fc_scope, extack); in fib_create_info()
1532 } else if (cfg->fc_scope == RT_SCOPE_HOST) { in fib_create_info()
1533 struct fib_nh *nh = fi->fib_nh; in fib_create_info()
1541 if (nh->fib_nh_gw_family) { in fib_create_info()
1546 nh->fib_nh_scope = RT_SCOPE_NOWHERE; in fib_create_info()
1547 nh->fib_nh_dev = dev_get_by_index(net, nh->fib_nh_oif); in fib_create_info()
1548 err = -ENODEV; in fib_create_info()
1549 if (!nh->fib_nh_dev) in fib_create_info()
1551 netdev_tracker_alloc(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, in fib_create_info()
1557 err = fib_check_nh(cfg->fc_nlinfo.nl_net, nexthop_nh, in fib_create_info()
1558 cfg->fc_table, cfg->fc_scope, in fib_create_info()
1562 if (nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN) in fib_create_info()
1565 if (linkdown == fi->fib_nhs) in fib_create_info()
1566 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_create_info()
1569 if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { in fib_create_info()
1574 if (!fi->nh) { in fib_create_info()
1576 fib_info_update_nhc_saddr(net, &nexthop_nh->nh_common, in fib_create_info()
1577 fi->fib_scope); in fib_create_info()
1578 if (nexthop_nh->fib_nh_gw_family == AF_INET6) in fib_create_info()
1579 fi->fib_nh_is_v6 = true; in fib_create_info()
1589 fi->fib_dead = 1; in fib_create_info()
1591 refcount_inc(&ofi->fib_treeref); in fib_create_info()
1595 refcount_set(&fi->fib_treeref, 1); in fib_create_info()
1596 refcount_set(&fi->fib_clntref, 1); in fib_create_info()
1599 hlist_add_head(&fi->fib_hash, in fib_create_info()
1601 if (fi->fib_prefsrc) { in fib_create_info()
1604 head = fib_info_laddrhash_bucket(net, fi->fib_prefsrc); in fib_create_info()
1605 hlist_add_head(&fi->fib_lhash, head); in fib_create_info()
1607 if (fi->nh) { in fib_create_info()
1608 list_add(&fi->nh_list, &nh->fi_list); in fib_create_info()
1613 if (!nexthop_nh->fib_nh_dev) in fib_create_info()
1615 head = fib_info_devhash_bucket(nexthop_nh->fib_nh_dev); in fib_create_info()
1616 hlist_add_head(&nexthop_nh->nh_hash, head); in fib_create_info()
1623 err = -EINVAL; in fib_create_info()
1628 fi->fib_dead = 1; in fib_create_info()
1638 if (nhc->nhc_flags & RTNH_F_DEAD) in fib_nexthop_info()
1641 if (nhc->nhc_flags & RTNH_F_LINKDOWN) { in fib_nexthop_info()
1645 switch (nhc->nhc_family) { in fib_nexthop_info()
1647 if (ip_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1651 if (ip6_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1658 switch (nhc->nhc_gw_family) { in fib_nexthop_info()
1660 if (nla_put_in_addr(skb, RTA_GATEWAY, nhc->nhc_gw.ipv4)) in fib_nexthop_info()
1667 if (rt_family != nhc->nhc_gw_family) { in fib_nexthop_info()
1677 via->rtvia_family = AF_INET6; in fib_nexthop_info()
1678 memcpy(via->rtvia_addr, &nhc->nhc_gw.ipv6, alen); in fib_nexthop_info()
1680 &nhc->nhc_gw.ipv6) < 0) { in fib_nexthop_info()
1686 *flags |= (nhc->nhc_flags & in fib_nexthop_info()
1689 if (!skip_oif && nhc->nhc_dev && in fib_nexthop_info()
1690 nla_put_u32(skb, RTA_OIF, nhc->nhc_dev->ifindex)) in fib_nexthop_info()
1693 if (nhc->nhc_lwtstate && in fib_nexthop_info()
1694 lwtunnel_fill_encap(skb, nhc->nhc_lwtstate, in fib_nexthop_info()
1701 return -EMSGSIZE; in fib_nexthop_info()
1709 const struct net_device *dev = nhc->nhc_dev; in fib_add_nexthop()
1717 rtnh->rtnh_hops = nh_weight - 1; in fib_add_nexthop()
1718 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0; in fib_add_nexthop()
1723 rtnh->rtnh_flags = flags; in fib_add_nexthop()
1729 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh; in fib_add_nexthop()
1734 return -EMSGSIZE; in fib_add_nexthop()
1748 if (unlikely(fi->nh)) { in fib_add_multipath()
1749 if (nexthop_mpath_fill_node(skb, fi->nh, AF_INET) < 0) in fib_add_multipath()
1757 nh_tclassid = nh->nh_tclassid; in fib_add_multipath()
1759 if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight, in fib_add_multipath()
1770 return -EMSGSIZE; in fib_add_multipath()
1782 unsigned int nhs = fib_info_num_path(fri->fi); in fib_dump_info()
1783 struct fib_info *fi = fri->fi; in fib_dump_info()
1784 u32 tb_id = fri->tb_id; in fib_dump_info()
1786 struct rtmsg *rtm; in fib_dump_info() local
1788 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); in fib_dump_info()
1790 return -EMSGSIZE; in fib_dump_info()
1792 rtm = nlmsg_data(nlh); in fib_dump_info()
1793 rtm->rtm_family = AF_INET; in fib_dump_info()
1794 rtm->rtm_dst_len = fri->dst_len; in fib_dump_info()
1795 rtm->rtm_src_len = 0; in fib_dump_info()
1796 rtm->rtm_tos = inet_dscp_to_dsfield(fri->dscp); in fib_dump_info()
1798 rtm->rtm_table = tb_id; in fib_dump_info()
1800 rtm->rtm_table = RT_TABLE_COMPAT; in fib_dump_info()
1803 rtm->rtm_type = fri->type; in fib_dump_info()
1804 rtm->rtm_flags = fi->fib_flags; in fib_dump_info()
1805 rtm->rtm_scope = fi->fib_scope; in fib_dump_info()
1806 rtm->rtm_protocol = fi->fib_protocol; in fib_dump_info()
1808 if (rtm->rtm_dst_len && in fib_dump_info()
1809 nla_put_in_addr(skb, RTA_DST, fri->dst)) in fib_dump_info()
1811 if (fi->fib_priority && in fib_dump_info()
1812 nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) in fib_dump_info()
1814 if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0) in fib_dump_info()
1817 if (fi->fib_prefsrc && in fib_dump_info()
1818 nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc)) in fib_dump_info()
1821 if (fi->nh) { in fib_dump_info()
1822 if (nla_put_u32(skb, RTA_NH_ID, fi->nh->id)) in fib_dump_info()
1824 if (nexthop_is_blackhole(fi->nh)) in fib_dump_info()
1825 rtm->rtm_type = RTN_BLACKHOLE; in fib_dump_info()
1826 if (!READ_ONCE(fi->fib_net->ipv4.sysctl_nexthop_compat_mode)) in fib_dump_info()
1837 rtm->rtm_flags = flags; in fib_dump_info()
1839 if (nhc->nhc_family == AF_INET) { in fib_dump_info()
1843 if (nh->nh_tclassid && in fib_dump_info()
1844 nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) in fib_dump_info()
1854 if (fri->offload) in fib_dump_info()
1855 rtm->rtm_flags |= RTM_F_OFFLOAD; in fib_dump_info()
1856 if (fri->trap) in fib_dump_info()
1857 rtm->rtm_flags |= RTM_F_TRAP; in fib_dump_info()
1858 if (fri->offload_failed) in fib_dump_info()
1859 rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED; in fib_dump_info()
1866 return -EMSGSIZE; in fib_dump_info()
1871 * - local address disappeared -> we must delete all the entries
1873 * - device went down -> we must shutdown all nexthops going via it.
1888 if (!net_eq(fi->fib_net, net) || in fib_sync_down_addr()
1889 fi->fib_tb_id != tb_id) in fib_sync_down_addr()
1891 if (fi->fib_prefsrc == local) { in fib_sync_down_addr()
1892 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_addr()
1893 fi->pfsrc_removed = true; in fib_sync_down_addr()
1903 bool ignore_link_down = ip_ignore_linkdown(nh->fib_nh_dev); in call_fib_nh_notifiers()
1910 if (nh->fib_nh_flags & RTNH_F_DEAD) in call_fib_nh_notifiers()
1912 if (ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) in call_fib_nh_notifiers()
1914 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), event_type, in call_fib_nh_notifiers()
1917 if ((ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) || in call_fib_nh_notifiers()
1918 (nh->fib_nh_flags & RTNH_F_DEAD)) in call_fib_nh_notifiers()
1919 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), in call_fib_nh_notifiers()
1930 * - the new MTU of the first hop becomes smaller than the PMTU
1931 * - the old MTU was the same as the PMTU, and it limited discovery of
1936 * - if the new MTU is greater than the PMTU, don't make any change
1937 * - otherwise, unlock and set PMTU
1944 bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1); in fib_nhc_update_mtu()
1953 fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) { in fib_nhc_update_mtu()
1954 if (fnhe->fnhe_mtu_locked) { in fib_nhc_update_mtu()
1955 if (new <= fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1956 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1957 fnhe->fnhe_mtu_locked = false; in fib_nhc_update_mtu()
1959 } else if (new < fnhe->fnhe_pmtu || in fib_nhc_update_mtu()
1960 orig == fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1961 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1973 if (nh->fib_nh_dev == dev) in fib_sync_mtu()
1974 fib_nhc_update_mtu(&nh->nh_common, dev->mtu, orig_mtu); in fib_sync_mtu()
1995 scope = -1; in fib_sync_down_dev()
1998 struct fib_info *fi = nh->nh_parent; in fib_sync_down_dev()
2001 BUG_ON(!fi->fib_nhs); in fib_sync_down_dev()
2002 if (nh->fib_nh_dev != dev || fi == prev_fi) in fib_sync_down_dev()
2007 if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD) in fib_sync_down_dev()
2009 else if (nexthop_nh->fib_nh_dev == dev && in fib_sync_down_dev()
2010 nexthop_nh->fib_nh_scope != scope) { in fib_sync_down_dev()
2014 nexthop_nh->fib_nh_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
2017 nexthop_nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2026 nexthop_nh->fib_nh_dev == dev) { in fib_sync_down_dev()
2027 dead = fi->fib_nhs; in fib_sync_down_dev()
2032 if (dead == fi->fib_nhs) { in fib_sync_down_dev()
2036 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
2039 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2055 struct hlist_head *fa_head = res->fa_head; in fib_select_default()
2056 struct fib_table *tb = res->table; in fib_select_default()
2057 u8 slen = 32 - res->prefixlen; in fib_select_default()
2058 int order = -1, last_idx = -1; in fib_select_default()
2060 u32 last_prio = res->fi->fib_priority; in fib_select_default()
2064 struct fib_info *next_fi = fa->fa_info; in fib_select_default()
2067 if (fa->fa_slen != slen) in fib_select_default()
2069 if (fa->fa_dscp && in fib_select_default()
2070 fa->fa_dscp != inet_dsfield_to_dscp(flp->flowi4_tos)) in fib_select_default()
2072 if (fa->tb_id != tb->tb_id) in fib_select_default()
2074 if (next_fi->fib_priority > last_prio && in fib_select_default()
2075 fa->fa_dscp == last_dscp) { in fib_select_default()
2080 if (next_fi->fib_flags & RTNH_F_DEAD) in fib_select_default()
2082 last_dscp = fa->fa_dscp; in fib_select_default()
2083 last_prio = next_fi->fib_priority; in fib_select_default()
2085 if (next_fi->fib_scope != res->scope || in fib_select_default()
2086 fa->fa_type != RTN_UNICAST) in fib_select_default()
2090 if (!nhc->nhc_gw_family || nhc->nhc_scope != RT_SCOPE_LINK) in fib_select_default()
2096 if (next_fi != res->fi) in fib_select_default()
2100 &last_idx, fa1->fa_default)) { in fib_select_default()
2102 fa1->fa_default = order; in fib_select_default()
2111 fa1->fa_default = -1; in fib_select_default()
2116 fa1->fa_default)) { in fib_select_default()
2118 fa1->fa_default = order; in fib_select_default()
2124 fa1->fa_default = last_idx; in fib_select_default()
2142 if (!(dev->flags & IFF_UP)) in fib_sync_up()
2157 struct fib_info *fi = nh->nh_parent; in fib_sync_up()
2160 BUG_ON(!fi->fib_nhs); in fib_sync_up()
2161 if (nh->fib_nh_dev != dev || fi == prev_fi) in fib_sync_up()
2167 if (!(nexthop_nh->fib_nh_flags & nh_flags)) { in fib_sync_up()
2171 if (!nexthop_nh->fib_nh_dev || in fib_sync_up()
2172 !(nexthop_nh->fib_nh_dev->flags & IFF_UP)) in fib_sync_up()
2174 if (nexthop_nh->fib_nh_dev != dev || in fib_sync_up()
2178 nexthop_nh->fib_nh_flags &= ~nh_flags; in fib_sync_up()
2183 fi->fib_flags &= ~nh_flags; in fib_sync_up()
2198 if (nh->fib_nh_scope == RT_SCOPE_LINK) { in fib_good_nh()
2203 if (likely(nh->fib_nh_gw_family == AF_INET)) in fib_good_nh()
2204 n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev, in fib_good_nh()
2205 (__force u32)nh->fib_nh_gw4); in fib_good_nh()
2206 else if (nh->fib_nh_gw_family == AF_INET6) in fib_good_nh()
2207 n = __ipv6_neigh_lookup_noref_stub(nh->fib_nh_dev, in fib_good_nh()
2208 &nh->fib_nh_gw6); in fib_good_nh()
2212 state = READ_ONCE(n->nud_state); in fib_good_nh()
2222 struct fib_info *fi = res->fi; in fib_select_multipath()
2223 struct net *net = fi->fib_net; in fib_select_multipath()
2226 if (unlikely(res->fi->nh)) { in fib_select_multipath()
2232 if (READ_ONCE(net->ipv4.sysctl_fib_multipath_use_neigh)) { in fib_select_multipath()
2236 res->nh_sel = nhsel; in fib_select_multipath()
2237 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2242 if (hash > atomic_read(&nexthop_nh->fib_nh_upper_bound)) in fib_select_multipath()
2245 res->nh_sel = nhsel; in fib_select_multipath()
2246 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2255 if (fl4->flowi4_oif) in fib_select_path()
2259 if (fib_info_num_path(res->fi) > 1) { in fib_select_path()
2266 if (!res->prefixlen && in fib_select_path()
2267 res->table->tb_num_default > 1 && in fib_select_path()
2268 res->type == RTN_UNICAST) in fib_select_path()
2272 if (!fl4->saddr) { in fib_select_path()
2275 l3mdev = dev_get_by_index_rcu(net, fl4->flowi4_l3mdev); in fib_select_path()
2279 fl4->saddr = fib_result_prefsrc(net, res); in fib_select_path()
2281 fl4->saddr = inet_select_addr(l3mdev, 0, RT_SCOPE_LINK); in fib_select_path()