perf(driver/modern_bpf): skip dynamic snaplen when it cannot change the outcome - #3075
Draft
therealbobo wants to merge 2 commits into
Draft
Conversation
…he outcome `apply_dynamic_snaplen()` can only ever raise the snaplen: every assignment it performs is a `max()` against one of the `SNAPLEN_*` constants, so the value never goes down. (The constants are not necessarily above the configured snaplen - it is user-settable with no cap, while `SNAPLEN_DNS_UDP` is 512 - but the `max()` is what makes the logic monotonic, not their magnitude.) Callers then clamp the result back down to the number of bytes they are actually going to capture. So whenever that number already fits within the configured snaplen, the final value is that number regardless of what the dynamic snaplen logic computes, and the whole computation is dead work: an `fd -> file -> socket` walk (several kernel reads) plus a `DPI_LOOKAHEAD_SIZE` read of the user buffer. For the sendmmsg/recvmmsg `bpf_loop()` callbacks this was repeated once per message in the batch. Introduce `apply_dynamic_snaplen_if_relevant()` (and the matching `_port_range_if_relevant()` for the `__noinline` variant used inside the `bpf_loop()` callbacks) which takes the number of bytes the caller will capture and skips the call when it cannot affect the result. Callers that cannot know that number upfront pass a negative value and always apply the logic: `writev`/`pwritev`/`sendmsg`/`sendmmsg` do not clamp when `ret <= 0` (resp. `msg_len == 0`), so a raised snaplen still matters there. `send`/`sendto` only needed `bytes_to_read` to be computed before the call instead of after it; the call has no side effects beyond writing `*snaplen`. Measured with `scap-open --modern_bpf --ppm_sc 3`, 5M 64-byte reads pinned to one CPU, reading `run_time_ns` off the `sys_exit` dispatcher (which includes the tail-called handler) via `kernel.bpf_stats_enabled`, min of 8 runs: dynamic snaplen enabled: 477.6 -> 349.7 ns/read (-26.8%) dynamic snaplen disabled: 357.3 -> 355.6 ns/read (unchanged, within noise) Event output was verified byte-identical against the unpatched probe across read, write, sendto, writev, sendmsg, sendmmsg, recvmmsg and recvmsg, covering payloads below and above the snaplen, regular-file and UDP-socket fds, failing syscalls, and a payload that trips the HTTP heuristic so the dynamic snaplen is genuinely raised. Static instruction counts are flat (-6 to +15 out of 950-2830), and the probe loads with no verifier issues. Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
The dynamic snaplen logic is now skipped whenever the data already fits within the configured snaplen. Add tests pinning both sides of that boundary, plus the paths that had no dynamic snaplen coverage at all. - `sendmmsg`/`recvmmsg` had no dynamic snaplen tests despite running the logic once per message inside a `bpf_loop()` callback. Two tests each: a message longer than the snaplen must be captured in full via the fullcapture port, and a message shorter than the snaplen must be captured exactly. - `writev` had no dynamic snaplen tests either. It only applies the port-range part of the logic, so it is covered with a fullcapture port. - `dynamic_snaplen_writev_fullcapture_port_failed_syscall` covers the case where the syscall failed: the snaplen is then never clamped down to `ret`, so the logic has to run unconditionally. Skipping it there would silently truncate the captured data to DEFAULT_SNAPLEN. - `dynamic_snaplen_HTTP_below_snaplen` pins that a payload shorter than the snaplen is captured exactly, whether or not the HTTP heuristic runs. Every new test was checked to fail against a deliberately broken guard: making the logic always skip breaks the three `not_truncated`/`fullcapture_port` tests (80 bytes captured instead of 100/121/160), and dropping the negative-sentinel check breaks the failed-syscall test. The existing suite did not catch that last mutation. Full drivers suite passes against the modern BPF probe (403 tests). Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
therealbobo
force-pushed
the
perf/modern-bpf-skip-noop-dynamic-snaplen
branch
from
August 4, 2026 14:00
f709ee3 to
c08cdd5
Compare
Contributor
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: therealbobo The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Perf diff from master - unit testsHeap diff from master - unit testsHeap diff from master - scap fileBenchmarks diff from master |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3075 +/- ##
=======================================
Coverage 76.56% 76.56%
=======================================
Files 301 301
Lines 33693 33693
Branches 5038 5038
=======================================
Hits 25797 25797
Misses 7896 7896
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What type of PR is this?
Any specific area of the project related to this PR?
/area driver-modern-bpf
Does this PR require a change in the driver versions?
What this PR does / why we need it:
perf(driver/modern_bpf): skip dynamic snaplen when it cannot change the outcome
apply_dynamic_snaplen()can only ever raise the snaplen: every assignment itperforms is a
max()against one of theSNAPLEN_*constants, so the valuenever goes down. (The constants are not necessarily above the configured
snaplen - it is user-settable with no cap, while
SNAPLEN_DNS_UDPis 512 - butthe
max()is what makes the logic monotonic, not their magnitude.) Callersthen clamp the result back down to the number of bytes they are actually going
to capture.
So whenever that number already fits within the configured snaplen, the final
value is that number regardless of what the dynamic snaplen logic computes, and
the whole computation is dead work: an
fd -> file -> socketwalk (severalkernel reads) plus a
DPI_LOOKAHEAD_SIZEread of the user buffer. For thesendmmsg/recvmmsg
bpf_loop()callbacks this was repeated once per message inthe batch.
Introduce
apply_dynamic_snaplen_if_relevant()(and the matching_port_range_if_relevant()for the__noinlinevariant used inside thebpf_loop()callbacks) which takes the number of bytes the caller will captureand skips the call when it cannot affect the result. Callers that cannot know
that number upfront pass a negative value and always apply the logic:
writev/pwritev/sendmsg/sendmmsgdo not clamp whenret <= 0(resp.
msg_len == 0), so a raised snaplen still matters there.send/sendtoonly neededbytes_to_readto be computed before the callinstead of after it; the call has no side effects beyond writing
*snaplen.Measured with
scap-open --modern_bpf --ppm_sc 3, 5M 64-byte reads pinned toone CPU, reading
run_time_nsoff thesys_exitdispatcher (which includes thetail-called handler) via
kernel.bpf_stats_enabled, min of 8 runs:dynamic snaplen enabled: 477.6 -> 349.7 ns/read (-26.8%)
dynamic snaplen disabled: 357.3 -> 355.6 ns/read (unchanged, within noise)
Event output was verified byte-identical against the unpatched probe across
read, write, sendto, writev, sendmsg, sendmmsg, recvmmsg and recvmsg, covering
payloads below and above the snaplen, regular-file and UDP-socket fds, failing
syscalls, and a payload that trips the HTTP heuristic so the dynamic snaplen is
genuinely raised.
Static instruction counts are flat (-6 to +15 out of 950-2830), and the probe
loads with no verifier issues.
Which issue(s) this PR fixes:
Fixes #
Special notes for your reviewer:
Does this PR introduce a user-facing change?: