From: Andrey Grodzovsky <andrey.grodzovsky@crowdstrike.com>
To: <bpf@vger.kernel.org>, <andrii@kernel.org>
Cc: <ast@kernel.org>, <martin.kelly@crowdstrike.com>,
<slava.imameev@crowdstrike.com>,
<linux-open-source@crowdstrike.com>
Subject: [PATCH bpf-next v4 0/7] libbpf: BPF program manual loading
Date: Mon, 21 Sep 2026 18:39:30 -0400 [thread overview]
Message-ID: <20260921223937.3203093-1-andrey.grodzovsky@crowdstrike.com> (raw)
This series was originally posted in January 2025 [1] as a two-patch RFC
introducing a per-program tri-state load strategy (disabled/auto/dynamic)
to let large BPF applications load a subset of their programs lazily,
after the initial bpf_object load. This v4 addresses all outstanding review
feedback from v3's two CI bots, folds bpf_program__load_manually()/
unload_manually() into a single load()/unload() naming pair, and adds
a new patch that properly versions bpf_program__set_autoattach()'s
ABI change instead of leaving it as a silent break for out-of-tree
consumers (see changelog below).
Motivation:
Security tools built on top of libbpf commonly ship as a single large
BPF object containing many programs, only a subset of which are needed
on any given system -- the rest are gated on optional features or on
kernel/runtime capabilities that vary across deployments. For this class
of application, per-program manual loading helps in two ways:
- it shortens the initial load, since only the programs actually
needed for the running configuration are loaded and attached up
front instead of the whole object; and
- it lets a single failing program be unloaded and possibly reloaded
(or a feature toggled at runtime) without tearing down and reloading
the entire bpf_object.
Both reduce the time window during which the tool is partially loaded or
inactive -- for a security tool specifically, that is also the time
window during which the system it protects is unprotected.
We have been running this with our internal fork of libbpf in production
for about a year. Depending on kernel and configuration support, around
250 of our programs are potentially loadable on any given system; with
manual loading, only around 90 of those are actually loaded by default,
growing to the full 250 only when every optional feature is enabled.
Cutting the default set of loaded programs from 250 down to 90 measurably
reduces load time (we observed ~60% reduction in our own measurements),
and since unload time scales with the number of loaded programs, it
correspondingly shortens unload time as well -- which matters, since
slow unload can delay system shutdown. We believe this functionality
would benefit other libbpf consumers with similarly large, modular BPF
applications.
Patch overview:
1/7: replace bpf_program's boolean autoload field with an enum
(bpf_prog_load_strategy: DISABLED/AUTO), so a third state can be
added later without an ABI break
2/7: add BPF_PROG_LOAD_STRATEGY_MANUAL and bpf_program__load()/
bpf_program__unload(), letting a program be loaded and attached
independently of the bulk bpf_object load/attach pass, and
reloaded/reattached multiple times; unload() is now a single,
MANUAL-aware verb instead of a separate load()/load_manually()
and unload()/unload_manually() pair (see changelog)
3/7: let a program mark itself MANUAL from its own section name via a
SEC("!...") prefix, instead of requiring an imperative
bpf_program__set_load_strategy() call, mirroring the existing
SEC("?...") convention
4/7: reject bpf_object__gen_loader() for an object with a MANUAL
program, which would otherwise silently corrupt every later
program's generated prog_fd slot
5/7: version bpf_program__set_autoattach()'s void->int return-type and
behavior change via ELF symbol versioning (COMPAT_VERSION()/
DEFAULT_VERSION()), modeled on the xsk_umem__create and
bpf_prog_load precedents, so binaries already linked against the
old void-returning ABI keep that behavior instead of silently
hitting the new MANUAL-rejection logic underneath them
6/7: selftest covering every load-strategy transition
(DISABLED/AUTO/MANUAL), bpf_program__set_autoload()'s bool
compatibility, and autoattach restoration -- now including a case
that discriminates the restore logic from a hard-coded `true`
7/7: selftest covering the manual load/attach/detach/reload cycle, the
declarative SEC("!...") marker, prepare()-only load sufficiency,
a module BTF deferred load, and gen_loader rejection -- updated
for the merged load()/unload() API and with all four scenarios
now individually subtested
Changes since v3 [2]:
- Log the raw error via errstr(err) instead of a bare %d in
bpf_program__load()'s failure message (sashiko-bot)
- Let MANUAL programs use the caller-supplied kernel log buffer
instead of always falling back to libbpf's own realloc'd buffer
(bot+bpf-ci)
- Reject BPF_PROG_LOAD_STRATEGY_MANUAL for struct_ops programs:
bpf_map_prepare_vdata() bakes every member's fd into kern_vdata
during bpf_object__load(), before a MANUAL member could ever be
loaded, and nothing re-bakes it afterwards (bot+bpf-ci)
- Fix bpf_link leaks on every assertion-failure path in load_type.c
and dynamicload.c (sashiko-bot, bot+bpf-ci)
- Wrap all 4 dynamicload.c scenarios in test__start_subtest(), so
bpf_testmod's absence only skips the one scenario that needs it
instead of masking the other three as SKIP (bot+bpf-ci)
- Drop the dead !obj->fd_array_cnt disjunct in
bpf_object_post_load_cleanup()'s fd_array free guard (Andrii)
- Rename bpf_program__load_manually() to bpf_program__load(), and
fold bpf_program__unload_manually() into bpf_program__unload():
split the existing full-free body into an internal
bpf_program_unload_full() helper used unconditionally by
object-teardown paths and make the public unload() skip the helper for
manual programs (Andrii)
- New: version bpf_program__set_autoattach()'s void->int ABI change
via COMPAT_VERSION()/DEFAULT_VERSION() instead of leaving the
symbol under its original LIBBPF_1.0.0 node -- an already-linked
binary now keeps the old unconditional-set behavior at runtime
instead of silently gaining the new MANUAL-rejection behavior
underneath it after a libbpf upgrade (bot+bpf-ci)
- Misc. cosmetic fixes pointed out by the bots (Sashiko + bpf-ci)
[1] https://lore.kernel.org/bpf/20250122215206.59859-1-slava.imameev@crowdstrike.com/
[2] https://lore.kernel.org/bpf/20260917203040.3150212-1-andrey.grodzovsky@crowdstrike.com/
Andrey Grodzovsky (4):
libbpf: Support declarative manual load via SEC("!...") prefix
libbpf: Reject gen_loader for objects with already-manual programs
libbpf: Version bpf_program__set_autoattach() ABI change
selftests/bpf: Cover BPF program manual loading
Slava Imameev (3):
libbpf: BPF program load strategy enum
libbpf: BPF programs manual loading and attaching
selftests/bpf: Cover BPF program load strategy transitions
tools/lib/bpf/libbpf.c | 278 ++++++++++---
tools/lib/bpf/libbpf.h | 69 +++-
tools/lib/bpf/libbpf.map | 5 +
tools/lib/bpf/libbpf_common.h | 6 +
.../selftests/bpf/prog_tests/dynamicload.c | 365 ++++++++++++++++++
.../selftests/bpf/prog_tests/load_type.c | 186 +++++++++
.../selftests/bpf/prog_tests/signed_loader.c | 28 ++
.../selftests/bpf/progs/test_dynamicload.c | 54 +++
.../selftests/bpf/progs/test_load_type.c | 31 ++
9 files changed, 976 insertions(+), 46 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/dynamicload.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/load_type.c
create mode 100644 tools/testing/selftests/bpf/progs/test_dynamicload.c
create mode 100644 tools/testing/selftests/bpf/progs/test_load_type.c
--
2.34.1
next reply other threads:[~2026-09-21 22:39 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 22:39 Andrey Grodzovsky [this message]
2026-09-21 22:39 ` [PATCH bpf-next v4 1/7] libbpf: BPF program load strategy enum Andrey Grodzovsky
2026-09-21 23:21 ` bot+bpf-ci
2026-09-21 22:39 ` [PATCH bpf-next v4 2/7] libbpf: BPF programs manual loading and attaching Andrey Grodzovsky
2026-09-21 23:03 ` sashiko-bot
2026-09-22 23:51 ` Andrey Grodzovsky
2026-09-21 22:39 ` [PATCH bpf-next v4 3/7] libbpf: Support declarative manual load via SEC("!...") prefix Andrey Grodzovsky
2026-09-21 23:12 ` sashiko-bot
2026-09-21 23:21 ` bot+bpf-ci
2026-09-21 22:39 ` [PATCH bpf-next v4 4/7] libbpf: Reject gen_loader for objects with already-manual programs Andrey Grodzovsky
2026-09-21 22:39 ` [PATCH bpf-next v4 5/7] libbpf: Version bpf_program__set_autoattach() ABI change Andrey Grodzovsky
2026-09-21 23:31 ` sashiko-bot
2026-09-21 22:39 ` [PATCH bpf-next v4 6/7] selftests/bpf: Cover BPF program load strategy transitions Andrey Grodzovsky
2026-09-21 23:37 ` sashiko-bot
2026-09-21 22:39 ` [PATCH bpf-next v4 7/7] selftests/bpf: Cover BPF program manual loading Andrey Grodzovsky
2026-09-22 1:37 ` [PATCH bpf-next v4 0/7] libbpf: " Alexei Starovoitov
2026-09-22 14:34 ` Andrey Grodzovsky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260921223937.3203093-1-andrey.grodzovsky@crowdstrike.com \
--to=andrey.grodzovsky@crowdstrike.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=linux-open-source@crowdstrike.com \
--cc=martin.kelly@crowdstrike.com \
--cc=slava.imameev@crowdstrike.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox