From 2a93a325ce02c5e33405b6966ecaf3caeb600af5 Mon Sep 17 00:00:00 2001 From: varun-r-mallya Date: Thu, 2 Oct 2025 06:07:17 +0530 Subject: [PATCH] add ringbuf reserve function --- .pre-commit-config.yaml | 4 +- examples/hello_world.py | 4 -- pythonbpf/helper/bpf_helper_handler.py | 61 ++++++++++++++++++++++++++ tests/c-form/ringbuf.bpf.c | 32 +++++++------- tests/passing_tests/ringbuf.py | 14 ++---- 5 files changed, 82 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 89c6a80..bc11687 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,14 +41,14 @@ repos: - id: ruff args: ["--fix", "--show-fixes"] - id: ruff-format - exclude: ^(docs)|^(tests)|^(examples) + exclude: ^(tests/|examples/|docs/) # Checking static types - repo: https://github.com/pre-commit/mirrors-mypy rev: "v1.10.0" hooks: - id: mypy - exclude: ^(tests)|^(examples) + exclude: ^(tests/|examples/) additional_dependencies: [types-setuptools] # Changes tabs to spaces diff --git a/examples/hello_world.py b/examples/hello_world.py index 5ce35f9..9d29d59 100644 --- a/examples/hello_world.py +++ b/examples/hello_world.py @@ -22,9 +22,5 @@ def LICENSE() -> str: b = BPF() b.load_and_attach() -if b.is_loaded() and b.is_attached(): - print("Successfully loaded and attached") -else: - print("Could not load successfully") # Now cat /sys/kernel/debug/tracing/trace_pipe to see results of the execve syscall. diff --git a/pythonbpf/helper/bpf_helper_handler.py b/pythonbpf/helper/bpf_helper_handler.py index 87c0230..aa7bf80 100644 --- a/pythonbpf/helper/bpf_helper_handler.py +++ b/pythonbpf/helper/bpf_helper_handler.py @@ -19,6 +19,7 @@ class BPFHelperID(Enum): BPF_PRINTK = 6 BPF_GET_CURRENT_PID_TGID = 14 BPF_PERF_EVENT_OUTPUT = 25 + BPF_RINGBUF_RESERVE = 131 @HelperHandlerRegistry.register("ktime") @@ -181,6 +182,66 @@ def bpf_map_update_elem_emitter( return result, None +@HelperHandlerRegistry.register("reserve") +def bpf_ringbuf_reserve_emitter( + call, + map_ptr, + module, + builder, + func, + local_sym_tab=None, + struct_sym_tab=None, + local_var_metadata=None, +): + """ + Emit LLVM IR for bpf_ringbuf_reserve helper function call. + Expected call signature: ringbuf.reserve(size, flags=0) + """ + if not call.args or len(call.args) < 1 or len(call.args) > 2: + raise ValueError( + "Ringbuf reserve expects 1 or 2 args (size, flags), " + f"got {len(call.args)}" + ) + + # TODO: here, getting length of stuff does not actually work. need to fix this. + size_arg = call.args[0] + if isinstance(size_arg, ast.Constant): + size_val = ir.Constant(ir.IntType(64), size_arg.value) + elif isinstance(size_arg, ast.Name): + if size_arg.id not in local_sym_tab: + raise ValueError( + f"Variable '{size_arg.id}' not found in local symbol table" + ) + size_val = builder.load(local_sym_tab[size_arg.id]) + else: + raise NotImplementedError(f"Unsupported size argument type: {type(size_arg)}") + + flags_arg = call.args[1] if len(call.args) > 1 else None + flags_val = get_flags_val(flags_arg, builder, local_sym_tab) + + map_void_ptr = builder.bitcast(map_ptr, ir.PointerType()) + + # Args: (void* ringbuf, u64 size, u64 flags) + fn_type = ir.FunctionType( + ir.PointerType(), + [ir.PointerType(), ir.IntType(64), ir.IntType(64)], + var_arg=False, + ) + fn_ptr_type = ir.PointerType(fn_type) + + fn_addr = ir.Constant(ir.IntType(64), BPFHelperID.BPF_RINGBUF_RESERVE.value) + fn_ptr = builder.inttoptr(fn_addr, fn_ptr_type) + + if isinstance(flags_val, int): + flags_const = ir.Constant(ir.IntType(64), flags_val) + else: + flags_const = flags_val + + result = builder.call(fn_ptr, [map_void_ptr, size_val, flags_const], tail=True) + + return result, ir.PointerType() + + @HelperHandlerRegistry.register("delete") def bpf_map_delete_elem_emitter( call, diff --git a/tests/c-form/ringbuf.bpf.c b/tests/c-form/ringbuf.bpf.c index f0abb91..88319f3 100644 --- a/tests/c-form/ringbuf.bpf.c +++ b/tests/c-form/ringbuf.bpf.c @@ -28,22 +28,22 @@ int trace_execve(void *ctx) // Reserve space in the ringbuffer e = bpf_ringbuf_reserve(&events, sizeof(*e), 0); - if (!e) - return 0; - - // Fill the struct with data - pid_tgid = bpf_get_current_pid_tgid(); - e->pid = pid_tgid >> 32; - - uid_gid = bpf_get_current_uid_gid(); - e->uid = uid_gid & 0xFFFFFFFF; - - e->timestamp = bpf_ktime_get_ns(); - - bpf_get_current_comm(&e->comm, sizeof(e->comm)); - - // Submit the event to ringbuffer - bpf_ringbuf_submit(e, 0); +// if (!e) +// return 0; +// +// // Fill the struct with data +// pid_tgid = bpf_get_current_pid_tgid(); +// e->pid = pid_tgid >> 32; +// +// uid_gid = bpf_get_current_uid_gid(); +// e->uid = uid_gid & 0xFFFFFFFF; +// +// e->timestamp = bpf_ktime_get_ns(); +// +// bpf_get_current_comm(&e->comm, sizeof(e->comm)); +// +// // Submit the event to ringbuffer +// bpf_ringbuf_submit(e, 0); return 0; } diff --git a/tests/passing_tests/ringbuf.py b/tests/passing_tests/ringbuf.py index 0566d85..8d335fe 100644 --- a/tests/passing_tests/ringbuf.py +++ b/tests/passing_tests/ringbuf.py @@ -1,5 +1,5 @@ -from pythonbpf import bpf, BPF, map, bpfglobal, section, compile, compile_to_ir -from pythonbpf.maps import RingBuf, HashMap +from pythonbpf import bpf, map, bpfglobal, section, compile, compile_to_ir +from pythonbpf.maps import RingBuf from ctypes import c_int32, c_void_p @@ -9,17 +9,11 @@ from ctypes import c_int32, c_void_p def mymap() -> RingBuf: return RingBuf(max_entries=(1024)) - -@bpf -@map -def mymap2() -> HashMap: - return HashMap(key=c_int32, value=c_int32, max_entries=1024) - - @bpf @section("tracepoint/syscalls/sys_enter_clone") def random_section(ctx: c_void_p) -> c_int32: print("Hello") + e = mymap().reserve(16) return c_int32(0) @@ -31,5 +25,3 @@ def LICENSE() -> str: compile_to_ir("ringbuf.py", "ringbuf.ll") compile() -b = BPF() -b.load_and_attach()