]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: Split module_attach into subtests
authorViktor Malik <vmalik@redhat.com>
Wed, 25 Feb 2026 12:09:04 +0000 (13:09 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 3 Mar 2026 17:23:57 +0000 (09:23 -0800)
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>
tools/testing/selftests/bpf/prog_tests/module_attach.c
tools/testing/selftests/bpf/progs/test_module_attach.c

index 70fa7ae93173b64da2f8afd073d502103e40f0ad..67763f609b6e1868879e3c4c97ff61dd405746bb 100644 (file)
@@ -6,7 +6,22 @@
 #include "test_module_attach.skel.h"
 #include "testing_helpers.h"
 
-static int duration;
+static const char * const read_tests[] = {
+       "handle_raw_tp",
+       "handle_tp_btf",
+       "handle_fentry",
+       "handle_fentry_explicit",
+       "handle_fmod_ret",
+};
+
+static const char * const detach_tests[] = {
+       "handle_fentry",
+       "handle_fexit",
+       "kprobe_multi",
+};
+
+static const int READ_SZ = 456;
+static const int WRITE_SZ = 457;
 
 static int trigger_module_test_writable(int *val)
 {
@@ -33,53 +48,73 @@ static int trigger_module_test_writable(int *val)
        return 0;
 }
 
-void test_module_attach(void)
+static void test_module_attach_prog(const char *prog_name, int sz,
+                                   const char *attach_target, int ret)
 {
-       const int READ_SZ = 456;
-       const int WRITE_SZ = 457;
-       struct test_module_attach* skel;
-       struct test_module_attach__bss *bss;
-       struct bpf_link *link;
+       struct test_module_attach *skel;
+       struct bpf_program *prog;
        int err;
-       int writable_val = 0;
 
        skel = test_module_attach__open();
-       if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
+       if (!ASSERT_OK_PTR(skel, "module_attach open"))
                return;
 
-       err = bpf_program__set_attach_target(skel->progs.handle_fentry_manual,
-                                            0, "bpf_testmod_test_read");
-       ASSERT_OK(err, "set_attach_target");
+       prog = bpf_object__find_program_by_name(skel->obj, prog_name);
+       if (!ASSERT_OK_PTR(prog, "module_attach find_program"))
+               goto cleanup;
+       bpf_program__set_autoload(prog, true);
 
-       err = bpf_program__set_attach_target(skel->progs.handle_fentry_explicit_manual,
-                                            0, "bpf_testmod:bpf_testmod_test_read");
-       ASSERT_OK(err, "set_attach_target_explicit");
+       if (attach_target) {
+               err = bpf_program__set_attach_target(prog, 0, attach_target);
+               if (!ASSERT_OK(err, attach_target))
+                       goto cleanup;
+       }
 
        err = test_module_attach__load(skel);
-       if (CHECK(err, "skel_load", "failed to load skeleton\n"))
+       if (!ASSERT_OK(err, "module_attach load"))
+               goto cleanup;
+
+       err = test_module_attach__attach(skel);
+       if (!ASSERT_OK(err, "module_attach attach"))
+               goto cleanup;
+
+       if (sz) {
+               /* trigger both read and write though each test uses only one */
+               ASSERT_OK(trigger_module_test_read(sz), "trigger_read");
+               ASSERT_OK(trigger_module_test_write(sz), "trigger_write");
+
+               ASSERT_EQ(skel->bss->sz, sz, prog_name);
+       }
+
+       if (ret)
+               ASSERT_EQ(skel->bss->retval, ret, "ret");
+cleanup:
+       test_module_attach__destroy(skel);
+}
+
+static void test_module_attach_writable(void)
+{
+       struct test_module_attach__bss *bss;
+       struct test_module_attach *skel;
+       int writable_val = 0;
+       int err;
+
+       skel = test_module_attach__open();
+       if (!ASSERT_OK_PTR(skel, "module_attach open"))
                return;
 
+       bpf_program__set_autoload(skel->progs.handle_raw_tp_writable_bare, true);
+
+       err = test_module_attach__load(skel);
+       if (!ASSERT_OK(err, "module_attach load"))
+               goto cleanup;
+
        bss = skel->bss;
 
        err = test_module_attach__attach(skel);
-       if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
+       if (!ASSERT_OK(err, "module_attach attach"))
                goto cleanup;
 
-       /* trigger tracepoint */
-       ASSERT_OK(trigger_module_test_read(READ_SZ), "trigger_read");
-       ASSERT_OK(trigger_module_test_write(WRITE_SZ), "trigger_write");
-
-       ASSERT_EQ(bss->raw_tp_read_sz, READ_SZ, "raw_tp");
-       ASSERT_EQ(bss->raw_tp_bare_write_sz, WRITE_SZ, "raw_tp_bare");
-       ASSERT_EQ(bss->tp_btf_read_sz, READ_SZ, "tp_btf");
-       ASSERT_EQ(bss->fentry_read_sz, READ_SZ, "fentry");
-       ASSERT_EQ(bss->fentry_manual_read_sz, READ_SZ, "fentry_manual");
-       ASSERT_EQ(bss->fentry_explicit_read_sz, READ_SZ, "fentry_explicit");
-       ASSERT_EQ(bss->fentry_explicit_manual_read_sz, READ_SZ, "fentry_explicit_manual");
-       ASSERT_EQ(bss->fexit_read_sz, READ_SZ, "fexit");
-       ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet");
-       ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret");
-
        bss->raw_tp_writable_bare_early_ret = true;
        bss->raw_tp_writable_bare_out_val = 0xf1f2f3f4;
        ASSERT_OK(trigger_module_test_writable(&writable_val),
@@ -87,31 +122,73 @@ void test_module_attach(void)
        ASSERT_EQ(bss->raw_tp_writable_bare_in_val, 1024, "writable_test_in");
        ASSERT_EQ(bss->raw_tp_writable_bare_out_val, writable_val,
                  "writable_test_out");
+cleanup:
+       test_module_attach__destroy(skel);
+}
 
-       test_module_attach__detach(skel);
-
-       /* attach fentry/fexit and make sure it gets module reference */
-       link = bpf_program__attach(skel->progs.handle_fentry);
-       if (!ASSERT_OK_PTR(link, "attach_fentry"))
-               goto cleanup;
+static void test_module_attach_detach(const char *prog_name)
+{
+       struct test_module_attach *skel;
+       struct bpf_program *prog;
+       struct bpf_link *link;
+       int err;
 
-       ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod");
-       bpf_link__destroy(link);
+       skel = test_module_attach__open();
+       if (!ASSERT_OK_PTR(skel, "module_attach open"))
+               return;
 
-       link = bpf_program__attach(skel->progs.handle_fexit);
-       if (!ASSERT_OK_PTR(link, "attach_fexit"))
+       prog = bpf_object__find_program_by_name(skel->obj, prog_name);
+       if (!ASSERT_OK_PTR(prog, "module_attach find_program"))
                goto cleanup;
+       bpf_program__set_autoload(prog, true);
 
-       ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod");
-       bpf_link__destroy(link);
+       err = test_module_attach__load(skel);
+       if (!ASSERT_OK(err, "module_attach load"))
+               goto cleanup;
 
-       link = bpf_program__attach(skel->progs.kprobe_multi);
-       if (!ASSERT_OK_PTR(link, "attach_kprobe_multi"))
+       /* attach and make sure it gets module reference */
+       link = bpf_program__attach(prog);
+       if (!ASSERT_OK_PTR(link, "module_attach attach"))
                goto cleanup;
 
        ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod");
        bpf_link__destroy(link);
-
 cleanup:
        test_module_attach__destroy(skel);
 }
+
+void test_module_attach(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(read_tests); i++) {
+               if (!test__start_subtest(read_tests[i]))
+                       continue;
+               test_module_attach_prog(read_tests[i], READ_SZ, NULL, 0);
+       }
+       if (test__start_subtest("handle_raw_tp_bare"))
+               test_module_attach_prog("handle_raw_tp_bare", WRITE_SZ, NULL, 0);
+       if (test__start_subtest("handle_raw_tp_writable_bare"))
+               test_module_attach_writable();
+       if (test__start_subtest("handle_fentry_manual")) {
+               test_module_attach_prog("handle_fentry_manual", READ_SZ,
+                                       "bpf_testmod_test_read", 0);
+       }
+       if (test__start_subtest("handle_fentry_explicit_manual")) {
+               test_module_attach_prog("handle_fentry_explicit_manual",
+                                       READ_SZ,
+                                       "bpf_testmod:bpf_testmod_test_read", 0);
+       }
+       if (test__start_subtest("handle_fexit"))
+               test_module_attach_prog("handle_fexit", READ_SZ, NULL, -EIO);
+       if (test__start_subtest("handle_fexit_ret"))
+               test_module_attach_prog("handle_fexit_ret", 0, NULL, 0);
+       for (i = 0; i < ARRAY_SIZE(detach_tests); i++) {
+               char test_name[50];
+
+               snprintf(test_name, sizeof(test_name), "%s_detach", detach_tests[i]);
+               if (!test__start_subtest(test_name))
+                       continue;
+               test_module_attach_detach(detach_tests[i]);
+       }
+}
index 03d7f89787a18809995965e1236abd823252481a..5609e388fb58ad67af4addad6ca82930173da149 100644 (file)
@@ -7,23 +7,21 @@
 #include <bpf/bpf_core_read.h>
 #include "../test_kmods/bpf_testmod.h"
 
-__u32 raw_tp_read_sz = 0;
+__u32 sz = 0;
 
-SEC("raw_tp/bpf_testmod_test_read")
+SEC("?raw_tp/bpf_testmod_test_read")
 int BPF_PROG(handle_raw_tp,
             struct task_struct *task, struct bpf_testmod_test_read_ctx *read_ctx)
 {
-       raw_tp_read_sz = BPF_CORE_READ(read_ctx, len);
+       sz = BPF_CORE_READ(read_ctx, len);
        return 0;
 }
 
-__u32 raw_tp_bare_write_sz = 0;
-
-SEC("raw_tp/bpf_testmod_test_write_bare_tp")
+SEC("?raw_tp/bpf_testmod_test_write_bare_tp")
 int BPF_PROG(handle_raw_tp_bare,
             struct task_struct *task, struct bpf_testmod_test_write_ctx *write_ctx)
 {
-       raw_tp_bare_write_sz = BPF_CORE_READ(write_ctx, len);
+       sz = BPF_CORE_READ(write_ctx, len);
        return 0;
 }
 
@@ -31,7 +29,7 @@ int raw_tp_writable_bare_in_val = 0;
 int raw_tp_writable_bare_early_ret = 0;
 int raw_tp_writable_bare_out_val = 0;
 
-SEC("raw_tp.w/bpf_testmod_test_writable_bare_tp")
+SEC("?raw_tp.w/bpf_testmod_test_writable_bare_tp")
 int BPF_PROG(handle_raw_tp_writable_bare,
             struct bpf_testmod_test_writable_ctx *writable)
 {
@@ -41,76 +39,65 @@ int BPF_PROG(handle_raw_tp_writable_bare,
        return 0;
 }
 
-__u32 tp_btf_read_sz = 0;
-
-SEC("tp_btf/bpf_testmod_test_read")
+SEC("?tp_btf/bpf_testmod_test_read")
 int BPF_PROG(handle_tp_btf,
             struct task_struct *task, struct bpf_testmod_test_read_ctx *read_ctx)
 {
-       tp_btf_read_sz = read_ctx->len;
+       sz = read_ctx->len;
        return 0;
 }
 
-__u32 fentry_read_sz = 0;
-
-SEC("fentry/bpf_testmod_test_read")
+SEC("?fentry/bpf_testmod_test_read")
 int BPF_PROG(handle_fentry,
             struct file *file, struct kobject *kobj,
             struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len)
 {
-       fentry_read_sz = len;
+       sz = len;
        return 0;
 }
 
-__u32 fentry_manual_read_sz = 0;
-
-SEC("fentry")
+SEC("?fentry")
 int BPF_PROG(handle_fentry_manual,
             struct file *file, struct kobject *kobj,
             struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len)
 {
-       fentry_manual_read_sz = len;
+       sz = len;
        return 0;
 }
 
-__u32 fentry_explicit_read_sz = 0;
-
-SEC("fentry/bpf_testmod:bpf_testmod_test_read")
+SEC("?fentry/bpf_testmod:bpf_testmod_test_read")
 int BPF_PROG(handle_fentry_explicit,
             struct file *file, struct kobject *kobj,
             struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len)
 {
-       fentry_explicit_read_sz = len;
+       sz = len;
        return 0;
 }
 
 
-__u32 fentry_explicit_manual_read_sz = 0;
-
-SEC("fentry")
+SEC("?fentry")
 int BPF_PROG(handle_fentry_explicit_manual,
             struct file *file, struct kobject *kobj,
             struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len)
 {
-       fentry_explicit_manual_read_sz = len;
+       sz = len;
        return 0;
 }
 
-__u32 fexit_read_sz = 0;
-int fexit_ret = 0;
+int retval = 0;
 
-SEC("fexit/bpf_testmod_test_read")
+SEC("?fexit/bpf_testmod_test_read")
 int BPF_PROG(handle_fexit,
             struct file *file, struct kobject *kobj,
             struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len,
             int ret)
 {
-       fexit_read_sz = len;
-       fexit_ret = ret;
+       sz = len;
+       retval = ret;
        return 0;
 }
 
-SEC("fexit/bpf_testmod_return_ptr")
+SEC("?fexit/bpf_testmod_return_ptr")
 int BPF_PROG(handle_fexit_ret, int arg, struct file *ret)
 {
        long buf = 0;
@@ -122,18 +109,16 @@ int BPF_PROG(handle_fexit_ret, int arg, struct file *ret)
        return 0;
 }
 
-__u32 fmod_ret_read_sz = 0;
-
-SEC("fmod_ret/bpf_testmod_test_read")
+SEC("?fmod_ret/bpf_testmod_test_read")
 int BPF_PROG(handle_fmod_ret,
             struct file *file, struct kobject *kobj,
             struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len)
 {
-       fmod_ret_read_sz = len;
+       sz = len;
        return 0; /* don't override the exit code */
 }
 
-SEC("kprobe.multi/bpf_testmod_test_read")
+SEC("?kprobe.multi/bpf_testmod_test_read")
 int BPF_PROG(kprobe_multi)
 {
        return 0;