Add selftests covering selective kernel module BTF loading through bpf_object_open_opts.
The tests verify that: - the existing behavior is preserved when btf_module_names is not specified, and loading succeeds when the required module BTF is specified; - a required module BTF is skipped when the module is not specified in btf_module_names; - an empty btf_module_names list skips loading all module BTFs; - invalid module BTF name lists are rejected. Signed-off-by: Fuyu Zhao <[email protected]> --- .../bpf/prog_tests/btf_module_names.c | 139 ++++++++++++++++++ .../selftests/bpf/progs/btf_module_names.c | 13 ++ 2 files changed, 152 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_module_names.c create mode 100644 tools/testing/selftests/bpf/progs/btf_module_names.c diff --git a/tools/testing/selftests/bpf/prog_tests/btf_module_names.c b/tools/testing/selftests/bpf/prog_tests/btf_module_names.c new file mode 100644 index 000000000000..3dc72bef014c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/btf_module_names.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include "btf_module_names.skel.h" + +static void btf_module_names_load(void) +{ + struct btf_module_names *skel = NULL; + int ret; + static const char *mod_names[] = { "bpf_testmod" }; + + LIBBPF_OPTS(bpf_object_open_opts, opts, + .btf_module_names = mod_names, + .nr_btf_module_names = 1, + ); + + /* Verify backward compatibility. */ + skel = btf_module_names__open_opts(NULL); + if (!ASSERT_OK_PTR(skel, "btf_module_names__open_opts default")) + goto out; + + ret = btf_module_names__load(skel); + ASSERT_OK(ret, "btf_module_names__load default"); + + btf_module_names__destroy(skel); + skel = NULL; + + skel = btf_module_names__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "btf_module_names__open_opts")) + goto out; + + ret = btf_module_names__load(skel); + ASSERT_OK(ret, "btf_module_names__load"); +out: + btf_module_names__destroy(skel); +} + +/* + * Verify that an unrequested module BTF is skipped. The BPF program + * requires the BTF of bpf_testmod, but bpf_testmod is not specified in + * btf_module_names, so its BTF is skipped and the BPF program fails to load. + */ +static void btf_module_names_skip(void) +{ + struct btf_module_names *skel = NULL; + int ret; + static const char *mod_names[] = { "module_nonexist" }; + + LIBBPF_OPTS(bpf_object_open_opts, opts, + .btf_module_names = mod_names, + .nr_btf_module_names = 1, + ); + + skel = btf_module_names__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "btf_module_names__open_opts")) + goto out; + + ret = btf_module_names__load(skel); + ASSERT_EQ(ret, -ESRCH, "btf_module_names__load"); + +out: + btf_module_names__destroy(skel); +} + +/* + * Verify that an empty filter skips loading all module BTFs. The BPF + * program requires bpf_testmod BTF, so it fails to load. + */ +static void btf_module_names_empty(void) +{ + struct btf_module_names *skel = NULL; + int ret; + static const char *mod_names[] = { "" }; + + LIBBPF_OPTS(bpf_object_open_opts, opts, + .btf_module_names = mod_names, + ); + + skel = btf_module_names__open_opts(&opts); + if (!ASSERT_OK_PTR(skel, "btf_module_names__open_opts empty")) + goto out; + + ret = btf_module_names__load(skel); + ASSERT_EQ(ret, -ESRCH, "btf_module_names__load empty"); + +out: + btf_module_names__destroy(skel); +} + +static void btf_module_names_invalid(void) +{ + struct btf_module_names *skel = NULL; + const char *names[] = { NULL }; + const char *empty_names[] = { "" }; + const char *duplicate_names[] = { + "bpf_testmod", "bpf_testmod", + }; + LIBBPF_OPTS(bpf_object_open_opts, opts, + .btf_module_names = names, + .nr_btf_module_names = 1, + ); + + skel = btf_module_names__open_opts(&opts); + ASSERT_EQ(libbpf_get_error(skel), -EINVAL, + "btf_module_names__open_opts null"); + btf_module_names__destroy(skel); + + opts.btf_module_names = empty_names; + skel = btf_module_names__open_opts(&opts); + ASSERT_EQ(libbpf_get_error(skel), -EINVAL, + "btf_module_names__open_opts empty"); + btf_module_names__destroy(skel); + + opts.btf_module_names = duplicate_names; + opts.nr_btf_module_names = 2; + skel = btf_module_names__open_opts(&opts); + ASSERT_EQ(libbpf_get_error(skel), -EINVAL, + "btf_module_names__open_opts duplicate name"); + btf_module_names__destroy(skel); +} + +void test_btf_module_names(void) +{ + if (!env.has_testmod) { + test__skip(); + return; + } + + if (test__start_subtest("btf_module_names_load")) + btf_module_names_load(); + + if (test__start_subtest("btf_module_names_skip")) + btf_module_names_skip(); + + if (test__start_subtest("btf_module_names_empty")) + btf_module_names_empty(); + + if (test__start_subtest("btf_module_names_invalid")) + btf_module_names_invalid(); +} diff --git a/tools/testing/selftests/bpf/progs/btf_module_names.c b/tools/testing/selftests/bpf/progs/btf_module_names.c new file mode 100644 index 000000000000..232adc0f33f6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/btf_module_names.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +SEC("fentry/bpf_testmod_loop_test") +int BPF_PROG(test_btf_module_names) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; -- 2.34.1

