This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-rover.git
The following commit(s) were added to refs/heads/main by this push:
new d509c7a Reduce eBPF verifier complexity by converting hot inline
helpers to BPF-to-BPF calls (#209)
d509c7a is described below
commit d509c7aa18f821f9fec0c987b558a56530175d6c
Author: mrproliu <[email protected]>
AuthorDate: Fri Jun 26 16:39:27 2026 +0800
Reduce eBPF verifier complexity by converting hot inline helpers to
BPF-to-BPF calls (#209)
---
CHANGES.md | 1 +
bpf/accesslog/common/connection.h | 2 +-
bpf/include/api.h | 10 ++++++++++
bpf/include/protocol_analyzer.h | 4 +++-
bpf/include/socket_data.h | 4 ++--
bpf/include/socket_reader.h | 3 ++-
6 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index ddcb4d5..164ca9c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -26,6 +26,7 @@ Release Notes.
* Bump up go version to `1.24` and eBPF library to `0.18.0`.
* Support detect ztunnel environment in the inbound request.
* Increase the transmit buffer size in the network profiling and access log
module.
+* Reduce eBPF verifier complexity by converting hot inline helpers to
BPF-to-BPF calls, fixing the "program too large" failure when loading access
log programs on newer kernels.
#### Bug Fixes
* Fix the base image cannot run in the arm64.
diff --git a/bpf/accesslog/common/connection.h
b/bpf/accesslog/common/connection.h
index 5978fed..afcf82a 100644
--- a/bpf/accesslog/common/connection.h
+++ b/bpf/accesslog/common/connection.h
@@ -285,7 +285,7 @@ static __always_inline void submit_new_connection(void*
ctx, bool success, __u32
bpf_map_update_elem(&active_connection_map, &conid, &con, 0);
}
-static __inline struct active_connection_t* get_or_create_active_conn(void
*ctx, __u32 tgid, __u32 fd, __u32 func_name, __u8 role) {
+static __noinline struct active_connection_t* get_or_create_active_conn(void
*ctx, __u32 tgid, __u32 fd, __u32 func_name, __u8 role) {
__u64 conid = gen_tgid_fd(tgid, fd);
struct active_connection_t *conn =
bpf_map_lookup_elem(&active_connection_map, &conid);
if (conn != NULL) {
diff --git a/bpf/include/api.h b/bpf/include/api.h
index 33de9f3..a6840e4 100644
--- a/bpf/include/api.h
+++ b/bpf/include/api.h
@@ -28,6 +28,16 @@
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
+// Force a function to be emitted as a real BPF-to-BPF call instead of being
+// inlined. The verifier checks a non-inlined sub-program only once, instead of
+// re-verifying every inlined copy on every code path, which dramatically
lowers
+// the processed-instruction count for large programs (avoids the
+// "BPF program is too large" / 1M instruction limit). BPF-to-BPF calls require
+// kernel >= 4.16, which the network / access-log data path already mandates.
+#ifndef __noinline
+#define __noinline __attribute__((noinline))
+#endif
+
// Define types commonly needed but not in BPF headers
typedef __s64 ssize_t;
typedef __s8 int8_t;
diff --git a/bpf/include/protocol_analyzer.h b/bpf/include/protocol_analyzer.h
index 7103e4f..8a64dda 100644
--- a/bpf/include/protocol_analyzer.h
+++ b/bpf/include/protocol_analyzer.h
@@ -17,6 +17,8 @@
#pragma once
+#include "api.h"
+
#define CONNECTION_PROTOCOL_UNKNOWN 0
#define CONNECTION_PROTOCOL_HTTP1 1
#define CONNECTION_PROTOCOL_HTTP2 2
@@ -178,7 +180,7 @@ static __inline __u32 infer_http2_message(const char* buf,
size_t count) {
return CONNECTION_MESSAGE_TYPE_UNKNOWN;
}
-static __inline __u32 analyze_protocol(char *buf, __u32 count, __u8
*protocol_ref) {
+static __noinline __u32 analyze_protocol(char *buf, __u32 count, __u8
*protocol_ref) {
__u32 protocol = CONNECTION_PROTOCOL_UNKNOWN, type =
CONNECTION_MESSAGE_TYPE_UNKNOWN;
// support http 1.x and 2.x
diff --git a/bpf/include/socket_data.h b/bpf/include/socket_data.h
index 67f4823..7e195fd 100644
--- a/bpf/include/socket_data.h
+++ b/bpf/include/socket_data.h
@@ -142,7 +142,7 @@ static __always_inline void
__upload_socket_data_with_buffer(void *ctx, __u8 ind
rover_submit_buf(ctx, &socket_data_upload_queue, socket_data_event,
sizeof(*socket_data_event));
}
-static __always_inline void upload_socket_data_buf(void *ctx, char* buf,
ssize_t size, struct upload_data_args *args, __u8 force_unfinished) {
+static __noinline void upload_socket_data_buf(void *ctx, char* buf, ssize_t
size, struct upload_data_args *args, __u8 force_unfinished) {
ssize_t already_send = 0;
#pragma unroll
for (__u8 index = 0; index < SOCKET_UPLOAD_CHUNK_LIMIT; index++) {
@@ -195,7 +195,7 @@ if (iov_index < iovlen) {
\
loop_count++;
\
}
-static __always_inline void upload_socket_data_iov(void *ctx, struct iovec*
iov, const size_t iovlen, ssize_t size, struct upload_data_args *args) {
+static __noinline void upload_socket_data_iov(void *ctx, struct iovec* iov,
const size_t iovlen, ssize_t size, struct upload_data_args *args) {
ssize_t already_send = 0;
ssize_t cur_iov_sended = 0;
__u8 iov_index = 0;
diff --git a/bpf/include/socket_reader.h b/bpf/include/socket_reader.h
index 28b177d..159d4de 100644
--- a/bpf/include/socket_reader.h
+++ b/bpf/include/socket_reader.h
@@ -17,6 +17,7 @@
#pragma once
+#include "api.h"
#include "socket_opts.h"
struct socket_buffer_reader_t {
@@ -30,7 +31,7 @@ struct {
__uint(max_entries, 1);
} socket_buffer_reader_map SEC(".maps");
-static __inline struct socket_buffer_reader_t* read_socket_data(char* buf,
struct iovec *iovec, __u32 bytes_count) {
+static __noinline struct socket_buffer_reader_t* read_socket_data(char* buf,
struct iovec *iovec, __u32 bytes_count) {
__u64 size = 0;
__u32 kZero = 0;
char* data_buf;