Skip to content

Commit 51148ed

Browse files
jsitnickiKernel Patches Daemon
authored andcommitted
selftests/bpf: Verify skb metadata in BPF instead of userspace
Move metadata verification into the BPF TC programs. Previously, userspace read metadata from a map and verified it once at test end. Now TC programs compare metadata directly using __builtin_memcmp() and set a test_pass flag. This enables verification at multiple points during test execution rather than a single final check. Signed-off-by: Jakub Sitnicki <[email protected]>
1 parent 3a7d163 commit 51148ed

File tree

2 files changed

+57
-83
lines changed

2 files changed

+57
-83
lines changed

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

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -171,33 +171,6 @@ static int write_test_packet(int tap_fd)
171171
return 0;
172172
}
173173

174-
static void assert_test_result(const struct bpf_map *result_map)
175-
{
176-
int err;
177-
__u32 map_key = 0;
178-
__u8 map_value[TEST_PAYLOAD_LEN];
179-
180-
err = bpf_map__lookup_elem(result_map, &map_key, sizeof(map_key),
181-
&map_value, TEST_PAYLOAD_LEN, BPF_ANY);
182-
if (!ASSERT_OK(err, "lookup test_result"))
183-
return;
184-
185-
ASSERT_MEMEQ(&map_value, &test_payload, TEST_PAYLOAD_LEN,
186-
"test_result map contains test payload");
187-
}
188-
189-
static bool clear_test_result(struct bpf_map *result_map)
190-
{
191-
const __u8 v[sizeof(test_payload)] = {};
192-
const __u32 k = 0;
193-
int err;
194-
195-
err = bpf_map__update_elem(result_map, &k, sizeof(k), v, sizeof(v), BPF_ANY);
196-
ASSERT_OK(err, "update test_result");
197-
198-
return err == 0;
199-
}
200-
201174
void test_xdp_context_veth(void)
202175
{
203176
LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS);
@@ -270,11 +243,13 @@ void test_xdp_context_veth(void)
270243
if (!ASSERT_GE(tx_ifindex, 0, "if_nametoindex tx"))
271244
goto close;
272245

246+
skel->bss->test_pass = false;
247+
273248
ret = send_test_packet(tx_ifindex);
274249
if (!ASSERT_OK(ret, "send_test_packet"))
275250
goto close;
276251

277-
assert_test_result(skel->maps.test_result);
252+
ASSERT_TRUE(skel->bss->test_pass, "test_pass");
278253

279254
close:
280255
close_netns(nstoken);
@@ -286,7 +261,7 @@ void test_xdp_context_veth(void)
286261
static void test_tuntap(struct bpf_program *xdp_prog,
287262
struct bpf_program *tc_prio_1_prog,
288263
struct bpf_program *tc_prio_2_prog,
289-
struct bpf_map *result_map)
264+
bool *test_pass)
290265
{
291266
LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS);
292267
LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
@@ -295,8 +270,7 @@ static void test_tuntap(struct bpf_program *xdp_prog,
295270
int tap_ifindex;
296271
int ret;
297272

298-
if (!clear_test_result(result_map))
299-
return;
273+
*test_pass = false;
300274

301275
ns = netns_new(TAP_NETNS, true);
302276
if (!ASSERT_OK_PTR(ns, "create and open ns"))
@@ -340,7 +314,7 @@ static void test_tuntap(struct bpf_program *xdp_prog,
340314
if (!ASSERT_OK(ret, "write_test_packet"))
341315
goto close;
342316

343-
assert_test_result(result_map);
317+
ASSERT_TRUE(*test_pass, "test_pass");
344318

345319
close:
346320
if (tap_fd >= 0)
@@ -431,37 +405,37 @@ void test_xdp_context_tuntap(void)
431405
test_tuntap(skel->progs.ing_xdp,
432406
skel->progs.ing_cls,
433407
NULL, /* tc prio 2 */
434-
skel->maps.test_result);
408+
&skel->bss->test_pass);
435409
if (test__start_subtest("dynptr_read"))
436410
test_tuntap(skel->progs.ing_xdp,
437411
skel->progs.ing_cls_dynptr_read,
438412
NULL, /* tc prio 2 */
439-
skel->maps.test_result);
413+
&skel->bss->test_pass);
440414
if (test__start_subtest("dynptr_slice"))
441415
test_tuntap(skel->progs.ing_xdp,
442416
skel->progs.ing_cls_dynptr_slice,
443417
NULL, /* tc prio 2 */
444-
skel->maps.test_result);
418+
&skel->bss->test_pass);
445419
if (test__start_subtest("dynptr_write"))
446420
test_tuntap(skel->progs.ing_xdp_zalloc_meta,
447421
skel->progs.ing_cls_dynptr_write,
448422
skel->progs.ing_cls_dynptr_read,
449-
skel->maps.test_result);
423+
&skel->bss->test_pass);
450424
if (test__start_subtest("dynptr_slice_rdwr"))
451425
test_tuntap(skel->progs.ing_xdp_zalloc_meta,
452426
skel->progs.ing_cls_dynptr_slice_rdwr,
453427
skel->progs.ing_cls_dynptr_slice,
454-
skel->maps.test_result);
428+
&skel->bss->test_pass);
455429
if (test__start_subtest("dynptr_offset"))
456430
test_tuntap(skel->progs.ing_xdp_zalloc_meta,
457431
skel->progs.ing_cls_dynptr_offset_wr,
458432
skel->progs.ing_cls_dynptr_offset_rd,
459-
skel->maps.test_result);
433+
&skel->bss->test_pass);
460434
if (test__start_subtest("dynptr_offset_oob"))
461435
test_tuntap(skel->progs.ing_xdp,
462436
skel->progs.ing_cls_dynptr_offset_oob,
463437
skel->progs.ing_cls,
464-
skel->maps.test_result);
438+
&skel->bss->test_pass);
465439
if (test__start_subtest("clone_data_meta_empty_on_data_write"))
466440
test_tuntap_mirred(skel->progs.ing_xdp,
467441
skel->progs.clone_data_meta_empty_on_data_write,

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

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,55 +11,54 @@
1111

1212
#define ctx_ptr(ctx, mem) (void *)(unsigned long)ctx->mem
1313

14-
/* Demonstrates how metadata can be passed from an XDP program to a TC program
15-
* using bpf_xdp_adjust_meta.
16-
* For the sake of testing the metadata support in drivers, the XDP program uses
17-
* a fixed-size payload after the Ethernet header as metadata. The TC program
18-
* copies the metadata it receives into a map so it can be checked from
19-
* userspace.
14+
/* Demonstrate passing metadata from XDP to TC using bpf_xdp_adjust_meta.
15+
*
16+
* The XDP program extracts a fixed-size payload following the Ethernet header
17+
* and stores it as packet metadata to test the driver's metadata support. The
18+
* TC program then verifies if the passed metadata is correct.
2019
*/
2120

22-
struct {
23-
__uint(type, BPF_MAP_TYPE_ARRAY);
24-
__uint(max_entries, 1);
25-
__type(key, __u32);
26-
__uint(value_size, META_SIZE);
27-
} test_result SEC(".maps");
28-
2921
bool test_pass;
3022

23+
static const __u8 meta_want[META_SIZE] = {
24+
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
25+
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
26+
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
27+
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
28+
};
29+
3130
SEC("tc")
3231
int ing_cls(struct __sk_buff *ctx)
3332
{
34-
__u8 *data, *data_meta;
35-
__u32 key = 0;
36-
37-
data_meta = ctx_ptr(ctx, data_meta);
38-
data = ctx_ptr(ctx, data);
33+
__u8 *meta_have = ctx_ptr(ctx, data_meta);
34+
__u8 *data = ctx_ptr(ctx, data);
3935

40-
if (data_meta + META_SIZE > data)
41-
return TC_ACT_SHOT;
36+
if (meta_have + META_SIZE > data)
37+
goto out;
4238

43-
bpf_map_update_elem(&test_result, &key, data_meta, BPF_ANY);
39+
if (__builtin_memcmp(meta_want, meta_have, META_SIZE))
40+
goto out;
4441

42+
test_pass = true;
43+
out:
4544
return TC_ACT_SHOT;
4645
}
4746

4847
/* Read from metadata using bpf_dynptr_read helper */
4948
SEC("tc")
5049
int ing_cls_dynptr_read(struct __sk_buff *ctx)
5150
{
51+
__u8 meta_have[META_SIZE];
5252
struct bpf_dynptr meta;
53-
const __u32 zero = 0;
54-
__u8 *dst;
55-
56-
dst = bpf_map_lookup_elem(&test_result, &zero);
57-
if (!dst)
58-
return TC_ACT_SHOT;
5953

6054
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
61-
bpf_dynptr_read(dst, META_SIZE, &meta, 0, 0);
55+
bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0);
56+
57+
if (__builtin_memcmp(meta_want, meta_have, META_SIZE))
58+
goto out;
6259

60+
test_pass = true;
61+
out:
6362
return TC_ACT_SHOT;
6463
}
6564

