Skip to content

fix(modern_bpf): bpf_loop the sendmmsg/recvmmsg iovec data store - #3021

Open
deepskyblue86 wants to merge 1 commit into
masterfrom
fix/mmsg-iovec-bpf_loop
Open

fix(modern_bpf): bpf_loop the sendmmsg/recvmmsg iovec data store#3021
deepskyblue86 wants to merge 1 commit into
masterfrom
fix/mmsg-iovec-bpf_loop

Conversation

@deepskyblue86

Copy link
Copy Markdown
Member

What type of PR is this?
/kind bug

Any specific area of the project related to this PR?
/area drivers
/area driver-modern-bpf

Does this PR require a change in the driver versions?

What this PR does / why we need it:
Getting libbpf: prog 'sendmmsg_x': BPF program load failed: Argument list too long in Fedora 42, kernel 6.19.14-108.fc42, both aarch64 and x86_64.
This change converts auxmap__store_iovec_data_param_64 from having a regular for loop to using a bpf loop.

Which issue(s) this PR fixes:

Fixes #

Special notes for your reviewer:

Does this PR introduce a user-facing change?:

fix(modern_bpf): bpf_loop the sendmmsg/recvmmsg iovec data store

@poiana poiana added area/drivers Anything that cannot be associated to any other `area/driver-` label area/driver-modern-bpf labels Jun 10, 2026
On stricter verifiers sendmmsg_x/recvmmsg_x exceed the 1M processed-instruction
limit and fail to load with E2BIG. handle_exit() runs as a bpf_loop callback,
and the bounded for(j < MAX_IOVCNT) loop in the native iovec data store
(parameter 4) is re-explored on every SCC fixed-point pass of that callback,
multiplying the processed-instruction count.

Replace the inner for-loop with a bpf_loop() helper so the verifier checks the
per-iteration body once, collapsing that multiplication and keeping the program
within the limit. The loop callback re-fetches the per-cpu auxmap (a map-value
pointer cannot cross the bpf_loop context) and masks the index for bounds.

handle_exit() is shared with the legacy single-message programs
sendmmsg_old_x/recvmmsg_old_x, which are loaded only when the bpf_loop helper is
NOT available and therefore must not contain a bpf_loop call. The store is
chosen by a compile-time use_bpf_loop constant threaded from each program (true
for the bpf_loop programs, false for the legacy ones), NOT by a CO-RE feature
probe: some kernels expose BPF_FUNC_loop in their BTF enum without implementing
the helper, so bpf_core_enum_value_exists() would wrongly route the legacy
program through bpf_loop and it would fail to load with "invalid func
unknown#181".

The selector is a tiny __always_inline that, because use_bpf_loop is constant,
collapses to a single call to one of two __noinline stores: the bpf_loop store
for the _x programs and the for-loop store for the _old_x programs. The
__noinline boundary is required on its own -- inlining the bpf_loop store into
the callback re-introduces the SCC re-exploration and the E2BIG. The legacy
single-message path is not subject to the SCC blowup, so its for-loop store is
correct.

The ia32 (compat) mmsg path keeps the bounded for-loop. The 3-frame 512-byte
stack budget (program -> callback -> noinline callee) is preserved.

Signed-off-by: Angelo Puglisi <angelopuglisi86@gmail.com>
@poiana poiana added the size/L label Jun 10, 2026
@poiana
poiana requested review from hbrueckner and terror96 June 10, 2026 17:06
@poiana

poiana commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: deepskyblue86

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@github-actions

Copy link
Copy Markdown

Perf diff from master - unit tests

     9.89%     +1.05%  [.] std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_add_ref_lock_nothrow()
    22.18%     -0.82%  [.] std::__shared_ptr<sinsp_threadinfo, (__gnu_cxx::_Lock_policy)2>::__shared_ptr(std::__weak_ptr<sinsp_threadinfo, (__gnu_cxx::_Lock_policy)2> const&, std::nothrow_t)
    12.64%     -0.49%  [.] sinsp_thread_manager::create_thread_dependencies(std::shared_ptr<sinsp_threadinfo> const&)
     6.30%     -0.41%  [.] std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count(std::__weak_count<(__gnu_cxx::_Lock_policy)2> const&, std::nothrow_t)
     9.43%     -0.36%  [.] std::__shared_count<(__gnu_cxx::_Lock_policy)2>::_M_get_use_count() const
     3.76%     -0.20%  [.] sinsp_threadinfo::get_fd_table()
     9.82%     +0.19%  [.] std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release()
    15.32%     +0.13%  [.] sinsp_threadinfo::get_main_thread()
     4.60%     -0.12%  [.] thread_group_info::get_first_thread() const
     0.08%     +0.11%  [.] void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag)

Heap diff from master - unit tests

peak heap memory consumption: 0B
peak RSS (including heaptrack overhead): 0B
total memory leaked: 0B

Heap diff from master - scap file

peak heap memory consumption: 0B
peak RSS (including heaptrack overhead): 0B
total memory leaked: 0B

Benchmarks diff from master

Comparing gbench_data.json to /root/actions-runner/_work/libs/libs/build/gbench_data.json
Benchmark                                                                               Time             CPU      Time Old      Time New       CPU Old       CPU New
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
BM_sinsp_split_mean                                                                  +0.0148         +0.0149           286           291           286           291
BM_sinsp_split_median                                                                +0.0204         +0.0201           285           291           285           291
BM_sinsp_split_stddev                                                                +0.5158         +0.5228             4             6             4             5
BM_sinsp_split_cv                                                                    +0.4937         +0.5005             0             0             0             0
BM_sinsp_concatenate_paths_relative_path_mean                                        -0.0155         -0.0156            88            87            88            87
BM_sinsp_concatenate_paths_relative_path_median                                      -0.0130         -0.0133            88            87            88            87
BM_sinsp_concatenate_paths_relative_path_stddev                                      -0.2974         -0.3041             1             1             1             1
BM_sinsp_concatenate_paths_relative_path_cv                                          -0.2863         -0.2931             0             0             0             0
BM_sinsp_concatenate_paths_empty_path_mean                                           -0.0374         -0.0376            46            45            46            45
BM_sinsp_concatenate_paths_empty_path_median                                         -0.0375         -0.0377            46            45            46            45
BM_sinsp_concatenate_paths_empty_path_stddev                                         +0.2407         -0.0549             0             0             0             0
BM_sinsp_concatenate_paths_empty_path_cv                                             +0.2890         -0.0179             0             0             0             0
BM_sinsp_concatenate_paths_absolute_path_mean                                        -0.0289         -0.0289            88            85            87            85
BM_sinsp_concatenate_paths_absolute_path_median                                      -0.0319         -0.0320            87            84            87            84
BM_sinsp_concatenate_paths_absolute_path_stddev                                      -0.4214         -0.4221             4             2             4             2
BM_sinsp_concatenate_paths_absolute_path_cv                                          -0.4041         -0.4049             0             0             0             0
BM_sinsp_sanitize_string_fast_path_ascii_short_mean                                  -0.0022         -0.0022            19            19            19            19
BM_sinsp_sanitize_string_fast_path_ascii_short_median                                -0.0006         -0.0005            19            19            19            19
BM_sinsp_sanitize_string_fast_path_ascii_short_stddev                                +3.6189         +3.4824             0             0             0             0
BM_sinsp_sanitize_string_fast_path_ascii_short_cv                                    +3.6289         +3.4922             0             0             0             0
BM_sinsp_sanitize_string_fast_path_ascii_long_mean                                   -0.0004         -0.0003           165           165           165           165
BM_sinsp_sanitize_string_fast_path_ascii_long_median                                 -0.0002         -0.0003           165           165           165           165
BM_sinsp_sanitize_string_fast_path_ascii_long_stddev                                 +1.1992         +1.4866             0             0             0             0
BM_sinsp_sanitize_string_fast_path_ascii_long_cv                                     +1.2000         +1.4875             0             0             0             0
BM_sinsp_sanitize_string_fast_path_multibyte_short_mean                              +0.0026         +0.0025            14            14            14            14
BM_sinsp_sanitize_string_fast_path_multibyte_short_median                            +0.0005         +0.0004            14            14            14            14
BM_sinsp_sanitize_string_fast_path_multibyte_short_stddev                           +90.4501       +112.6439             0             0             0             0
BM_sinsp_sanitize_string_fast_path_multibyte_short_cv                               +90.2166       +112.3585             0             0             0             0
BM_sinsp_sanitize_string_fast_path_multibyte_long_mean                               +0.0873         +0.0873          4867          5292          4865          5290
BM_sinsp_sanitize_string_fast_path_multibyte_long_median                             +0.1238         +0.1237          4866          5469          4865          5467
BM_sinsp_sanitize_string_fast_path_multibyte_long_stddev                           +153.9667       +186.7896             2           281             1           281
BM_sinsp_sanitize_string_fast_path_multibyte_long_cv                               +141.5239       +171.7048             0             0             0             0
BM_sinsp_sanitize_string_fast_path_mixed_long_mean                                   +0.0039         +0.0039          2016          2023          2015          2023
BM_sinsp_sanitize_string_fast_path_mixed_long_median                                 +0.0019         +0.0020          2018          2022          2018          2022
BM_sinsp_sanitize_string_fast_path_mixed_long_stddev                                 +0.0942         +0.1042             6             7             6             7
BM_sinsp_sanitize_string_fast_path_mixed_long_cv                                     +0.0900         +0.1000             0             0             0             0
BM_sinsp_sanitize_string_slow_path_c1_controls_long_alloc_mean                       -0.0503         -0.0503          6144          5835          6142          5833
BM_sinsp_sanitize_string_slow_path_c1_controls_long_alloc_median                     -0.0498         -0.0497          6144          5838          6141          5836
BM_sinsp_sanitize_string_slow_path_c1_controls_long_alloc_stddev                    +92.1112        +94.6239             3           245             3           245
BM_sinsp_sanitize_string_slow_path_c1_controls_long_alloc_cv                        +97.0421        +99.6929             0             0             0             0
BM_sinsp_sanitize_string_slow_path_c1_controls_long_noalloc_mean                     -0.0002         -0.0004          6021          6019          6019          6016
BM_sinsp_sanitize_string_slow_path_c1_controls_long_noalloc_median                   -0.0002         -0.0004          6020          6018          6018          6015
BM_sinsp_sanitize_string_slow_path_c1_controls_long_noalloc_stddev                   +0.0037         -0.1894             2             2             2             2
BM_sinsp_sanitize_string_slow_path_c1_controls_long_noalloc_cv                       +0.0040         -0.1891             0             0             0             0
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_alloc_mean                    +0.0038         +0.0039           323           325           323           324
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_alloc_median                  +0.0063         +0.0062           322           324           322           324
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_alloc_stddev                  -0.4977         -0.4939             2             1             2             1
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_alloc_cv                      -0.4996         -0.4958             0             0             0             0
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_noalloc_mean                  -0.0051         -0.0051           219           218           219           218
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_noalloc_median                -0.0042         -0.0043           219           218           219           218
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_noalloc_stddev                -0.1238         -0.1315             1             1             1             1
BM_sinsp_sanitize_string_slow_path_sparse_invalid_long_noalloc_cv                    -0.1193         -0.1271             0             0             0             0
BM_sinsp_sanitize_string_slow_path_all_invalid_long_alloc_mean                       +0.0006         +0.0005         12468         12475         12464         12470
BM_sinsp_sanitize_string_slow_path_all_invalid_long_alloc_median                     +0.0004         +0.0002         12468         12473         12464         12466
BM_sinsp_sanitize_string_slow_path_all_invalid_long_alloc_stddev                     +0.2849         +0.2509             8            11             8            10
BM_sinsp_sanitize_string_slow_path_all_invalid_long_alloc_cv                         +0.2842         +0.2503             0             0             0             0
BM_sinsp_sanitize_string_slow_path_all_invalid_long_noalloc_mean                     -0.0019         -0.0018         12266         12243         12262         12239
BM_sinsp_sanitize_string_slow_path_all_invalid_long_noalloc_median                   -0.0018         -0.0017         12265         12242         12260         12239
BM_sinsp_sanitize_string_slow_path_all_invalid_long_noalloc_stddev                   -0.0075         -0.1135             6             6             7             6
BM_sinsp_sanitize_string_slow_path_all_invalid_long_noalloc_cv                       -0.0056         -0.1119             0             0             0             0

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.58%. Comparing base (01b5cf7) to head (e2f6faf).
⚠️ Report is 66 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #3021   +/-   ##
=======================================
  Coverage   75.58%   75.58%           
=======================================
  Files         299      299           
  Lines       33123    33123           
  Branches     5138     5140    +2     
=======================================
  Hits        25037    25037           
  Misses       8086     8086           
Flag Coverage Δ
libsinsp 75.58% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown

X64 kernel testing matrix

KERNEL CMAKE-CONFIGURE KMOD BUILD KMOD SCAP-OPEN MODERN-BPF SCAP-OPEN
amazonlinux2-5.10 🟢 🟢 🟢 🟢
amazonlinux2-5.15 🟢 🟢 🟢 🟢
amazonlinux2-5.4 🟢 🟢 🟢 🟡
amazonlinux2022-5.15 🟢 🟢 🟢 🟢
amazonlinux2023-6.1 🟢 🟢 🟢 🟢
archlinux-6.0 🟢 🟢 🟢 🟢
archlinux-6.7 🟢 🟢 🟢 🟢
centos-3.10 🟢 🟢 🟢 🟡
centos-4.18 🟢 🟢 🟢 🟢
centos-5.14 🟢 🟢 🟢 🟢
fedora-5.17 🟢 🟢 🟢 🟢
fedora-5.8 🟢 🟢 🟢 🟢
fedora-6.2 🟢 🟢 🟢 🟢
oraclelinux-3.10 🟢 🟢 🟢 🟡
oraclelinux-4.14 🟢 🟢 🟢 🟡
oraclelinux-5.15 🟢 🟢 🟢 🟢
oraclelinux-5.4 🟢 🟢 🟢 🟡
ubuntu-5.8 🟢 🟢 🟢 🟡
ubuntu-6.5 🟢 🟢 🟢 🟢

ARM64 kernel testing matrix

KERNEL CMAKE-CONFIGURE KMOD BUILD KMOD SCAP-OPEN MODERN-BPF SCAP-OPEN
amazonlinux2-5.4 🟢 🟢 🟢 🟡
amazonlinux2022-5.15 🟢 🟢 🟢 🟢
fedora-6.2 🟢 🟢 🟢 🟢
oraclelinux-4.14 🟢 🟢 🟢 🟡
oraclelinux-5.15 🟢 🟢 🟢 🟢
ubuntu-6.5 🟢 🟢 🟢 🟢

static long iovec_data_loop_callback(uint32_t index, void *ctx) {
iovec_data_loop_ctx_t *c = (iovec_data_loop_ctx_t *)ctx;

if(c->total_size_to_read > c->len_to_read) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just double checking: if c->total_size_to_read == c->len_to_read, do we still want to proceed? i.e. should we check for >= ?

.truncated = false,
};

bpf_loop(MAX_IOVCNT, iovec_data_loop_callback, &ctx, 0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle the return value?

uint16_t bytes_read = push__bytebuf(auxmap->data,
&auxmap->payload_pos,
(unsigned long)iovec[j].iov_base,
iovec[j].iov_len,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if we should already here limit the amount of reading not to exceed the remaining budget i.e. len_to_read - total_size_to_read ... the overshoot will be caught by the next iteration, though.

@leogr

leogr commented Jul 15, 2026

Copy link
Copy Markdown
Member

@deepskyblue86 any update on this?

@leogr leogr added this to the 0.26.0 milestone Jul 20, 2026
@leogr

leogr commented Aug 6, 2026

Copy link
Copy Markdown
Member

@deepskyblue86 any update on this?

@deepskyblue86 ping 👼

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

Labels

approved area/driver-modern-bpf area/drivers Anything that cannot be associated to any other `area/driver-` label dco-signoff: yes kind/bug Something isn't working release-note size/L

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

4 participants