Skip to content

Commit 97f91a7

Browse files
jrfastabdavem330
authored andcommitted
bpf: add bpf_redirect_map helper routine
BPF programs can use the devmap with a bpf_redirect_map() helper routine to forward packets to netdevice in map. Signed-off-by: John Fastabend <[email protected]> Signed-off-by: Jesper Dangaard Brouer <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 546ac1f commit 97f91a7

File tree

5 files changed

+78
-1
lines changed

5 files changed

+78
-1
lines changed

Diff for: include/linux/bpf.h

+3
Original file line numberDiff line numberDiff line change
@@ -379,4 +379,7 @@ extern const struct bpf_func_proto bpf_get_stackid_proto;
379379
void bpf_user_rnd_init_once(void);
380380
u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
381381

382+
/* Map specifics */
383+
struct net_device *__dev_map_lookup_elem(struct bpf_map *map, u32 key);
384+
382385
#endif /* _LINUX_BPF_H */

Diff for: include/uapi/linux/bpf.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ union bpf_attr {
348348
* @flags: bit 0 - if set, redirect to ingress instead of egress
349349
* other bits - reserved
350350
* Return: TC_ACT_REDIRECT
351+
* int bpf_redirect_map(key, map, flags)
352+
* redirect to endpoint in map
353+
* @key: index in map to lookup
354+
* @map: fd of map to do lookup in
355+
* @flags: --
351356
*
352357
* u32 bpf_get_route_realm(skb)
353358
* retrieve a dst's tclassid
@@ -592,7 +597,8 @@ union bpf_attr {
592597
FN(get_socket_uid), \
593598
FN(set_hash), \
594599
FN(setsockopt), \
595-
FN(skb_adjust_room),
600+
FN(skb_adjust_room), \
601+
FN(redirect_map),
596602

597603
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
598604
* function eBPF program intends to call

Diff for: kernel/bpf/devmap.c

+12
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,18 @@ static int dev_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
159159
return 0;
160160
}
161161

162+
struct net_device *__dev_map_lookup_elem(struct bpf_map *map, u32 key)
163+
{
164+
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
165+
struct bpf_dtab_netdev *dev;
166+
167+
if (key >= map->max_entries)
168+
return NULL;
169+
170+
dev = READ_ONCE(dtab->netdev_map[key]);
171+
return dev ? dev->dev : NULL;
172+
}
173+
162174
/* rcu_read_lock (from syscall and BPF contexts) ensures that if a delete and/or
163175
* update happens in parallel here a dev_put wont happen until after reading the
164176
* ifindex.

Diff for: kernel/bpf/verifier.c

+4
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,10 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id)
13121312
if (map->map_type != BPF_MAP_TYPE_CGROUP_ARRAY)
13131313
goto error;
13141314
break;
1315+
case BPF_FUNC_redirect_map:
1316+
if (map->map_type != BPF_MAP_TYPE_DEVMAP)
1317+
goto error;
1318+
break;
13151319
default:
13161320
break;
13171321
}

Diff for: net/core/filter.c

+52
Original file line numberDiff line numberDiff line change
@@ -1779,6 +1779,7 @@ static const struct bpf_func_proto bpf_clone_redirect_proto = {
17791779
struct redirect_info {
17801780
u32 ifindex;
17811781
u32 flags;
1782+
struct bpf_map *map;
17821783
};
17831784

17841785
static DEFINE_PER_CPU(struct redirect_info, redirect_info);
@@ -1792,6 +1793,7 @@ BPF_CALL_2(bpf_redirect, u32, ifindex, u64, flags)
17921793

17931794
ri->ifindex = ifindex;
17941795
ri->flags = flags;
1796+
ri->map = NULL;
17951797

17961798
return TC_ACT_REDIRECT;
17971799
}
@@ -1819,6 +1821,29 @@ static const struct bpf_func_proto bpf_redirect_proto = {
18191821
.arg2_type = ARG_ANYTHING,
18201822
};
18211823

1824+
BPF_CALL_3(bpf_redirect_map, struct bpf_map *, map, u32, ifindex, u64, flags)
1825+
{
1826+
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
1827+
1828+
if (unlikely(flags))
1829+
return XDP_ABORTED;
1830+
1831+
ri->ifindex = ifindex;
1832+
ri->flags = flags;
1833+
ri->map = map;
1834+
1835+
return XDP_REDIRECT;
1836+
}
1837+
1838+
static const struct bpf_func_proto bpf_redirect_map_proto = {
1839+
.func = bpf_redirect_map,
1840+
.gpl_only = false,
1841+
.ret_type = RET_INTEGER,
1842+
.arg1_type = ARG_CONST_MAP_PTR,
1843+
.arg2_type = ARG_ANYTHING,
1844+
.arg3_type = ARG_ANYTHING,
1845+
};
1846+
18221847
BPF_CALL_1(bpf_get_cgroup_classid, const struct sk_buff *, skb)
18231848
{
18241849
return task_get_classid(skb);
@@ -2423,14 +2448,39 @@ static int __bpf_tx_xdp(struct net_device *dev, struct xdp_buff *xdp)
24232448
return -EOPNOTSUPP;
24242449
}
24252450

2451+
int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp,
2452+
struct bpf_prog *xdp_prog)
2453+
{
2454+
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
2455+
struct bpf_map *map = ri->map;
2456+
struct net_device *fwd;
2457+
int err = -EINVAL;
2458+
2459+
ri->ifindex = 0;
2460+
ri->map = NULL;
2461+
2462+
fwd = __dev_map_lookup_elem(map, ri->ifindex);
2463+
if (!fwd)
2464+
goto out;
2465+
2466+
trace_xdp_redirect(dev, fwd, xdp_prog, XDP_REDIRECT);
2467+
err = __bpf_tx_xdp(fwd, xdp);
2468+
out:
2469+
return err;
2470+
}
2471+
24262472
int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
24272473
struct bpf_prog *xdp_prog)
24282474
{
24292475
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
24302476
struct net_device *fwd;
24312477

2478+
if (ri->map)
2479+
return xdp_do_redirect_map(dev, xdp, xdp_prog);
2480+
24322481
fwd = dev_get_by_index_rcu(dev_net(dev), ri->ifindex);
24332482
ri->ifindex = 0;
2483+
ri->map = NULL;
24342484
if (unlikely(!fwd)) {
24352485
bpf_warn_invalid_xdp_redirect(ri->ifindex);
24362486
return -EINVAL;
@@ -3089,6 +3139,8 @@ xdp_func_proto(enum bpf_func_id func_id)
30893139
return &bpf_xdp_adjust_head_proto;
30903140
case BPF_FUNC_redirect:
30913141
return &bpf_xdp_redirect_proto;
3142+
case BPF_FUNC_redirect_map:
3143+
return &bpf_redirect_map_proto;
30923144
default:
30933145
return bpf_base_func_proto(func_id);
30943146
}

0 commit comments

Comments
 (0)