@@ -86,20 +85,18 @@ SEC("tc")
8685
int ing_cls_dynptr_slice(struct __sk_buff *ctx)
8786
{
8887
struct bpf_dynptr meta;
89-
const __u32 zero = 0;
90-
__u8 *dst, *src;
91-
92-
dst = bpf_map_lookup_elem(&test_result, &zero);
93-
if (!dst)
94-
return TC_ACT_SHOT;
88+
__u8 *meta_have;
9589

9690
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
97-
src = bpf_dynptr_slice(&meta, 0, NULL, META_SIZE);
98-
if (!src)
99-
return TC_ACT_SHOT;
91+
meta_have = bpf_dynptr_slice(&meta, 0, NULL, META_SIZE);
92+
if (!meta_have)
93+
goto out;
10094

101-
__builtin_memcpy(dst, src, META_SIZE);
95+
if (__builtin_memcmp(meta_want, meta_have, META_SIZE))
96+
goto out;
10297

98+
test_pass = true;
99+
out:
103100
return TC_ACT_SHOT;
104101
}
105102

@@ -129,14 +126,12 @@ int ing_cls_dynptr_slice_rdwr(struct __sk_buff *ctx)
129126
SEC("tc")
130127
int ing_cls_dynptr_offset_rd(struct __sk_buff *ctx)
131128
{
132-
struct bpf_dynptr meta;
133129
const __u32 chunk_len = META_SIZE / 4;
134-
const __u32 zero = 0;
130+
__u8 meta_have[META_SIZE];
131+
struct bpf_dynptr meta;
135132
__u8 *dst, *src;
136133

137-
dst = bpf_map_lookup_elem(&test_result, &zero);
138-
if (!dst)
139-
return TC_ACT_SHOT;
134+
dst = meta_have;
140135

141136
/* 1. Regular read */
142137
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
@@ -155,9 +150,14 @@ int ing_cls_dynptr_offset_rd(struct __sk_buff *ctx)
155150
/* 4. Read from a slice starting at an offset */
156151
src = bpf_dynptr_slice(&meta, 2 * chunk_len, NULL, chunk_len);
157152
if (!src)
158-
return TC_ACT_SHOT;
153+
goto out;
159154
__builtin_memcpy(dst, src, chunk_len);
160155

156+
if (__builtin_memcmp(meta_want, meta_have, META_SIZE))
157+
goto out;
158+
159+
test_pass = true;
160+
out:
161161
return TC_ACT_SHOT;
162162
}
163163

0 commit comments

Comments
 (0)