Skip to content

Commit c940f45

Browse files
committed
Add detach API for eBPF programs in userspace and enhance related code generation.
1 parent 6b5824f commit c940f45

28 files changed

+670
-17
lines changed

SPEC.md

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -812,12 +812,65 @@ fn main() -> i32 {
812812
- **Cgroup**: target = cgroup path ("/sys/fs/cgroup/test"), flags = unused (0)
813813
- Returns 0 on success, negative error code on failure
814814

815+
**`detach(handle: ProgramHandle) -> void`**
816+
- Detaches the program from its current attachment point using its handle
817+
- Automatically determines the correct detachment method based on program type:
818+
- **XDP**: Uses `bpf_xdp_detach()` with stored interface and flags
819+
- **TC**: Uses `bpf_tc_detach()` with stored interface and direction
820+
- **Kprobe/Tracepoint**: Destroys the stored `bpf_link` handle
821+
- No return value (void) - logs errors to stderr if detachment fails
822+
- Safe to call multiple times on the same handle (no-op if already detached)
823+
- Automatically cleans up internal attachment tracking
824+
815825
**Safety Benefits:**
816826
- **Compile-time enforcement**: Cannot call `attach()` without first calling `load()` - the type system prevents this
817827
- **Implementation abstraction**: Users work with `ProgramHandle` instead of raw file descriptors
818828
- **Resource safety**: Program handles abstract away the underlying resource management
829+
- **Automatic cleanup**: `detach()` handles all program types uniformly and cleans up tracking data
830+
- **Idempotent operations**: Safe to call `detach()` multiple times without side effects
831+
832+
#### 3.5.3 Lifecycle Best Practices
833+
834+
**Proper Cleanup Patterns:**
835+
```kernelscript
836+
fn main() -> i32 {
837+
var prog1 = load(filter)
838+
var prog2 = load(monitor)
839+
840+
// Attach programs
841+
var result1 = attach(prog1, "eth0", 0)
842+
var result2 = attach(prog2, "eth0", 1)
843+
844+
// Error handling with partial cleanup
845+
if (result1 != 0 || result2 != 0) {
846+
// Clean up any successful attachments before returning
847+
if (result1 == 0) detach(prog1)
848+
if (result2 == 0) detach(prog2)
849+
return 1
850+
}
851+
852+
// Normal operation...
853+
print("Programs running...")
854+
855+
// Proper shutdown: detach in reverse order
856+
detach(prog2) // Last attached, first detached
857+
detach(prog1)
858+
859+
return 0
860+
}
861+
```
862+
863+
**Multi-Program Detachment Order:**
864+
- Always detach programs in **reverse order** of attachment
865+
- This ensures dependencies are cleaned up properly
866+
- Example: if `filter` depends on `monitor`, detach `monitor` first
867+
868+
**Error Recovery:**
869+
- Use conditional detachment for partial failure scenarios
870+
- Safe to call `detach()` multiple times on the same handle
871+
- Always clean up successful attachments before returning error codes
819872

820-
#### 3.5.3 Advanced Usage Patterns
873+
#### 3.5.4 Advanced Usage Patterns
821874

822875
**Configuration Between Load and Attach:**
823876
```kernelscript
@@ -855,6 +908,13 @@ fn main(args: Args) -> i32 {
855908
856909
if (result == 0) {
857910
print("Filter attached successfully")
911+
912+
// Simulate running the program (in real usage, this might be an event loop)
913+
print("Filter is processing packets...")
914+
915+
// Proper cleanup when shutting down
916+
detach(prog_handle)
917+
print("Filter detached successfully")
858918
} else {
859919
print("Failed to attach filter")
860920
return 1
@@ -2749,6 +2809,14 @@ fn main() -> i32 {
27492809
attach(filter_handle, "eth0", 0)
27502810
attach(monitor_handle, "eth0", 1)
27512811
2812+
print("Multiple programs attached to eth0")
2813+
print("Running packet processing pipeline...")
2814+
2815+
// Proper cleanup - detach in reverse order (best practice)
2816+
detach(monitor_handle)
2817+
detach(filter_handle)
2818+
print("All programs detached successfully")
2819+
27522820
return 0
27532821
}
27542822
```
@@ -3196,7 +3264,7 @@ fn main() -> i32 {
31963264
fn main() -> i32 {
31973265
try {
31983266
var prog = load(packet_filter)
3199-
attach(prog, "eth0", 0)
3267+
attach(prog, "eth0", 0)
32003268
print("Program attached successfully")
32013269
return 0
32023270
@@ -4085,6 +4153,13 @@ fn main(args: Args) -> i32 {
40854153
40864154
if (filter_result != 0 || monitor_result != 0) {
40874155
print("Failed to attach programs to interface: ", args.interface)
4156+
// Clean up any successful attachments
4157+
if (filter_result == 0) {
4158+
detach(filter_handle)
4159+
}
4160+
if (monitor_result == 0) {
4161+
detach(monitor_handle)
4162+
}
40884163
return 1
40894164
}
40904165
@@ -4099,13 +4174,21 @@ fn main(args: Args) -> i32 {
40994174
}
41004175
41014176
// Monitor system health using config stats
4102-
while (true) {
4177+
var iteration_count = 0
4178+
while (iteration_count < 100) { // Run for limited time in example
41034179
if (system.packets_dropped > 1000 && !args.quiet_mode) {
41044180
print("High drop rate detected: ", system.packets_dropped)
41054181
}
41064182
sleep(10000)
4183+
iteration_count += 1
41074184
}
41084185
4186+
// Proper cleanup when shutting down
4187+
print("Shutting down, detaching programs...")
4188+
detach(monitor_handle) // Detach in reverse order
4189+
detach(filter_handle)
4190+
print("All programs detached successfully")
4191+
41094192
return 0
41104193
}
41114194
```

examples/basic_match.ks

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ fn packet_classifier(ctx: *xdp_md) -> xdp_action {
9595
fn main() -> i32 {
9696
var prog = load(packet_classifier)
9797
attach(prog, "lo", 0)
98+
99+
print("Packet classifier attached to loopback interface")
100+
print("Processing packets with pattern matching...")
101+
102+
// In a real application, the program would run here
103+
// For demonstration, we detach after showing the lifecycle
104+
detach(prog)
105+
print("Packet classifier detached")
106+
107+
return 0
98108
}
99109

100110

examples/break_continue_unbound.ks

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,12 @@ fn main() -> i32 {
6767
var prog = load(packet_filter)
6868
attach(prog, "lo", 0)
6969

70+
print("Break/continue demo program attached to loopback")
71+
print("Demonstrating break and continue functionality...")
72+
73+
// Show break/continue working
74+
detach(prog)
75+
print("Break/continue demo program detached")
76+
7077
return 0
7178
}

examples/import_demo.ks

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,13 @@ fn main() -> i32 {
3434

3535
var prog = load(intelligent_filter)
3636
attach(prog, "eth0", 0)
37+
38+
print("Packet processor with imported utilities attached to eth0")
39+
print("Processing packets with external functions...")
40+
41+
// Demonstrate the import functionality
42+
detach(prog)
43+
print("Packet processor detached")
44+
3745
return 0
3846
}

examples/local_global_vars.ks

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,13 @@ fn main() -> i32 {
5454
packet_count = 666
5555
print("After assignment packet_count = %u", packet_count)
5656
attach(prog, "lo", 0)
57+
58+
print("Local/global vars demo program attached to loopback")
59+
print("Demonstrating local and global variable scoping...")
60+
61+
// Show variable scoping working
62+
detach(prog)
63+
print("Local/global vars demo program detached")
64+
65+
return 0
5766
}

examples/map_operations_demo.ks

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,5 +239,16 @@ fn main() -> i32 {
239239
attach(prog3, "sys_enter_open", 0)
240240
attach(prog4, "vfs_read", 0)
241241

242+
print("Map operations demo: All programs attached")
243+
print("Traffic monitor & stats on eth0, event logger on sys_enter_open, data processor on vfs_read")
244+
print("Demonstrating coordinated map operations...")
245+
246+
// Detach in reverse order
247+
detach(prog4)
248+
detach(prog3)
249+
detach(prog2)
250+
detach(prog1)
251+
print("All map operation demo programs detached")
252+
242253
return 0
243254
}

examples/maps_demo.ks

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,14 @@ fn main() -> i32 {
148148
var prog2 = load(packet_analyzer)
149149
attach(prog1, "lo", 0)
150150
attach(prog2, "lo", 0)
151+
152+
print("Maps demo: Traffic shaper and packet analyzer attached to loopback")
153+
print("Demonstrating shared map operations between programs...")
154+
155+
// Detach in reverse order
156+
detach(prog2)
157+
detach(prog1)
158+
print("Maps demo programs detached")
159+
151160
return 0
152161
}

examples/multi_programs.ks

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,13 @@ fn main() -> i32 {
6363
attach(prog1, "eth0", 0)
6464
attach(prog2, "eth0", 0)
6565

66+
print("Multiple XDP programs attached to eth0")
67+
print("Counter and filter working together...")
68+
69+
// Detach in reverse order (good practice)
70+
detach(prog2)
71+
detach(prog1)
72+
print("All programs detached")
73+
6674
return 0
6775
}

examples/object_allocation.ks

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,12 @@ fn main() -> i32 {
8585
var prog = load(packet_inspector)
8686
attach(prog, "eth0", 0)
8787

88+
print("Object allocation demo program attached to eth0")
89+
print("Demonstrating dynamic memory management...")
90+
91+
// Show object allocation working
92+
detach(prog)
93+
print("Object allocation demo program detached")
94+
8895
return 0
8996
}

examples/packet_filter.ks

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,14 @@ enum xdp_action {
2828
fn main() -> i32 {
2929
var prog = load(packet_filter)
3030
attach(prog, "eth0", 0)
31+
32+
print("Packet filter attached to eth0")
33+
print("Filtering incoming packets...")
34+
35+
// In a real application, this would run indefinitely
36+
// For demonstration, we detach after setup
37+
detach(prog)
38+
print("Packet filter detached")
39+
3140
return 0
3241
}

0 commit comments

Comments
 (0)