xref: /linux/tools/testing/selftests/bpf/prog_tests/map_kptr.c (revision c16ce856e422e73a54c41131e0332de1afe09b8b)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <network_helpers.h>
4 
5 #include "map_kptr.skel.h"
6 #include "map_kptr_fail.skel.h"
7 #include "rcu_tasks_trace_gp.skel.h"
8 
9 static void test_map_kptr_success(bool test_run)
10 {
11 	LIBBPF_OPTS(bpf_test_run_opts, lopts);
12 	LIBBPF_OPTS(bpf_test_run_opts, opts,
13 		.data_in = &pkt_v4,
14 		.data_size_in = sizeof(pkt_v4),
15 		.repeat = 1,
16 	);
17 	int key = 0, ret, cpu;
18 	struct map_kptr *skel;
19 	char buf[16], *pbuf;
20 
21 	skel = map_kptr__open_and_load();
22 	if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load"))
23 		return;
24 
25 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref1), &opts);
26 	ASSERT_OK(ret, "test_map_kptr_ref1 refcount");
27 	ASSERT_OK(opts.retval, "test_map_kptr_ref1 retval");
28 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref2), &opts);
29 	ASSERT_OK(ret, "test_map_kptr_ref2 refcount");
30 	ASSERT_OK(opts.retval, "test_map_kptr_ref2 retval");
31 
32 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_ls_map_kptr_ref1), &lopts);
33 	ASSERT_OK(ret, "test_ls_map_kptr_ref1 refcount");
34 	ASSERT_OK(lopts.retval, "test_ls_map_kptr_ref1 retval");
35 
36 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_ls_map_kptr_ref2), &lopts);
37 	ASSERT_OK(ret, "test_ls_map_kptr_ref2 refcount");
38 	ASSERT_OK(lopts.retval, "test_ls_map_kptr_ref2 retval");
39 
40 	if (test_run)
41 		goto exit;
42 
43 	cpu = libbpf_num_possible_cpus();
44 	if (!ASSERT_GT(cpu, 0, "libbpf_num_possible_cpus"))
45 		goto exit;
46 
47 	pbuf = calloc(cpu, sizeof(buf));
48 	if (!ASSERT_OK_PTR(pbuf, "calloc(pbuf)"))
49 		goto exit;
50 
51 	ret = bpf_map__update_elem(skel->maps.array_map,
52 				   &key, sizeof(key), buf, sizeof(buf), 0);
53 	ASSERT_OK(ret, "array_map update");
54 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
55 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
56 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
57 
58 	ret = bpf_map__update_elem(skel->maps.pcpu_array_map,
59 				   &key, sizeof(key), pbuf, cpu * sizeof(buf), 0);
60 	ASSERT_OK(ret, "pcpu_array_map update");
61 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
62 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
63 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
64 
65 	ret = bpf_map__delete_elem(skel->maps.hash_map, &key, sizeof(key), 0);
66 	ASSERT_OK(ret, "hash_map delete");
67 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
68 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
69 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
70 
71 	ret = bpf_map__delete_elem(skel->maps.pcpu_hash_map, &key, sizeof(key), 0);
72 	ASSERT_OK(ret, "pcpu_hash_map delete");
73 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
74 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
75 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
76 
77 	ret = bpf_map__delete_elem(skel->maps.hash_malloc_map, &key, sizeof(key), 0);
78 	ASSERT_OK(ret, "hash_malloc_map delete");
79 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
80 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
81 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
82 
83 	ret = bpf_map__delete_elem(skel->maps.pcpu_hash_malloc_map, &key, sizeof(key), 0);
84 	ASSERT_OK(ret, "pcpu_hash_malloc_map delete");
85 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
86 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
87 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
88 
89 	ret = bpf_map__delete_elem(skel->maps.lru_hash_map, &key, sizeof(key), 0);
90 	ASSERT_OK(ret, "lru_hash_map delete");
91 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
92 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
93 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
94 
95 	ret = bpf_map__delete_elem(skel->maps.lru_pcpu_hash_map, &key, sizeof(key), 0);
96 	ASSERT_OK(ret, "lru_pcpu_hash_map delete");
97 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts);
98 	ASSERT_OK(ret, "test_map_kptr_ref3 refcount");
99 	ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval");
100 
101 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_ls_map_kptr_ref_del), &lopts);
102 	ASSERT_OK(ret, "test_ls_map_kptr_ref_del delete");
103 	skel->data->ref--;
104 	ASSERT_OK(lopts.retval, "test_ls_map_kptr_ref_del retval");
105 
106 	free(pbuf);
107 exit:
108 	map_kptr__destroy(skel);
109 }
110 
111 static int kern_sync_rcu_tasks_trace(struct rcu_tasks_trace_gp *rcu)
112 {
113 	LIBBPF_OPTS(bpf_test_run_opts, opts);
114 	int ret;
115 
116 	WRITE_ONCE(rcu->bss->done, 0);
117 	ret = bpf_prog_test_run_opts(bpf_program__fd(rcu->progs.call_rcu_tasks_trace), &opts);
118 	if (!ASSERT_OK(ret, "call_rcu_tasks_trace"))
119 		return -EFAULT;
120 	if (!ASSERT_OK(opts.retval, "call_rcu_tasks_trace retval"))
121 		return -EFAULT;
122 	while (!READ_ONCE(rcu->bss->done))
123 		sched_yield();
124 	return 0;
125 }
126 
127 static void wait_for_map_release(void)
128 {
129 	LIBBPF_OPTS(bpf_test_run_opts, lopts);
130 	struct map_kptr *skel;
131 	int ret;
132 
133 	skel = map_kptr__open_and_load();
134 	if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load"))
135 		return;
136 
137 	do {
138 		ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.count_ref), &lopts);
139 		ASSERT_OK(ret, "count_ref ret");
140 		ASSERT_OK(lopts.retval, "count_ref retval");
141 	} while (skel->bss->num_of_refs != 2);
142 
143 	map_kptr__destroy(skel);
144 }
145 
146 enum map_update_kptr_case {
147 	MAP_UPDATE_KPTR_ARRAY,
148 	MAP_UPDATE_KPTR_HASH,
149 	MAP_UPDATE_KPTR_HASH_MALLOC,
150 };
151 
152 static struct bpf_program *map_update_kptr_prog(struct map_kptr *skel,
153 						enum map_update_kptr_case test)
154 {
155 	switch (test) {
156 	case MAP_UPDATE_KPTR_ARRAY:
157 		return skel->progs.test_array_map_update_kptr;
158 	case MAP_UPDATE_KPTR_HASH:
159 		return skel->progs.test_hash_map_update_kptr;
160 	case MAP_UPDATE_KPTR_HASH_MALLOC:
161 		return skel->progs.test_hash_malloc_map_update_kptr;
162 	}
163 
164 	return NULL;
165 }
166 
167 static void test_map_update_kptr(enum map_update_kptr_case test)
168 {
169 	LIBBPF_OPTS(bpf_test_run_opts, opts);
170 	struct map_kptr *skel;
171 	struct bpf_program *prog;
172 	int ret;
173 
174 	skel = map_kptr__open_and_load();
175 	if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load"))
176 		return;
177 
178 	prog = map_update_kptr_prog(skel, test);
179 	if (!ASSERT_OK_PTR(prog, "map_update_kptr_prog"))
180 		goto out;
181 
182 	ret = bpf_prog_test_run_opts(bpf_program__fd(prog), &opts);
183 	if (!ASSERT_OK(ret, "map_update_kptr"))
184 		goto out;
185 	if (!ASSERT_OK(opts.retval, "map_update_kptr retval"))
186 		goto out;
187 
188 	ASSERT_EQ(skel->bss->num_of_refs, 3, "refs_after_update");
189 
190 out:
191 	map_kptr__destroy(skel);
192 	wait_for_map_release();
193 }
194 
195 void serial_test_map_kptr(void)
196 {
197 	struct rcu_tasks_trace_gp *skel;
198 
199 	RUN_TESTS(map_kptr_fail);
200 
201 	if (test__start_subtest("update_array_map_kptr"))
202 		test_map_update_kptr(MAP_UPDATE_KPTR_ARRAY);
203 	if (test__start_subtest("update_hash_map_kptr"))
204 		test_map_update_kptr(MAP_UPDATE_KPTR_HASH);
205 	if (test__start_subtest("update_hash_malloc_map_kptr"))
206 		test_map_update_kptr(MAP_UPDATE_KPTR_HASH_MALLOC);
207 
208 	skel = rcu_tasks_trace_gp__open_and_load();
209 	if (!ASSERT_OK_PTR(skel, "rcu_tasks_trace_gp__open_and_load"))
210 		return;
211 
212 	if (test__start_subtest("success-map")) {
213 		test_map_kptr_success(true);
214 
215 		ASSERT_OK(kern_sync_rcu_tasks_trace(skel), "sync rcu_tasks_trace");
216 		ASSERT_OK(kern_sync_rcu(), "sync rcu");
217 		wait_for_map_release();
218 
219 		/* Observe refcount dropping to 1 on bpf_map_free_deferred */
220 		test_map_kptr_success(false);
221 
222 		ASSERT_OK(kern_sync_rcu_tasks_trace(skel), "sync rcu_tasks_trace");
223 		ASSERT_OK(kern_sync_rcu(), "sync rcu");
224 		wait_for_map_release();
225 
226 		/* Observe refcount dropping to 1 on map release. */
227 		test_map_kptr_success(true);
228 	}
229 
230 	rcu_tasks_trace_gp__destroy(skel);
231 }
232