Lines Matching +full:use +full:- +full:rtm
1 // SPDX-License-Identifier: GPL-2.0-or-later
66 for (nhsel = 0, nh = (fi)->fib_nh; \
72 for (nhsel = 0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
81 int nhsel; const struct fib_nh *nh = (fi)->fib_nh; \
86 struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
120 .error = -EINVAL,
124 .error = -EHOSTUNREACH,
128 .error = -EACCES,
132 .error = -EAGAIN,
136 .error = -EINVAL,
140 .error = -EINVAL,
157 dst_dev_put(&rt->dst); in rt_fibinfo_free()
158 dst_release_immediate(&rt->dst); in rt_fibinfo_free()
166 hash = rcu_dereference_protected(nhc->nhc_exceptions, 1); in free_nh_exceptions()
176 next = rcu_dereference_protected(fnhe->fnhe_next, 1); in free_nh_exceptions()
178 rt_fibinfo_free(&fnhe->fnhe_rth_input); in free_nh_exceptions()
179 rt_fibinfo_free(&fnhe->fnhe_rth_output); in free_nh_exceptions()
201 dst_dev_put(&rt->dst); in rt_fibinfo_free_cpus()
202 dst_release_immediate(&rt->dst); in rt_fibinfo_free_cpus()
210 netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker); in fib_nh_common_release()
211 lwtstate_put(nhc->nhc_lwtstate); in fib_nh_common_release()
212 rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); in fib_nh_common_release()
213 rt_fibinfo_free(&nhc->nhc_rth_input); in fib_nh_common_release()
221 if (fib_nh->nh_tclassid) in fib_nh_release()
222 atomic_dec(&net->ipv4.fib_num_tclassid_users); in fib_nh_release()
224 fib_nh_common_release(&fib_nh->nh_common); in fib_nh_release()
232 if (fi->nh) { in free_fib_info_rcu()
233 nexthop_put(fi->nh); in free_fib_info_rcu()
236 fib_nh_release(fi->fib_net, nexthop_nh); in free_fib_info_rcu()
240 ip_fib_metrics_put(fi->fib_metrics); in free_fib_info_rcu()
247 if (fi->fib_dead == 0) { in free_fib_info()
252 call_rcu_hurry(&fi->rcu, free_fib_info_rcu); in free_fib_info()
259 if (fi && refcount_dec_and_test(&fi->fib_treeref)) { in fib_release_info()
260 hlist_del(&fi->fib_hash); in fib_release_info()
262 fib_info_cnt--; in fib_release_info()
264 if (fi->fib_prefsrc) in fib_release_info()
265 hlist_del(&fi->fib_lhash); in fib_release_info()
266 if (fi->nh) { in fib_release_info()
267 list_del(&fi->nh_list); in fib_release_info()
270 if (!nexthop_nh->fib_nh_dev) in fib_release_info()
272 hlist_del_rcu(&nexthop_nh->nh_hash); in fib_release_info()
276 WRITE_ONCE(fi->fib_dead, 1); in fib_release_info()
285 if (fi->nh || ofi->nh) in nh_comp()
286 return nexthop_cmp(fi->nh, ofi->nh) ? 0 : -1; in nh_comp()
288 if (ofi->fib_nhs == 0) in nh_comp()
294 if (nh->fib_nh_oif != onh->fib_nh_oif || in nh_comp()
295 nh->fib_nh_gw_family != onh->fib_nh_gw_family || in nh_comp()
296 nh->fib_nh_scope != onh->fib_nh_scope || in nh_comp()
298 nh->fib_nh_weight != onh->fib_nh_weight || in nh_comp()
301 nh->nh_tclassid != onh->nh_tclassid || in nh_comp()
303 lwtunnel_cmp_encap(nh->fib_nh_lws, onh->fib_nh_lws) || in nh_comp()
304 ((nh->fib_nh_flags ^ onh->fib_nh_flags) & ~RTNH_COMPARE_MASK)) in nh_comp()
305 return -1; in nh_comp()
307 if (nh->fib_nh_gw_family == AF_INET && in nh_comp()
308 nh->fib_nh_gw4 != onh->fib_nh_gw4) in nh_comp()
309 return -1; in nh_comp()
311 if (nh->fib_nh_gw_family == AF_INET6 && in nh_comp()
312 ipv6_addr_cmp(&nh->fib_nh_gw6, &onh->fib_nh_gw6)) in nh_comp()
313 return -1; in nh_comp()
320 return &dev->fib_nh_head; in fib_nh_head()
345 val = fib_info_hashfn_1(fi->fib_nhs, fi->fib_protocol, in fib_info_hashfn()
346 fi->fib_scope, (__force u32)fi->fib_prefsrc, in fib_info_hashfn()
347 fi->fib_priority); in fib_info_hashfn()
349 if (fi->nh) { in fib_info_hashfn()
350 val ^= fi->nh->id; in fib_info_hashfn()
353 val ^= nh->fib_nh_oif; in fib_info_hashfn()
357 return fib_info_hashfn_result(fi->fib_net, val); in fib_info_hashfn()
368 hash = fib_info_hashfn_1(cfg->fc_nh_id, in fib_find_info_nh()
369 cfg->fc_protocol, cfg->fc_scope, in fib_find_info_nh()
370 (__force u32)cfg->fc_prefsrc, in fib_find_info_nh()
371 cfg->fc_priority); in fib_find_info_nh()
376 if (!net_eq(fi->fib_net, net)) in fib_find_info_nh()
378 if (!fi->nh || fi->nh->id != cfg->fc_nh_id) in fib_find_info_nh()
380 if (cfg->fc_protocol == fi->fib_protocol && in fib_find_info_nh()
381 cfg->fc_scope == fi->fib_scope && in fib_find_info_nh()
382 cfg->fc_prefsrc == fi->fib_prefsrc && in fib_find_info_nh()
383 cfg->fc_priority == fi->fib_priority && in fib_find_info_nh()
384 cfg->fc_type == fi->fib_type && in fib_find_info_nh()
385 cfg->fc_table == fi->fib_tb_id && in fib_find_info_nh()
386 !((cfg->fc_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK)) in fib_find_info_nh()
403 if (!net_eq(fi->fib_net, nfi->fib_net)) in fib_find_info()
405 if (fi->fib_nhs != nfi->fib_nhs) in fib_find_info()
407 if (nfi->fib_protocol == fi->fib_protocol && in fib_find_info()
408 nfi->fib_scope == fi->fib_scope && in fib_find_info()
409 nfi->fib_prefsrc == fi->fib_prefsrc && in fib_find_info()
410 nfi->fib_priority == fi->fib_priority && in fib_find_info()
411 nfi->fib_type == fi->fib_type && in fib_find_info()
412 nfi->fib_tb_id == fi->fib_tb_id && in fib_find_info()
413 memcmp(nfi->fib_metrics, fi->fib_metrics, in fib_find_info()
415 !((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK) && in fib_find_info()
434 DEBUG_NET_WARN_ON_ONCE(nh->fib_nh_dev != dev); in ip_fib_check_default()
435 if (nh->fib_nh_gw4 == gw && in ip_fib_check_default()
436 !(nh->fib_nh_flags & RTNH_F_DEAD)) { in ip_fib_check_default()
441 return -1; in ip_fib_check_default()
457 if (fi->nh) in fib_nlmsg_size()
475 if (nhc->nhc_lwtstate) { in fib_nlmsg_size()
478 nhc->nhc_lwtstate); in fib_nlmsg_size()
498 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; in rtmsg_fib()
499 int err = -ENOBUFS; in rtmsg_fib()
501 skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); in rtmsg_fib()
505 fri.fi = fa->fa_info; in rtmsg_fib()
509 fri.dscp = fa->fa_dscp; in rtmsg_fib()
510 fri.type = fa->fa_type; in rtmsg_fib()
511 fri.offload = READ_ONCE(fa->offload); in rtmsg_fib()
512 fri.trap = READ_ONCE(fa->trap); in rtmsg_fib()
513 fri.offload_failed = READ_ONCE(fa->offload_failed); in rtmsg_fib()
514 err = fib_dump_info(skb, info->portid, seq, event, &fri, nlm_flags); in rtmsg_fib()
516 /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ in rtmsg_fib()
517 WARN_ON(err == -EMSGSIZE); in rtmsg_fib()
521 rtnl_notify(skb, info->nl_net, info->portid, RTNLGRP_IPV4_ROUTE, in rtmsg_fib()
522 info->nlh, GFP_KERNEL); in rtmsg_fib()
525 rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); in rtmsg_fib()
536 if (likely(nhc->nhc_gw_family == AF_INET)) in fib_detect_death()
537 n = neigh_lookup(&arp_tbl, &nhc->nhc_gw.ipv4, nhc->nhc_dev); in fib_detect_death()
538 else if (nhc->nhc_gw_family == AF_INET6) in fib_detect_death()
539 n = neigh_lookup(ipv6_stub->nd_tbl, &nhc->nhc_gw.ipv6, in fib_detect_death()
540 nhc->nhc_dev); in fib_detect_death()
545 state = READ_ONCE(n->nud_state); in fib_detect_death()
569 nhc->nhc_pcpu_rth_output = alloc_percpu_gfp(struct rtable __rcu *, in fib_nh_common_init()
571 if (!nhc->nhc_pcpu_rth_output) in fib_nh_common_init()
572 return -ENOMEM; in fib_nh_common_init()
579 err = -EINVAL; in fib_nh_common_init()
583 nhc->nhc_family, cfg, &lwtstate, in fib_nh_common_init()
588 nhc->nhc_lwtstate = lwtstate_get(lwtstate); in fib_nh_common_init()
594 rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); in fib_nh_common_init()
595 nhc->nhc_pcpu_rth_output = NULL; in fib_nh_common_init()
606 nh->fib_nh_family = AF_INET; in fib_nh_init()
608 err = fib_nh_common_init(net, &nh->nh_common, cfg->fc_encap, in fib_nh_init()
609 cfg->fc_encap_type, cfg, GFP_KERNEL, extack); in fib_nh_init()
613 nh->fib_nh_oif = cfg->fc_oif; in fib_nh_init()
614 nh->fib_nh_gw_family = cfg->fc_gw_family; in fib_nh_init()
615 if (cfg->fc_gw_family == AF_INET) in fib_nh_init()
616 nh->fib_nh_gw4 = cfg->fc_gw4; in fib_nh_init()
617 else if (cfg->fc_gw_family == AF_INET6) in fib_nh_init()
618 nh->fib_nh_gw6 = cfg->fc_gw6; in fib_nh_init()
620 nh->fib_nh_flags = cfg->fc_flags; in fib_nh_init()
623 nh->nh_tclassid = cfg->fc_flow; in fib_nh_init()
624 if (nh->nh_tclassid) in fib_nh_init()
625 atomic_inc(&net->ipv4.fib_num_tclassid_users); in fib_nh_init()
628 nh->fib_nh_weight = nh_weight; in fib_nh_init()
648 "Invalid nexthop configuration - extra data after nexthops"); in fib_count_nexthops()
660 return -EINVAL; in fib_gw_from_attr()
673 struct net *net = fi->fib_net; in fib_get_nhs()
685 "Invalid nexthop configuration - extra data after nexthop"); in fib_get_nhs()
686 return -EINVAL; in fib_get_nhs()
689 if (rtnh->rtnh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) { in fib_get_nhs()
691 "Invalid flags for nexthop - can not contain DEAD or LINKDOWN"); in fib_get_nhs()
692 return -EINVAL; in fib_get_nhs()
695 fib_cfg.fc_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; in fib_get_nhs()
696 fib_cfg.fc_oif = rtnh->rtnh_ifindex; in fib_get_nhs()
707 return -EINVAL; in fib_get_nhs()
727 return -EINVAL; in fib_get_nhs()
742 rtnh->rtnh_hops + 1, extack); in fib_get_nhs()
749 ret = -EINVAL; in fib_get_nhs()
751 if (cfg->fc_oif && nh->fib_nh_oif != cfg->fc_oif) { in fib_get_nhs()
756 if (cfg->fc_gw_family) { in fib_get_nhs()
757 if (cfg->fc_gw_family != nh->fib_nh_gw_family || in fib_get_nhs()
758 (cfg->fc_gw_family == AF_INET && in fib_get_nhs()
759 nh->fib_nh_gw4 != cfg->fc_gw4) || in fib_get_nhs()
760 (cfg->fc_gw_family == AF_INET6 && in fib_get_nhs()
761 ipv6_addr_cmp(&nh->fib_nh_gw6, &cfg->fc_gw6))) { in fib_get_nhs()
768 if (cfg->fc_flow && nh->nh_tclassid != cfg->fc_flow) { in fib_get_nhs()
790 if (nh->fib_nh_flags & RTNH_F_DEAD) in fib_rebalance()
793 if (ip_ignore_linkdown(nh->fib_nh_dev) && in fib_rebalance()
794 nh->fib_nh_flags & RTNH_F_LINKDOWN) in fib_rebalance()
797 total += nh->fib_nh_weight; in fib_rebalance()
804 if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD) { in fib_rebalance()
805 upper_bound = -1; in fib_rebalance()
806 } else if (ip_ignore_linkdown(nexthop_nh->fib_nh_dev) && in fib_rebalance()
807 nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN) { in fib_rebalance()
808 upper_bound = -1; in fib_rebalance()
810 w += nexthop_nh->fib_nh_weight; in fib_rebalance()
812 total) - 1; in fib_rebalance()
815 atomic_set(&nexthop_nh->fib_nh_upper_bound, upper_bound); in fib_rebalance()
826 return -EINVAL; in fib_get_nhs()
848 result = lwtunnel_cmp_encap(lwtstate, nh->fib_nh_lws); in fib_encap_match()
863 if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority) in fib_nh_match()
866 if (cfg->fc_nh_id) { in fib_nh_match()
867 if (fi->nh && cfg->fc_nh_id == fi->nh->id) in fib_nh_match()
872 if (fi->nh) { in fib_nh_match()
873 if (cfg->fc_oif || cfg->fc_gw_family || cfg->fc_mp) in fib_nh_match()
878 if (cfg->fc_oif || cfg->fc_gw_family) { in fib_nh_match()
882 if (cfg->fc_encap) { in fib_nh_match()
883 if (fib_encap_match(net, cfg->fc_encap_type, in fib_nh_match()
884 cfg->fc_encap, nh, cfg, extack)) in fib_nh_match()
888 if (cfg->fc_flow && in fib_nh_match()
889 cfg->fc_flow != nh->nh_tclassid) in fib_nh_match()
892 if ((cfg->fc_oif && cfg->fc_oif != nh->fib_nh_oif) || in fib_nh_match()
893 (cfg->fc_gw_family && in fib_nh_match()
894 cfg->fc_gw_family != nh->fib_nh_gw_family)) in fib_nh_match()
897 if (cfg->fc_gw_family == AF_INET && in fib_nh_match()
898 cfg->fc_gw4 != nh->fib_nh_gw4) in fib_nh_match()
901 if (cfg->fc_gw_family == AF_INET6 && in fib_nh_match()
902 ipv6_addr_cmp(&cfg->fc_gw6, &nh->fib_nh_gw6)) in fib_nh_match()
909 if (!cfg->fc_mp) in fib_nh_match()
912 rtnh = cfg->fc_mp; in fib_nh_match()
913 remaining = cfg->fc_mp_len; in fib_nh_match()
919 return -EINVAL; in fib_nh_match()
921 if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->fib_nh_oif) in fib_nh_match()
934 return -EINVAL; in fib_nh_match()
944 if (nh->fib_nh_gw_family != AF_INET || in fib_nh_match()
945 gw != nh->fib_nh_gw4) in fib_nh_match()
954 switch (nh->fib_nh_gw_family) { in fib_nh_match()
957 cfg2.fc_gw4 != nh->fib_nh_gw4) in fib_nh_match()
963 &nh->fib_nh_gw6)) in fib_nh_match()
974 return -EINVAL; in fib_nh_match()
976 if (nla_get_u32(nla) != nh->nh_tclassid) in fib_nh_match()
993 if (!cfg->fc_mx) in fib_metrics_match()
996 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { in fib_metrics_match()
1018 fi_val = fi->fib_metrics->metrics[type - 1]; in fib_metrics_match()
1034 .fc_flags = nh->fib_nh_flags | RTF_GATEWAY, in fib_check_nh_v6_gw()
1035 .fc_ifindex = nh->fib_nh_oif, in fib_check_nh_v6_gw()
1036 .fc_gateway = nh->fib_nh_gw6, in fib_check_nh_v6_gw()
1041 err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack); in fib_check_nh_v6_gw()
1043 nh->fib_nh_dev = fib6_nh.fib_nh_dev; in fib_check_nh_v6_gw()
1044 netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, in fib_check_nh_v6_gw()
1046 nh->fib_nh_oif = nh->fib_nh_dev->ifindex; in fib_check_nh_v6_gw()
1047 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v6_gw()
1049 ipv6_stub->fib6_nh_release(&fib6_nh); in fib_check_nh_v6_gw()
1057 * -------
1063 * b) gateway must be on-link address, possibly
1067 * d) If we use tunnel routes, gateway could be not on-link.
1069 * Attempt to reconcile all of these (alas, self-contradictory) conditions
1086 * consistent and very flexible. F.e. as by-product it allows
1087 * to co-exists in peace independent exterior and interior
1092 * {universe prefix} -> (gw, oif) [scope link]
1094 * |-> {link prefix} -> (gw, oif) [scope local]
1096 * |-> {local prefix} (terminal node)
1105 if (nh->fib_nh_flags & RTNH_F_ONLINK) { in fib_check_nh_v4_gw()
1110 return -EINVAL; in fib_check_nh_v4_gw()
1112 dev = __dev_get_by_index(net, nh->fib_nh_oif); in fib_check_nh_v4_gw()
1115 return -ENODEV; in fib_check_nh_v4_gw()
1117 if (!(dev->flags & IFF_UP)) { in fib_check_nh_v4_gw()
1119 return -ENETDOWN; in fib_check_nh_v4_gw()
1121 addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4); in fib_check_nh_v4_gw()
1124 return -EINVAL; in fib_check_nh_v4_gw()
1127 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1128 nh->fib_nh_dev = dev; in fib_check_nh_v4_gw()
1129 netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_v4_gw()
1130 nh->fib_nh_scope = RT_SCOPE_LINK; in fib_check_nh_v4_gw()
1137 .daddr = nh->fib_nh_gw4, in fib_check_nh_v4_gw()
1139 .flowi4_oif = nh->fib_nh_oif, in fib_check_nh_v4_gw()
1170 err = -EINVAL; in fib_check_nh_v4_gw()
1175 nh->fib_nh_scope = res.scope; in fib_check_nh_v4_gw()
1176 nh->fib_nh_oif = FIB_RES_OIF(res); in fib_check_nh_v4_gw()
1177 nh->fib_nh_dev = dev = FIB_RES_DEV(res); in fib_check_nh_v4_gw()
1183 netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_v4_gw()
1185 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_v4_gw()
1186 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; in fib_check_nh_v4_gw()
1198 if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) { in fib_check_nh_nongw()
1200 "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set"); in fib_check_nh_nongw()
1201 return -EINVAL; in fib_check_nh_nongw()
1206 err = -ENODEV; in fib_check_nh_nongw()
1207 in_dev = inetdev_by_index(net, nh->fib_nh_oif); in fib_check_nh_nongw()
1210 err = -ENETDOWN; in fib_check_nh_nongw()
1211 if (!(in_dev->dev->flags & IFF_UP)) { in fib_check_nh_nongw()
1216 nh->fib_nh_dev = in_dev->dev; in fib_check_nh_nongw()
1217 netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); in fib_check_nh_nongw()
1218 nh->fib_nh_scope = RT_SCOPE_HOST; in fib_check_nh_nongw()
1219 if (!netif_carrier_ok(nh->fib_nh_dev)) in fib_check_nh_nongw()
1220 nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_check_nh_nongw()
1232 if (nh->fib_nh_gw_family == AF_INET) in fib_check_nh()
1234 else if (nh->fib_nh_gw_family == AF_INET6) in fib_check_nh()
1276 hlist_add_head(&fi->fib_hash, dest); in fib_info_hash_move()
1290 ldest = fib_info_laddrhash_bucket(fi->fib_net, in fib_info_hash_move()
1291 fi->fib_prefsrc); in fib_info_hash_move()
1292 hlist_add_head(&fi->fib_lhash, ldest); in fib_info_hash_move()
1306 if (nhc->nhc_family != AF_INET) in fib_info_update_nhc_saddr()
1307 return inet_select_addr(nhc->nhc_dev, 0, scope); in fib_info_update_nhc_saddr()
1310 saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope); in fib_info_update_nhc_saddr()
1312 WRITE_ONCE(nh->nh_saddr, saddr); in fib_info_update_nhc_saddr()
1313 WRITE_ONCE(nh->nh_saddr_genid, atomic_read(&net->ipv4.dev_addr_genid)); in fib_info_update_nhc_saddr()
1320 struct fib_nh_common *nhc = res->nhc; in fib_result_prefsrc()
1322 if (res->fi->fib_prefsrc) in fib_result_prefsrc()
1323 return res->fi->fib_prefsrc; in fib_result_prefsrc()
1325 if (nhc->nhc_family == AF_INET) { in fib_result_prefsrc()
1329 if (READ_ONCE(nh->nh_saddr_genid) == in fib_result_prefsrc()
1330 atomic_read(&net->ipv4.dev_addr_genid)) in fib_result_prefsrc()
1331 return READ_ONCE(nh->nh_saddr); in fib_result_prefsrc()
1334 return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope); in fib_result_prefsrc()
1339 if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || in fib_valid_prefsrc()
1340 fib_prefsrc != cfg->fc_dst) { in fib_valid_prefsrc()
1341 u32 tb_id = cfg->fc_table; in fib_valid_prefsrc()
1347 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1351 rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, in fib_valid_prefsrc()
1369 struct net *net = cfg->fc_nlinfo.nl_net; in fib_create_info()
1372 if (cfg->fc_type > RTN_MAX) in fib_create_info()
1376 if (fib_props[cfg->fc_type].scope > cfg->fc_scope) { in fib_create_info()
1381 if (cfg->fc_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) { in fib_create_info()
1383 "Invalid rtm_flags - can not contain DEAD or LINKDOWN"); in fib_create_info()
1387 if (cfg->fc_nh_id) { in fib_create_info()
1388 if (!cfg->fc_mx) { in fib_create_info()
1391 refcount_inc(&fi->fib_treeref); in fib_create_info()
1396 nh = nexthop_find_by_id(net, cfg->fc_nh_id); in fib_create_info()
1405 if (cfg->fc_mp) { in fib_create_info()
1406 nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len, extack); in fib_create_info()
1412 err = -ENOBUFS; in fib_create_info()
1438 fi->fib_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len, extack); in fib_create_info()
1439 if (IS_ERR(fi->fib_metrics)) { in fib_create_info()
1440 err = PTR_ERR(fi->fib_metrics); in fib_create_info()
1445 fi->fib_net = net; in fib_create_info()
1446 fi->fib_protocol = cfg->fc_protocol; in fib_create_info()
1447 fi->fib_scope = cfg->fc_scope; in fib_create_info()
1448 fi->fib_flags = cfg->fc_flags; in fib_create_info()
1449 fi->fib_priority = cfg->fc_priority; in fib_create_info()
1450 fi->fib_prefsrc = cfg->fc_prefsrc; in fib_create_info()
1451 fi->fib_type = cfg->fc_type; in fib_create_info()
1452 fi->fib_tb_id = cfg->fc_table; in fib_create_info()
1454 fi->fib_nhs = nhs; in fib_create_info()
1458 err = -EINVAL; in fib_create_info()
1461 fi->nh = nh; in fib_create_info()
1465 nexthop_nh->nh_parent = fi; in fib_create_info()
1468 if (cfg->fc_mp) in fib_create_info()
1469 err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, in fib_create_info()
1472 err = fib_nh_init(net, fi->fib_nh, cfg, 1, extack); in fib_create_info()
1478 if (fib_props[cfg->fc_type].error) { in fib_create_info()
1479 if (cfg->fc_gw_family || cfg->fc_oif || cfg->fc_mp) { in fib_create_info()
1486 switch (cfg->fc_type) { in fib_create_info()
1499 if (cfg->fc_scope > RT_SCOPE_HOST) { in fib_create_info()
1504 if (fi->nh) { in fib_create_info()
1505 err = fib_check_nexthop(fi->nh, cfg->fc_scope, extack); in fib_create_info()
1508 } else if (cfg->fc_scope == RT_SCOPE_HOST) { in fib_create_info()
1509 struct fib_nh *nh = fi->fib_nh; in fib_create_info()
1517 if (nh->fib_nh_gw_family) { in fib_create_info()
1522 nh->fib_nh_scope = RT_SCOPE_NOWHERE; in fib_create_info()
1523 nh->fib_nh_dev = dev_get_by_index(net, nh->fib_nh_oif); in fib_create_info()
1524 err = -ENODEV; in fib_create_info()
1525 if (!nh->fib_nh_dev) in fib_create_info()
1527 netdev_tracker_alloc(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, in fib_create_info()
1533 err = fib_check_nh(cfg->fc_nlinfo.nl_net, nexthop_nh, in fib_create_info()
1534 cfg->fc_table, cfg->fc_scope, in fib_create_info()
1538 if (nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN) in fib_create_info()
1541 if (linkdown == fi->fib_nhs) in fib_create_info()
1542 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_create_info()
1545 if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { in fib_create_info()
1550 if (!fi->nh) { in fib_create_info()
1552 fib_info_update_nhc_saddr(net, &nexthop_nh->nh_common, in fib_create_info()
1553 fi->fib_scope); in fib_create_info()
1554 if (nexthop_nh->fib_nh_gw_family == AF_INET6) in fib_create_info()
1555 fi->fib_nh_is_v6 = true; in fib_create_info()
1565 fi->fib_dead = 1; in fib_create_info()
1567 refcount_inc(&ofi->fib_treeref); in fib_create_info()
1571 refcount_set(&fi->fib_treeref, 1); in fib_create_info()
1572 refcount_set(&fi->fib_clntref, 1); in fib_create_info()
1575 hlist_add_head(&fi->fib_hash, in fib_create_info()
1577 if (fi->fib_prefsrc) { in fib_create_info()
1580 head = fib_info_laddrhash_bucket(net, fi->fib_prefsrc); in fib_create_info()
1581 hlist_add_head(&fi->fib_lhash, head); in fib_create_info()
1583 if (fi->nh) { in fib_create_info()
1584 list_add(&fi->nh_list, &nh->fi_list); in fib_create_info()
1589 if (!nexthop_nh->fib_nh_dev) in fib_create_info()
1591 head = fib_nh_head(nexthop_nh->fib_nh_dev); in fib_create_info()
1592 hlist_add_head_rcu(&nexthop_nh->nh_hash, head); in fib_create_info()
1598 err = -EINVAL; in fib_create_info()
1603 fi->fib_dead = 1; in fib_create_info()
1613 if (nhc->nhc_flags & RTNH_F_DEAD) in fib_nexthop_info()
1616 if (nhc->nhc_flags & RTNH_F_LINKDOWN) { in fib_nexthop_info()
1620 switch (nhc->nhc_family) { in fib_nexthop_info()
1622 if (ip_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1626 if (ip6_ignore_linkdown(nhc->nhc_dev)) in fib_nexthop_info()
1633 switch (nhc->nhc_gw_family) { in fib_nexthop_info()
1635 if (nla_put_in_addr(skb, RTA_GATEWAY, nhc->nhc_gw.ipv4)) in fib_nexthop_info()
1642 if (rt_family != nhc->nhc_gw_family) { in fib_nexthop_info()
1652 via->rtvia_family = AF_INET6; in fib_nexthop_info()
1653 memcpy(via->rtvia_addr, &nhc->nhc_gw.ipv6, alen); in fib_nexthop_info()
1655 &nhc->nhc_gw.ipv6) < 0) { in fib_nexthop_info()
1661 *flags |= (nhc->nhc_flags & in fib_nexthop_info()
1664 if (!skip_oif && nhc->nhc_dev && in fib_nexthop_info()
1665 nla_put_u32(skb, RTA_OIF, nhc->nhc_dev->ifindex)) in fib_nexthop_info()
1668 if (nhc->nhc_lwtstate && in fib_nexthop_info()
1669 lwtunnel_fill_encap(skb, nhc->nhc_lwtstate, in fib_nexthop_info()
1676 return -EMSGSIZE; in fib_nexthop_info()
1684 const struct net_device *dev = nhc->nhc_dev; in fib_add_nexthop()
1692 rtnh->rtnh_hops = nh_weight - 1; in fib_add_nexthop()
1693 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0; in fib_add_nexthop()
1698 rtnh->rtnh_flags = flags; in fib_add_nexthop()
1704 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh; in fib_add_nexthop()
1709 return -EMSGSIZE; in fib_add_nexthop()
1723 if (unlikely(fi->nh)) { in fib_add_multipath()
1724 if (nexthop_mpath_fill_node(skb, fi->nh, AF_INET) < 0) in fib_add_multipath()
1732 nh_tclassid = nh->nh_tclassid; in fib_add_multipath()
1734 if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight, in fib_add_multipath()
1745 return -EMSGSIZE; in fib_add_multipath()
1757 unsigned int nhs = fib_info_num_path(fri->fi); in fib_dump_info()
1758 struct fib_info *fi = fri->fi; in fib_dump_info()
1759 u32 tb_id = fri->tb_id; in fib_dump_info()
1761 struct rtmsg *rtm; in fib_dump_info() local
1763 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); in fib_dump_info()
1765 return -EMSGSIZE; in fib_dump_info()
1767 rtm = nlmsg_data(nlh); in fib_dump_info()
1768 rtm->rtm_family = AF_INET; in fib_dump_info()
1769 rtm->rtm_dst_len = fri->dst_len; in fib_dump_info()
1770 rtm->rtm_src_len = 0; in fib_dump_info()
1771 rtm->rtm_tos = inet_dscp_to_dsfield(fri->dscp); in fib_dump_info()
1773 rtm->rtm_table = tb_id; in fib_dump_info()
1775 rtm->rtm_table = RT_TABLE_COMPAT; in fib_dump_info()
1778 rtm->rtm_type = fri->type; in fib_dump_info()
1779 rtm->rtm_flags = fi->fib_flags; in fib_dump_info()
1780 rtm->rtm_scope = fi->fib_scope; in fib_dump_info()
1781 rtm->rtm_protocol = fi->fib_protocol; in fib_dump_info()
1783 if (rtm->rtm_dst_len && in fib_dump_info()
1784 nla_put_in_addr(skb, RTA_DST, fri->dst)) in fib_dump_info()
1786 if (fi->fib_priority && in fib_dump_info()
1787 nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) in fib_dump_info()
1789 if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0) in fib_dump_info()
1792 if (fi->fib_prefsrc && in fib_dump_info()
1793 nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc)) in fib_dump_info()
1796 if (fi->nh) { in fib_dump_info()
1797 if (nla_put_u32(skb, RTA_NH_ID, fi->nh->id)) in fib_dump_info()
1799 if (nexthop_is_blackhole(fi->nh)) in fib_dump_info()
1800 rtm->rtm_type = RTN_BLACKHOLE; in fib_dump_info()
1801 if (!READ_ONCE(fi->fib_net->ipv4.sysctl_nexthop_compat_mode)) in fib_dump_info()
1812 rtm->rtm_flags = flags; in fib_dump_info()
1814 if (nhc->nhc_family == AF_INET) { in fib_dump_info()
1818 if (nh->nh_tclassid && in fib_dump_info()
1819 nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) in fib_dump_info()
1829 if (fri->offload) in fib_dump_info()
1830 rtm->rtm_flags |= RTM_F_OFFLOAD; in fib_dump_info()
1831 if (fri->trap) in fib_dump_info()
1832 rtm->rtm_flags |= RTM_F_TRAP; in fib_dump_info()
1833 if (fri->offload_failed) in fib_dump_info()
1834 rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED; in fib_dump_info()
1841 return -EMSGSIZE; in fib_dump_info()
1846 * - local address disappeared -> we must delete all the entries
1848 * - device went down -> we must shutdown all nexthops going via it.
1863 if (!net_eq(fi->fib_net, net) || in fib_sync_down_addr()
1864 fi->fib_tb_id != tb_id) in fib_sync_down_addr()
1866 if (fi->fib_prefsrc == local) { in fib_sync_down_addr()
1867 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_addr()
1868 fi->pfsrc_removed = true; in fib_sync_down_addr()
1878 bool ignore_link_down = ip_ignore_linkdown(nh->fib_nh_dev); in call_fib_nh_notifiers()
1885 if (nh->fib_nh_flags & RTNH_F_DEAD) in call_fib_nh_notifiers()
1887 if (ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) in call_fib_nh_notifiers()
1889 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), event_type, in call_fib_nh_notifiers()
1892 if ((ignore_link_down && nh->fib_nh_flags & RTNH_F_LINKDOWN) || in call_fib_nh_notifiers()
1893 (nh->fib_nh_flags & RTNH_F_DEAD)) in call_fib_nh_notifiers()
1894 return call_fib4_notifiers(dev_net(nh->fib_nh_dev), in call_fib_nh_notifiers()
1905 * - the new MTU of the first hop becomes smaller than the PMTU
1906 * - the old MTU was the same as the PMTU, and it limited discovery of
1911 * - if the new MTU is greater than the PMTU, don't make any change
1912 * - otherwise, unlock and set PMTU
1919 bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1); in fib_nhc_update_mtu()
1928 fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) { in fib_nhc_update_mtu()
1929 if (fnhe->fnhe_mtu_locked) { in fib_nhc_update_mtu()
1930 if (new <= fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1931 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1932 fnhe->fnhe_mtu_locked = false; in fib_nhc_update_mtu()
1934 } else if (new < fnhe->fnhe_pmtu || in fib_nhc_update_mtu()
1935 orig == fnhe->fnhe_pmtu) { in fib_nhc_update_mtu()
1936 fnhe->fnhe_pmtu = new; in fib_nhc_update_mtu()
1948 DEBUG_NET_WARN_ON_ONCE(nh->fib_nh_dev != dev); in fib_sync_mtu()
1949 fib_nhc_update_mtu(&nh->nh_common, dev->mtu, orig_mtu); in fib_sync_mtu()
1970 scope = -1; in fib_sync_down_dev()
1973 struct fib_info *fi = nh->nh_parent; in fib_sync_down_dev()
1976 BUG_ON(!fi->fib_nhs); in fib_sync_down_dev()
1977 DEBUG_NET_WARN_ON_ONCE(nh->fib_nh_dev != dev); in fib_sync_down_dev()
1983 if (nexthop_nh->fib_nh_flags & RTNH_F_DEAD) in fib_sync_down_dev()
1985 else if (nexthop_nh->fib_nh_dev == dev && in fib_sync_down_dev()
1986 nexthop_nh->fib_nh_scope != scope) { in fib_sync_down_dev()
1990 nexthop_nh->fib_nh_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
1993 nexthop_nh->fib_nh_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2002 nexthop_nh->fib_nh_dev == dev) { in fib_sync_down_dev()
2003 dead = fi->fib_nhs; in fib_sync_down_dev()
2008 if (dead == fi->fib_nhs) { in fib_sync_down_dev()
2012 fi->fib_flags |= RTNH_F_DEAD; in fib_sync_down_dev()
2015 fi->fib_flags |= RTNH_F_LINKDOWN; in fib_sync_down_dev()
2031 struct hlist_head *fa_head = res->fa_head; in fib_select_default()
2032 struct fib_table *tb = res->table; in fib_select_default()
2033 u8 slen = 32 - res->prefixlen; in fib_select_default()
2034 int order = -1, last_idx = -1; in fib_select_default()
2036 u32 last_prio = res->fi->fib_priority; in fib_select_default()
2040 struct fib_info *next_fi = fa->fa_info; in fib_select_default()
2043 if (fa->fa_slen != slen) in fib_select_default()
2045 if (fa->fa_dscp && !fib_dscp_masked_match(fa->fa_dscp, flp)) in fib_select_default()
2047 if (fa->tb_id != tb->tb_id) in fib_select_default()
2049 if (next_fi->fib_priority > last_prio && in fib_select_default()
2050 fa->fa_dscp == last_dscp) { in fib_select_default()
2055 if (next_fi->fib_flags & RTNH_F_DEAD) in fib_select_default()
2057 last_dscp = fa->fa_dscp; in fib_select_default()
2058 last_prio = next_fi->fib_priority; in fib_select_default()
2060 if (next_fi->fib_scope != res->scope || in fib_select_default()
2061 fa->fa_type != RTN_UNICAST) in fib_select_default()
2065 if (!nhc->nhc_gw_family || nhc->nhc_scope != RT_SCOPE_LINK) in fib_select_default()
2071 if (next_fi != res->fi) in fib_select_default()
2075 &last_idx, fa1->fa_default)) { in fib_select_default()
2077 fa1->fa_default = order; in fib_select_default()
2086 fa1->fa_default = -1; in fib_select_default()
2091 fa1->fa_default)) { in fib_select_default()
2093 fa1->fa_default = order; in fib_select_default()
2099 fa1->fa_default = last_idx; in fib_select_default()
2117 if (!(dev->flags & IFF_UP)) in fib_sync_up()
2132 struct fib_info *fi = nh->nh_parent; in fib_sync_up()
2135 BUG_ON(!fi->fib_nhs); in fib_sync_up()
2136 DEBUG_NET_WARN_ON_ONCE(nh->fib_nh_dev != dev); in fib_sync_up()
2143 if (!(nexthop_nh->fib_nh_flags & nh_flags)) { in fib_sync_up()
2147 if (!nexthop_nh->fib_nh_dev || in fib_sync_up()
2148 !(nexthop_nh->fib_nh_dev->flags & IFF_UP)) in fib_sync_up()
2150 if (nexthop_nh->fib_nh_dev != dev || in fib_sync_up()
2154 nexthop_nh->fib_nh_flags &= ~nh_flags; in fib_sync_up()
2159 fi->fib_flags &= ~nh_flags; in fib_sync_up()
2174 if (nh->fib_nh_scope == RT_SCOPE_LINK) { in fib_good_nh()
2179 if (likely(nh->fib_nh_gw_family == AF_INET)) in fib_good_nh()
2180 n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev, in fib_good_nh()
2181 (__force u32)nh->fib_nh_gw4); in fib_good_nh()
2182 else if (nh->fib_nh_gw_family == AF_INET6) in fib_good_nh()
2183 n = __ipv6_neigh_lookup_noref_stub(nh->fib_nh_dev, in fib_good_nh()
2184 &nh->fib_nh_gw6); in fib_good_nh()
2188 state = READ_ONCE(n->nud_state); in fib_good_nh()
2198 struct fib_info *fi = res->fi; in fib_select_multipath()
2199 struct net *net = fi->fib_net; in fib_select_multipath()
2202 if (unlikely(res->fi->nh)) { in fib_select_multipath()
2208 if (READ_ONCE(net->ipv4.sysctl_fib_multipath_use_neigh)) { in fib_select_multipath()
2212 res->nh_sel = nhsel; in fib_select_multipath()
2213 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2218 if (hash > atomic_read(&nexthop_nh->fib_nh_upper_bound)) in fib_select_multipath()
2221 res->nh_sel = nhsel; in fib_select_multipath()
2222 res->nhc = &nexthop_nh->nh_common; in fib_select_multipath()
2231 if (fl4->flowi4_oif) in fib_select_path()
2235 if (fib_info_num_path(res->fi) > 1) { in fib_select_path()
2242 if (!res->prefixlen && in fib_select_path()
2243 res->table->tb_num_default > 1 && in fib_select_path()
2244 res->type == RTN_UNICAST) in fib_select_path()
2248 if (!fl4->saddr) { in fib_select_path()
2251 l3mdev = dev_get_by_index_rcu(net, fl4->flowi4_l3mdev); in fib_select_path()
2255 fl4->saddr = fib_result_prefsrc(net, res); in fib_select_path()
2257 fl4->saddr = inet_select_addr(l3mdev, 0, RT_SCOPE_LINK); in fib_select_path()