validator/c-libbpf/bin/bpfcompat-validator is executed inside each VM target and performs real kernel-facing validation steps for one artifact.
--artifact <path>(required)--out <result.json>(required)--manifest <path>(optional)--functional-plan <path>(optional, generated from manifestfunctional_tests)--log-dir <dir>(optional)--attach-mode <disabled|best-effort|required>(optional, defaultbest-effort)--probe-features <bool>(optional, defaulttrue)--set-map-max-entries <map>=<n|cpus>(repeatable, generated from manifestmaps)--set-map-inner-ringbuf <map>=<bytes>(repeatable, generated from manifestmaps)--prog-variants <group>=<prog>:<helper_id>,...(repeatable, generated from manifestprogram_variants)
Some artifacts compile maps with max_entries=0 and rely on their userspace
loader to size them before load — per-CPU arrays and ring buffers sized from
the CPU count are the common cases (Falco's modern_bpf probe does both).
Under a generic loader such objects fail with EINVAL on every kernel, which
is a loader-contract issue, not a kernel-compatibility signal.
Declaring the maps in the manifest makes the validator mirror the real
loader between bpf_object open and load:
maps:
- name: auxiliary_maps
max_entries: cpus # or a positive integer
- name: ringbuf_maps
max_entries: cpus
inner_ringbuf_bytes: 8388608max_entries: cpusresolves tolibbpf_num_possible_cpus()on the target kernel at load time.inner_ringbuf_bytescreates aBPF_MAP_TYPE_RINGBUFof that size and installs it as the inner-map prototype for an array-of-maps (bpf_map__set_inner_map_fd).
Fixups apply to the whole-object load and to isolated per-program load
probes. Per-fixup outcomes are emitted in the result JSON under
map_fixups and surfaced as target notes in the report.
Some artifacts ship multiple programs for the same event and let their
loader pick one by probing kernel helper support — Falco's loader selects
recvmmsg_x (requires bpf_loop, kernel >= 5.17) or falls back to
recvmmsg_old_x, disabling the loser before load. The losing variant is
expected to fail verification on kernels missing its helper, so loading
it is a loader-contract violation, not kernel-compatibility evidence.
Declare the groups in the manifest; the validator mirrors the selection between open and load:
program_variants:
- group: recvmmsg_x
programs:
- name: recvmmsg_x
requires_helper: bpf_loop # known helper name or numeric id
- name: recvmmsg_old_x # unconditional fallbackVariant order is selection priority. Helper support is probed with
libbpf_probe_bpf_helper (raw-tracepoint program type, matching Falco's
libpman). The chosen/disabled variants per group are emitted in the result
JSON under program_variants and surfaced as target notes — so the
matrix records not just pass/fail but which variant a kernel gets.
Isolated per-program load probes are unaffected: they still report each
variant's own load result on the kernel, which is exactly the per-variant
evidence the selection is based on. Objects that statically initialize
prog-array (tail-call) slots cannot be loaded one program at a time;
those per-program probes are reported as skipped rather than fail.
- Capture host metadata (
uname, timestamp). - Capture BTF metadata:
- kernel BTF presence/size
- artifact
.BTF/.BTF.extpresence
- Capability probing:
bpftool feature probecapture when available- custom map/program probe fallback
- attach prerequisite checks
- Open BPF object with libbpf.
- Discover maps/program sections and initialize per-program attach/load state.
- When feature probing is enabled, run isolated per-program load probes and capture bounded verifier logs.
- Attempt whole-object load (
bpf_object__load). - Attempt auto-attach for eligible sections based on attach mode.
- If a functional plan is supplied, keep successful BPF links alive and run project-specific functional commands.
- Emit JSON result and optional libbpf log file.
Primary output is a JSON document (currently schema_version: validator.v0.4) containing:
status(pass/fail)hostmetadatainputsettings (artifact path, attach mode, probe mode)btfdetailscapabilitiesdetails (bpftool + custom probes)discoverydetails (program/map counts and per-program attach status)- per-program isolated load status (
load_status,load_errno,load_log) when feature probing is enabled loadstatus (pass/fail, error code/message)attachaggregate status and countersfunctionalaggregate status and per-command result detailslogs.libbpfcaptured log stream
Functional tests are declared in the manifest and converted by the Go runner into a strict validator plan. They are executed inside the VM while successful libbpf links are still alive. This lets a project supply a command such as a smoke script or event-capture harness that proves more than "the object loaded."
Example:
functional_tests:
- name: execve-stimulus-smoke
command: "sh -c 'printf bpfcompat-functional-smoke'"
timeout: 5s
expect_exit_code: 0
expect_stdout_contains: bpfcompat-functional-smokeA required functional-test failure marks the target as FUNCTIONAL_TEST_FAILURE.
The examples/functional-execve fixture is the concrete event-capture example:
it attaches to sys_enter_execve, triggers /bin/true while the BPF link is
alive, and requires the expected marker to appear in trace_pipe.
disabled: no attach attempts.best-effort: attach failures do not fail overall status if load passed.required: attach failures fail overall validator status.
Host-side classification consumes:
- load status/error code/message
- attach status/mode
- BTF presence signals
- libbpf/verifier text
- per-program isolated load failures and verifier log tails
- functional test status/output when supplied
This supports deterministic classification into codes such as:
UNSUPPORTED_ATTACH_TYPE, UNSUPPORTED_MAP_TYPE, UNSUPPORTED_PROGRAM_TYPE,
MISSING_BTF, CORE_RELOCATION_FAILURE, POLICY_DENIED,
UNSUPPORTED_TRANSPORT, and others.