Skip to content

Commit 1e7e634

Browse files
bastien-curutchetMartin KaFai Lau
authored andcommitted
selftests/bpf: test_xdp_veth: Add XDP broadcast redirection tests
XDP redirections with BPF_F_BROADCAST and BPF_F_EXCLUDE_INGRESS flags are tested by test_xdp_redirect_multi.sh but not within the test_progs framework. Add a broadcast test case in test_xdp_veth.c to test them. Use the same BPF programs than the one used by test_xdp_redirect_multi.sh. Use a BPF map to select the broadcast flags. Use a BPF map with an entry per veth to check whether packets are received or not Signed-off-by: Bastien Curutchet (eBPF Foundation) <[email protected]> Signed-off-by: Martin KaFai Lau <[email protected]> Acked-by: Stanislav Fomichev <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 09c8bb1 commit 1e7e634

File tree

2 files changed

+205
-0
lines changed

2 files changed

+205
-0
lines changed

tools/testing/selftests/bpf/prog_tests/test_xdp_veth.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@
2828
* | | | | | |
2929
* | ------------------ ------------------ |
3030
* -----------------------------------------
31+
*
32+
* - [test_xdp_veth_broadcast_redirect]: broadcast from veth11
33+
* - IPv4 ping : BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS
34+
* -> echo request received by all except veth11
35+
* - IPv4 ping : BPF_F_BROADCAST
36+
* -> echo request received by all veth
37+
*
38+
* veth11 veth22 veth33
39+
* (XDP_PASS) (XDP_PASS) (XDP_PASS)
40+
* | | |
41+
* | | |
42+
* veth1 veth2 veth3
43+
* (XDP_REDIRECT) (XDP_REDIRECT) (XDP_REDIRECT)
44+
* | ^ ^
45+
* | | |
46+
* ----------------------------------------
47+
*
3148
*/
3249

3350
#define _GNU_SOURCE
@@ -36,6 +53,7 @@
3653
#include "network_helpers.h"
3754
#include "xdp_dummy.skel.h"
3855
#include "xdp_redirect_map.skel.h"
56+
#include "xdp_redirect_multi_kern.skel.h"
3957
#include "xdp_tx.skel.h"
4058
#include <uapi/linux/if_link.h>
4159

@@ -44,6 +62,7 @@
4462
#define IP_MAX_LEN 16
4563
#define IP_SRC "10.1.1.11"
4664
#define IP_DST "10.1.1.33"
65+
#define IP_NEIGH "10.1.1.253"
4766
#define PROG_NAME_MAX_LEN 128
4867
#define NS_NAME_MAX_LEN 32
4968

@@ -297,6 +316,121 @@ static void xdp_veth_redirect(u32 flags)
297316
cleanup_network(&net_config);
298317
}
299318

