|
@@ -4073,8 +4073,9 @@ static int bpf_fib_set_fwd_params(struct bpf_fib_lookup *params,
|
|
|
memcpy(params->smac, dev->dev_addr, ETH_ALEN);
|
|
|
params->h_vlan_TCI = 0;
|
|
|
params->h_vlan_proto = 0;
|
|
|
+ params->ifindex = dev->ifindex;
|
|
|
|
|
|
- return dev->ifindex;
|
|
|
+ return 0;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -4098,7 +4099,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
/* verify forwarding is enabled on this interface */
|
|
|
in_dev = __in_dev_get_rcu(dev);
|
|
|
if (unlikely(!in_dev || !IN_DEV_FORWARD(in_dev)))
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_FWD_DISABLED;
|
|
|
|
|
|
if (flags & BPF_FIB_LOOKUP_OUTPUT) {
|
|
|
fl4.flowi4_iif = 1;
|
|
@@ -4123,7 +4124,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
|
|
|
tb = fib_get_table(net, tbid);
|
|
|
if (unlikely(!tb))
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
|
|
|
err = fib_table_lookup(tb, &fl4, &res, FIB_LOOKUP_NOREF);
|
|
|
} else {
|
|
@@ -4135,8 +4136,20 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
err = fib_lookup(net, &fl4, &res, FIB_LOOKUP_NOREF);
|
|
|
}
|
|
|
|
|
|
- if (err || res.type != RTN_UNICAST)
|
|
|
- return 0;
|
|
|
+ if (err) {
|
|
|
+ /* map fib lookup errors to RTN_ type */
|
|
|
+ if (err == -EINVAL)
|
|
|
+ return BPF_FIB_LKUP_RET_BLACKHOLE;
|
|
|
+ if (err == -EHOSTUNREACH)
|
|
|
+ return BPF_FIB_LKUP_RET_UNREACHABLE;
|
|
|
+ if (err == -EACCES)
|
|
|
+ return BPF_FIB_LKUP_RET_PROHIBIT;
|
|
|
+
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (res.type != RTN_UNICAST)
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
|
|
|
if (res.fi->fib_nhs > 1)
|
|
|
fib_select_path(net, &res, &fl4, NULL);
|
|
@@ -4144,19 +4157,16 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
if (check_mtu) {
|
|
|
mtu = ip_mtu_from_fib_result(&res, params->ipv4_dst);
|
|
|
if (params->tot_len > mtu)
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_FRAG_NEEDED;
|
|
|
}
|
|
|
|
|
|
nh = &res.fi->fib_nh[res.nh_sel];
|
|
|
|
|
|
/* do not handle lwt encaps right now */
|
|
|
if (nh->nh_lwtstate)
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_UNSUPP_LWT;
|
|
|
|
|
|
dev = nh->nh_dev;
|
|
|
- if (unlikely(!dev))
|
|
|
- return 0;
|
|
|
-
|
|
|
if (nh->nh_gw)
|
|
|
params->ipv4_dst = nh->nh_gw;
|
|
|
|
|
@@ -4166,10 +4176,10 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
* rcu_read_lock_bh is not needed here
|
|
|
*/
|
|
|
neigh = __ipv4_neigh_lookup_noref(dev, (__force u32)params->ipv4_dst);
|
|
|
- if (neigh)
|
|
|
- return bpf_fib_set_fwd_params(params, neigh, dev);
|
|
|
+ if (!neigh)
|
|
|
+ return BPF_FIB_LKUP_RET_NO_NEIGH;
|
|
|
|
|
|
- return 0;
|
|
|
+ return bpf_fib_set_fwd_params(params, neigh, dev);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -4190,7 +4200,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
|
|
|
/* link local addresses are never forwarded */
|
|
|
if (rt6_need_strict(dst) || rt6_need_strict(src))
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
|
|
|
dev = dev_get_by_index_rcu(net, params->ifindex);
|
|
|
if (unlikely(!dev))
|
|
@@ -4198,7 +4208,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
|
|
|
idev = __in6_dev_get_safely(dev);
|
|
|
if (unlikely(!idev || !net->ipv6.devconf_all->forwarding))
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_FWD_DISABLED;
|
|
|
|
|
|
if (flags & BPF_FIB_LOOKUP_OUTPUT) {
|
|
|
fl6.flowi6_iif = 1;
|
|
@@ -4225,7 +4235,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
|
|
|
tb = ipv6_stub->fib6_get_table(net, tbid);
|
|
|
if (unlikely(!tb))
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
|
|
|
f6i = ipv6_stub->fib6_table_lookup(net, tb, oif, &fl6, strict);
|
|
|
} else {
|
|
@@ -4238,11 +4248,23 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
}
|
|
|
|
|
|
if (unlikely(IS_ERR_OR_NULL(f6i) || f6i == net->ipv6.fib6_null_entry))
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
+
|
|
|
+ if (unlikely(f6i->fib6_flags & RTF_REJECT)) {
|
|
|
+ switch (f6i->fib6_type) {
|
|
|
+ case RTN_BLACKHOLE:
|
|
|
+ return BPF_FIB_LKUP_RET_BLACKHOLE;
|
|
|
+ case RTN_UNREACHABLE:
|
|
|
+ return BPF_FIB_LKUP_RET_UNREACHABLE;
|
|
|
+ case RTN_PROHIBIT:
|
|
|
+ return BPF_FIB_LKUP_RET_PROHIBIT;
|
|
|
+ default:
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (unlikely(f6i->fib6_flags & RTF_REJECT ||
|
|
|
- f6i->fib6_type != RTN_UNICAST))
|
|
|
- return 0;
|
|
|
+ if (f6i->fib6_type != RTN_UNICAST)
|
|
|
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
|
|
|
|
|
|
if (f6i->fib6_nsiblings && fl6.flowi6_oif == 0)
|
|
|
f6i = ipv6_stub->fib6_multipath_select(net, f6i, &fl6,
|
|
@@ -4252,11 +4274,11 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
if (check_mtu) {
|
|
|
mtu = ipv6_stub->ip6_mtu_from_fib6(f6i, dst, src);
|
|
|
if (params->tot_len > mtu)
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_FRAG_NEEDED;
|
|
|
}
|
|
|
|
|
|
if (f6i->fib6_nh.nh_lwtstate)
|
|
|
- return 0;
|
|
|
+ return BPF_FIB_LKUP_RET_UNSUPP_LWT;
|
|
|
|
|
|
if (f6i->fib6_flags & RTF_GATEWAY)
|
|
|
*dst = f6i->fib6_nh.nh_gw;
|
|
@@ -4270,10 +4292,10 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
|
|
|
*/
|
|
|
neigh = ___neigh_lookup_noref(ipv6_stub->nd_tbl, neigh_key_eq128,
|
|
|
ndisc_hashfn, dst, dev);
|
|
|
- if (neigh)
|
|
|
- return bpf_fib_set_fwd_params(params, neigh, dev);
|
|
|
+ if (!neigh)
|
|
|
+ return BPF_FIB_LKUP_RET_NO_NEIGH;
|
|
|
|
|
|
- return 0;
|
|
|
+ return bpf_fib_set_fwd_params(params, neigh, dev);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -4315,7 +4337,7 @@ BPF_CALL_4(bpf_skb_fib_lookup, struct sk_buff *, skb,
|
|
|
struct bpf_fib_lookup *, params, int, plen, u32, flags)
|
|
|
{
|
|
|
struct net *net = dev_net(skb->dev);
|
|
|
- int index = -EAFNOSUPPORT;
|
|
|
+ int rc = -EAFNOSUPPORT;
|
|
|
|
|
|
if (plen < sizeof(*params))
|
|
|
return -EINVAL;
|
|
@@ -4326,25 +4348,25 @@ BPF_CALL_4(bpf_skb_fib_lookup, struct sk_buff *, skb,
|
|
|
switch (params->family) {
|
|
|
#if IS_ENABLED(CONFIG_INET)
|
|
|
case AF_INET:
|
|
|
- index = bpf_ipv4_fib_lookup(net, params, flags, false);
|
|
|
+ rc = bpf_ipv4_fib_lookup(net, params, flags, false);
|
|
|
break;
|
|
|
#endif
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
|
case AF_INET6:
|
|
|
- index = bpf_ipv6_fib_lookup(net, params, flags, false);
|
|
|
+ rc = bpf_ipv6_fib_lookup(net, params, flags, false);
|
|
|
break;
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
- if (index > 0) {
|
|
|
+ if (!rc) {
|
|
|
struct net_device *dev;
|
|
|
|
|
|
- dev = dev_get_by_index_rcu(net, index);
|
|
|
+ dev = dev_get_by_index_rcu(net, params->ifindex);
|
|
|
if (!is_skb_forwardable(dev, skb))
|
|
|
- index = 0;
|
|
|
+ rc = BPF_FIB_LKUP_RET_FRAG_NEEDED;
|
|
|
}
|
|
|
|
|
|
- return index;
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
static const struct bpf_func_proto bpf_skb_fib_lookup_proto = {
|