Skip to content

Commit 03beced

Browse files
haoluo1022Nobody
authored andcommitted
selftests/bpf: Add a test for btf_type_tag "percpu"
Add test for percpu btf_type_tag. Similar to the "user" tag, we test the following cases: 1. __percpu struct field. 2. __percpu as function parameter. 3. per_cpu_ptr() accepts dynamically allocated __percpu memory. Because the test for "user" and the test for "percpu" are very similar, a little bit of refactoring has been done in btf_tag.c. Basically, both tests share the same function for loading vmlinux and module btf. Example output from log: > ./test_progs -v -t btf_tag libbpf: prog 'test_percpu1': BPF program load failed: Permission denied libbpf: prog 'test_percpu1': -- BEGIN PROG LOAD LOG -- ... ; g = arg->a; 1: (61) r1 = *(u32 *)(r1 +0) R1 is ptr_bpf_testmod_btf_type_tag_1 access percpu memory: off=0 ... test_btf_type_tag_mod_percpu:PASS:btf_type_tag_percpu 0 nsec #26/6 btf_tag/btf_type_tag_percpu_mod1:OK libbpf: prog 'test_percpu2': BPF program load failed: Permission denied libbpf: prog 'test_percpu2': -- BEGIN PROG LOAD LOG -- ... ; g = arg->p->a; 2: (61) r1 = *(u32 *)(r1 +0) R1 is ptr_bpf_testmod_btf_type_tag_1 access percpu memory: off=0 ... test_btf_type_tag_mod_percpu:PASS:btf_type_tag_percpu 0 nsec #26/7 btf_tag/btf_type_tag_percpu_mod2:OK libbpf: prog 'test_percpu_load': BPF program load failed: Permission denied libbpf: prog 'test_percpu_load': -- BEGIN PROG LOAD LOG -- ... ; g = (__u64)cgrp->rstat_cpu->updated_children; 2: (79) r1 = *(u64 *)(r1 +48) R1 is ptr_cgroup_rstat_cpu access percpu memory: off=48 ... test_btf_type_tag_vmlinux_percpu:PASS:btf_type_tag_percpu_load 0 nsec #26/8 btf_tag/btf_type_tag_percpu_vmlinux_load:OK load_btfs:PASS:could not load vmlinux BTF 0 nsec test_btf_type_tag_vmlinux_percpu:PASS:btf_type_tag_percpu 0 nsec test_btf_type_tag_vmlinux_percpu:PASS:btf_type_tag_percpu_helper 0 nsec #26/9 btf_tag/btf_type_tag_percpu_vmlinux_helper:OK Signed-off-by: Hao Luo <[email protected]>
1 parent f2b2bb8 commit 03beced

File tree

3 files changed

+218
-29
lines changed

3 files changed

+218
-29
lines changed

tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ struct bpf_testmod_btf_type_tag_2 {
3333
struct bpf_testmod_btf_type_tag_1 __user *p;
3434
};
3535

