Positively verify that a tail call from a BPF subprog works when the subprog is traced by fentry.multi. Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Leon Hwang --- .../selftests/bpf/prog_tests/tailcalls.c | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/tailcalls.c b/tools/testing/selftests/bpf/prog_tests/tailcalls.c index 88d223110ecd..3b122520711b 100644 --- a/tools/testing/selftests/bpf/prog_tests/tailcalls.c +++ b/tools/testing/selftests/bpf/prog_tests/tailcalls.c @@ -16,7 +16,9 @@ #include "tailcall_sleepable.skel.h" #include "tailcall_callback.skel.h" #include "tailcall_bpf2bpf2.skel.h" +#include "tailcall_bpf2bpf4.skel.h" #include "tailcall_bpf2bpf_fexit.skel.h" +#include "tracing_multi_bpf.skel.h" /* test_tailcall_1 checks basic functionality by patching multiple locations * in a single program for a single tail call slot with nop->jmp, jmp->nop @@ -2065,6 +2067,66 @@ static void test_tailcall_large_stack(void) tailcall_large_stack__destroy(skel); } +/* + * Verify that a tail call from a BPF subprog works when the subprog is + * traced by fentry.multi. + */ +static void test_tailcall_bpf2bpf_fentry_multi(void) +{ + static const char *funcs[] = { "subprog_tail_2" }; + struct tracing_multi_bpf *skel_tracing = NULL; + LIBBPF_OPTS(bpf_tracing_multi_opts, opts); + struct tailcall_bpf2bpf4 *skel_tc; + struct bpf_link *link = NULL; + int fds[ARRAY_SIZE(funcs)]; + char buff[128] = {}; + int err, key; + LIBBPF_OPTS(bpf_test_run_opts, topts, + .data_in = buff, + .data_size_in = sizeof(buff), + .repeat = 1, + ); + + skel_tc = tailcall_bpf2bpf4__open_and_load(); + if (!ASSERT_OK_PTR(skel_tc, "tailcall_bpf2bpf4__open_and_load")) + return; + + skel_tracing = tracing_multi_bpf__open_and_load(); + if (!ASSERT_OK_PTR(skel_tracing, "tracing_multi_bpf__open_and_load")) + goto out; + + key = 0; + fds[0] = bpf_program__fd(skel_tc->progs.classifier_2); + err = bpf_map_update_elem(bpf_map__fd(skel_tc->maps.jmp_table), &key, &fds[0], BPF_ANY); + if (!ASSERT_OK(err, "bpf_map_update_elem")) + goto out; + + key = 2; + err = bpf_map_update_elem(bpf_map__fd(skel_tc->maps.jmp_table), &key, &fds[0], BPF_ANY); + if (!ASSERT_OK(err, "bpf_map_update_elem_loop")) + goto out; + + opts.fds = fds; + opts.funcs = funcs; + opts.cnt = ARRAY_SIZE(fds); + link = bpf_program__attach_tracing_multi(skel_tracing->progs.test_fentry, NULL, &opts); + if (!ASSERT_OK_PTR(link, "bpf_program__attach_tracing_multi")) + goto out; + + err = bpf_prog_test_run_opts(bpf_program__fd(skel_tc->progs.entry), &topts); + if (!ASSERT_OK(err, "bpf_prog_test_run_opts")) + goto out; + + ASSERT_EQ(topts.retval, sizeof(buff) * 3, "retval"); + ASSERT_EQ(skel_tc->bss->count, 33, "count"); + ASSERT_EQ(skel_tracing->bss->test_result_fentry, 33, "fentry.multi count"); + +out: + bpf_link__destroy(link); + tracing_multi_bpf__destroy(skel_tracing); + tailcall_bpf2bpf4__destroy(skel_tc); +} + void test_tailcalls(void) { if (test__start_subtest("tailcall_1")) @@ -2138,4 +2200,6 @@ void test_tailcalls(void) test_tailcall_bpf2bpf_fexit_links(); if (test__start_subtest("tailcall_large_stack")) test_tailcall_large_stack(); + if (test__start_subtest("tailcall_bpf2bpf_fentry_multi")) + test_tailcall_bpf2bpf_fentry_multi(); } -- 2.55.0