xref: /linux/tools/testing/selftests/bpf/prog_tests/tracing_multi.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <test_progs.h>
4 #include <bpf/btf.h>
5 #include <search.h>
6 #include "bpf/libbpf_internal.h"
7 #include "tracing_multi.skel.h"
8 #include "tracing_multi_module.skel.h"
9 #include "tracing_multi_intersect.skel.h"
10 #include "tracing_multi_session.skel.h"
11 #include "tracing_multi_fail.skel.h"
12 #include "tracing_multi_verifier.skel.h"
13 #include "tracing_multi_bench.skel.h"
14 #include "tracing_multi_rollback.skel.h"
15 #include "trace_helpers.h"
16 
17 static __u64 bpf_fentry_test_cookies[] = {
18 	8,  /* bpf_fentry_test1 */
19 	9,  /* bpf_fentry_test2 */
20 	7,  /* bpf_fentry_test3 */
21 	5,  /* bpf_fentry_test4 */
22 	4,  /* bpf_fentry_test5 */
23 	2,  /* bpf_fentry_test6 */
24 	3,  /* bpf_fentry_test7 */
25 	1,  /* bpf_fentry_test8 */
26 	10, /* bpf_fentry_test9 */
27 	6,  /* bpf_fentry_test10 */
28 };
29 
30 static const char * const bpf_fentry_test[] = {
31 	"bpf_fentry_test1",
32 	"bpf_fentry_test2",
33 	"bpf_fentry_test3",
34 	"bpf_fentry_test4",
35 	"bpf_fentry_test5",
36 	"bpf_fentry_test6",
37 	"bpf_fentry_test7",
38 	"bpf_fentry_test8",
39 	"bpf_fentry_test9",
40 	"bpf_fentry_test10",
41 };
42 
43 static const char * const bpf_testmod_fentry_test[] = {
44 	"bpf_testmod_fentry_test1",
45 	"bpf_testmod_fentry_test2",
46 	"bpf_testmod_fentry_test3",
47 	"bpf_testmod_fentry_test7",
48 	"bpf_testmod_fentry_test11",
49 };
50 
51 #define FUNCS_CNT (ARRAY_SIZE(bpf_fentry_test))
52 
get_random_funcs(const char ** funcs)53 static int get_random_funcs(const char **funcs)
54 {
55 	int i, cnt = 0;
56 
57 	for (i = 0; i < FUNCS_CNT; i++) {
58 		if (rand() % 2)
59 			funcs[cnt++] = bpf_fentry_test[i];
60 	}
61 	/* we always need at least one.. */
62 	if (!cnt)
63 		funcs[cnt++] = bpf_fentry_test[rand() % FUNCS_CNT];
64 	return cnt;
65 }
66 
compare(const void * ppa,const void * ppb)67 static int compare(const void *ppa, const void *ppb)
68 {
69 	const char *pa = *(const char **) ppa;
70 	const char *pb = *(const char **) ppb;
71 
72 	return strcmp(pa, pb);
73 }
74 
tdestroy_free_nop(void * ptr)75 static void tdestroy_free_nop(void *ptr)
76 {
77 }
78 
get_ids(const char * const funcs[],int funcs_cnt,const char * mod)79 static __u32 *get_ids(const char * const funcs[], int funcs_cnt, const char *mod)
80 {
81 	struct btf *btf, *vmlinux_btf = NULL;
82 	__u32 nr, type_id, cnt = 0;
83 	void *root = NULL;
84 	__u32 *ids = NULL;
85 	int i, err = 0;
86 
87 	btf = btf__load_vmlinux_btf();
88 	if (!ASSERT_OK_PTR(btf, "btf__load_vmlinux_btf"))
89 		return NULL;
90 
91 	if (mod) {
92 		vmlinux_btf = btf;
93 		btf = btf__load_module_btf(mod, vmlinux_btf);
94 		if (!ASSERT_OK_PTR(btf, "btf__load_module_btf")) {
95 			btf__free(vmlinux_btf);
96 			return NULL;
97 		}
98 	}
99 
100 	ids = calloc(funcs_cnt, sizeof(ids[0]));
101 	if (!ids)
102 		goto out;
103 
104 	/*
105 	 * We sort function names by name and search them
106 	 * below for each function.
107 	 */
108 	for (i = 0; i < funcs_cnt; i++) {
109 		if (!tsearch(&funcs[i], &root, compare)) {
110 			ASSERT_FAIL("tsearch failed");
111 			err = -1;
112 			goto error;
113 		}
114 	}
115 
116 	nr = btf__type_cnt(btf);
117 	for (type_id = 1; type_id < nr && cnt < funcs_cnt; type_id++) {
118 		const struct btf_type *type;
119 		const char *str, ***val;
120 		unsigned int idx;
121 
122 		type = btf__type_by_id(btf, type_id);
123 		if (!type) {
124 			err = -1;
125 			break;
126 		}
127 
128 		if (BTF_INFO_KIND(type->info) != BTF_KIND_FUNC)
129 			continue;
130 
131 		str = btf__name_by_offset(btf, type->name_off);
132 		if (!str) {
133 			err = -1;
134 			break;
135 		}
136 
137 		val = tfind(&str, &root, compare);
138 		if (!val)
139 			continue;
140 
141 		/*
142 		 * We keep pointer for each function name so we can get the original
143 		 * array index and have the resulting ids array matching the original
144 		 * function array.
145 		 *
146 		 * Doing it this way allow us to easily test the cookies support,
147 		 * because each cookie is attached to particular function/id.
148 		 */
149 		idx = *val - funcs;
150 		ids[idx] = type_id;
151 		cnt++;
152 	}
153 
154 error:
155 	if (err) {
156 		free(ids);
157 		ids = NULL;
158 	}
159 
160 out:
161 	tdestroy(root, tdestroy_free_nop);
162 	btf__free(vmlinux_btf);
163 	btf__free(btf);
164 	return ids;
165 }
166 
tracing_multi_test_run(struct tracing_multi * skel)167 static void tracing_multi_test_run(struct tracing_multi *skel)
168 {
169 	LIBBPF_OPTS(bpf_test_run_opts, topts);
170 	int err, prog_fd;
171 
172 	prog_fd = bpf_program__fd(skel->progs.test_fentry);
173 	err = bpf_prog_test_run_opts(prog_fd, &topts);
174 	ASSERT_OK(err, "test_run");
175 
176 	/* extra +1 count for sleepable programs */
177 	ASSERT_EQ(skel->bss->test_result_fentry, FUNCS_CNT + 1, "test_result_fentry");
178 	ASSERT_EQ(skel->bss->test_result_fexit, FUNCS_CNT + 1, "test_result_fexit");
179 }
180 
test_skel_api(void)181 static void test_skel_api(void)
182 {
183 	struct tracing_multi *skel;
184 	int err;
185 
186 	skel = tracing_multi__open_and_load();
187 	if (!ASSERT_OK_PTR(skel, "tracing_multi__open_and_load"))
188 		return;
189 
190 	skel->bss->pid = getpid();
191 
192 	err = tracing_multi__attach(skel);
193 	if (!ASSERT_OK(err, "tracing_multi__attach"))
194 		goto cleanup;
195 
196 	tracing_multi_test_run(skel);
197 
198 cleanup:
199 	tracing_multi__destroy(skel);
200 }
201 
test_link_api_pattern(void)202 static void test_link_api_pattern(void)
203 {
204 	struct tracing_multi *skel;
205 
206 	skel = tracing_multi__open_and_load();
207 	if (!ASSERT_OK_PTR(skel, "tracing_multi__open_and_load"))
208 		return;
209 
210 	skel->bss->pid = getpid();
211 
212 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
213 					"bpf_fentry_test*", NULL);
214 	if (!ASSERT_OK_PTR(skel->links.test_fentry, "bpf_program__attach_tracing_multi"))
215 		goto cleanup;
216 
217 	skel->links.test_fexit = bpf_program__attach_tracing_multi(skel->progs.test_fexit,
218 					"bpf_fentry_test*", NULL);
219 	if (!ASSERT_OK_PTR(skel->links.test_fexit, "bpf_program__attach_tracing_multi"))
220 		goto cleanup;
221 
222 	skel->links.test_fentry_s = bpf_program__attach_tracing_multi(skel->progs.test_fentry_s,
223 					"bpf_fentry_test1", NULL);
224 	if (!ASSERT_OK_PTR(skel->links.test_fentry_s, "bpf_program__attach_tracing_multi"))
225 		goto cleanup;
226 
227 	skel->links.test_fexit_s = bpf_program__attach_tracing_multi(skel->progs.test_fexit_s,
228 					"bpf_fentry_test1", NULL);
229 	if (!ASSERT_OK_PTR(skel->links.test_fexit_s, "bpf_program__attach_tracing_multi"))
230 		goto cleanup;
231 
232 	tracing_multi_test_run(skel);
233 
234 cleanup:
235 	tracing_multi__destroy(skel);
236 }
237 
test_link_api_ids(bool test_cookies)238 static void test_link_api_ids(bool test_cookies)
239 {
240 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
241 	struct tracing_multi *skel;
242 	size_t cnt = FUNCS_CNT;
243 	__u32 *ids;
244 
245 	skel = tracing_multi__open_and_load();
246 	if (!ASSERT_OK_PTR(skel, "tracing_multi__open_and_load"))
247 		return;
248 
249 	skel->bss->pid = getpid();
250 	skel->bss->test_cookies = test_cookies;
251 
252 	ids = get_ids(bpf_fentry_test, cnt, NULL);
253 	if (!ASSERT_OK_PTR(ids, "get_ids"))
254 		goto cleanup;
255 
256 	opts.ids = ids;
257 	opts.cnt = cnt;
258 
259 	if (test_cookies)
260 		opts.cookies = bpf_fentry_test_cookies;
261 
262 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
263 						NULL, &opts);
264 	if (!ASSERT_OK_PTR(skel->links.test_fentry, "bpf_program__attach_tracing_multi"))
265 		goto cleanup;
266 
267 	skel->links.test_fexit = bpf_program__attach_tracing_multi(skel->progs.test_fexit,
268 						NULL, &opts);
269 	if (!ASSERT_OK_PTR(skel->links.test_fexit, "bpf_program__attach_tracing_multi"))
270 		goto cleanup;
271 
272 	/* Only bpf_fentry_test1 is allowed for sleepable programs. */
273 	opts.cnt = 1;
274 	skel->links.test_fentry_s = bpf_program__attach_tracing_multi(skel->progs.test_fentry_s,
275 						NULL, &opts);
276 	if (!ASSERT_OK_PTR(skel->links.test_fentry_s, "bpf_program__attach_tracing_multi"))
277 		goto cleanup;
278 
279 	skel->links.test_fexit_s = bpf_program__attach_tracing_multi(skel->progs.test_fexit_s,
280 						NULL, &opts);
281 	if (!ASSERT_OK_PTR(skel->links.test_fexit_s, "bpf_program__attach_tracing_multi"))
282 		goto cleanup;
283 
284 	tracing_multi_test_run(skel);
285 
286 cleanup:
287 	tracing_multi__destroy(skel);
288 	free(ids);
289 }
290 
test_module_skel_api(void)291 static void test_module_skel_api(void)
292 {
293 	struct tracing_multi_module *skel = NULL;
294 	int err;
295 
296 	skel = tracing_multi_module__open_and_load();
297 	if (!ASSERT_OK_PTR(skel, "tracing_multi__open_and_load"))
298 		return;
299 
300 	skel->bss->pid = getpid();
301 
302 	err = tracing_multi_module__attach(skel);
303 	if (!ASSERT_OK(err, "tracing_multi__attach"))
304 		goto cleanup;
305 
306 	ASSERT_OK(trigger_module_test_read(1), "trigger_read");
307 	ASSERT_EQ(skel->bss->test_result_fentry, 5, "test_result_fentry");
308 	ASSERT_EQ(skel->bss->test_result_fexit, 5, "test_result_fexit");
309 
310 cleanup:
311 	tracing_multi_module__destroy(skel);
312 }
313 
test_module_link_api_pattern(void)314 static void test_module_link_api_pattern(void)
315 {
316 	struct tracing_multi_module *skel = NULL;
317 
318 	skel = tracing_multi_module__open_and_load();
319 	if (!ASSERT_OK_PTR(skel, "tracing_multi_module__open_and_load"))
320 		return;
321 
322 	skel->bss->pid = getpid();
323 
324 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
325 					"bpf_testmod:bpf_testmod_fentry_test*", NULL);
326 	if (!ASSERT_OK_PTR(skel->links.test_fentry, "bpf_program__attach_tracing_multi"))
327 		goto cleanup;
328 
329 	skel->links.test_fexit = bpf_program__attach_tracing_multi(skel->progs.test_fexit,
330 					"bpf_testmod:bpf_testmod_fentry_test*", NULL);
331 	if (!ASSERT_OK_PTR(skel->links.test_fexit, "bpf_program__attach_tracing_multi"))
332 		goto cleanup;
333 
334 	ASSERT_OK(trigger_module_test_read(1), "trigger_read");
335 	ASSERT_EQ(skel->bss->test_result_fentry, 5, "test_result_fentry");
336 	ASSERT_EQ(skel->bss->test_result_fexit, 5, "test_result_fexit");
337 
338 cleanup:
339 	tracing_multi_module__destroy(skel);
340 }
341 
test_module_link_api_ids(void)342 static void test_module_link_api_ids(void)
343 {
344 	size_t cnt = ARRAY_SIZE(bpf_testmod_fentry_test);
345 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
346 	struct tracing_multi_module *skel = NULL;
347 	__u32 *ids;
348 
349 	skel = tracing_multi_module__open_and_load();
350 	if (!ASSERT_OK_PTR(skel, "tracing_multi_module__open_and_load"))
351 		return;
352 
353 	skel->bss->pid = getpid();
354 
355 	ids = get_ids(bpf_testmod_fentry_test, cnt, "bpf_testmod");
356 	if (!ASSERT_OK_PTR(ids, "get_ids"))
357 		goto cleanup;
358 
359 	opts.ids = ids;
360 	opts.cnt = cnt;
361 
362 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
363 						NULL, &opts);
364 	if (!ASSERT_OK_PTR(skel->links.test_fentry, "bpf_program__attach_tracing_multi"))
365 		goto cleanup;
366 
367 	skel->links.test_fexit = bpf_program__attach_tracing_multi(skel->progs.test_fexit,
368 						NULL, &opts);
369 	if (!ASSERT_OK_PTR(skel->links.test_fexit, "bpf_program__attach_tracing_multi"))
370 		goto cleanup;
371 
372 	ASSERT_OK(trigger_module_test_read(1), "trigger_read");
373 	ASSERT_EQ(skel->bss->test_result_fentry, 5, "test_result_fentry");
374 	ASSERT_EQ(skel->bss->test_result_fexit, 5, "test_result_fexit");
375 
376 cleanup:
377 	tracing_multi_module__destroy(skel);
378 	free(ids);
379 }
380 
is_set(__u32 mask,__u32 bit)381 static bool is_set(__u32 mask, __u32 bit)
382 {
383 	return (1 << bit) & mask;
384 }
385 
__test_intersect(__u32 mask,const struct bpf_program * progs[4],__u64 * test_results[4])386 static void __test_intersect(__u32 mask, const struct bpf_program *progs[4], __u64 *test_results[4])
387 {
388 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
389 	LIBBPF_OPTS(bpf_test_run_opts, topts);
390 	struct bpf_link *links[4] = { NULL };
391 	const char *funcs[FUNCS_CNT];
392 	__u64 expected[4];
393 	__u32 *ids, i;
394 	int err, cnt;
395 
396 	/*
397 	 * We have 4 programs in progs and the mask bits pick which
398 	 * of them gets attached to randomly chosen functions.
399 	 */
400 	for (i = 0; i < 4; i++) {
401 		if (!is_set(mask, i))
402 			continue;
403 
404 		cnt = get_random_funcs(funcs);
405 		ids = get_ids(funcs, cnt, NULL);
406 		if (!ASSERT_OK_PTR(ids, "get_ids"))
407 			goto cleanup;
408 
409 		opts.ids = ids;
410 		opts.cnt = cnt;
411 		links[i] = bpf_program__attach_tracing_multi(progs[i], NULL, &opts);
412 		free(ids);
413 
414 		if (!ASSERT_OK_PTR(links[i], "bpf_program__attach_tracing_multi"))
415 			goto cleanup;
416 
417 		expected[i] = *test_results[i] + cnt;
418 	}
419 
420 	err = bpf_prog_test_run_opts(bpf_program__fd(progs[0]), &topts);
421 	ASSERT_OK(err, "test_run");
422 
423 	for (i = 0; i < 4; i++) {
424 		if (!is_set(mask, i))
425 			continue;
426 		ASSERT_EQ(*test_results[i], expected[i], "test_results");
427 	}
428 
429 cleanup:
430 	for (i = 0; i < 4; i++)
431 		bpf_link__destroy(links[i]);
432 }
433 
test_intersect(void)434 static void test_intersect(void)
435 {
436 	struct tracing_multi_intersect *skel;
437 	const struct bpf_program *progs[4];
438 	__u64 *test_results[4];
439 	__u32 i;
440 
441 	skel = tracing_multi_intersect__open_and_load();
442 	if (!ASSERT_OK_PTR(skel, "tracing_multi_intersect__open_and_load"))
443 		return;
444 
445 	skel->bss->pid = getpid();
446 
447 	progs[0] = skel->progs.fentry_1;
448 	progs[1] = skel->progs.fexit_1;
449 	progs[2] = skel->progs.fentry_2;
450 	progs[3] = skel->progs.fexit_2;
451 
452 	test_results[0] = &skel->bss->test_result_fentry_1;
453 	test_results[1] = &skel->bss->test_result_fexit_1;
454 	test_results[2] = &skel->bss->test_result_fentry_2;
455 	test_results[3] = &skel->bss->test_result_fexit_2;
456 
457 	for (i = 1; i < 16; i++)
458 		__test_intersect(i, progs, test_results);
459 
460 	tracing_multi_intersect__destroy(skel);
461 }
462 
test_fentry_after_multi(void)463 static void test_fentry_after_multi(void)
464 {
465 	static const char * const funcs[] = {
466 		"bpf_fentry_test1",
467 	};
468 	struct bpf_link *fentry_link = NULL, *multi_link = NULL;
469 	struct tracing_multi_intersect *skel = NULL;
470 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
471 	LIBBPF_OPTS(bpf_test_run_opts, topts);
472 	__u32 *ids = NULL;
473 	int err;
474 
475 	skel = tracing_multi_intersect__open_and_load();
476 	if (!ASSERT_OK_PTR(skel, "tracing_multi_intersect__open_and_load"))
477 		return;
478 
479 	skel->bss->pid = getpid();
480 
481 	ids = get_ids(funcs, ARRAY_SIZE(funcs), NULL);
482 	if (!ASSERT_OK_PTR(ids, "get_ids"))
483 		goto cleanup;
484 
485 	opts.ids = ids;
486 	opts.cnt = ARRAY_SIZE(funcs);
487 	multi_link = bpf_program__attach_tracing_multi(skel->progs.fentry_1, NULL, &opts);
488 	if (!ASSERT_OK_PTR(multi_link, "attach_multi"))
489 		goto cleanup;
490 
491 	fentry_link = bpf_program__attach(skel->progs.fentry);
492 	if (!ASSERT_OK_PTR(fentry_link, "attach_fentry"))
493 		goto cleanup;
494 
495 	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.fentry_1), &topts);
496 	if (!ASSERT_OK(err, "test_run"))
497 		goto cleanup;
498 	ASSERT_EQ(skel->bss->test_result_fentry_1, 1, "multi_fentry");
499 	ASSERT_EQ(skel->bss->test_result_fentry, 1, "fentry");
500 
501 	err = bpf_link__destroy(fentry_link);
502 	fentry_link = NULL;
503 	if (!ASSERT_OK(err, "destroy_fentry"))
504 		goto cleanup;
505 
506 	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.fentry_1), &topts);
507 	if (!ASSERT_OK(err, "test_run_multi"))
508 		goto cleanup;
509 	ASSERT_EQ(skel->bss->test_result_fentry_1, 2, "multi_fentry_only");
510 	ASSERT_EQ(skel->bss->test_result_fentry, 1, "fentry_detached");
511 
512 	err = bpf_link__destroy(multi_link);
513 	multi_link = NULL;
514 	if (!ASSERT_OK(err, "destroy_multi"))
515 		goto cleanup;
516 
517 	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.fentry_1), &topts);
518 	if (!ASSERT_OK(err, "test_run_detached"))
519 		goto cleanup;
520 	ASSERT_EQ(skel->bss->test_result_fentry_1, 2, "multi_fentry_detached");
521 	ASSERT_EQ(skel->bss->test_result_fentry, 1, "fentry_still_detached");
522 
523 cleanup:
524 	bpf_link__destroy(fentry_link);
525 	bpf_link__destroy(multi_link);
526 	free(ids);
527 	tracing_multi_intersect__destroy(skel);
528 }
529 
test_session(void)530 static void test_session(void)
531 {
532 	LIBBPF_OPTS(bpf_test_run_opts, topts);
533 	struct tracing_multi_session *skel;
534 	int err, prog_fd;
535 
536 	skel = tracing_multi_session__open_and_load();
537 	if (!ASSERT_OK_PTR(skel, "tracing_multi_session__open_and_load"))
538 		return;
539 
540 	skel->bss->pid = getpid();
541 
542 	err = tracing_multi_session__attach(skel);
543 	if (!ASSERT_OK(err, "tracing_multi_session__attach"))
544 		goto cleanup;
545 
546 	/* execute kernel session */
547 	prog_fd = bpf_program__fd(skel->progs.test_session_1);
548 	err = bpf_prog_test_run_opts(prog_fd, &topts);
549 	ASSERT_OK(err, "test_run");
550 
551 	/* 10 for test_session_1, 1 for test_fsession_s */
552 	ASSERT_EQ(skel->bss->test_result_fentry, 11, "test_result_fentry");
553 	/* extra count (+1 for each fexit execution) for test_result_fexit cookie check/inc */
554 	ASSERT_EQ(skel->bss->test_result_fexit, 22, "test_result_fexit");
555 
556 	skel->bss->test_result_fentry = 0;
557 	skel->bss->test_result_fexit = 0;
558 
559 	/* execute bpf_testmo.ko session */
560 	ASSERT_OK(trigger_module_test_read(1), "trigger_read");
561 
562 	/* 5 for test_session_2 */
563 	ASSERT_EQ(skel->bss->test_result_fentry, 5, "test_result_fentry");
564 	/* extra count (+1 for each fexit execution) for test_result_fexit cookie */
565 	ASSERT_EQ(skel->bss->test_result_fexit, 10, "test_result_fexit");
566 
567 
568 cleanup:
569 	tracing_multi_session__destroy(skel);
570 }
571 
test_attach_api_fails(void)572 static void test_attach_api_fails(void)
573 {
574 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
575 	static const char * const func[] = {
576 		"bpf_fentry_test2",
577 	};
578 	struct tracing_multi_fail *skel = NULL;
579 	__u32 ids[2] = {}, *ids2 = NULL;
580 	__u64 cookies[2];
581 
582 	skel = tracing_multi_fail__open_and_load();
583 	if (!ASSERT_OK_PTR(skel, "tracing_multi_fail__open_and_load"))
584 		return;
585 
586 	/* fail#1 (libbpf) pattern and opts NULL */
587 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
588 						NULL, NULL);
589 	if (!ASSERT_EQ(libbpf_get_error(skel->links.test_fentry), -EINVAL, "fail_1"))
590 		goto cleanup;
591 
592 	/* fail#2 (libbpf) pattern and ids */
593 	LIBBPF_OPTS_RESET(opts,
594 		.ids = ids,
595 		.cnt = 2,
596 	);
597 
598 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
599 						"bpf_fentry_test*", &opts);
600 	if (!ASSERT_EQ(libbpf_get_error(skel->links.test_fentry), -EINVAL, "fail_2"))
601 		goto cleanup;
602 
603 	/* fail#3 (libbpf) pattern and cookies */
604 	LIBBPF_OPTS_RESET(opts,
605 		.ids = NULL,
606 		.cnt = 2,
607 		.cookies = cookies,
608 	);
609 
610 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
611 						"bpf_fentry_test*", &opts);
612 	if (!ASSERT_EQ(libbpf_get_error(skel->links.test_fentry), -EINVAL, "fail_3"))
613 		goto cleanup;
614 
615 	/* fail#4 (libbpf) bogus pattern */
616 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
617 						"bpf_not_really_a_function*", NULL);
618 	if (!ASSERT_EQ(libbpf_get_error(skel->links.test_fentry), -EINVAL, "fail_4"))
619 		goto cleanup;
620 
621 	/* fail#5 (kernel) abnormal cnt */
622 	LIBBPF_OPTS_RESET(opts,
623 		.ids = ids,
624 		.cnt = INT_MAX,
625 	);
626 
627 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
628 						NULL, &opts);
629 	if (!ASSERT_EQ(libbpf_get_error(skel->links.test_fentry), -E2BIG, "fail_5"))
630 		goto cleanup;
631 
632 	/* fail#6 (kernel) attach sleepable program to not-allowed function */
633 	ids2 = get_ids(func, 1, NULL);
634 	if (!ASSERT_OK_PTR(ids2, "get_ids"))
635 		goto cleanup;
636 
637 	LIBBPF_OPTS_RESET(opts,
638 		.ids = ids2,
639 		.cnt = 1,
640 	);
641 
642 	skel->links.test_fentry_s = bpf_program__attach_tracing_multi(skel->progs.test_fentry_s,
643 						NULL, &opts);
644 	if (!ASSERT_EQ(libbpf_get_error(skel->links.test_fentry_s), -EINVAL, "fail_6"))
645 		goto cleanup;
646 
647 	/* fail#7 (kernel) attach with duplicate id */
648 	ids[0] = ids2[0];
649 	ids[1] = ids2[0];
650 
651 	LIBBPF_OPTS_RESET(opts,
652 		.ids = ids,
653 		.cnt = 2,
654 	);
655 
656 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
657 						NULL, &opts);
658 	ASSERT_EQ(libbpf_get_error(skel->links.test_fentry), -EINVAL, "fail_7");
659 
660 cleanup:
661 	tracing_multi_fail__destroy(skel);
662 	free(ids2);
663 }
664 
serial_test_tracing_multi_bench_attach(void)665 void serial_test_tracing_multi_bench_attach(void)
666 {
667 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
668 	struct tracing_multi_bench *skel = NULL;
669 	long attach_start_ns, attach_end_ns;
670 	long detach_start_ns, detach_end_ns;
671 	double attach_delta, detach_delta;
672 	struct bpf_link *link = NULL;
673 	size_t i, cap = 0, cnt = 0;
674 	struct ksyms *ksyms = NULL;
675 	void *root = NULL;
676 	void *dups = NULL;
677 	__u32 *ids = NULL;
678 	__u32 nr, type_id;
679 	struct btf *btf;
680 	int err;
681 
682 #ifndef __x86_64__
683 	test__skip();
684 	return;
685 #endif
686 
687 	btf = btf__load_vmlinux_btf();
688 	if (!ASSERT_OK_PTR(btf, "btf__load_vmlinux_btf"))
689 		return;
690 
691 	skel = tracing_multi_bench__open_and_load();
692 	if (!ASSERT_OK_PTR(skel, "tracing_multi_bench__open_and_load"))
693 		goto cleanup;
694 
695 	if (!ASSERT_OK(bpf_get_ksyms(&ksyms, true), "get_syms"))
696 		goto cleanup;
697 
698 	/* Get all ftrace 'safe' symbols.. */
699 	for (i = 0; i < ksyms->filtered_cnt; i++) {
700 		if (!tsearch(&ksyms->filtered_syms[i], &root, compare)) {
701 			ASSERT_FAIL("tsearch failed");
702 			goto cleanup;
703 		}
704 	}
705 
706 	/*
707 	 * Collect names that are not unique in kallsyms. The kernel resolves a
708 	 * tracing-multi BTF id to an address with kallsyms_lookup_name(), which
709 	 * returns the first symbol of that name. For a duplicate name that may
710 	 * be a different (non-ftrace-able) instance than the ftrace-able one in
711 	 * available_filter_functions, so attaching to it by BTF id fails with
712 	 * -ENOENT (e.g. t_start/t_next/t_stop). ksyms->syms is sorted by name,
713 	 * so equal names are adjacent.
714 	 */
715 	for (i = 1; i < ksyms->sym_cnt; i++) {
716 		if (strcmp(ksyms->syms[i].name, ksyms->syms[i - 1].name))
717 			continue;
718 		if (!tsearch(&ksyms->syms[i].name, &dups, compare)) {
719 			ASSERT_FAIL("tsearch failed");
720 			goto cleanup;
721 		}
722 	}
723 
724 	/* ..and filter them through BTF and btf_type_is_traceable_func. */
725 	nr = btf__type_cnt(btf);
726 	for (type_id = 1; type_id < nr; type_id++) {
727 		const struct btf_type *type;
728 		const char *str;
729 
730 		type = btf__type_by_id(btf, type_id);
731 		if (!type)
732 			break;
733 
734 		if (BTF_INFO_KIND(type->info) != BTF_KIND_FUNC)
735 			continue;
736 
737 		str = btf__name_by_offset(btf, type->name_off);
738 		if (!str)
739 			break;
740 
741 		if (!tfind(&str, &root, compare))
742 			continue;
743 
744 		/* Skip names that are not unique in kallsyms, see above. */
745 		if (tfind(&str, &dups, compare))
746 			continue;
747 
748 		if (!btf_type_is_traceable_func(btf, type))
749 			continue;
750 
751 		err = libbpf_ensure_mem((void **) &ids, &cap, sizeof(*ids), cnt + 1);
752 		if (err)
753 			goto cleanup;
754 
755 		ids[cnt++] = type_id;
756 	}
757 
758 	opts.ids = ids;
759 	opts.cnt = cnt;
760 
761 	attach_start_ns = get_time_ns();
762 	link = bpf_program__attach_tracing_multi(skel->progs.bench, NULL, &opts);
763 	attach_end_ns = get_time_ns();
764 
765 	if (!ASSERT_OK_PTR(link, "bpf_program__attach_tracing_multi"))
766 		goto cleanup;
767 
768 	detach_start_ns = get_time_ns();
769 	bpf_link__destroy(link);
770 	detach_end_ns = get_time_ns();
771 
772 	attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
773 	detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
774 
775 	printf("%s: found %lu functions\n", __func__, cnt);
776 	printf("%s: attached in %7.3lfs\n", __func__, attach_delta);
777 	printf("%s: detached in %7.3lfs\n", __func__, detach_delta);
778 
779 cleanup:
780 	tracing_multi_bench__destroy(skel);
781 	tdestroy(root, tdestroy_free_nop);
782 	tdestroy(dups, tdestroy_free_nop);
783 	free_kallsyms_local(ksyms);
784 	free(ids);
785 	btf__free(btf);
786 }
787 
tracing_multi_rollback_run(struct tracing_multi_rollback * skel)788 static void tracing_multi_rollback_run(struct tracing_multi_rollback *skel)
789 {
790 	LIBBPF_OPTS(bpf_test_run_opts, topts);
791 	int err, prog_fd;
792 
793 	prog_fd = bpf_program__fd(skel->progs.test_fentry);
794 	err = bpf_prog_test_run_opts(prog_fd, &topts);
795 	ASSERT_OK(err, "test_run");
796 
797 	/* make sure the rollback code did not leave any program attached */
798 	ASSERT_EQ(skel->bss->test_result_fentry, 0, "test_result_fentry");
799 	ASSERT_EQ(skel->bss->test_result_fexit, 0, "test_result_fexit");
800 }
801 
test_rollback_put(void)802 static void test_rollback_put(void)
803 {
804 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
805 	struct tracing_multi_rollback *skel = NULL;
806 	size_t cnt = FUNCS_CNT;
807 	__u32 *ids = NULL;
808 	int err;
809 
810 	skel = tracing_multi_rollback__open();
811 	if (!ASSERT_OK_PTR(skel, "tracing_multi_rollback__open"))
812 		return;
813 
814 	bpf_program__set_autoload(skel->progs.test_fentry, true);
815 	bpf_program__set_autoload(skel->progs.test_fexit, true);
816 
817 	err = tracing_multi_rollback__load(skel);
818 	if (!ASSERT_OK(err, "tracing_multi_rollback__load"))
819 		goto cleanup;
820 
821 	ids = get_ids(bpf_fentry_test, cnt, NULL);
822 	if (!ASSERT_OK_PTR(ids, "get_ids"))
823 		goto cleanup;
824 
825 	/*
826 	 * Mangle last id to trigger rollback, which needs to do put
827 	 * on get-ed trampolines.
828 	 */
829 	ids[9] = 0;
830 
831 	opts.ids = ids;
832 	opts.cnt = cnt;
833 
834 	skel->bss->pid = getpid();
835 
836 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
837 						NULL, &opts);
838 	if (!ASSERT_ERR_PTR(skel->links.test_fentry, "bpf_program__attach_tracing_multi"))
839 		goto cleanup;
840 
841 	skel->links.test_fexit = bpf_program__attach_tracing_multi(skel->progs.test_fexit,
842 						NULL, &opts);
843 	if (!ASSERT_ERR_PTR(skel->links.test_fexit, "bpf_program__attach_tracing_multi"))
844 		goto cleanup;
845 
846 	/* We don't really attach any program, but let's make sure. */
847 	tracing_multi_rollback_run(skel);
848 
849 cleanup:
850 	tracing_multi_rollback__destroy(skel);
851 	free(ids);
852 }
853 
fillers_cleanup(struct tracing_multi_rollback ** skels,int cnt)854 static void fillers_cleanup(struct tracing_multi_rollback **skels, int cnt)
855 {
856 	int i;
857 
858 	for (i = 0; i < cnt; i++)
859 		tracing_multi_rollback__destroy(skels[i]);
860 
861 	free(skels);
862 }
863 
extra_load_and_link(void)864 static struct tracing_multi_rollback *extra_load_and_link(void)
865 {
866 	struct tracing_multi_rollback *skel;
867 	int err;
868 
869 	skel = tracing_multi_rollback__open();
870 	if (!ASSERT_OK_PTR(skel, "tracing_multi_rollback__open"))
871 		goto cleanup;
872 
873 	bpf_program__set_autoload(skel->progs.extra, true);
874 
875 	err = tracing_multi_rollback__load(skel);
876 	if (!ASSERT_OK(err, "tracing_multi_rollback__load"))
877 		goto cleanup;
878 
879 	skel->links.extra = bpf_program__attach_trace(skel->progs.extra);
880 	if (!ASSERT_OK_PTR(skel->links.extra, "bpf_program__attach_trace"))
881 		goto cleanup;
882 
883 	return skel;
884 
885 cleanup:
886 	tracing_multi_rollback__destroy(skel);
887 	return NULL;
888 }
889 
fillers_load_and_link(int max)890 static struct tracing_multi_rollback **fillers_load_and_link(int max)
891 {
892 	struct tracing_multi_rollback **skels, *skel;
893 	int i, err;
894 
895 	skels = calloc(max + 1, sizeof(*skels));
896 	if (!ASSERT_OK_PTR(skels, "calloc"))
897 		return NULL;
898 
899 	for (i = 0; i < max; i++) {
900 		skel = skels[i] = tracing_multi_rollback__open();
901 		if (!ASSERT_OK_PTR(skels[i], "tracing_multi_rollback__open"))
902 			goto cleanup;
903 
904 		bpf_program__set_autoload(skel->progs.filler, true);
905 
906 		err = tracing_multi_rollback__load(skel);
907 		if (!ASSERT_OK(err, "tracing_multi_rollback__load"))
908 			goto cleanup;
909 
910 		skel->links.filler = bpf_program__attach_trace(skel->progs.filler);
911 		if (!ASSERT_OK_PTR(skels[i]->links.filler, "bpf_program__attach_trace"))
912 			goto cleanup;
913 	}
914 
915 	return skels;
916 
917 cleanup:
918 	fillers_cleanup(skels, i + 1);
919 	return NULL;
920 }
921 
test_rollback_unlink(void)922 static void test_rollback_unlink(void)
923 {
924 	struct tracing_multi_rollback *skel = NULL, *extra;
925 	LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
926 	struct tracing_multi_rollback **fillers;
927 	size_t cnt = FUNCS_CNT;
928 	__u32 *ids = NULL;
929 	int err, max;
930 
931 	max = get_bpf_max_tramp_links();
932 	if (!ASSERT_GE(max, 1, "bpf_max_tramp_links"))
933 		return;
934 
935 	/* Attach maximum allowed programs to bpf_fentry_test10 */
936 	fillers = fillers_load_and_link(max);
937 	if (!ASSERT_OK_PTR(fillers, "fillers_load_and_link"))
938 		return;
939 
940 	extra = extra_load_and_link();
941 	if (!ASSERT_OK_PTR(extra, "extra_load_and_link"))
942 		goto cleanup;
943 
944 	skel = tracing_multi_rollback__open();
945 	if (!ASSERT_OK_PTR(skel, "tracing_multi_rollback__open"))
946 		goto cleanup;
947 
948 	bpf_program__set_autoload(skel->progs.test_fentry, true);
949 	bpf_program__set_autoload(skel->progs.test_fexit, true);
950 
951 	/*
952 	 * Attach tracing_multi link on bpf_fentry_test1-10, which will
953 	 * fail on bpf_fentry_test10 function, because it already has
954 	 * maximum allowed programs attached.
955 	 *
956 	 * The rollback needs to unlink already link-ed trampolines and
957 	 * put all of them.
958 	 */
959 	err = tracing_multi_rollback__load(skel);
960 	if (!ASSERT_OK(err, "tracing_multi_rollback__load"))
961 		goto cleanup;
962 
963 	ids = get_ids(bpf_fentry_test, cnt, NULL);
964 	if (!ASSERT_OK_PTR(ids, "get_ids"))
965 		goto cleanup;
966 
967 	opts.ids = ids;
968 	opts.cnt = cnt;
969 
970 	skel->bss->pid = getpid();
971 
972 	skel->links.test_fentry = bpf_program__attach_tracing_multi(skel->progs.test_fentry,
973 						NULL, &opts);
974 	if (!ASSERT_ERR_PTR(skel->links.test_fentry, "bpf_program__attach_tracing_multi"))
975 		goto cleanup;
976 
977 	skel->links.test_fexit = bpf_program__attach_tracing_multi(skel->progs.test_fexit,
978 						NULL, &opts);
979 	if (!ASSERT_ERR_PTR(skel->links.test_fexit, "bpf_program__attach_tracing_multi"))
980 		goto cleanup;
981 
982 	tracing_multi_rollback_run(skel);
983 
984 cleanup:
985 	fillers_cleanup(fillers, max);
986 	tracing_multi_rollback__destroy(extra);
987 	tracing_multi_rollback__destroy(skel);
988 	free(ids);
989 }
990 
serial_test_tracing_multi_attach_rollback(void)991 void serial_test_tracing_multi_attach_rollback(void)
992 {
993 	if (test__start_subtest("put"))
994 		test_rollback_put();
995 	if (test__start_subtest("unlink"))
996 		test_rollback_unlink();
997 }
998 
test_tracing_multi_test(void)999 void test_tracing_multi_test(void)
1000 {
1001 #ifndef __x86_64__
1002 	test__skip();
1003 	return;
1004 #endif
1005 
1006 	if (test__start_subtest("skel_api"))
1007 		test_skel_api();
1008 	if (test__start_subtest("link_api_pattern"))
1009 		test_link_api_pattern();
1010 	if (test__start_subtest("link_api_ids"))
1011 		test_link_api_ids(false);
1012 	if (test__start_subtest("module_skel_api"))
1013 		test_module_skel_api();
1014 	if (test__start_subtest("module_link_api_pattern"))
1015 		test_module_link_api_pattern();
1016 	if (test__start_subtest("module_link_api_ids"))
1017 		test_module_link_api_ids();
1018 	if (test__start_subtest("intersect"))
1019 		test_intersect();
1020 	if (test__start_subtest("cookies"))
1021 		test_link_api_ids(true);
1022 	if (test__start_subtest("session"))
1023 		test_session();
1024 	if (test__start_subtest("attach_api_fails"))
1025 		test_attach_api_fails();
1026 	RUN_TESTS(tracing_multi_verifier);
1027 	if (test__start_subtest("fentry_after_multi"))
1028 		test_fentry_after_multi();
1029 }
1030