319+
#define BROADCAST_REDIRECT_SKEL_NB 2
320+
static void xdp_veth_broadcast_redirect(u32 attach_flags, u64 redirect_flags)
321+
{
322+
struct prog_configuration prog_cfg[VETH_PAIRS_COUNT] = {
323+
{
324+
.local_name = "xdp_redirect_map_multi_prog",
325+
.remote_name = "xdp_count_0",
326+
.local_flags = attach_flags,
327+
.remote_flags = attach_flags,
328+
},
329+
{
330+
.local_name = "xdp_redirect_map_multi_prog",
331+
.remote_name = "xdp_count_1",
332+
.local_flags = attach_flags,
333+
.remote_flags = attach_flags,
334+
},
335+
{
336+
.local_name = "xdp_redirect_map_multi_prog",
337+
.remote_name = "xdp_count_2",
338+
.local_flags = attach_flags,
339+
.remote_flags = attach_flags,
340+
}
341+
};
342+
struct bpf_object *bpf_objs[BROADCAST_REDIRECT_SKEL_NB];
343+
struct xdp_redirect_multi_kern *xdp_redirect_multi_kern;
344+
struct xdp_redirect_map *xdp_redirect_map;
345+
struct bpf_devmap_val devmap_val = {};
346+
struct net_configuration net_config;
347+
struct nstoken *nstoken = NULL;
348+
u16 protocol = ETH_P_IP;
349+
int group_map;
350+
int flags_map;
351+
int cnt_map;
352+
u64 cnt = 0;
353+
int i, err;
354+
355+
xdp_redirect_multi_kern = xdp_redirect_multi_kern__open_and_load();
356+
if (!ASSERT_OK_PTR(xdp_redirect_multi_kern, "xdp_redirect_multi_kern__open_and_load"))
357+
return;
358+
359+
xdp_redirect_map = xdp_redirect_map__open_and_load();
360+
if (!ASSERT_OK_PTR(xdp_redirect_map, "xdp_redirect_map__open_and_load"))
361+
goto destroy_xdp_redirect_multi_kern;
362+
363+
if (!ASSERT_OK(create_network(&net_config), "create network"))
364+
goto destroy_xdp_redirect_map;
365+
366+
group_map = bpf_map__fd(xdp_redirect_multi_kern->maps.map_all);
367+
if (!ASSERT_OK_FD(group_map, "open map_all"))
368+
goto destroy_xdp_redirect_map;
369+
370+
flags_map = bpf_map__fd(xdp_redirect_multi_kern->maps.redirect_flags);
371+
if (!ASSERT_OK_FD(group_map, "open map_all"))
372+
goto destroy_xdp_redirect_map;
373+
374+
err = bpf_map_update_elem(flags_map, &protocol, &redirect_flags, BPF_NOEXIST);
375+
if (!ASSERT_OK(err, "init IP count"))
376+
goto destroy_xdp_redirect_map;
377+
378+
cnt_map = bpf_map__fd(xdp_redirect_map->maps.rxcnt);
379+
if (!ASSERT_OK_FD(cnt_map, "open rxcnt map"))
380+
goto destroy_xdp_redirect_map;
381+
382+
bpf_objs[0] = xdp_redirect_multi_kern->obj;
383+
bpf_objs[1] = xdp_redirect_map->obj;
384+
385+
nstoken = open_netns(net_config.ns0_name);
386+
if (!ASSERT_OK_PTR(nstoken, "open NS0"))
387+
goto destroy_xdp_redirect_map;
388+
389+
for (i = 0; i < VETH_PAIRS_COUNT; i++) {
390+
int ifindex = if_nametoindex(net_config.veth_cfg[i].local_veth);
391+
392+
if (attach_programs_to_veth_pair(bpf_objs, BROADCAST_REDIRECT_SKEL_NB,
393+
&net_config, prog_cfg, i))
394+
goto destroy_xdp_redirect_map;
395+
396+
SYS(destroy_xdp_redirect_map,
397+
"ip -n %s neigh add %s lladdr 00:00:00:00:00:01 dev %s",
398+
net_config.veth_cfg[i].namespace, IP_NEIGH, net_config.veth_cfg[i].remote_veth);
399+
400+
devmap_val.ifindex = ifindex;
401+
err = bpf_map_update_elem(group_map, &ifindex, &devmap_val, 0);
402+
if (!ASSERT_OK(err, "bpf_map_update_elem"))
403+
goto destroy_xdp_redirect_map;
404+
405+
}
406+
407+
SYS_NOFAIL("ip netns exec %s ping %s -i 0.1 -c 4 -W1 > /dev/null ",
408+
net_config.veth_cfg[0].namespace, IP_NEIGH);
409+
410+
for (i = 0; i < VETH_PAIRS_COUNT; i++) {
411+
err = bpf_map_lookup_elem(cnt_map, &i, &cnt);
412+
if (!ASSERT_OK(err, "get IP cnt"))
413+
goto destroy_xdp_redirect_map;
414+
415+
if (redirect_flags & BPF_F_EXCLUDE_INGRESS)
416+
/* veth11 shouldn't receive the ICMP requests;
417+
* others should
418+
*/
419+
ASSERT_EQ(cnt, i ? 4 : 0, "compare IP cnt");
420+
else
421+
/* All remote veth should receive the ICMP requests */
422+
ASSERT_EQ(cnt, 4, "compare IP cnt");
423+
}
424+
425+
destroy_xdp_redirect_map:
426+
close_netns(nstoken);
427+
xdp_redirect_map__destroy(xdp_redirect_map);
428+
destroy_xdp_redirect_multi_kern:
429+
xdp_redirect_multi_kern__destroy(xdp_redirect_multi_kern);
430+
431+
cleanup_network(&net_config);
432+
}
433+
300434
void test_xdp_veth_redirect(void)
301435
{
302436
if (test__start_subtest("0"))
@@ -308,3 +442,26 @@ void test_xdp_veth_redirect(void)
308442
if (test__start_subtest("SKB_MODE"))
309443
xdp_veth_redirect(XDP_FLAGS_SKB_MODE);
310444
}
445+
446+
void test_xdp_veth_broadcast_redirect(void)
447+
{
448+
if (test__start_subtest("0/BROADCAST"))
449+
xdp_veth_broadcast_redirect(0, BPF_F_BROADCAST);
450+
451+
if (test__start_subtest("0/(BROADCAST | EXCLUDE_INGRESS)"))
452+
xdp_veth_broadcast_redirect(0, BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
453+
454+
if (test__start_subtest("DRV_MODE/BROADCAST"))
455+
xdp_veth_broadcast_redirect(XDP_FLAGS_DRV_MODE, BPF_F_BROADCAST);
456+
457+
if (test__start_subtest("DRV_MODE/(BROADCAST | EXCLUDE_INGRESS)"))
458+
xdp_veth_broadcast_redirect(XDP_FLAGS_DRV_MODE,
459+
BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
460+
461+
if (test__start_subtest("SKB_MODE/BROADCAST"))
462+
xdp_veth_broadcast_redirect(XDP_FLAGS_SKB_MODE, BPF_F_BROADCAST);
463+
464+
if (test__start_subtest("SKB_MODE/(BROADCAST | EXCLUDE_INGRESS)"))
465+
xdp_veth_broadcast_redirect(XDP_FLAGS_SKB_MODE,
466+
BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
467+
}

tools/testing/selftests/bpf/progs/xdp_redirect_map.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3+
#include <linux/if_ether.h>
4+
35
#include <linux/bpf.h>
46
#include <bpf/bpf_helpers.h>
7+
#include <bpf/bpf_endian.h>
58

69
struct {
710
__uint(type, BPF_MAP_TYPE_DEVMAP);
@@ -28,4 +31,49 @@ int xdp_redirect_map_2(struct xdp_md *xdp)
2831
return bpf_redirect_map(&tx_port, 2, 0);
2932
}
3033

34+
struct {
35+
__uint(type, BPF_MAP_TYPE_ARRAY);
36+
__uint(max_entries, 3);
37+
__type(key, __u32);
38+
__type(value, __u64);
39+
} rxcnt SEC(".maps");
40+
41+
static int xdp_count(struct xdp_md *xdp, __u32 key)
42+
{
43+
void *data_end = (void *)(long)xdp->data_end;
44+
void *data = (void *)(long)xdp->data;
45+
struct ethhdr *eth = data;
46+
__u64 *count;
47+
48+
if (data + sizeof(*eth) > data_end)
49+
return XDP_DROP;
50+
51+
if (bpf_htons(eth->h_proto) == ETH_P_IP) {
52+
/* We only count IPv4 packets */
53+
count = bpf_map_lookup_elem(&rxcnt, &key);
54+
if (count)
55+
*count += 1;
56+
}
57+
58+
return XDP_PASS;
59+
}
60+
61+
SEC("xdp")
62+
int xdp_count_0(struct xdp_md *xdp)
63+
{
64+
return xdp_count(xdp, 0);
65+
}
66+
67+
SEC("xdp")
68+
int xdp_count_1(struct xdp_md *xdp)
69+
{
70+
return xdp_count(xdp, 1);
71+
}
72+
73+
SEC("xdp")
74+
int xdp_count_2(struct xdp_md *xdp)
75+
{
76+
return xdp_count(xdp, 2);
77+
}
78+
3179
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)