@@ -68,7 +68,7 @@ fn monitor(ctx: *xdp_md) -> xdp_action {
6868 return XDP_PASS
6969}
7070
71- @tc
71+ @tc("ingress")
7272fn analyzer(ctx: *__sk_buff) -> int {
7373 update_counters(1) // Same kernel-shared function
7474 return 0 // TC_ACT_OK
@@ -217,9 +217,49 @@ fn arbitrary_address() -> i32 {
217217** Key Benefits:**
218218- ** Intelligent Probe Selection** : Automatically chooses fprobe for function entrance (better performance) or kprobe for arbitrary addresses
219219- ** Type Safety** : Function entrance probes have correct types extracted from kernel BTF information
220- - ** No Magic Numbers** : Direct parameter access for function entrance probes
221- - ** Self-Documenting** : Function signature matches the actual kernel function for entrance probes
222- - ** Compile-Time Validation** : Invalid parameter access caught at compile time
220+
221+ #### 3.1.2 Traffic Control (TC) Programs with Direction Support
222+
223+ TC programs must specify traffic direction for proper kernel attachment point selection.
224+
225+ ``` kernelscript
226+ // Ingress traffic control (packets entering the interface)
227+ @tc("ingress")
228+ fn ingress_filter(ctx: *__sk_buff) -> int {
229+ var packet_size = ctx->len
230+
231+ // Drop oversized packets at ingress
232+ if (packet_size > 1500) {
233+ return TC_ACT_SHOT // Drop packet
234+ }
235+
236+ return TC_ACT_OK // Allow packet
237+ }
238+
239+ // Egress traffic control (packets leaving the interface)
240+ @tc("egress")
241+ fn egress_shaper(ctx: *__sk_buff) -> int {
242+ var protocol = ctx->protocol
243+
244+ // Shape traffic based on protocol at egress
245+ if (protocol == ETH_P_IP) {
246+ // Apply rate limiting logic
247+ return TC_ACT_PIPE // Continue processing
248+ }
249+
250+ return TC_ACT_OK // Allow packet
251+ }
252+ ```
253+
254+ ** TC Direction Specification:**
255+ - ** @tc ("ingress")** : Attaches to ingress hook (packets entering interface)
256+ - ** @tc ("egress")** : Attaches to egress hook (packets leaving interface)
257+ - Direction parameter is ** required** - no default direction is assumed
258+
259+ ** Key Benefits:**
260+ - ** Explicit Direction Control** : Clear specification of traffic direction for precise attachment
261+ - ** Type Safety** : All TC programs use standard __ sk_buff context with compile-time validation
262+ - ** Kernel Integration** : Direct mapping to kernel TC ingress/egress hooks
223263
224264** Probe Type Selection:**
225265- ` @probe("function_name") ` → Uses ** fprobe** for function entrance with direct parameter access
@@ -726,7 +766,7 @@ fn packet_analyzer(ctx: *xdp_md) -> xdp_action {
726766 return XDP_PASS
727767}
728768
729- @tc
769+ @tc("ingress")
730770fn flow_tracker(ctx: *__sk_buff) -> int {
731771 // Track flow information using shared config
732772 if (monitoring.enable_stats && (ctx.hash() % monitoring.sample_rate == 0)) {
@@ -795,7 +835,7 @@ fn packet_filter(ctx: *xdp_md) -> xdp_action {
795835 return XDP_PASS
796836}
797837
798- @tc
838+ @tc("ingress")
799839fn flow_monitor(ctx: *__sk_buff) -> int {
800840 return 0 // TC_ACT_OK
801841}
@@ -827,7 +867,7 @@ fn main() -> i32 {
827867- First parameter must be a ProgramHandle returned from load()
828868- Target and flags interpretation depends on program type:
829869 - ** XDP** : target = interface name ("eth0"), flags = XDP attachment flags
830- - ** TC** : target = interface name ("eth0"), flags = direction ( ingress/ egress)
870+ - ** TC** : target = interface name ("eth0"), direction determined from @ tc (" ingress"/" egress") attribute
831871 - ** Kprobe** : target = function name ("sys_read"), flags = unused (0)
832872 - ** Cgroup** : target = cgroup path ("/sys/fs/cgroup/test"), flags = unused (0)
833873- Returns 0 on success, negative error code on failure
@@ -949,7 +989,7 @@ fn main(args: Args) -> i32 {
949989@xdp
950990fn ingress_monitor(ctx: *xdp_md) -> xdp_action { return XDP_PASS }
951991
952- @tc
992+ @tc("egress")
953993fn egress_monitor(ctx: *__sk_buff) -> int { return 0 } // TC_ACT_OK
954994
955995// Struct_ops example using impl block approach
@@ -1245,7 +1285,7 @@ fn packet_filter(ctx: *xdp_md) -> xdp_action {
12451285 return XDP_PASS
12461286}
12471287
1248- @tc
1288+ @tc("ingress")
12491289fn traffic_shaper(ctx: *__sk_buff) -> int {
12501290 var packet = ctx.packet()
12511291
@@ -1301,7 +1341,7 @@ fn ddos_protection(ctx: *xdp_md) -> xdp_action {
13011341 return XDP_PASS
13021342}
13031343
1304- @tc
1344+ @tc("ingress")
13051345fn connection_tracker(ctx: *__sk_buff) -> int {
13061346 var tcp_info = extract_tcp_info(ctx) // Reuse same helper
13071347 if (tcp_info != null) {
@@ -1435,7 +1475,7 @@ fn high_level_filter(packet: *u8, len: u32) -> i32 {
14351475}
14361476
14371477// eBPF usage
1438- @tc
1478+ @tc("ingress")
14391479fn traffic_analyzer(ctx: *__sk_buff) -> int {
14401480 var packet = ctx.packet()
14411481
@@ -2342,7 +2382,7 @@ fn ingress_monitor(ctx: *xdp_md) -> xdp_action {
23422382}
23432383
23442384// Program 2: Automatically has access to the same global maps
2345- @tc
2385+ @tc("egress")
23462386fn egress_monitor(ctx: *__sk_buff) -> int {
23472387 var flow_key = extract_flow_key(ctx)?
23482388
@@ -2802,7 +2842,7 @@ fn packet_filter(ctx: *xdp_md) -> xdp_action {
28022842 return XDP_PASS
28032843}
28042844
2805- @tc
2845+ @tc("ingress")
28062846fn flow_monitor(ctx: *__sk_buff) -> int {
28072847 // Can call the same kernel-shared functions
28082848 if (!validate_packet(ctx.packet())) {
@@ -2907,7 +2947,7 @@ fn main_filter(ctx: *xdp_md) -> xdp_action {
29072947 return specialized_filter(ctx) // ✅ Same type (@xdp), return position
29082948}
29092949
2910- @tc
2950+ @tc("ingress")
29112951fn ingress_handler(ctx: *__sk_buff) -> int {
29122952 return security_check(ctx) // ✅ Same type (@tc), return position
29132953}
@@ -4016,7 +4056,7 @@ mod program {
40164056 // Attach a program to a target with optional flags using its handle
40174057 // - First parameter must be a ProgramHandle returned from load()
40184058 // - For XDP: target is interface name (e.g., "eth0"), flags are XDP attachment flags
4019- // - For TC: target is interface name, flags indicate direction (ingress/egress)
4059+ // - For TC: target is interface name, direction determined from @tc attribute
40204060 // - For Kprobe: target is function name (e.g., "sys_read"), flags are unused (0)
40214061 // - For Cgroup: target is cgroup path (e.g., "/sys/fs/cgroup/test"), flags are unused (0)
40224062 pub fn attach(handle: ProgramHandle, target: string, flags: u32) -> u32
@@ -4120,7 +4160,7 @@ fn simple_filter(ctx: *xdp_md) -> xdp_action {
41204160 return XDP_PASS
41214161}
41224162
4123- @tc
4163+ @tc("ingress")
41244164fn security_monitor(ctx: *__sk_buff) -> int {
41254165 var packet = ctx.packet()
41264166 if (packet == null) {
0 commit comments