Commit 7d21fec9 authored by David Ahern's avatar David Ahern Committed by David S. Miller

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: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent effda4dd
...@@ -193,6 +193,8 @@ struct rt6_info { ...@@ -193,6 +193,8 @@ struct rt6_info {
struct fib6_result { struct fib6_result {
struct fib6_nh *nh; struct fib6_nh *nh;
struct fib6_info *f6i; struct fib6_info *f6i;
u32 fib6_flags;
u8 fib6_type;
}; };
#define for_each_fib6_node_rt_rcu(fn) \ #define for_each_fib6_node_rt_rcu(fn) \
......
...@@ -39,7 +39,7 @@ TRACE_EVENT(fib6_table_lookup, ...@@ -39,7 +39,7 @@ TRACE_EVENT(fib6_table_lookup,
struct in6_addr *in6; struct in6_addr *in6;
__entry->tb_id = table->tb6_id; __entry->tb_id = table->tb6_id;
__entry->err = ip6_rt_type_to_error(res->f6i->fib6_type); __entry->err = ip6_rt_type_to_error(res->fib6_type);
__entry->oif = flp->flowi6_oif; __entry->oif = flp->flowi6_oif;
__entry->iif = flp->flowi6_iif; __entry->iif = flp->flowi6_iif;
__entry->tos = ip6_tclass(flp->flowlabel); __entry->tos = ip6_tclass(flp->flowlabel);
......
...@@ -4741,8 +4741,10 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, ...@@ -4741,8 +4741,10 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
res.f6i == net->ipv6.fib6_null_entry)) res.f6i == net->ipv6.fib6_null_entry))
return BPF_FIB_LKUP_RET_NOT_FWDED; return BPF_FIB_LKUP_RET_NOT_FWDED;
if (unlikely(res.f6i->fib6_flags & RTF_REJECT)) { switch (res.fib6_type) {
switch (res.f6i->fib6_type) { /* only unicast is forwarded */
case RTN_UNICAST:
break;
case RTN_BLACKHOLE: case RTN_BLACKHOLE:
return BPF_FIB_LKUP_RET_BLACKHOLE; return BPF_FIB_LKUP_RET_BLACKHOLE;
case RTN_UNREACHABLE: case RTN_UNREACHABLE:
...@@ -4752,10 +4754,6 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, ...@@ -4752,10 +4754,6 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
default: default:
return BPF_FIB_LKUP_RET_NOT_FWDED; return BPF_FIB_LKUP_RET_NOT_FWDED;
} }
}
if (res.f6i->fib6_type != RTN_UNICAST)
return BPF_FIB_LKUP_RET_NOT_FWDED;
ipv6_stub->fib6_select_path(net, &res, &fl6, fl6.flowi6_oif, ipv6_stub->fib6_select_path(net, &res, &fl6, fl6.flowi6_oif,
fl6.flowi6_oif != 0, NULL, strict); fl6.flowi6_oif != 0, NULL, strict);
......
...@@ -500,31 +500,33 @@ static void rt6_device_match(struct net *net, struct fib6_result *res, ...@@ -500,31 +500,33 @@ static void rt6_device_match(struct net *net, struct fib6_result *res,
if (!oif && ipv6_addr_any(saddr)) { if (!oif && ipv6_addr_any(saddr)) {
nh = &f6i->fib6_nh; nh = &f6i->fib6_nh;
if (!(nh->fib_nh_flags & RTNH_F_DEAD)) { if (!(nh->fib_nh_flags & RTNH_F_DEAD))
res->nh = nh; goto out;
return;
}
} }
for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) { for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) {
nh = &spf6i->fib6_nh; nh = &spf6i->fib6_nh;
if (__rt6_device_match(net, nh, saddr, oif, flags)) { if (__rt6_device_match(net, nh, saddr, oif, flags)) {
res->f6i = spf6i; res->f6i = spf6i;
res->nh = nh; goto out;
} }
} }
if (oif && flags & RT6_LOOKUP_F_IFACE) { if (oif && flags & RT6_LOOKUP_F_IFACE) {
res->f6i = net->ipv6.fib6_null_entry; res->f6i = net->ipv6.fib6_null_entry;
res->nh = &res->f6i->fib6_nh; nh = &res->f6i->fib6_nh;
return; goto out;
} }
res->nh = &f6i->fib6_nh; nh = &f6i->fib6_nh;
if (res->nh->fib_nh_flags & RTNH_F_DEAD) { if (nh->fib_nh_flags & RTNH_F_DEAD) {
res->f6i = net->ipv6.fib6_null_entry; res->f6i = net->ipv6.fib6_null_entry;
res->nh = &res->f6i->fib6_nh; nh = &res->f6i->fib6_nh;
} }
out:
res->nh = nh;
res->fib6_type = res->f6i->fib6_type;
res->fib6_flags = res->f6i->fib6_flags;
} }
#ifdef CONFIG_IPV6_ROUTER_PREF #ifdef CONFIG_IPV6_ROUTER_PREF
...@@ -719,6 +721,8 @@ static void __find_rr_leaf(struct fib6_info *f6i_start, ...@@ -719,6 +721,8 @@ static void __find_rr_leaf(struct fib6_info *f6i_start,
if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) { if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) {
res->f6i = f6i; res->f6i = f6i;
res->nh = nh; res->nh = nh;
res->fib6_flags = f6i->fib6_flags;
res->fib6_type = f6i->fib6_type;
} }
} }
} }
...@@ -796,6 +800,8 @@ static void rt6_select(struct net *net, struct fib6_node *fn, int oif, ...@@ -796,6 +800,8 @@ static void rt6_select(struct net *net, struct fib6_node *fn, int oif,
if (!res->f6i) { if (!res->f6i) {
res->f6i = net->ipv6.fib6_null_entry; res->f6i = net->ipv6.fib6_null_entry;
res->nh = &res->f6i->fib6_nh; res->nh = &res->f6i->fib6_nh;
res->fib6_flags = res->f6i->fib6_flags;
res->fib6_type = res->f6i->fib6_type;
} }
} }
...@@ -889,15 +895,14 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, ...@@ -889,15 +895,14 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res) static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res)
{ {
struct net_device *dev = res->nh->fib_nh_dev; struct net_device *dev = res->nh->fib_nh_dev;
const struct fib6_info *f6i = res->f6i;
if (f6i->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) { if (res->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
/* for copies of local routes, dst->dev needs to be the /* for copies of local routes, dst->dev needs to be the
* device if it is a master device, the master device if * device if it is a master device, the master device if
* device is enslaved, and the loopback as the default * device is enslaved, and the loopback as the default
*/ */
if (netif_is_l3_slave(dev) && if (netif_is_l3_slave(dev) &&
!rt6_need_strict(&f6i->fib6_dst.addr)) !rt6_need_strict(&res->f6i->fib6_dst.addr))
dev = l3mdev_master_dev_rcu(dev); dev = l3mdev_master_dev_rcu(dev);
else if (!netif_is_l3_master(dev)) else if (!netif_is_l3_master(dev))
dev = dev_net(dev)->loopback_dev; dev = dev_net(dev)->loopback_dev;
...@@ -943,11 +948,11 @@ static unsigned short fib6_info_dst_flags(struct fib6_info *rt) ...@@ -943,11 +948,11 @@ static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
return flags; return flags;
} }
static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort) static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type)
{ {
rt->dst.error = ip6_rt_type_to_error(ort->fib6_type); rt->dst.error = ip6_rt_type_to_error(fib6_type);
switch (ort->fib6_type) { switch (fib6_type) {
case RTN_BLACKHOLE: case RTN_BLACKHOLE:
rt->dst.output = dst_discard_out; rt->dst.output = dst_discard_out;
rt->dst.input = dst_discard; 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,19 +972,19 @@ static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort)
static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res) static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res)
{ {
struct fib6_info *ort = res->f6i; struct fib6_info *f6i = res->f6i;
if (ort->fib6_flags & RTF_REJECT) { if (res->fib6_flags & RTF_REJECT) {
ip6_rt_init_dst_reject(rt, ort); ip6_rt_init_dst_reject(rt, res->fib6_type);
return; return;
} }
rt->dst.error = 0; rt->dst.error = 0;
rt->dst.output = ip6_output; rt->dst.output = ip6_output;
if (ort->fib6_type == RTN_LOCAL || ort->fib6_type == RTN_ANYCAST) { if (res->fib6_type == RTN_LOCAL || res->fib6_type == RTN_ANYCAST) {
rt->dst.input = ip6_input; rt->dst.input = ip6_input;
} else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) { } else if (ipv6_addr_type(&f6i->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
rt->dst.input = ip6_mc_input; rt->dst.input = ip6_mc_input;
} else { } else {
rt->dst.input = ip6_forward; 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,7 +1017,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, const struct fib6_result *res)
rt->rt6i_dst = f6i->fib6_dst; rt->rt6i_dst = f6i->fib6_dst;
rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
rt->rt6i_flags = f6i->fib6_flags; rt->rt6i_flags = res->fib6_flags;
if (nh->fib_nh_gw_family) { if (nh->fib_nh_gw_family) {
rt->rt6i_gateway = nh->fib_nh_gw6; rt->rt6i_gateway = nh->fib_nh_gw6;
rt->rt6i_flags |= RTF_GATEWAY; rt->rt6i_flags |= RTF_GATEWAY;
...@@ -2365,6 +2370,9 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, ...@@ -2365,6 +2370,9 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
return; return;
} }
res.nh = &res.f6i->fib6_nh; res.nh = &res.f6i->fib6_nh;
res.fib6_flags = res.f6i->fib6_flags;
res.fib6_type = res.f6i->fib6_type;
nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr); nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr);
if (nrt6) { if (nrt6) {
rt6_do_update_pmtu(nrt6, mtu); rt6_do_update_pmtu(nrt6, mtu);
...@@ -2530,10 +2538,13 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, ...@@ -2530,10 +2538,13 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
res.f6i = rt; res.f6i = rt;
res.nh = &rt->fib6_nh; res.nh = &rt->fib6_nh;
out: out:
if (ret) if (ret) {
ip6_hold_safe(net, &ret); ip6_hold_safe(net, &ret);
else } else {
res.fib6_flags = res.f6i->fib6_flags;
res.fib6_type = res.f6i->fib6_type;
ret = ip6_create_rt_rcu(&res); ret = ip6_create_rt_rcu(&res);
}
rcu_read_unlock(); rcu_read_unlock();
...@@ -3491,6 +3502,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu ...@@ -3491,6 +3502,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
rcu_read_unlock(); rcu_read_unlock();
res.nh = &res.f6i->fib6_nh; res.nh = &res.f6i->fib6_nh;
res.fib6_flags = res.f6i->fib6_flags;
res.fib6_type = res.f6i->fib6_type;
nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL); nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL);
if (!nrt) if (!nrt)
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment