Skip to content

libbpf: Improve BPF load performance by selectively loading kmod BTFs - #13432

Open
kernel-patches-daemon-bpf[bot] wants to merge 2 commits into
bpf-next_basefrom
series/1150896=>bpf-next
Open

libbpf: Improve BPF load performance by selectively loading kmod BTFs#13432
kernel-patches-daemon-bpf[bot] wants to merge 2 commits into
bpf-next_basefrom
series/1150896=>bpf-next

Conversation

@kernel-patches-daemon-bpf

Copy link
Copy Markdown

Pull request for series with
subject: libbpf: Improve BPF load performance by selectively loading kmod BTFs
version: 4
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=1150896

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: 5e289c5
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1150896
version: 4

@kernel-patches-review-bot

Copy link
Copy Markdown
commit bef0d955b0b11a4eaee33ef8e1ff70724b82e66f
Author: Fuyu Zhao <zhaofuyu@vivo.com>

selftests/bpf: add tests for selective module BTF loading

Add selftests covering selective kernel module BTF loading through
bpf_object_open_opts. The tests verify that loading succeeds when the
required module BTF is requested, fails when only an unrelated module
BTF is requested, and skips loading all module BTFs when an empty module
BTF name list is provided.

> 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..d5674cad0017
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/btf_module_names.c
> @@ -0,0 +1,93 @@
> +// 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,
> +	);
> +
> +	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");

The three subtests (btf_module_names_load, btf_module_names_skip, and
btf_module_names_empty) leave the input-validation paths from the
preceding commit completely unexercised.

That commit adds checks in bpf_object_init_btf_module_names() that are
documented in libbpf.h as part of the API contract, particularly:
"The list must not contain duplicate entries; otherwise -EINVAL is
returned."

Uncovered paths in bpf_object_init_btf_module_names():
- Empty or NULL entry detection (if (!names[i] || !names[i][0]))
- Duplicate name detection (the for loop with strcmp checking all
  previous entries)
- Error cleanup path (err_out:) that calls
  bpf_object_free_btf_module_names() after partial strdup() walk

Would it make sense to add subtests covering these validation paths? A
single extra __open_opts() call checked with ASSERT_ERR_PTR() or
ASSERT_NULL() would exercise each. The duplicate-detection loop is
non-trivial enough to deserve one.

Also, nothing in the series asserts the default btf_module_names == NULL
case (load everything, unchanged behaviour), so a regression that makes
the option mandatory would pass undetected.

> +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_ERR(ret, "btf_module_names__load");

A subsystem pattern flags this as potentially concerning: both negative
subtests assert only that the load failed, not the specific reason why.
ASSERT_ERR expands to check ___res < 0, so btf_module_names_skip() and
btf_module_names_empty() pass for any negative return from
btf_module_names__load().

The intended error is specific: with bpf_testmod's BTF filtered out,
find_kernel_btf_id() walks obj->btf_modules and falls through to return
-ESRCH, which bpf_object_load() propagates to __load(). Asserting that
value (for example, ASSERT_EQ(ret, -ESRCH, ...)) would pin the
behaviour.

As written, several unrelated conditions make both subtests report
success while proving nothing about the new filter:

- CONFIG_DEBUG_INFO_BTF_MODULES=n: bpf_testmod loads (so env.has_testmod
  is true and the test is not skipped) but has no BTF at all.
  Attach-target resolution then fails regardless of btf_module_names, so
  both negative subtests pass vacuously.

- Unprivileged/EPERM: load_module_btfs() returns 0 early without loading
  any module BTF (pr_debug skipping message), again yielding -ESRCH from
  an unrelated cause.

- Any future validation of the new opts that rejects the list at load
  time rather than at open time.

Would pinning the expected -ESRCH value make these subtests more robust?

> +
> +out:
> +	btf_module_names__destroy(skel);
> +}

[ ... ]



AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

In-Reply-To-Subject: selftests/bpf: add tests for selective module BTF loading
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/32730521630

@kernel-patches-review-bot

