Skip to content

Commit 939b9c6

Browse files
zeffronAlexei Starovoitov
authored andcommitted
selftests/bpf: Add test for xdp_md context in BPF_PROG_TEST_RUN
Add a test for using xdp_md as a context to BPF_PROG_TEST_RUN for XDP programs. The test uses a BPF program that takes in a return value from XDP meta data, then reduces the size of the XDP meta data by 4 bytes. Test cases validate the possible failure cases for passing in invalid xdp_md contexts, that the return value is successfully passed in, and that the adjusted meta data is successfully copied out. Co-developed-by: Cody Haas <chaas@riotgames.com> Co-developed-by: Lisa Watanabe <lwatanabe@riotgames.com> Signed-off-by: Cody Haas <chaas@riotgames.com> Signed-off-by: Lisa Watanabe <lwatanabe@riotgames.com> Signed-off-by: Zvi Effron <zeffron@riotgames.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/bpf/20210707221657.3985075-5-zeffron@riotgames.com
1 parent ec94670 commit 939b9c6

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <test_progs.h>
3+
#include <network_helpers.h>
4+
#include "test_xdp_context_test_run.skel.h"
5+
6+
void test_xdp_context_error(int prog_fd, struct bpf_test_run_opts opts,
7+
__u32 data_meta, __u32 data, __u32 data_end,
8+
__u32 ingress_ifindex, __u32 rx_queue_index,
9+
__u32 egress_ifindex)
10+
{
11+
struct xdp_md ctx = {
12+
.data = data,
13+
.data_end = data_end,
14+
.data_meta = data_meta,
15+
.ingress_ifindex = ingress_ifindex,
16+
.rx_queue_index = rx_queue_index,
17+
.egress_ifindex = egress_ifindex,
18+
};
19+
int err;
20+
21+
opts.ctx_in = &ctx;
22+
opts.ctx_size_in = sizeof(ctx);
23+
err = bpf_prog_test_run_opts(prog_fd, &opts);
24+
ASSERT_EQ(errno, EINVAL, "errno-EINVAL");
25+
ASSERT_ERR(err, "bpf_prog_test_run");
26+
}
27+
28+
void test_xdp_context_test_run(void)
29+
{
30+
struct test_xdp_context_test_run *skel = NULL;
31+
char data[sizeof(pkt_v4) + sizeof(__u32)];
32+
char bad_ctx[sizeof(struct xdp_md) + 1];
33+
struct xdp_md ctx_in, ctx_out;
34+
DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,
35+
.data_in = &data,
36+
.data_size_in = sizeof(data),
37+
.ctx_out = &ctx_out,
38+
.ctx_size_out = sizeof(ctx_out),
39+
.repeat = 1,
40+
);
41+
int err, prog_fd;
42+
43+
skel = test_xdp_context_test_run__open_and_load();
44+
if (!ASSERT_OK_PTR(skel, "skel"))
45+
return;
46+
prog_fd = bpf_program__fd(skel->progs.xdp_context);
47+
48+
/* Data past the end of the kernel's struct xdp_md must be 0 */
49+
bad_ctx[sizeof(bad_ctx) - 1] = 1;
50+
opts.ctx_in = bad_ctx;
51+
opts.ctx_size_in = sizeof(bad_ctx);
52+
err = bpf_prog_test_run_opts(prog_fd, &opts);
53+
ASSERT_EQ(errno, E2BIG, "extradata-errno");
54+
ASSERT_ERR(err, "bpf_prog_test_run(extradata)");
55+
56+
*(__u32 *)data = XDP_PASS;
57+
*(struct ipv4_packet *)(data + sizeof(__u32)) = pkt_v4;
58+
opts.ctx_in = &ctx_in;
59+
opts.ctx_size_in = sizeof(ctx_in);
60+
memset(&ctx_in, 0, sizeof(ctx_in));
61+
ctx_in.data_meta = 0;
62+
ctx_in.data = sizeof(__u32);
63+
ctx_in.data_end = ctx_in.data + sizeof(pkt_v4);
64+
err = bpf_prog_test_run_opts(prog_fd, &opts);
65+
ASSERT_OK(err, "bpf_prog_test_run(valid)");
66+
ASSERT_EQ(opts.retval, XDP_PASS, "valid-retval");
67+
ASSERT_EQ(opts.data_size_out, sizeof(pkt_v4), "valid-datasize");
68+
ASSERT_EQ(opts.ctx_size_out, opts.ctx_size_in, "valid-ctxsize");
69+
ASSERT_EQ(ctx_out.data_meta, 0, "valid-datameta");
70+
ASSERT_EQ(ctx_out.data, 0, "valid-data");
71+
ASSERT_EQ(ctx_out.data_end, sizeof(pkt_v4), "valid-dataend");
72+
73+
/* Meta data's size must be a multiple of 4 */
74+
test_xdp_context_error(prog_fd, opts, 0, 1, sizeof(data), 0, 0, 0);
75+
76+
/* data_meta must reference the start of data */
77+
test_xdp_context_error(prog_fd, opts, 4, sizeof(__u32), sizeof(data),
78+
0, 0, 0);
79+
80+
/* Meta data must be 32 bytes or smaller */
81+
test_xdp_context_error(prog_fd, opts, 0, 36, sizeof(data), 0, 0, 0);
82+
83+
/* Total size of data must match data_end - data_meta */
84+
test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32),
85+
sizeof(data) - 1, 0, 0, 0);
86+
test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32),
87+
sizeof(data) + 1, 0, 0, 0);
88+
89+
/* RX queue cannot be specified without specifying an ingress */
90+
test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32), sizeof(data),
91+
0, 1, 0);
92+
93+
/* Interface 1 is always the loopback interface which always has only
94+
* one RX queue (index 0). This makes index 1 an invalid rx queue index
95+
* for interface 1.
96+
*/
97+
test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32), sizeof(data),
98+
1, 1, 0);
99+
100+
/* The egress cannot be specified */
101+
test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32), sizeof(data),
102+
0, 0, 1);
103+
104+
test_xdp_context_test_run__destroy(skel);
105+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_helpers.h>
4+
5+
SEC("xdp")
6+
int xdp_context(struct xdp_md *xdp)
7+
{
8+
void *data = (void *)(long)xdp->data;
9+
__u32 *metadata = (void *)(long)xdp->data_meta;
10+
__u32 ret;
11+
12+
if (metadata + 1 > data)
13+
return XDP_ABORTED;
14+
ret = *metadata;
15+
if (bpf_xdp_adjust_meta(xdp, 4))
16+
return XDP_ABORTED;
17+
return ret;
18+
}
19+
20+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)