22
33PythonBPF provides helper functions and utilities for BPF programs and userspace code.
44
5+ ``` {note}
6+ **Work in Progress:** PythonBPF is under active development. We are constantly adding support for more helpers, kfuncs, and map types. Check back for updates!
7+ ```
8+ For comprehensive documentation on BPF helpers, see the [ eBPF Helper Functions documentation on ebpf.io] ( https://ebpf.io/what-is-ebpf/#helper-calls ) .
9+
510## BPF Helper Functions
611
712BPF helper functions are kernel-provided functions that BPF programs can call to interact with the system. PythonBPF exposes these through the ` pythonbpf.helper ` module.
@@ -16,6 +21,8 @@ from pythonbpf.helper import pid, ktime, comm
1621
1722Get the current process ID.
1823
24+ > ** Linux Kernel Helper:** ` bpf_get_current_pid_tgid() `
25+
1926``` python
2027from pythonbpf.helper import pid
2128
@@ -24,39 +31,28 @@ from pythonbpf.helper import pid
2431def trace_open (ctx : c_void_p) -> c_int64:
2532 process_id = pid()
2633 print (f " Process { process_id} opened a file " )
27- return c_int64( 0 )
34+ return 0
2835```
2936
3037** Returns:** ` c_int32 ` - The process ID of the current task
3138
3239#### comm()
3340
34- Get the current process command name (up to 16 characters) .
41+ Get the current process command name.
3542
36- ``` python
37- from pythonbpf.helper import comm
38-
39- @bpf
40- @section (" tracepoint/syscalls/sys_enter_execve" )
41- def trace_exec (ctx : c_void_p) -> c_int64:
42- # comm requires a buffer to fill
43- process_name = str (16 )
44- comm(process_name)
45- print (f " Executing: { process_name} " )
46- return c_int64(0 )
47- ```
43+ > ** Linux Kernel Helper:** ` bpf_get_current_comm() `
4844
4945** Parameters:**
5046* ` buf ` - Buffer to fill with the process command name
5147
5248** Returns:** ` c_int64 ` - 0 on success, negative on error
5349
54- ** Note:** The buffer should be at least 16 bytes (TASK_COMM_LEN) to hold the full command name.
55-
5650#### uid()
5751
5852Get the current user ID.
5953
54+ > ** Linux Kernel Helper:** ` bpf_get_current_uid_gid() `
55+
6056``` python
6157from pythonbpf.helper import uid
6258
@@ -66,7 +62,7 @@ def trace_open(ctx: c_void_p) -> c_int64:
6662 user_id = uid()
6763 if user_id == 0 :
6864 print (" Root user opened a file" )
69- return c_int64( 0 )
65+ return 0
7066```
7167
7268** Returns:** ` c_int32 ` - The user ID of the current task
@@ -77,6 +73,8 @@ def trace_open(ctx: c_void_p) -> c_int64:
7773
7874Get the current kernel time in nanoseconds since system boot.
7975
76+ > ** Linux Kernel Helper:** ` bpf_ktime_get_ns() `
77+
8078``` python
8179from pythonbpf.helper import ktime
8280
@@ -85,7 +83,7 @@ from pythonbpf.helper import ktime
8583def measure_latency (ctx : c_void_p) -> c_int64:
8684 start_time = ktime()
8785 # Store for later comparison
88- return c_int64( 0 )
86+ return 0
8987```
9088
9189** Returns:** ` c_int64 ` - Current time in nanoseconds
@@ -102,6 +100,8 @@ def measure_latency(ctx: c_void_p) -> c_int64:
102100
103101Get the ID of the CPU on which the BPF program is running.
104102
103+ > ** Linux Kernel Helper:** ` bpf_get_smp_processor_id() `
104+
105105``` python
106106from pythonbpf.helper import smp_processor_id
107107
@@ -110,7 +110,7 @@ from pythonbpf.helper import smp_processor_id
110110def track_cpu (ctx : c_void_p) -> c_int64:
111111 cpu = smp_processor_id()
112112 print (f " Running on CPU { cpu} " )
113- return c_int64( 0 )
113+ return 0
114114```
115115
116116** Returns:** ` c_int32 ` - The current CPU ID
@@ -126,19 +126,21 @@ def track_cpu(ctx: c_void_p) -> c_int64:
126126
127127Safely read data from kernel memory.
128128
129+ > ** Linux Kernel Helper:** ` bpf_probe_read() `
130+
129131``` python
130132from pythonbpf.helper import probe_read
131133
132134@bpf
133135def read_kernel_data (ctx : c_void_p) -> c_int64:
134- dst = c_uint64( 0 )
136+ dst = 0
135137 size = 8
136- src = c_void_p( ... ) # kernel address
137-
138+ src = ctx # kernel address
139+
138140 result = probe_read(dst, size, src)
139141 if result == 0 :
140142 print (f " Read value: { dst} " )
141- return c_int64( 0 )
143+ return 0
142144```
143145
144146** Parameters:**
@@ -154,52 +156,22 @@ def read_kernel_data(ctx: c_void_p) -> c_int64:
154156
155157Safely read a null-terminated string from kernel memory.
156158
157- ``` python
158- from pythonbpf.helper import probe_read_str
159-
160- @bpf
161- def read_filename (ctx : c_void_p) -> c_int64:
162- filename = str (256 )
163- src = c_void_p(... ) # pointer to filename in kernel
164-
165- result = probe_read_str(filename, src)
166- if result > 0 :
167- print (f " Filename: { filename} " )
168- return c_int64(0 )
169- ```
159+ > ** Linux Kernel Helper:** ` bpf_probe_read_str() `
170160
171161** Parameters:**
172162* ` dst ` - Destination buffer (string)
173163* ` src ` - Source kernel address
174164
175165** Returns:** ` c_int64 ` - Length of string on success, negative on error
176166
177- #### deref()
178-
179- Dereference a pointer safely.
180-
181- ``` python
182- from pythonbpf.helper import deref
183-
184- @bpf
185- def access_pointer (ctx : c_void_p) -> c_int64:
186- ptr = c_void_p(... )
187- value = deref(ptr)
188- print (f " Value at pointer: { value} " )
189- return c_int64(0 )
190- ```
191-
192- ** Parameters:**
193- * ` ptr ` - Pointer to dereference
194-
195- ** Returns:** The dereferenced value or 0 if null
196-
197167### Random Numbers
198168
199169#### random()
200170
201171Generate a pseudo-random 32-bit number.
202172
173+ > ** Linux Kernel Helper:** ` bpf_get_prandom_u32() `
174+
203175``` python
204176from pythonbpf.helper import random
205177
@@ -209,23 +181,19 @@ def sample_events(ctx: c_void_p) -> c_int64:
209181 # Sample 1% of events
210182 if (random() % 100 ) == 0 :
211183 print (" Sampled event" )
212- return c_int64( 0 )
184+ return 0
213185```
214186
215187** Returns:** ` c_int32 ` - A pseudo-random number
216188
217- ** Use cases:**
218- * Event sampling
219- * Load shedding
220- * A/B testing
221- * Randomized algorithms
222-
223189### Network Helpers
224190
225191#### skb_store_bytes()
226192
227193Store bytes into a socket buffer (for network programs).
228194
195+ > ** Linux Kernel Helper:** ` bpf_skb_store_bytes() `
196+
229197``` python
230198from pythonbpf.helper import skb_store_bytes
231199
@@ -235,9 +203,9 @@ def modify_packet(ctx: c_void_p) -> c_int32:
235203 offset = 14 # Skip Ethernet header
236204 data = b " \x00\x01\x02\x03 "
237205 size = len (data)
238-
206+
239207 result = skb_store_bytes(offset, data, size)
240- return c_int32( 0 )
208+ return 0
241209```
242210
243211** Parameters:**
@@ -277,7 +245,7 @@ from ctypes import c_void_p, c_int64
277245@section (" tracepoint/syscalls/sys_enter_execve" )
278246def trace_exec (ctx : c_void_p) -> c_int64:
279247 print (" Process started" ) # This goes to trace_pipe
280- return c_int64( 0 )
248+ return 0
281249
282250@bpf
283251@bpfglobal
@@ -336,7 +304,7 @@ from ctypes import c_void_p, c_int64
336304@section (" tracepoint/syscalls/sys_enter_execve" )
337305def trace_exec (ctx : c_void_p) -> c_int64:
338306 print (f " PID: { pid()} " )
339- return c_int64( 0 )
307+ return 0
340308
341309@bpf
342310@bpfglobal
@@ -382,20 +350,20 @@ def read_start(ctx: c_void_p) -> c_int64:
382350 process_id = pid()
383351 start = ktime()
384352 start_times.update(process_id, start)
385- return c_int64( 0 )
353+ return 0
386354
387355@bpf
388356@section (" tracepoint/syscalls/sys_exit_read" )
389357def read_end (ctx : c_void_p) -> c_int64:
390358 process_id = pid()
391359 start = start_times.lookup(process_id)
392-
360+
393361 if start:
394362 latency = ktime() - start
395363 print (f " Read latency: { latency} ns " )
396364 start_times.delete(process_id)
397-
398- return c_int64( 0 )
365+
366+ return 0
399367
400368@bpf
401369@bpfglobal
@@ -419,9 +387,9 @@ from ctypes import c_void_p, c_int64
419387def track_exec (ctx : c_void_p) -> c_int64:
420388 process_id = pid()
421389 user_id = uid()
422-
390+
423391 print (f " User { user_id} started process (PID: { process_id} ) " )
424- return c_int64( 0 )
392+ return 0
425393
426394@bpf
427395@bpfglobal
@@ -451,13 +419,13 @@ def cpu_counts() -> HashMap:
451419def count_switches (ctx : c_void_p) -> c_int64:
452420 cpu = smp_processor_id()
453421 count = cpu_counts.lookup(cpu)
454-
422+
455423 if count:
456424 cpu_counts.update(cpu, count + 1 )
457425 else :
458- cpu_counts.update(cpu, c_uint64( 1 ) )
459-
460- return c_int64( 0 )
426+ cpu_counts.update(cpu, 1 )
427+
428+ return 0
461429
462430@bpf
463431@bpfglobal
@@ -491,8 +459,8 @@ def sample_opens(ctx: c_void_p) -> c_int64:
491459 if (random() % 100 ) < 5 :
492460 process_id = pid()
493461 print (f " Sampled: PID { process_id} opening file " )
494-
495- return c_int64( 0 )
462+
463+ return 0
496464
497465@bpf
498466@bpfglobal
@@ -504,56 +472,12 @@ b.load_and_attach()
504472trace_pipe()
505473```
506474
507- ## Best Practices
508-
509- 1 . ** Use appropriate helpers** - Choose the right helper for your use case
510- 2 . ** Handle errors** - Check return values from helpers like ` probe_read() `
511- 3 . ** Minimize overhead** - Helper calls have cost; use judiciously
512- 4 . ** Sample when appropriate** - Use ` random() ` for high-frequency events
513- 5 . ** Clean up resources** - Delete map entries when done
514-
515- ## Common Patterns
516-
517- ### Store-and-Compare Pattern
518-
519- ``` python
520- # Store a value
521- key = pid()
522- value = ktime()
523- my_map.update(key, value)
524-
525- # Later: compare
526- stored = my_map.lookup(key)
527- if stored:
528- difference = ktime() - stored
529- ```
530-
531- ### Filtering Pattern
532-
533- ``` python
534- # Filter by user
535- user_id = uid()
536- if user_id == 0 : # Only root
537- # Process event
538- pass
539- ```
540-
541- ### Sampling Pattern
542-
543- ``` python
544- # Sample 1 in N events
545- if (random() % N) == 0 :
546- # Process sampled event
547- pass
548- ```
549-
550475## Troubleshooting
551476
552477### Helper Not Available
553478
554479If a helper function doesn't work:
555480* Check your kernel version (some helpers are newer)
556- * Verify the helper is available with ` bpftool feature `
557481* Ensure your LICENSE is GPL-compatible
558482
559483### Trace Pipe Access Denied
@@ -563,13 +487,6 @@ If `trace_pipe()` fails:
563487* Check ` /sys/kernel/tracing/ ` is accessible
564488* Verify tracing is enabled in kernel config
565489
566- ### probe_read Failures
567-
568- If ` probe_read() ` returns errors:
569- * Ensure the source address is valid kernel memory
570- * Check that the size is reasonable
571- * Verify you're not reading from restricted areas
572-
573490## Next Steps
574491
575492* Explore {doc}` maps ` for data storage with helpers
0 commit comments