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

Configure Feed

Select the types of activity you want to include in your feed.

selftests/bpf: Split module_attach into subtests

The test verifies attachment to various hooks in a kernel module,
however, everything is flattened into a single test. This makes it
impossible to run or skip test cases selectively.

Isolate each BPF program into a separate subtest. This is done by
disabling auto-loading of programs and loading and testing each program
separately.

At the same time, modernize the test to use ASSERT* instead of CHECK and
replace `return` by `goto cleanup` where necessary.

Signed-off-by: Viktor Malik <vmalik@redhat.com>
Link: https://lore.kernel.org/r/20260225120904.1529112-1-vmalik@redhat.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Viktor Malik and committed by
Alexei Starovoitov
05c9b2ed 44dd647b

+158 -96
+134 -57
tools/testing/selftests/bpf/prog_tests/module_attach.c
··· 6 6 #include "test_module_attach.skel.h" 7 7 #include "testing_helpers.h" 8 8 9 - static int duration; 9 + static const char * const read_tests[] = { 10 + "handle_raw_tp", 11 + "handle_tp_btf", 12 + "handle_fentry", 13 + "handle_fentry_explicit", 14 + "handle_fmod_ret", 15 + }; 16 + 17 + static const char * const detach_tests[] = { 18 + "handle_fentry", 19 + "handle_fexit", 20 + "kprobe_multi", 21 + }; 22 + 23 + static const int READ_SZ = 456; 24 + static const int WRITE_SZ = 457; 10 25 11 26 static int trigger_module_test_writable(int *val) 12 27 { ··· 48 33 return 0; 49 34 } 50 35 51 - void test_module_attach(void) 36 + static void test_module_attach_prog(const char *prog_name, int sz, 37 + const char *attach_target, int ret) 52 38 { 53 - const int READ_SZ = 456; 54 - const int WRITE_SZ = 457; 55 - struct test_module_attach* skel; 56 - struct test_module_attach__bss *bss; 57 - struct bpf_link *link; 39 + struct test_module_attach *skel; 40 + struct bpf_program *prog; 58 41 int err; 59 - int writable_val = 0; 60 42 61 43 skel = test_module_attach__open(); 62 - if (CHECK(!skel, "skel_open", "failed to open skeleton\n")) 44 + if (!ASSERT_OK_PTR(skel, "module_attach open")) 63 45 return; 64 46 65 - err = bpf_program__set_attach_target(skel->progs.handle_fentry_manual, 66 - 0, "bpf_testmod_test_read"); 67 - ASSERT_OK(err, "set_attach_target"); 47 + prog = bpf_object__find_program_by_name(skel->obj, prog_name); 48 + if (!ASSERT_OK_PTR(prog, "module_attach find_program")) 49 + goto cleanup; 50 + bpf_program__set_autoload(prog, true); 68 51 69 - err = bpf_program__set_attach_target(skel->progs.handle_fentry_explicit_manual, 70 - 0, "bpf_testmod:bpf_testmod_test_read"); 71 - ASSERT_OK(err, "set_attach_target_explicit"); 52 + if (attach_target) { 53 + err = bpf_program__set_attach_target(prog, 0, attach_target); 54 + if (!ASSERT_OK(err, attach_target)) 55 + goto cleanup; 56 + } 72 57 73 58 err = test_module_attach__load(skel); 74 - if (CHECK(err, "skel_load", "failed to load skeleton\n")) 59 + if (!ASSERT_OK(err, "module_attach load")) 60 + goto cleanup; 61 + 62 + err = test_module_attach__attach(skel); 63 + if (!ASSERT_OK(err, "module_attach attach")) 64 + goto cleanup; 65 + 66 + if (sz) { 67 + /* trigger both read and write though each test uses only one */ 68 + ASSERT_OK(trigger_module_test_read(sz), "trigger_read"); 69 + ASSERT_OK(trigger_module_test_write(sz), "trigger_write"); 70 + 71 + ASSERT_EQ(skel->bss->sz, sz, prog_name); 72 + } 73 + 74 + if (ret) 75 + ASSERT_EQ(skel->bss->retval, ret, "ret"); 76 + cleanup: 77 + test_module_attach__destroy(skel); 78 + } 79 + 80 + static void test_module_attach_writable(void) 81 + { 82 + struct test_module_attach__bss *bss; 83 + struct test_module_attach *skel; 84 + int writable_val = 0; 85 + int err; 86 + 87 + skel = test_module_attach__open(); 88 + if (!ASSERT_OK_PTR(skel, "module_attach open")) 75 89 return; 90 + 91 + bpf_program__set_autoload(skel->progs.handle_raw_tp_writable_bare, true); 92 + 93 + err = test_module_attach__load(skel); 94 + if (!ASSERT_OK(err, "module_attach load")) 95 + goto cleanup; 76 96 77 97 bss = skel->bss; 78 98 79 99 err = test_module_attach__attach(skel); 80 - if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err)) 100 + if (!ASSERT_OK(err, "module_attach attach")) 81 101 goto cleanup; 82 - 83 - /* trigger tracepoint */ 84 - ASSERT_OK(trigger_module_test_read(READ_SZ), "trigger_read"); 85 - ASSERT_OK(trigger_module_test_write(WRITE_SZ), "trigger_write"); 86 - 87 - ASSERT_EQ(bss->raw_tp_read_sz, READ_SZ, "raw_tp"); 88 - ASSERT_EQ(bss->raw_tp_bare_write_sz, WRITE_SZ, "raw_tp_bare"); 89 - ASSERT_EQ(bss->tp_btf_read_sz, READ_SZ, "tp_btf"); 90 - ASSERT_EQ(bss->fentry_read_sz, READ_SZ, "fentry"); 91 - ASSERT_EQ(bss->fentry_manual_read_sz, READ_SZ, "fentry_manual"); 92 - ASSERT_EQ(bss->fentry_explicit_read_sz, READ_SZ, "fentry_explicit"); 93 - ASSERT_EQ(bss->fentry_explicit_manual_read_sz, READ_SZ, "fentry_explicit_manual"); 94 - ASSERT_EQ(bss->fexit_read_sz, READ_SZ, "fexit"); 95 - ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); 96 - ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); 97 102 98 103 bss->raw_tp_writable_bare_early_ret = true; 99 104 bss->raw_tp_writable_bare_out_val = 0xf1f2f3f4; ··· 122 87 ASSERT_EQ(bss->raw_tp_writable_bare_in_val, 1024, "writable_test_in"); 123 88 ASSERT_EQ(bss->raw_tp_writable_bare_out_val, writable_val, 124 89 "writable_test_out"); 125 - 126 - test_module_attach__detach(skel); 127 - 128 - /* attach fentry/fexit and make sure it gets module reference */ 129 - link = bpf_program__attach(skel->progs.handle_fentry); 130 - if (!ASSERT_OK_PTR(link, "attach_fentry")) 131 - goto cleanup; 132 - 133 - ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); 134 - bpf_link__destroy(link); 135 - 136 - link = bpf_program__attach(skel->progs.handle_fexit); 137 - if (!ASSERT_OK_PTR(link, "attach_fexit")) 138 - goto cleanup; 139 - 140 - ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); 141 - bpf_link__destroy(link); 142 - 143 - link = bpf_program__attach(skel->progs.kprobe_multi); 144 - if (!ASSERT_OK_PTR(link, "attach_kprobe_multi")) 145 - goto cleanup; 146 - 147 - ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); 148 - bpf_link__destroy(link); 149 - 150 90 cleanup: 151 91 test_module_attach__destroy(skel); 92 + } 93 + 94 + static void test_module_attach_detach(const char *prog_name) 95 + { 96 + struct test_module_attach *skel; 97 + struct bpf_program *prog; 98 + struct bpf_link *link; 99 + int err; 100 + 101 + skel = test_module_attach__open(); 102 + if (!ASSERT_OK_PTR(skel, "module_attach open")) 103 + return; 104 + 105 + prog = bpf_object__find_program_by_name(skel->obj, prog_name); 106 + if (!ASSERT_OK_PTR(prog, "module_attach find_program")) 107 + goto cleanup; 108 + bpf_program__set_autoload(prog, true); 109 + 110 + err = test_module_attach__load(skel); 111 + if (!ASSERT_OK(err, "module_attach load")) 112 + goto cleanup; 113 + 114 + /* attach and make sure it gets module reference */ 115 + link = bpf_program__attach(prog); 116 + if (!ASSERT_OK_PTR(link, "module_attach attach")) 117 + goto cleanup; 118 + 119 + ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); 120 + bpf_link__destroy(link); 121 + cleanup: 122 + test_module_attach__destroy(skel); 123 + } 124 + 125 + void test_module_attach(void) 126 + { 127 + int i; 128 + 129 + for (i = 0; i < ARRAY_SIZE(read_tests); i++) { 130 + if (!test__start_subtest(read_tests[i])) 131 + continue; 132 + test_module_attach_prog(read_tests[i], READ_SZ, NULL, 0); 133 + } 134 + if (test__start_subtest("handle_raw_tp_bare")) 135 + test_module_attach_prog("handle_raw_tp_bare", WRITE_SZ, NULL, 0); 136 + if (test__start_subtest("handle_raw_tp_writable_bare")) 137 + test_module_attach_writable(); 138 + if (test__start_subtest("handle_fentry_manual")) { 139 + test_module_attach_prog("handle_fentry_manual", READ_SZ, 140 + "bpf_testmod_test_read", 0); 141 + } 142 + if (test__start_subtest("handle_fentry_explicit_manual")) { 143 + test_module_attach_prog("handle_fentry_explicit_manual", 144 + READ_SZ, 145 + "bpf_testmod:bpf_testmod_test_read", 0); 146 + } 147 + if (test__start_subtest("handle_fexit")) 148 + test_module_attach_prog("handle_fexit", READ_SZ, NULL, -EIO); 149 + if (test__start_subtest("handle_fexit_ret")) 150 + test_module_attach_prog("handle_fexit_ret", 0, NULL, 0); 151 + for (i = 0; i < ARRAY_SIZE(detach_tests); i++) { 152 + char test_name[50]; 153 + 154 + snprintf(test_name, sizeof(test_name), "%s_detach", detach_tests[i]); 155 + if (!test__start_subtest(test_name)) 156 + continue; 157 + test_module_attach_detach(detach_tests[i]); 158 + } 152 159 }
+24 -39
tools/testing/selftests/bpf/progs/test_module_attach.c
··· 7 7 #include <bpf/bpf_core_read.h> 8 8 #include "../test_kmods/bpf_testmod.h" 9 9 10 - __u32 raw_tp_read_sz = 0; 10 + __u32 sz = 0; 11 11 12 - SEC("raw_tp/bpf_testmod_test_read") 12 + SEC("?raw_tp/bpf_testmod_test_read") 13 13 int BPF_PROG(handle_raw_tp, 14 14 struct task_struct *task, struct bpf_testmod_test_read_ctx *read_ctx) 15 15 { 16 - raw_tp_read_sz = BPF_CORE_READ(read_ctx, len); 16 + sz = BPF_CORE_READ(read_ctx, len); 17 17 return 0; 18 18 } 19 19 20 - __u32 raw_tp_bare_write_sz = 0; 21 - 22 - SEC("raw_tp/bpf_testmod_test_write_bare_tp") 20 + SEC("?raw_tp/bpf_testmod_test_write_bare_tp") 23 21 int BPF_PROG(handle_raw_tp_bare, 24 22 struct task_struct *task, struct bpf_testmod_test_write_ctx *write_ctx) 25 23 { 26 - raw_tp_bare_write_sz = BPF_CORE_READ(write_ctx, len); 24 + sz = BPF_CORE_READ(write_ctx, len); 27 25 return 0; 28 26 } 29 27 ··· 29 31 int raw_tp_writable_bare_early_ret = 0; 30 32 int raw_tp_writable_bare_out_val = 0; 31 33 32 - SEC("raw_tp.w/bpf_testmod_test_writable_bare_tp") 34 + SEC("?raw_tp.w/bpf_testmod_test_writable_bare_tp") 33 35 int BPF_PROG(handle_raw_tp_writable_bare, 34 36 struct bpf_testmod_test_writable_ctx *writable) 35 37 { ··· 39 41 return 0; 40 42 } 41 43 42 - __u32 tp_btf_read_sz = 0; 43 - 44 - SEC("tp_btf/bpf_testmod_test_read") 44 + SEC("?tp_btf/bpf_testmod_test_read") 45 45 int BPF_PROG(handle_tp_btf, 46 46 struct task_struct *task, struct bpf_testmod_test_read_ctx *read_ctx) 47 47 { 48 - tp_btf_read_sz = read_ctx->len; 48 + sz = read_ctx->len; 49 49 return 0; 50 50 } 51 51 52 - __u32 fentry_read_sz = 0; 53 - 54 - SEC("fentry/bpf_testmod_test_read") 52 + SEC("?fentry/bpf_testmod_test_read") 55 53 int BPF_PROG(handle_fentry, 56 54 struct file *file, struct kobject *kobj, 57 55 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len) 58 56 { 59 - fentry_read_sz = len; 57 + sz = len; 60 58 return 0; 61 59 } 62 60 63 - __u32 fentry_manual_read_sz = 0; 64 - 65 - SEC("fentry") 61 + SEC("?fentry") 66 62 int BPF_PROG(handle_fentry_manual, 67 63 struct file *file, struct kobject *kobj, 68 64 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len) 69 65 { 70 - fentry_manual_read_sz = len; 66 + sz = len; 71 67 return 0; 72 68 } 73 69 74 - __u32 fentry_explicit_read_sz = 0; 75 - 76 - SEC("fentry/bpf_testmod:bpf_testmod_test_read") 70 + SEC("?fentry/bpf_testmod:bpf_testmod_test_read") 77 71 int BPF_PROG(handle_fentry_explicit, 78 72 struct file *file, struct kobject *kobj, 79 73 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len) 80 74 { 81 - fentry_explicit_read_sz = len; 75 + sz = len; 82 76 return 0; 83 77 } 84 78 85 79 86 - __u32 fentry_explicit_manual_read_sz = 0; 87 - 88 - SEC("fentry") 80 + SEC("?fentry") 89 81 int BPF_PROG(handle_fentry_explicit_manual, 90 82 struct file *file, struct kobject *kobj, 91 83 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len) 92 84 { 93 - fentry_explicit_manual_read_sz = len; 85 + sz = len; 94 86 return 0; 95 87 } 96 88 97 - __u32 fexit_read_sz = 0; 98 - int fexit_ret = 0; 89 + int retval = 0; 99 90 100 - SEC("fexit/bpf_testmod_test_read") 91 + SEC("?fexit/bpf_testmod_test_read") 101 92 int BPF_PROG(handle_fexit, 102 93 struct file *file, struct kobject *kobj, 103 94 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len, 104 95 int ret) 105 96 { 106 - fexit_read_sz = len; 107 - fexit_ret = ret; 97 + sz = len; 98 + retval = ret; 108 99 return 0; 109 100 } 110 101 111 - SEC("fexit/bpf_testmod_return_ptr") 102 + SEC("?fexit/bpf_testmod_return_ptr") 112 103 int BPF_PROG(handle_fexit_ret, int arg, struct file *ret) 113 104 { 114 105 long buf = 0; ··· 109 122 return 0; 110 123 } 111 124 112 - __u32 fmod_ret_read_sz = 0; 113 - 114 - SEC("fmod_ret/bpf_testmod_test_read") 125 + SEC("?fmod_ret/bpf_testmod_test_read") 115 126 int BPF_PROG(handle_fmod_ret, 116 127 struct file *file, struct kobject *kobj, 117 128 struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len) 118 129 { 119 - fmod_ret_read_sz = len; 130 + sz = len; 120 131 return 0; /* don't override the exit code */ 121 132 } 122 133 123 - SEC("kprobe.multi/bpf_testmod_test_read") 134 + SEC("?kprobe.multi/bpf_testmod_test_read") 124 135 int BPF_PROG(kprobe_multi) 125 136 { 126 137 return 0;