36+
struct bpf_testmod_btf_type_tag_3 {
37+
struct bpf_testmod_btf_type_tag_1 __percpu *p;
38+
};
39+
3640
noinline int
3741
bpf_testmod_test_btf_type_tag_user_1(struct bpf_testmod_btf_type_tag_1 __user *arg) {
3842
BTF_TYPE_EMIT(func_proto_typedef);
@@ -46,6 +50,19 @@ bpf_testmod_test_btf_type_tag_user_2(struct bpf_testmod_btf_type_tag_2 *arg) {
4650
return arg->p->a;
4751
}
4852

53+
noinline int
54+
bpf_testmod_test_btf_type_tag_percpu_1(struct bpf_testmod_btf_type_tag_1 __percpu *arg) {
55+
BTF_TYPE_EMIT(func_proto_typedef);
56+
BTF_TYPE_EMIT(func_proto_typedef_nested1);
57+
BTF_TYPE_EMIT(func_proto_typedef_nested2);
58+
return arg->a;
59+
}
60+
61+
noinline int
62+
bpf_testmod_test_btf_type_tag_percpu_2(struct bpf_testmod_btf_type_tag_3 *arg) {
63+
return arg->p->a;
64+
}
65+
4966
noinline int bpf_testmod_loop_test(int n)
5067
{
5168
int i, sum = 0;

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

Lines changed: 135 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ struct btf_type_tag_test {
1010
};
1111
#include "btf_type_tag.skel.h"
1212
#include "btf_type_tag_user.skel.h"
13+
#include "btf_type_tag_percpu.skel.h"
1314

1415
static void test_btf_decl_tag(void)
1516
{
@@ -43,38 +44,81 @@ static void test_btf_type_tag(void)
4344
btf_type_tag__destroy(skel);
4445
}
4546

46-
static void test_btf_type_tag_mod_user(bool load_test_user1)
47+
/* loads vmlinux_btf as well as module_btf. If the caller passes NULL as
48+
* module_btf, it will not load module btf.
49+
*
50+
* Returns 0 on success.
51+
* Return -1 On error. In case of error, the loaded btf will be freed and the
52+
* input parameters will be set to pointing to NULL.
53+
*/
54+
static int load_btfs(struct btf **vmlinux_btf, struct btf **module_btf,
55+
bool needs_vmlinux_tag)
4756
{
4857
const char *module_name = "bpf_testmod";
49-
struct btf *vmlinux_btf, *module_btf;
50-
struct btf_type_tag_user *skel;
5158
__s32 type_id;
52-
int err;
5359

5460
if (!env.has_testmod) {
5561
test__skip();
56-
return;
62+
return -1;
5763
}
5864

59-
/* skip the test if the module does not have __user tags */
60-
vmlinux_btf = btf__load_vmlinux_btf();
61-
if (!ASSERT_OK_PTR(vmlinux_btf, "could not load vmlinux BTF"))
62-
return;
65+
*vmlinux_btf = btf__load_vmlinux_btf();
66+
if (!ASSERT_OK_PTR(*vmlinux_btf, "could not load vmlinux BTF"))
67+
return -1;
68+
69+
if (!needs_vmlinux_tag)
70+
goto load_module_btf;
6371

64-
module_btf = btf__load_module_btf(module_name, vmlinux_btf);
65-
if (!ASSERT_OK_PTR(module_btf, "could not load module BTF"))
72+
/* skip the test if the vmlinux does not have __user tags */
73+
type_id = btf__find_by_name_kind(*vmlinux_btf, "user", BTF_KIND_TYPE_TAG);
74+
if (type_id <= 0) {
75+
printf("%s:SKIP: btf_type_tag attribute not in vmlinux btf", __func__);
76+
test__skip();
6677
goto free_vmlinux_btf;
78+
}
6779

68-
type_id = btf__find_by_name_kind(module_btf, "user", BTF_KIND_TYPE_TAG);
80+
load_module_btf:
81+
/* skip loading module_btf, if not requested by caller */
82+
if (!module_btf)
83+
return 0;
84+
85+
*module_btf = btf__load_module_btf(module_name, *vmlinux_btf);
86+
if (!ASSERT_OK_PTR(*module_btf, "could not load module BTF"))
87+
goto free_vmlinux_btf;
88+
89+
/* skip the test if the module does not have __user tags */
90+
type_id = btf__find_by_name_kind(*module_btf, "user", BTF_KIND_TYPE_TAG);
6991
if (type_id <= 0) {
7092
printf("%s:SKIP: btf_type_tag attribute not in %s", __func__, module_name);
7193
test__skip();
7294
goto free_module_btf;
7395
}
7496

97+
return 0;
98+
99+
free_module_btf:
100+
btf__free(*module_btf);
101+
free_vmlinux_btf:
102+
btf__free(*vmlinux_btf);
103+
104+
*vmlinux_btf = NULL;
105+
if (module_btf)
106+
*module_btf = NULL;
107+
return -1;
108+
}
109+
110+
static void test_btf_type_tag_mod_user(bool load_test_user1)
111+
{
112+
struct btf *vmlinux_btf = NULL, *module_btf = NULL;
113+
struct btf_type_tag_user *skel;
114+
int err;
115+
116+
if (load_btfs(&vmlinux_btf, &module_btf, /*needs_vmlinux_tag=*/false))
117+
return;
118+
75119
skel = btf_type_tag_user__open();
76120
if (!ASSERT_OK_PTR(skel, "btf_type_tag_user"))
77-
goto free_module_btf;
121+
goto cleanup;
78122

79123
bpf_program__set_autoload(skel->progs.test_sys_getsockname, false);
80124
if (load_test_user1)
@@ -87,34 +131,23 @@ static void test_btf_type_tag_mod_user(bool load_test_user1)
87131

88132
btf_type_tag_user__destroy(skel);
89133

90-
free_module_btf:
134+
cleanup:
91135
btf__free(module_btf);
92-
free_vmlinux_btf:
93136
btf__free(vmlinux_btf);
94137
}
95138

96139
static void test_btf_type_tag_vmlinux_user(void)
97140
{
98141
struct btf_type_tag_user *skel;
99-
struct btf *vmlinux_btf;
100-
__s32 type_id;
142+
struct btf *vmlinux_btf = NULL;
101143
int err;
102144

103-
/* skip the test if the vmlinux does not have __user tags */
104-
vmlinux_btf = btf__load_vmlinux_btf();
105-
if (!ASSERT_OK_PTR(vmlinux_btf, "could not load vmlinux BTF"))
145+
if (load_btfs(&vmlinux_btf, NULL, /*needs_vmlinux_tag=*/true))
106146
return;
107147

108-
type_id = btf__find_by_name_kind(vmlinux_btf, "user", BTF_KIND_TYPE_TAG);
109-
if (type_id <= 0) {
110-
printf("%s:SKIP: btf_type_tag attribute not in vmlinux btf", __func__);
111-
test__skip();
112-
goto free_vmlinux_btf;
113-
}
114-
115148
skel = btf_type_tag_user__open();
116149
if (!ASSERT_OK_PTR(skel, "btf_type_tag_user"))
117-
goto free_vmlinux_btf;
150+
goto cleanup;
118151

119152
bpf_program__set_autoload(skel->progs.test_user2, false);
120153
bpf_program__set_autoload(skel->progs.test_user1, false);
@@ -124,7 +157,70 @@ static void test_btf_type_tag_vmlinux_user(void)
124157

125158
btf_type_tag_user__destroy(skel);
126159

127-
free_vmlinux_btf:
160+
cleanup:
161+
btf__free(vmlinux_btf);
162+
}
163+
164+
static void test_btf_type_tag_mod_percpu(bool load_test_percpu1)
165+
{
166+
struct btf *vmlinux_btf, *module_btf;
167+
struct btf_type_tag_percpu *skel;
168+
int err;
169+
170+
if (load_btfs(&vmlinux_btf, &module_btf, /*needs_vmlinux_tag=*/false))
171+
return;
172+
173+
skel = btf_type_tag_percpu__open();
174+
if (!ASSERT_OK_PTR(skel, "btf_type_tag_percpu"))
175+
goto cleanup;
176+
177+
bpf_program__set_autoload(skel->progs.test_percpu_load, false);
178+
bpf_program__set_autoload(skel->progs.test_percpu_helper, false);
179+
if (load_test_percpu1)
180+
bpf_program__set_autoload(skel->progs.test_percpu2, false);
181+
else
182+
bpf_program__set_autoload(skel->progs.test_percpu1, false);
183+
184+
err = btf_type_tag_percpu__load(skel);
185+
ASSERT_ERR(err, "btf_type_tag_percpu");
186+
187+
btf_type_tag_percpu__destroy(skel);
188+
189+
cleanup:
190+
btf__free(module_btf);
191+
btf__free(vmlinux_btf);
192+
}
193+
194+
static void test_btf_type_tag_vmlinux_percpu(bool load_test)
195+
{
196+
struct btf_type_tag_percpu *skel;
197+
struct btf *vmlinux_btf = NULL;
198+
int err;
199+
200+
if (load_btfs(&vmlinux_btf, NULL, /*needs_vmlinux_tag=*/true))
201+
return;
202+
203+
skel = btf_type_tag_percpu__open();
204+
if (!ASSERT_OK_PTR(skel, "btf_type_tag_percpu"))
205+
goto cleanup;
206+
207+
bpf_program__set_autoload(skel->progs.test_percpu2, false);
208+
bpf_program__set_autoload(skel->progs.test_percpu1, false);
209+
if (load_test) {
210+
bpf_program__set_autoload(skel->progs.test_percpu_helper, false);
211+
212+
err = btf_type_tag_percpu__load(skel);
213+
ASSERT_ERR(err, "btf_type_tag_percpu_load");
214+
} else {
215+
bpf_program__set_autoload(skel->progs.test_percpu_load, false);
216+
217+
err = btf_type_tag_percpu__load(skel);
218+
ASSERT_OK(err, "btf_type_tag_percpu_helper");
219+
}
220+
221+
btf_type_tag_percpu__destroy(skel);
222+
223+
cleanup:
128224
btf__free(vmlinux_btf);
129225
}
130226

@@ -134,10 +230,20 @@ void test_btf_tag(void)
134230
test_btf_decl_tag();
135231
if (test__start_subtest("btf_type_tag"))
136232
test_btf_type_tag();
233+
137234
if (test__start_subtest("btf_type_tag_user_mod1"))
138235
test_btf_type_tag_mod_user(true);
139236
if (test__start_subtest("btf_type_tag_user_mod2"))
140237
test_btf_type_tag_mod_user(false);
141238
if (test__start_subtest("btf_type_tag_sys_user_vmlinux"))
142239
test_btf_type_tag_vmlinux_user();
240+
241+
if (test__start_subtest("btf_type_tag_percpu_mod1"))
242+
test_btf_type_tag_mod_percpu(true);
243+
if (test__start_subtest("btf_type_tag_percpu_mod2"))
244+
test_btf_type_tag_mod_percpu(false);
245+
if (test__start_subtest("btf_type_tag_percpu_vmlinux_load"))
246+
test_btf_type_tag_vmlinux_percpu(true);
247+
if (test__start_subtest("btf_type_tag_percpu_vmlinux_helper"))
248+
test_btf_type_tag_vmlinux_percpu(false);
143249
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2022 Google */
3+
#include "vmlinux.h"
4+
#include <bpf/bpf_helpers.h>
5+
#include <bpf/bpf_tracing.h>
6+
7+
struct bpf_testmod_btf_type_tag_1 {
8+
int a;
9+
};
10+
11+
struct bpf_testmod_btf_type_tag_2 {
12+
struct bpf_testmod_btf_type_tag_1 *p;
13+
};
14+
15+
__u64 g;
16+
17+
SEC("fentry/bpf_testmod_test_btf_type_tag_percpu_1")
18+
int BPF_PROG(test_percpu1, struct bpf_testmod_btf_type_tag_1 *arg)
19+
{
20+
g = arg->a;
21+
return 0;
22+
}
23+
24+
SEC("fentry/bpf_testmod_test_btf_type_tag_percpu_2")
25+
int BPF_PROG(test_percpu2, struct bpf_testmod_btf_type_tag_2 *arg)
26+
{
27+
g = arg->p->a;
28+
return 0;
29+
}
30+
31+
/* trace_cgroup_mkdir(struct cgroup *cgrp, const char *path)
32+
*
33+
* struct cgroup_rstat_cpu {
34+
* ...
35+
* struct cgroup *updated_children;
36+
* ...
37+
* };
38+
*
39+
* struct cgroup {
40+
* ...
41+
* struct cgroup_rstat_cpu __percpu *rstat_cpu;
42+
* ...
43+
* };
44+
*/
45+
SEC("tp_btf/cgroup_mkdir")
46+
int BPF_PROG(test_percpu_load, struct cgroup *cgrp, const char *path)
47+
{
48+
g = (__u64)cgrp->rstat_cpu->updated_children;
49+
return 0;
50+
}
51+
52+
SEC("tp_btf/cgroup_mkdir")
53+
int BPF_PROG(test_percpu_helper, struct cgroup *cgrp, const char *path)
54+
{
55+
struct cgroup_rstat_cpu *rstat;
56+
__u32 cpu;
57+
58+
cpu = bpf_get_smp_processor_id();
59+
rstat = (struct cgroup_rstat_cpu *)bpf_per_cpu_ptr(cgrp->rstat_cpu, cpu);
60+
if (rstat) {
61+
/* READ_ONCE */
62+
*(volatile int *)rstat;
63+
}
64+
65+
return 0;
66+
}

0 commit comments

Comments
 (0)