mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2026-02-07 13:40:59 +00:00
docs: Fix user-guide/bpf-structs
This commit is contained in:
@ -119,18 +119,17 @@ def capture_event(ctx: c_void_p) -> c_int64:
|
||||
# Set fields
|
||||
event.timestamp = ktime()
|
||||
event.pid = pid()
|
||||
# Note: comm() requires a buffer parameter to fill
|
||||
# comm(event.comm) # Fills event.comm with process name
|
||||
comm(event.comm) # Fills event.comm with process name
|
||||
|
||||
# Use the struct
|
||||
print(f"Process with PID {event.pid}")
|
||||
|
||||
return c_int64(0)
|
||||
return 0
|
||||
```
|
||||
|
||||
### As Map Values
|
||||
### As Map Keys and Values
|
||||
|
||||
Use structs as values in maps for complex state storage:
|
||||
Use structs as keys and values in maps for complex state storage:
|
||||
|
||||
```python
|
||||
from pythonbpf import bpf, struct, map, section
|
||||
@ -168,12 +167,12 @@ def track_syscalls(ctx: c_void_p) -> c_int64:
|
||||
else:
|
||||
# Create new stats
|
||||
new_stats = ProcessStats()
|
||||
new_stats.syscall_count = c_uint64(1)
|
||||
new_stats.total_time = c_uint64(0)
|
||||
new_stats.max_latency = c_uint64(0)
|
||||
new_stats.syscall_count = 1
|
||||
new_stats.total_time = 0
|
||||
new_stats.max_latency = 0
|
||||
stats.update(process_id, new_stats)
|
||||
|
||||
return c_int64(0)
|
||||
return 0
|
||||
```
|
||||
|
||||
### With Perf Events
|
||||
@ -205,19 +204,16 @@ def trace_fork(ctx: c_void_p) -> c_int64:
|
||||
event = ProcessEvent()
|
||||
event.timestamp = ktime()
|
||||
event.pid = pid()
|
||||
# Note: comm() requires a buffer parameter
|
||||
# comm(event.comm) # Fills event.comm with process name
|
||||
comm(event.comm) # Fills event.comm with process name
|
||||
|
||||
# Send to userspace
|
||||
events.output(event)
|
||||
|
||||
return c_int64(0)
|
||||
return 0
|
||||
```
|
||||
|
||||
### With Ring Buffers
|
||||
|
||||
Ring buffers provide efficient event delivery:
|
||||
|
||||
```python
|
||||
from pythonbpf import bpf, struct, map, section
|
||||
from pythonbpf.maps import RingBuffer
|
||||
@ -240,11 +236,10 @@ def trace_open(ctx: c_void_p) -> c_int64:
|
||||
event = FileEvent()
|
||||
event.timestamp = ktime()
|
||||
event.pid = pid()
|
||||
# event.filename would be populated from ctx
|
||||
|
||||
events.output(event)
|
||||
|
||||
return c_int64(0)
|
||||
return 0
|
||||
```
|
||||
|
||||
## Field Access and Modification
|
||||
@ -267,31 +262,7 @@ Assign values to fields:
|
||||
event = Event()
|
||||
event.timestamp = ktime()
|
||||
event.pid = pid()
|
||||
# Note: comm() requires a buffer parameter
|
||||
# comm(event.comm) # Fills event.comm with process name
|
||||
```
|
||||
|
||||
### String Fields
|
||||
|
||||
String fields have special handling:
|
||||
|
||||
```python
|
||||
@bpf
|
||||
@struct
|
||||
class Message:
|
||||
text: str(64)
|
||||
|
||||
@bpf
|
||||
def example(ctx: c_void_p) -> c_int64:
|
||||
msg = Message()
|
||||
|
||||
# Assign string value
|
||||
msg.text = "Hello from BPF"
|
||||
|
||||
# Use helper to get process name (requires buffer)
|
||||
# comm(msg.text) # Fills msg.text with process name
|
||||
|
||||
return c_int64(0)
|
||||
comm(event.comm)
|
||||
```
|
||||
|
||||
## StructType Class
|
||||
@ -347,7 +318,6 @@ def capture_packets(ctx: c_void_p) -> c_int64:
|
||||
|
||||
packets.output(pkt)
|
||||
|
||||
# XDP_PASS
|
||||
return XDP_PASS
|
||||
```
|
||||
|
||||
@ -381,12 +351,10 @@ def track_fork(ctx: c_void_p) -> c_int64:
|
||||
info = ProcessLifecycle()
|
||||
info.pid = process_id
|
||||
info.start_time = ktime()
|
||||
# Note: comm() requires a buffer parameter
|
||||
# comm(info.comm) # Fills info.comm with process name
|
||||
|
||||
process_info.update(process_id, info)
|
||||
|
||||
return c_int64(0)
|
||||
return 0
|
||||
|
||||
@bpf
|
||||
@section("tracepoint/sched/sched_process_exit")
|
||||
@ -398,100 +366,7 @@ def track_exit(ctx: c_void_p) -> c_int64:
|
||||
info.exit_time = ktime()
|
||||
process_info.update(process_id, info)
|
||||
|
||||
return c_int64(0)
|
||||
```
|
||||
|
||||
### Aggregated Statistics
|
||||
|
||||
```python
|
||||
@bpf
|
||||
@struct
|
||||
class FileStats:
|
||||
read_count: c_uint64
|
||||
write_count: c_uint64
|
||||
total_bytes_read: c_uint64
|
||||
total_bytes_written: c_uint64
|
||||
last_access: c_uint64
|
||||
|
||||
@bpf
|
||||
@map
|
||||
def file_stats() -> HashMap:
|
||||
return HashMap(
|
||||
key=str(256), # Filename as key
|
||||
value=FileStats,
|
||||
max_entries=1024
|
||||
)
|
||||
```
|
||||
|
||||
## Memory Layout
|
||||
|
||||
Structs in BPF follow C struct layout rules:
|
||||
|
||||
* Fields are laid out in order
|
||||
* Padding may be added for alignment
|
||||
* Size is rounded up to alignment
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
@bpf
|
||||
@struct
|
||||
class Aligned:
|
||||
a: c_uint8 # 1 byte
|
||||
# 3 bytes padding
|
||||
b: c_uint32 # 4 bytes
|
||||
c: c_uint64 # 8 bytes
|
||||
# Total: 16 bytes
|
||||
```
|
||||
|
||||
```{tip}
|
||||
For optimal memory usage, order fields from largest to smallest to minimize padding.
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use descriptive field names** - Makes code self-documenting
|
||||
2. **Order fields by size** - Reduces padding and memory usage
|
||||
3. **Use appropriate sizes** - Don't use `c_uint64` when `c_uint32` suffices
|
||||
4. **Document complex structs** - Add comments explaining field purposes
|
||||
5. **Keep structs focused** - Each struct should represent one logical entity
|
||||
6. **Use fixed-size strings** - Always specify string lengths explicitly
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Timestamp + Data Pattern
|
||||
|
||||
```python
|
||||
@bpf
|
||||
@struct
|
||||
class TimestampedEvent:
|
||||
timestamp: c_uint64 # Always first for sorting
|
||||
# ... other fields
|
||||
```
|
||||
|
||||
### Identification Pattern
|
||||
|
||||
```python
|
||||
@bpf
|
||||
@struct
|
||||
class Identifiable:
|
||||
pid: c_uint32
|
||||
tid: c_uint32
|
||||
cpu: c_uint32
|
||||
# ... additional fields
|
||||
```
|
||||
|
||||
### Stats Aggregation Pattern
|
||||
|
||||
```python
|
||||
@bpf
|
||||
@struct
|
||||
class Statistics:
|
||||
count: c_uint64
|
||||
sum: c_uint64
|
||||
min: c_uint64
|
||||
max: c_uint64
|
||||
avg: c_uint64 # Computed in userspace
|
||||
return 0
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
@ -522,17 +397,8 @@ If you get type errors:
|
||||
After capturing struct data, read it in Python:
|
||||
|
||||
```python
|
||||
import ctypes
|
||||
from pylibbpf import BpfMap
|
||||
|
||||
# Define matching Python class
|
||||
class Event(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("timestamp", ctypes.c_uint64),
|
||||
("pid", ctypes.c_uint32),
|
||||
("comm", ctypes.c_char * 16),
|
||||
]
|
||||
|
||||
# Read from map
|
||||
map_obj = BpfMap(b, stats)
|
||||
for key, value_bytes in map_obj.items():
|
||||
|
||||
Reference in New Issue
Block a user