Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Test multi_st_ops and calling kfuncs from different programs

Test multi_st_ops and demonstrate how different bpf programs can call
a kfuncs that refers to the struct_ops instance in the same source file
by id. The id is defined as a global vairable and initialized before
attaching the skeleton. Kfuncs that take the id can hide the argument
with a macro to make it almost transparent to bpf program developers.

The test involves two struct_ops returning different values from
.test_1. In syscall and tracing programs, check if the correct value is
returned by a kfunc that calls .test_1.

Signed-off-by: Amery Hung <ameryhung@gmail.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20250806162540.681679-4-ameryhung@gmail.com

authored by

Amery Hung and committed by
Martin KaFai Lau
ba7000f1 eeb52b62

+192
+74
tools/testing/selftests/bpf/prog_tests/test_struct_ops_id_ops_mapping.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <test_progs.h> 4 + #include "struct_ops_id_ops_mapping1.skel.h" 5 + #include "struct_ops_id_ops_mapping2.skel.h" 6 + 7 + static void test_st_ops_id_ops_mapping(void) 8 + { 9 + struct struct_ops_id_ops_mapping1 *skel1 = NULL; 10 + struct struct_ops_id_ops_mapping2 *skel2 = NULL; 11 + struct bpf_map_info info = {}; 12 + __u32 len = sizeof(info); 13 + int err, pid, prog1_fd, prog2_fd; 14 + 15 + skel1 = struct_ops_id_ops_mapping1__open_and_load(); 16 + if (!ASSERT_OK_PTR(skel1, "struct_ops_id_ops_mapping1__open")) 17 + goto out; 18 + 19 + skel2 = struct_ops_id_ops_mapping2__open_and_load(); 20 + if (!ASSERT_OK_PTR(skel2, "struct_ops_id_ops_mapping2__open")) 21 + goto out; 22 + 23 + err = bpf_map_get_info_by_fd(bpf_map__fd(skel1->maps.st_ops_map), 24 + &info, &len); 25 + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd")) 26 + goto out; 27 + 28 + skel1->bss->st_ops_id = info.id; 29 + 30 + err = bpf_map_get_info_by_fd(bpf_map__fd(skel2->maps.st_ops_map), 31 + &info, &len); 32 + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd")) 33 + goto out; 34 + 35 + skel2->bss->st_ops_id = info.id; 36 + 37 + err = struct_ops_id_ops_mapping1__attach(skel1); 38 + if (!ASSERT_OK(err, "struct_ops_id_ops_mapping1__attach")) 39 + goto out; 40 + 41 + err = struct_ops_id_ops_mapping2__attach(skel2); 42 + if (!ASSERT_OK(err, "struct_ops_id_ops_mapping2__attach")) 43 + goto out; 44 + 45 + /* run tracing prog that calls .test_1 and checks return */ 46 + pid = getpid(); 47 + skel1->bss->test_pid = pid; 48 + skel2->bss->test_pid = pid; 49 + sys_gettid(); 50 + skel1->bss->test_pid = 0; 51 + skel2->bss->test_pid = 0; 52 + 53 + /* run syscall_prog that calls .test_1 and checks return */ 54 + prog1_fd = bpf_program__fd(skel1->progs.syscall_prog); 55 + err = bpf_prog_test_run_opts(prog1_fd, NULL); 56 + ASSERT_OK(err, "bpf_prog_test_run_opts"); 57 + 58 + prog2_fd = bpf_program__fd(skel2->progs.syscall_prog); 59 + err = bpf_prog_test_run_opts(prog2_fd, NULL); 60 + ASSERT_OK(err, "bpf_prog_test_run_opts"); 61 + 62 + ASSERT_EQ(skel1->bss->test_err, 0, "skel1->bss->test_err"); 63 + ASSERT_EQ(skel2->bss->test_err, 0, "skel2->bss->test_err"); 64 + 65 + out: 66 + struct_ops_id_ops_mapping1__destroy(skel1); 67 + struct_ops_id_ops_mapping2__destroy(skel2); 68 + } 69 + 70 + void test_struct_ops_id_ops_mapping(void) 71 + { 72 + if (test__start_subtest("st_ops_id_ops_mapping")) 73 + test_st_ops_id_ops_mapping(); 74 + }
+59
tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping1.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <vmlinux.h> 4 + #include <bpf/bpf_tracing.h> 5 + #include "bpf_misc.h" 6 + #include "../test_kmods/bpf_testmod.h" 7 + #include "../test_kmods/bpf_testmod_kfunc.h" 8 + 9 + char _license[] SEC("license") = "GPL"; 10 + 11 + #define bpf_kfunc_multi_st_ops_test_1(args) bpf_kfunc_multi_st_ops_test_1(args, st_ops_id) 12 + int st_ops_id; 13 + 14 + int test_pid; 15 + int test_err; 16 + 17 + #define MAP1_MAGIC 1234 18 + 19 + SEC("struct_ops") 20 + int BPF_PROG(test_1, struct st_ops_args *args) 21 + { 22 + return MAP1_MAGIC; 23 + } 24 + 25 + SEC("tp_btf/sys_enter") 26 + int BPF_PROG(sys_enter, struct pt_regs *regs, long id) 27 + { 28 + struct st_ops_args args = {}; 29 + struct task_struct *task; 30 + int ret; 31 + 32 + task = bpf_get_current_task_btf(); 33 + if (!test_pid || task->pid != test_pid) 34 + return 0; 35 + 36 + ret = bpf_kfunc_multi_st_ops_test_1(&args); 37 + if (ret != MAP1_MAGIC) 38 + test_err++; 39 + 40 + return 0; 41 + } 42 + 43 + SEC("syscall") 44 + int syscall_prog(void *ctx) 45 + { 46 + struct st_ops_args args = {}; 47 + int ret; 48 + 49 + ret = bpf_kfunc_multi_st_ops_test_1(&args); 50 + if (ret != MAP1_MAGIC) 51 + test_err++; 52 + 53 + return 0; 54 + } 55 + 56 + SEC(".struct_ops.link") 57 + struct bpf_testmod_multi_st_ops st_ops_map = { 58 + .test_1 = (void *)test_1, 59 + };
+59
tools/testing/selftests/bpf/progs/struct_ops_id_ops_mapping2.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <vmlinux.h> 4 + #include <bpf/bpf_tracing.h> 5 + #include "bpf_misc.h" 6 + #include "../test_kmods/bpf_testmod.h" 7 + #include "../test_kmods/bpf_testmod_kfunc.h" 8 + 9 + char _license[] SEC("license") = "GPL"; 10 + 11 + #define bpf_kfunc_multi_st_ops_test_1(args) bpf_kfunc_multi_st_ops_test_1(args, st_ops_id) 12 + int st_ops_id; 13 + 14 + int test_pid; 15 + int test_err; 16 + 17 + #define MAP2_MAGIC 4567 18 + 19 + SEC("struct_ops") 20 + int BPF_PROG(test_1, struct st_ops_args *args) 21 + { 22 + return MAP2_MAGIC; 23 + } 24 + 25 + SEC("tp_btf/sys_enter") 26 + int BPF_PROG(sys_enter, struct pt_regs *regs, long id) 27 + { 28 + struct st_ops_args args = {}; 29 + struct task_struct *task; 30 + int ret; 31 + 32 + task = bpf_get_current_task_btf(); 33 + if (!test_pid || task->pid != test_pid) 34 + return 0; 35 + 36 + ret = bpf_kfunc_multi_st_ops_test_1(&args); 37 + if (ret != MAP2_MAGIC) 38 + test_err++; 39 + 40 + return 0; 41 + } 42 + 43 + SEC("syscall") 44 + int syscall_prog(void *ctx) 45 + { 46 + struct st_ops_args args = {}; 47 + int ret; 48 + 49 + ret = bpf_kfunc_multi_st_ops_test_1(&args); 50 + if (ret != MAP2_MAGIC) 51 + test_err++; 52 + 53 + return 0; 54 + } 55 + 56 + SEC(".struct_ops.link") 57 + struct bpf_testmod_multi_st_ops st_ops_map = { 58 + .test_1 = (void *)test_1, 59 + };