Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2
3#include <test_progs.h>
4#include "struct_ops_assoc.skel.h"
5#include "struct_ops_assoc_reuse.skel.h"
6#include "struct_ops_assoc_in_timer.skel.h"
7
8static void test_st_ops_assoc(void)
9{
10 struct struct_ops_assoc *skel = NULL;
11 int err, pid;
12
13 skel = struct_ops_assoc__open_and_load();
14 if (!ASSERT_OK_PTR(skel, "struct_ops_assoc__open"))
15 goto out;
16
17 /* cannot explicitly associate struct_ops program */
18 err = bpf_program__assoc_struct_ops(skel->progs.test_1_a,
19 skel->maps.st_ops_map_a, NULL);
20 ASSERT_ERR(err, "bpf_program__assoc_struct_ops(test_1_a, st_ops_map_a)");
21
22 err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_a,
23 skel->maps.st_ops_map_a, NULL);
24 ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_a, st_ops_map_a)");
25
26 err = bpf_program__assoc_struct_ops(skel->progs.sys_enter_prog_a,
27 skel->maps.st_ops_map_a, NULL);
28 ASSERT_OK(err, "bpf_program__assoc_struct_ops(sys_enter_prog_a, st_ops_map_a)");
29
30 err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_b,
31 skel->maps.st_ops_map_b, NULL);
32 ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_b, st_ops_map_b)");
33
34 err = bpf_program__assoc_struct_ops(skel->progs.sys_enter_prog_b,
35 skel->maps.st_ops_map_b, NULL);
36 ASSERT_OK(err, "bpf_program__assoc_struct_ops(sys_enter_prog_b, st_ops_map_b)");
37
38 /* sys_enter_prog_a already associated with map_a */
39 err = bpf_program__assoc_struct_ops(skel->progs.sys_enter_prog_a,
40 skel->maps.st_ops_map_b, NULL);
41 ASSERT_ERR(err, "bpf_program__assoc_struct_ops(sys_enter_prog_a, st_ops_map_b)");
42
43 err = struct_ops_assoc__attach(skel);
44 if (!ASSERT_OK(err, "struct_ops_assoc__attach"))
45 goto out;
46
47 /* run tracing prog that calls .test_1 and checks return */
48 pid = getpid();
49 skel->bss->test_pid = pid;
50 sys_gettid();
51 skel->bss->test_pid = 0;
52
53 ASSERT_EQ(skel->bss->test_err_a, 0, "skel->bss->test_err_a");
54 ASSERT_EQ(skel->bss->test_err_b, 0, "skel->bss->test_err_b");
55
56 /* run syscall_prog that calls .test_1 and checks return */
57 err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_a), NULL);
58 ASSERT_OK(err, "bpf_prog_test_run_opts");
59
60 err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_b), NULL);
61 ASSERT_OK(err, "bpf_prog_test_run_opts");
62
63 ASSERT_EQ(skel->bss->test_err_a, 0, "skel->bss->test_err_a");
64 ASSERT_EQ(skel->bss->test_err_b, 0, "skel->bss->test_err_b");
65
66out:
67 struct_ops_assoc__destroy(skel);
68}
69
70static void test_st_ops_assoc_reuse(void)
71{
72 struct struct_ops_assoc_reuse *skel = NULL;
73 int err;
74
75 skel = struct_ops_assoc_reuse__open_and_load();
76 if (!ASSERT_OK_PTR(skel, "struct_ops_assoc_reuse__open"))
77 goto out;
78
79 err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_a,
80 skel->maps.st_ops_map_a, NULL);
81 ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_a, st_ops_map_a)");
82
83 err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog_b,
84 skel->maps.st_ops_map_b, NULL);
85 ASSERT_OK(err, "bpf_program__assoc_struct_ops(syscall_prog_b, st_ops_map_b)");
86
87 err = struct_ops_assoc_reuse__attach(skel);
88 if (!ASSERT_OK(err, "struct_ops_assoc__attach"))
89 goto out;
90
91 /* run syscall_prog that calls .test_1 and checks return */
92 err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_a), NULL);
93 ASSERT_OK(err, "bpf_prog_test_run_opts");
94
95 err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog_b), NULL);
96 ASSERT_OK(err, "bpf_prog_test_run_opts");
97
98 ASSERT_EQ(skel->bss->test_err_a, 0, "skel->bss->test_err_a");
99 ASSERT_EQ(skel->bss->test_err_b, 0, "skel->bss->test_err_b");
100
101out:
102 struct_ops_assoc_reuse__destroy(skel);
103}
104
105static void test_st_ops_assoc_in_timer(void)
106{
107 struct struct_ops_assoc_in_timer *skel = NULL;
108 int err;
109
110 skel = struct_ops_assoc_in_timer__open_and_load();
111 if (!ASSERT_OK_PTR(skel, "struct_ops_assoc_in_timer__open"))
112 goto out;
113
114 err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog,
115 skel->maps.st_ops_map, NULL);
116 ASSERT_OK(err, "bpf_program__assoc_struct_ops");
117
118 err = struct_ops_assoc_in_timer__attach(skel);
119 if (!ASSERT_OK(err, "struct_ops_assoc__attach"))
120 goto out;
121
122 /*
123 * Run .test_1 by calling kfunc bpf_kfunc_multi_st_ops_test_1_prog_arg() and checks
124 * the return value. .test_1 will also schedule timer_cb that runs .test_1 again
125 * immediately.
126 */
127 err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog), NULL);
128 ASSERT_OK(err, "bpf_prog_test_run_opts");
129
130 /* Check the return of the kfunc after timer_cb runs */
131 while (!READ_ONCE(skel->bss->timer_cb_run))
132 sched_yield();
133 ASSERT_EQ(skel->bss->timer_test_1_ret, 1234, "skel->bss->timer_test_1_ret");
134 ASSERT_EQ(skel->bss->test_err, 0, "skel->bss->test_err_a");
135out:
136 struct_ops_assoc_in_timer__destroy(skel);
137}
138
139static void test_st_ops_assoc_in_timer_no_uref(void)
140{
141 struct struct_ops_assoc_in_timer *skel = NULL;
142 struct bpf_link *link;
143 int err;
144
145 skel = struct_ops_assoc_in_timer__open_and_load();
146 if (!ASSERT_OK_PTR(skel, "struct_ops_assoc_in_timer__open"))
147 goto out;
148
149 err = bpf_program__assoc_struct_ops(skel->progs.syscall_prog,
150 skel->maps.st_ops_map, NULL);
151 ASSERT_OK(err, "bpf_program__assoc_struct_ops");
152
153 link = bpf_map__attach_struct_ops(skel->maps.st_ops_map);
154 if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops"))
155 goto out;
156
157 /*
158 * Run .test_1 by calling kfunc bpf_kfunc_multi_st_ops_test_1_prog_arg() and checks
159 * the return value. .test_1 will also schedule timer_cb that runs .test_1 again.
160 * timer_cb will run 500ms after syscall_prog runs, when the user space no longer
161 * holds a reference to st_ops_map.
162 */
163 skel->bss->timer_ns = 500000000;
164 err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.syscall_prog), NULL);
165 ASSERT_OK(err, "bpf_prog_test_run_opts");
166
167 /* Detach and close struct_ops map to cause it to be freed */
168 bpf_link__destroy(link);
169 close(bpf_program__fd(skel->progs.syscall_prog));
170 close(bpf_map__fd(skel->maps.st_ops_map));
171
172 /* Check the return of the kfunc after timer_cb runs */
173 while (!READ_ONCE(skel->bss->timer_cb_run))
174 sched_yield();
175 ASSERT_EQ(skel->bss->timer_test_1_ret, -1, "skel->bss->timer_test_1_ret");
176 ASSERT_EQ(skel->bss->test_err, 0, "skel->bss->test_err_a");
177out:
178 struct_ops_assoc_in_timer__destroy(skel);
179}
180
181void test_struct_ops_assoc(void)
182{
183 if (test__start_subtest("st_ops_assoc"))
184 test_st_ops_assoc();
185 if (test__start_subtest("st_ops_assoc_reuse"))
186 test_st_ops_assoc_reuse();
187 if (test__start_subtest("st_ops_assoc_in_timer"))
188 test_st_ops_assoc_in_timer();
189 if (test__start_subtest("st_ops_assoc_in_timer_no_uref"))
190 test_st_ops_assoc_in_timer_no_uref();
191}