diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/filter.c | 26 | ||||
| -rw-r--r-- | net/ipv6/route.c | 61 |
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 | } |
| 526 | out: | ||
| 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, | |||
| 889 | static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res) | 895 | static 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 | ||
| 946 | static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort) | 951 | static 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 | ||
| 968 | static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res) | 973 | static 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; |
| 2532 | out: | 2540 | out: |
| 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; |
