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