Copy link
Copy Markdown
commit 69592430b5945ba6b1ccd1ea0e5785435c823e51
Author: Fuyu Zhao <zhaofuyu@vivo.com>

libbpf: support selective kernel module BTF loading via bpf_object_open_opts

Add btf_module_names and nr_btf_module_names fields to
bpf_object_open_opts to support selective kernel module BTF loading.
When btf_module_names is provided, libbpf loads BTFs only for the
specified kernel modules and skips other module BTFs. If
btf_module_names is NULL, all module BTFs are loaded as before.
This avoids unnecessary module BTF loading and reduces BPF object
loading time when only a subset of kernel module BTFs is needed.

Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Signed-off-by: Fuyu Zhao <zhaofuyu@vivo.com>

> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index b965ad571540..838602319da8 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h

[ ... ]

> @@ -224,10 +224,32 @@ struct bpf_object_open_opts {
>  	 * point (/sys/fs/bpf), in case this default behavior is undesirable.
>  	 */
>  	const char *bpf_token_path;
> +	/*
> +	 * Optional list of kernel module names whose BTFs should be loaded.
> +	 * nr_btf_module_names specifies the number of entries in
> +	 * btf_module_names.
> +	 *
> +	 * If btf_module_names is NULL, all module BTFs are loaded,
> +	 * preserving the default behavior. Otherwise, only the BTFs of
> +	 * the listed modules are loaded. A non-NULL btf_module_names
> +	 * with nr_btf_module_names equal to zero means that no module
> +	 * BTFs are loaded.
> +	 *
> +	 * The list must not contain duplicate entries; otherwise
> +	 * -EINVAL is returned.
> +	 *
> +	 * This affects:
> +	 * - BPF CO-RE relocations against types defined in modules;
> +	 * - BTF-based resolution of function attach targets for
> +	 *   fentry/fexit/fmod_ret/freplace/LSM programs;
> +	 * - extern (ksym) resolution for kernel symbols defined in modules.
                   ^^^^

This isn't a bug, but would it be worth adding struct_ops kernel-type
resolution to the "This affects:" list?

find_struct_ops_kern_types() (tools/lib/bpf/libbpf.c:1049) looks up
'bpf_struct_ops_<name>' via find_ksym_btf_id(), which falls back to
obj->btf_modules[] after load_module_btfs().

A struct_ops implementation whose kernel type lives in a module (e.g. a
module-provided tcp_congestion_ops or sched_ext-style struct_ops) will
therefore stop resolving once a filter that omits that module is supplied.

> +	 */
> +	const char **btf_module_names;
> +	size_t nr_btf_module_names;
>
>  	size_t :0;
>  };
> -#define bpf_object_open_opts__last_field bpf_token_path
> +#define bpf_object_open_opts__last_field nr_btf_module_names




AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

In-Reply-To-Subject: libbpf: support selective kernel module BTF loading via bpf_object_open_opts
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/32730521630

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: d83fba2
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1150896
version: 4

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: ce36e38
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1150896
version: 4

@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: 05ea1b6
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1150896
version: 4

…en_opts

Add btf_module_names and nr_btf_module_names fields to
bpf_object_open_opts to support selective kernel module BTF loading.

When btf_module_names is provided, libbpf loads BTFs only for the
specified kernel modules and skips other module BTFs. If
btf_module_names is NULL, all module BTFs are loaded as before.

This avoids unnecessary module BTF loading and reduces BPF object
loading time when only a subset of kernel module BTFs is needed.

Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Signed-off-by: Fuyu Zhao <zhaofuyu@vivo.com>
Add selftests covering selective kernel module BTF loading through
bpf_object_open_opts.

The tests verify that loading succeeds when the required module BTF is
requested, fails when only an unrelated module BTF is requested, and
skips loading all module BTFs when an empty module BTF name list is
provided.

Signed-off-by: Fuyu Zhao <zhaofuyu@vivo.com>
@kernel-patches-daemon-bpf

Copy link
Copy Markdown
Author

Upstream branch: 1555de3
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1150896
version: 4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant