Skip to content

Commit 3701d30

Browse files
authored
Merge pull request #45 from xdp-project/vestas08_cleanups
Cleanups for AF_XDP-interaction code and btf_unit_test
2 parents c673cf6 + 1890887 commit 3701d30

File tree

5 files changed

+361
-61
lines changed

5 files changed

+361
-61
lines changed

AF_XDP-interaction/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
22

33
USER_TARGETS := af_xdp_user
4+
USER_TARGETS += btf_unit_test
45
BPF_TARGETS := af_xdp_kern
6+
BPF_TARGETS += btf_unit_test_bpf
57

68
# Define C-code objects USER_TARGETS needs
79
USER_TARGETS_OBJS := common_params.o common_user_bpf_xdp.o

AF_XDP-interaction/af_xdp_user.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,11 @@ struct xsk_btf_info *setup_btf_info(struct btf *btf,
143143

144144
err = xsk_btf__init_xdp_hint(btf, struct_name, &xbi);
145145
if (err) {
146-
fprintf(stderr, "WARN(%d): Cannot BTF find struct:%s\n",
146+
fprintf(stderr, "WARN(%d): Cannot BTF locate valid struct:%s\n",
147147
err, struct_name);
148148
return NULL;
149149
}
150150

151-
if (!xsk_btf__has_field("btf_id", xbi)) {
152-
fprintf(stderr, "ERR: %s doesn't contain member btf_id\n",
153-
struct_name);
154-
xsk_btf__free_xdp_hint(xbi);
155-
return NULL;
156-
}
157-
158151
if (debug_meta)
159152
printf("Setup BTF based XDP hints for struct: %s\n",
160153
struct_name);

AF_XDP-interaction/btf_unit_test.c

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
/* Code exercising BTF userspace decoding */
2+
3+
#include <stddef.h>
4+
#include <stdlib.h>
5+
#include <stdio.h>
6+
7+
#include <errno.h>
8+
9+
#include <bpf/bpf.h>
10+
#include <bpf/libbpf.h>
11+
12+
#include <bpf/btf.h> /* provided by libbpf */
13+
14+
#include "lib_xsk_extend.h"
15+
16+
static int verbose = 1;
17+
18+
/* Exit return codes - can be used by scripts looking at exit code */
19+
#define EXIT_OK 0 /* == EXIT_SUCCESS (stdlib.h) man exit(3) */
20+
#define EXIT_FAIL 1 /* == EXIT_FAILURE (stdlib.h) man exit(3) */
21+
#define EXIT_FAIL_OPTION 2
22+
#define EXIT_FAIL_XDP 3
23+
#define EXIT_FAIL_BPF 4
24+
#define EXIT_FAIL_BTF 5
25+
26+
struct bpf_object *load_bpf_object(const char *filename) {
27+
struct bpf_object *obj;
28+
char buf[100];
29+
int err;
30+
31+
obj = bpf_object__open_file(filename, NULL);
32+
err = libbpf_get_error(obj);
33+
if (err) {
34+
libbpf_strerror(err, buf, sizeof(buf));
35+
printf("Error opening file: %s\n", buf);
36+
return NULL;
37+
}
38+
return obj;
39+
}
40+
41+
/**
42+
* BTF setup XDP-hints
43+
* -------------------
44+
* Setup the data structures for accessing the XDP-hints provided by
45+
* kernel side BPF-prog via decoding BTF-info provided in BPF
46+
* ELF-object file.
47+
*/
48+
49+
/* This struct BTF mirrors kernel-side struct xdp_hints_rx_time */
50+
struct xdp_hints_rx_time {
51+
__u32 btf_type_id; /* cached xsk_btf__btf_type_id(xbi) */
52+
struct xsk_btf_info *xbi;
53+
struct xsk_btf_member rx_ktime;
54+
struct xsk_btf_member xdp_rx_cpu;
55+
} xdp_hints_rx_time = { 0 };
56+
57+
/* This struct BTF mirrors kernel-side struct xdp_hints_mark */
58+
struct xdp_hints_mark {
59+
__u32 btf_type_id; /* cached xsk_btf__btf_type_id(xbi) */
60+
struct xsk_btf_info *xbi;
61+
struct xsk_btf_member mark;
62+
} xdp_hints_mark = { 0 };
63+
64+
struct xsk_btf_info *setup_btf_info(struct btf *btf,
65+
const char *struct_name,
66+
int *errval)
67+
{
68+
struct xsk_btf_info *xbi = NULL;
69+
int err;
70+
71+
err = xsk_btf__init_xdp_hint(btf, struct_name, &xbi);
72+
if (err) {
73+
if (errval) {
74+
/* Expect caller to handle err detection */
75+
*errval = err;
76+
} else {
77+
fprintf(stderr,
78+
"WARN(%d): Cannot BTF locate valid struct:%s\n",
79+
err, struct_name);
80+
}
81+
return NULL;
82+
}
83+
84+
if (verbose) {
85+
int btf_id = xsk_btf__btf_type_id(xbi);
86+
printf("Setup BTF based XDP hints for (btf_id:%d) struct: %s\n",
87+
btf_id, struct_name);
88+
}
89+
90+
return xbi;
91+
}
92+
93+
int init_btf_info_via_bpf_object(struct bpf_object *bpf_obj)
94+
{
95+
struct btf *btf = bpf_object__btf(bpf_obj);
96+
struct xsk_btf_info *xbi;
97+
98+
xbi = setup_btf_info(btf, "xdp_hints_rx_time", NULL);
99+
if (xbi) {
100+
/* Lookup info on required member "rx_ktime" */
101+
if (!xsk_btf__field_member("rx_ktime", xbi,
102+
&xdp_hints_rx_time.rx_ktime))
103+
return -EBADSLT;
104+
if (!xsk_btf__field_member("xdp_rx_cpu", xbi,
105+
&xdp_hints_rx_time.xdp_rx_cpu))
106+
return -EBADSLT;
107+
xdp_hints_rx_time.btf_type_id = xsk_btf__btf_type_id(xbi);
108+
xdp_hints_rx_time.xbi = xbi;
109+
}
110+
/* Remember to cleanup later: xsk_btf__free_xdp_hint(xbi); */
111+
112+
xbi = setup_btf_info(btf, "xdp_hints_mark", NULL);
113+
if (xbi) {
114+
if (!xsk_btf__field_member("mark", xbi, &xdp_hints_mark.mark))
115+
return -EBADSLT;
116+
xdp_hints_mark.btf_type_id = xsk_btf__btf_type_id(xbi);
117+
xdp_hints_mark.xbi = xbi;
118+
}
119+
120+
return 0;
121+
}
122+
123+
int test01_normal()
124+
{
125+
struct bpf_object *bpf_obj;
126+
int err = 0;
127+
128+
bpf_obj = load_bpf_object("af_xdp_kern.o");
129+
if (!bpf_obj)
130+
return EXIT_FAIL_BPF;
131+
132+
err = init_btf_info_via_bpf_object(bpf_obj);
133+
if (err) {
134+
if (verbose)
135+
printf("ERR(%d): Failed loading BTF info", err);
136+
bpf_object__close(bpf_obj);
137+
return EXIT_FAIL_BTF;
138+
}
139+
/* Teardown structs and memory again */
140+
xsk_btf__free_xdp_hint(xdp_hints_rx_time.xbi);
141+
xsk_btf__free_xdp_hint(xdp_hints_mark.xbi);
142+
bpf_object__close(bpf_obj);
143+
144+
return EXIT_OK;
145+
}
146+
147+
int helper_expect_invalid_btf_id(struct btf *btf,
148+
const char *xdp_hint_name)
149+
{
150+
struct xsk_btf_info *xbi;
151+
int ret = EXIT_OK;
152+
int errval = 0;
153+
154+
xbi = setup_btf_info(btf, xdp_hint_name, &errval);
155+
if (xbi) {
156+
/* Unexpected success - as hints layout should be invalid */
157+
printf(" - Unexpected success in test that should fail\n");
158+
xsk_btf__free_xdp_hint(xbi);
159+
ret = EXIT_FAIL_BPF;
160+
goto out;
161+
}
162+
if (errval != -EOVERFLOW) {
163+
/* Expecting failure with EOVERFLOW as btf_id not last member */
164+
printf("Unexpect FAIL - with errno:%d\n", errval);
165+
ret = EXIT_FAIL_BTF;
166+
goto out;
167+
}
168+
if (verbose) {
169+
printf("SUCCESS - "
170+
"detect btf_id not last member in struct %s\n",
171+
xdp_hint_name);
172+
}
173+
174+
out:
175+
return ret;
176+
}
177+
178+
int test02_should_fail()
179+
{
180+
const char *xdp_hint01 = "xdp_hints_fail001";
181+
const char *xdp_hint02 = "xdp_hints_fail002";
182+
struct bpf_object *bpf_obj;
183+
int ret = EXIT_OK;
184+
struct btf *btf;
185+
186+
bpf_obj = load_bpf_object("btf_unit_test_bpf.o");
187+
if (!bpf_obj)
188+
return EXIT_FAIL_BPF;
189+
190+
btf = bpf_object__btf(bpf_obj);
191+
192+
ret = helper_expect_invalid_btf_id(btf, xdp_hint01);
193+
if (ret)
194+
goto out;
195+
196+
ret = helper_expect_invalid_btf_id(btf, xdp_hint02);
197+
if (ret)
198+
goto out;
199+
200+
out:
201+
bpf_object__close(bpf_obj);
202+
return ret;
203+
}
204+
205+
int main(int argc, char **argv)
206+
{
207+
int err;
208+
209+
err = test01_normal();
210+
if (err)
211+
return err;
212+
213+
err = test02_should_fail();
214+
if (err)
215+
return err;
216+
217+
return EXIT_OK;
218+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_helpers.h>
4+
5+
#include <bpf/bpf_core_read.h> /* bpf_core_type_id_local */
6+
7+
/*
8+
* The xdp_hints_xxx struct's are stored in the XDP 'data_meta' area,
9+
* which is located just in-front-of the raw packet payload data.
10+
*
11+
* Explaining the struct attribute's:
12+
* ----------------------------------
13+
* The struct must be 4 byte aligned (kernel requirement), which here
14+
* is enforced by the struct __attribute__((aligned(4))).
15+
*
16+
* To avoid any C-struct padding attribute "packed" is used.
17+
*
18+
* NOTICE: Do NOT define __attribute__((preserve_access_index)) here,
19+
* as libbpf will try to find a matching kernel data-structure,
20+
* e.g. it will cause BPF-prog loading step to fail (with invalid func
21+
* unknown#195896080 which is 0xbad2310 in hex for "bad relo").
22+
*/
23+
24+
struct xdp_hints_fail001 {
25+
__u64 hash64;
26+
__u32 btf_id;
27+
__u32 pad; /* Pad that breaks btf_id as last member */
28+
} __attribute__((aligned(4))) __attribute__((packed));
29+
30+
/* Notice struct is without attribute "packed", thus (64-bit) C-compiler will
31+
* add padding. This will cause btf_id to NOT be the last member (which is a
32+
* requirement).
33+
*/
34+
struct xdp_hints_fail002 {
35+
__u64 hash64;
36+
__u32 btf_id;
37+
} __attribute__((aligned(4))) /* not packed */;
38+
39+
40+
SEC("xdp")
41+
int xdp_prog_fail001(struct xdp_md *ctx)
42+
{
43+
struct xdp_hints_fail001 *meta;
44+
void *data;
45+
int err;
46+
47+
err = bpf_xdp_adjust_meta(ctx, -(int)sizeof(*meta));
48+
if (err)
49+
return XDP_ABORTED;
50+
51+
data = (void *)(unsigned long)ctx->data;
52+
meta = (void *)(unsigned long)ctx->data_meta;
53+
if (meta + 1 > data) /* Verify meta area is accessible */
54+
return XDP_ABORTED;
55+
56+
meta->btf_id = bpf_core_type_id_local(struct xdp_hints_fail001);
57+
meta->hash64 = 0x4142434445464748;
58+
59+
return XDP_PASS;
60+
}
61+
62+
SEC("xdp")
63+
int xdp_prog_fail002(struct xdp_md *ctx)
64+
{
65+
struct xdp_hints_fail002 f002;
66+
f002.btf_id = bpf_core_type_id_local(struct xdp_hints_fail002);
67+
if (f002.btf_id == 0)
68+
return XDP_ABORTED;
69+
70+
return XDP_PASS;
71+
}
72+
73+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)