summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2019-04-16 17:36:11 -0400
committerDavid S. Miller <davem@davemloft.net>2019-04-18 02:11:30 -0400
commit7d21fec90438941b44b699ae73673d2f8a3a9d76 (patch)
tree74b78bdf8b3f7e2121ca4005ee3c7c0af17619ec /net
parenteffda4dd97e878ab83336bec7411cc41b5cc6d37 (diff)
ipv6: Add fib6_type and fib6_flags to fib6_result
Add the fib6_flags and fib6_type to fib6_result. Update the lookup helpers to set them and update post fib lookup users to use the version from the result. This allows nexthop objects to have blackhole nexthop. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/filter.c26
-rw-r--r--net/ipv6/route.c61
2 files changed, 49 insertions, 38 deletions
diff --git a/net/core/filter.c b/net/core/filter.c
index d17347cbeb1e..1644a16afcec 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4741,21 +4741,19 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
4741 res.f6i == net->ipv6.fib6_null_entry)) 4741 res.f6i == net->ipv6.fib6_null_entry))
4742 return BPF_FIB_LKUP_RET_NOT_FWDED; 4742 return BPF_FIB_LKUP_RET_NOT_FWDED;
4743 4743
4744 if (unlikely(res.f6i->fib6_flags & RTF_REJECT)) { 4744 switch (res.fib6_type) {
4745 switch (res.f6i->fib6_type) { 4745 /* only unicast is forwarded */
4746 case RTN_BLACKHOLE: 4746 case RTN_UNICAST:
4747 return BPF_FIB_LKUP_RET_BLACKHOLE; 4747 break;
4748 case RTN_UNREACHABLE: 4748 case RTN_BLACKHOLE:
4749 return BPF_FIB_LKUP_RET_UNREACHABLE; 4749 return BPF_FIB_LKUP_RET_BLACKHOLE;
4750 case RTN_PROHIBIT: 4750 case RTN_UNREACHABLE:
4751 return BPF_FIB_LKUP_RET_PROHIBIT; 4751 return BPF_FIB_LKUP_RET_UNREACHABLE;
4752 default: 4752 case RTN_PROHIBIT:
4753 return BPF_FIB_LKUP_RET_NOT_FWDED; 4753 return BPF_FIB_LKUP_RET_PROHIBIT;
4754 } 4754 default:
4755 }
4756
4757 if (res.f6i->fib6_type != RTN_UNICAST)
4758 return BPF_FIB_LKUP_RET_NOT_FWDED; 4755 return BPF_FIB_LKUP_RET_NOT_FWDED;
4756 }
4759 4757
4760 ipv6_stub->fib6_select_path(net, &res, &fl6, fl6.flowi6_oif, 4758 ipv6_stub->fib6_select_path(net, &res, &fl6, fl6.flowi6_oif,
4761 fl6.flowi6_oif != 0, NULL, strict); 4759 fl6.flowi6_oif != 0, NULL, strict);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 5a1e1176c33c..e8c73b7782cd 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -500,31 +500,33 @@ static void rt6_device_match(struct net *net, struct fib6_result *res,
500 500
501 if (!oif && ipv6_addr_any(saddr)) { 501 if (!oif && ipv6_addr_any(saddr)) {
502 nh = &f6i->fib6_nh; 502 nh = &f6i->fib6_nh;
503 if (!(nh->fib_nh_flags & RTNH_F_DEAD)) { 503 if (!(nh->fib_nh_flags & RTNH_F_DEAD))
504 res->nh = nh; 504 goto out;
505 return;
506 }
507 } 505 }
508 506
509 for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) { 507 for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) {
510 nh = &spf6i->fib6_nh; 508 nh = &spf6i->fib6_nh;
511 if (__rt6_device_match(net, nh, saddr, oif, flags)) { 509 if (__rt6_device_match(net, nh, saddr, oif, flags)) {
512 res->f6i = spf6i; 510 res->f6i = spf6i;
513 res->nh = nh; 511 goto out;
514 } 512 }
515 } 513 }
516 514
517 if (oif && flags & RT6_LOOKUP_F_IFACE) { 515 if (oif && flags & RT6_LOOKUP_F_IFACE) {
518 res->f6i = net->ipv6.fib6_null_entry; 516 res->f6i = net->ipv6.fib6_null_entry;
519 res->nh = &res->f6i->fib6_nh; 517 nh = &res->f6i->fib6_nh;
520 return; 518 goto out;
521 } 519 }
522 520
523 res->nh = &f6i->fib6_nh; 521 nh = &f6i->fib6_nh;
524 if (res->nh->fib_nh_flags & RTNH_F_DEAD) { 522 if (nh->fib_nh_flags & RTNH_F_DEAD) {
525 res->f6i = net->ipv6.fib6_null_entry; 523 res->f6i = net->ipv6.fib6_null_entry;
526 res->nh = &res->f6i->fib6_nh; 524 nh = &res->f6i->fib6_nh;
527 } 525 }
526out:
527 res->nh = nh;
528 res->fib6_type = res->f6i->fib6_type;
529 res->fib6_flags = res->f6i->fib6_flags;
528} 530}
529 531
530#ifdef CONFIG_IPV6_ROUTER_PREF 532#ifdef CONFIG_IPV6_ROUTER_PREF
@@ -719,6 +721,8 @@ static void __find_rr_leaf(struct fib6_info *f6i_start,
719 if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) { 721 if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) {
720 res->f6i = f6i; 722 res->f6i = f6i;
721 res->nh = nh; 723 res->nh = nh;
724 res->fib6_flags = f6i->fib6_flags;
725 res->fib6_type = f6i->fib6_type;
722 } 726 }
723 } 727 }
724} 728}
@@ -796,6 +800,8 @@ out:
796 if (!res->f6i) { 800 if (!res->f6i) {
797 res->f6i = net->ipv6.fib6_null_entry; 801 res->f6i = net->ipv6.fib6_null_entry;
798 res->nh = &res->f6i->fib6_nh; 802 res->nh = &res->f6i->fib6_nh;
803 res->fib6_flags = res->f6i->fib6_flags;
804 res->fib6_type = res->f6i->fib6_type;
799 } 805 }
800} 806}
801 807
@@ -889,15 +895,14 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
889static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res) 895static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res)
890{ 896{
891 struct net_device *dev = res->nh->fib_nh_dev; 897 struct net_device *dev = res->nh->fib_nh_dev;
892 const struct fib6_info *f6i = res->f6i;
893 898
894 if (f6i->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) { 899 if (res->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
895 /* for copies of local routes, dst->dev needs to be the 900 /* for copies of local routes, dst->dev needs to be the
896 * device if it is a master device, the master device if 901 * device if it is a master device, the master device if
897 * device is enslaved, and the loopback as the default 902 * device is enslaved, and the loopback as the default
898 */ 903 */
899 if (netif_is_l3_slave(dev) && 904 if (netif_is_l3_slave(dev) &&
900 !rt6_need_strict(&f6i->fib6_dst.addr)) 905 !rt6_need_strict(&res->f6i->fib6_dst.addr))
901 dev = l3mdev_master_dev_rcu(dev); 906 dev = l3mdev_master_dev_rcu(dev);
902 else if (!netif_is_l3_master(dev)) 907 else if (!netif_is_l3_master(dev))
903 dev = dev_net(dev)->loopback_dev; 908 dev = dev_net(dev)->loopback_dev;
@@ -943,11 +948,11 @@ static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
943 return flags; 948 return flags;
944} 949}
945 950
946static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort) 951static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type)
947{ 952{
948 rt->dst.error = ip6_rt_type_to_error(ort->fib6_type); 953 rt->dst.error = ip6_rt_type_to_error(fib6_type);
949 954
950 switch (ort->fib6_type) { 955 switch (fib6_type) {
951 case RTN_BLACKHOLE: 956 case RTN_BLACKHOLE:
952 rt->dst.output = dst_discard_out; 957 rt->dst.output = dst_discard_out;
953 rt->dst.input = dst_discard; 958 rt->dst.input = dst_discard;
@@ -967,19 +972,19 @@ static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort)
967 972
968static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res) 973static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res)
969{ 974{
970 struct fib6_info *ort = res->f6i; 975 struct fib6_info *f6i = res->f6i;
971 976
972 if (ort->fib6_flags & RTF_REJECT) { 977 if (res->fib6_flags & RTF_REJECT) {
973 ip6_rt_init_dst_reject(rt, ort); 978 ip6_rt_init_dst_reject(rt, res->fib6_type);
974 return; 979 return;
975 } 980 }
976 981
977 rt->dst.error = 0; 982 rt->dst.error = 0;
978 rt->dst.output = ip6_output; 983 rt->dst.output = ip6_output;
979 984
980 if (ort->fib6_type == RTN_LOCAL || ort->fib6_type == RTN_ANYCAST) { 985 if (res->fib6_type == RTN_LOCAL || res->fib6_type == RTN_ANYCAST) {
981 rt->dst.input = ip6_input; 986 rt->dst.input = ip6_input;
982 } else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) { 987 } else if (ipv6_addr_type(&f6i->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
983 rt->dst.input = ip6_mc_input; 988 rt->dst.input = ip6_mc_input;
984 } else { 989 } else {
985 rt->dst.input = ip6_forward; 990 rt->dst.input = ip6_forward;
@@ -1012,7 +1017,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, const struct fib6_result *res)
1012 1017
1013 rt->rt6i_dst = f6i->fib6_dst; 1018 rt->rt6i_dst = f6i->fib6_dst;
1014 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; 1019 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
1015 rt->rt6i_flags = f6i->fib6_flags; 1020 rt->rt6i_flags = res->fib6_flags;
1016 if (nh->fib_nh_gw_family) { 1021 if (nh->fib_nh_gw_family) {
1017 rt->rt6i_gateway = nh->fib_nh_gw6; 1022 rt->rt6i_gateway = nh->fib_nh_gw6;
1018 rt->rt6i_flags |= RTF_GATEWAY; 1023 rt->rt6i_flags |= RTF_GATEWAY;
@@ -2365,6 +2370,9 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2365 return; 2370 return;
2366 } 2371 }
2367 res.nh = &res.f6i->fib6_nh; 2372 res.nh = &res.f6i->fib6_nh;
2373 res.fib6_flags = res.f6i->fib6_flags;
2374 res.fib6_type = res.f6i->fib6_type;
2375
2368 nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr); 2376 nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr);
2369 if (nrt6) { 2377 if (nrt6) {
2370 rt6_do_update_pmtu(nrt6, mtu); 2378 rt6_do_update_pmtu(nrt6, mtu);
@@ -2530,10 +2538,13 @@ restart:
2530 res.f6i = rt; 2538 res.f6i = rt;
2531 res.nh = &rt->fib6_nh; 2539 res.nh = &rt->fib6_nh;
2532out: 2540out:
2533 if (ret) 2541 if (ret) {
2534 ip6_hold_safe(net, &ret); 2542 ip6_hold_safe(net, &ret);
2535 else 2543 } else {
2544 res.fib6_flags = res.f6i->fib6_flags;
2545 res.fib6_type = res.f6i->fib6_type;
2536 ret = ip6_create_rt_rcu(&res); 2546 ret = ip6_create_rt_rcu(&res);
2547 }
2537 2548
2538 rcu_read_unlock(); 2549 rcu_read_unlock();
2539 2550
@@ -3491,6 +3502,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3491 rcu_read_unlock(); 3502 rcu_read_unlock();
3492 3503
3493 res.nh = &res.f6i->fib6_nh; 3504 res.nh = &res.f6i->fib6_nh;
3505 res.fib6_flags = res.f6i->fib6_flags;
3506 res.fib6_type = res.f6i->fib6_type;
3494 nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL); 3507 nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL);
3495 if (!nrt) 3508 if (!nrt)
3496 goto out; 3509 goto out;