1+ #include "vmlinux.h"
2+ #include <bpf/bpf_helpers.h>
3+ #include <bpf/bpf_core_read.h>
4+ #include <bpf/bpf_tracing.h>
5+ #include <bpf/bpf_endian.h>
6+
7+ #ifndef AF_INET
8+ #define AF_INET 2
9+ #endif
10+ #ifndef AF_INET6
11+ #define AF_INET6 10
12+ #endif
13+ #ifndef TASK_COMM_LEN
14+ #define TASK_COMM_LEN 16
15+ #endif
16+ #ifndef ETH_P_IP
17+ #define ETH_P_IP 0x0800
18+ #endif
19+ #ifndef ETH_P_IPV6
20+ #define ETH_P_IPV6 0x86dd
21+ #endif
22+
23+ struct event {
24+ u64 timestamp ;
25+ u32 pid ;
26+ u32 drop_reason ;
27+ u32 ip_version ; // 4 for IPv4, 6 for IPv6
28+ union {
29+ u32 saddr_v4 ;
30+ unsigned __int128 saddr_v6 ;
31+ };
32+ union {
33+ u32 daddr_v4 ;
34+ unsigned __int128 daddr_v6 ;
35+ };
36+ u16 sport ;
37+ u16 dport ;
38+ u8 state ;
39+ u8 tcpflags ;
40+ char comm [TASK_COMM_LEN ];
41+ u32 stack_id ;
42+ };
43+
44+ struct {
45+ __uint (type , BPF_MAP_TYPE_RINGBUF );
46+ __uint (max_entries , 512 );
47+ } events SEC (".maps" );
48+
49+ #define MAX_STACK_DEPTH 15
50+ struct {
51+ __uint (type , BPF_MAP_TYPE_STACK_TRACE );
52+ __uint (max_entries , 512 );
53+ __uint (key_size , sizeof (u32 ));
54+ __uint (value_size , MAX_STACK_DEPTH * sizeof (u64 ));
55+ } stack_traces SEC (".maps" );
56+
57+ char ipv4_only = 0 ;
58+ char ipv6_only = 0 ;
59+ __u32 netns_id = 0 ;
60+
61+ SEC ("tracepoint/skb/kfree_skb" )
62+ int tp__skb_free_skb (struct trace_event_raw_kfree_skb * args )
63+ {
64+ if (args -> reason <= SKB_DROP_REASON_NOT_SPECIFIED ) {
65+ return 0 ;
66+ }
67+
68+ if (bpf_ringbuf_query (& events , BPF_RB_AVAIL_DATA ) >= 511 ) {
69+ bpf_printk ("Ring buffer is almost full\n" );
70+ return 0 ;
71+ }
72+
73+ u64 pid_tgid = bpf_get_current_pid_tgid ();
74+ u32 pid = pid_tgid >> 32 ;
75+
76+ struct sk_buff * skb = args -> skbaddr ;
77+ if (!skb ) {
78+ return 0 ;
79+ }
80+ struct sock * sk = NULL ;
81+ bpf_core_read (& sk , sizeof (sk ), & skb -> sk );
82+
83+ // Get packet headers
84+ void * head ;
85+ u16 network_header , transport_header ;
86+ if (bpf_core_read (& head , sizeof (head ), & skb -> head ) ||
87+ bpf_core_read (& network_header , sizeof (network_header ), & skb -> network_header ) ||
88+ bpf_core_read (& transport_header , sizeof (transport_header ), & skb -> transport_header )) {
89+ bpf_printk ("Failed to read skb headers\n" );
90+ return 0 ;
91+ }
92+
93+ // Check protocol and filter by IP family
94+ u16 protocol = args -> protocol ;
95+ if (protocol != ETH_P_IP && protocol != ETH_P_IPV6 ) {
96+ bpf_printk ("Unsupported protocol: %u\n" , protocol );
97+ return 0 ;
98+ }
99+ if (ipv4_only && protocol != ETH_P_IP ) {
100+ return 0 ;
101+ }
102+ if (ipv6_only && protocol != ETH_P_IPV6 ) {
103+ return 0 ;
104+ }
105+
106+ // Filter by network namespace
107+ if (netns_id && sk ) {
108+ struct net * net = NULL ;
109+ bpf_core_read (& net , sizeof (net ), & sk -> __sk_common .skc_net .net );
110+ if (net ) {
111+ u32 inum ;
112+ bpf_core_read (& inum , sizeof (inum ), & net -> ns .inum );
113+ if (inum != netns_id ) {
114+ bpf_printk ("Skipping packet from different netns: %u != %u\n" , inum , netns_id );
115+ return 0 ;
116+ }
117+ }
118+ }
119+
120+ struct event * event = bpf_ringbuf_reserve (& events , sizeof (* event ), 0 );
121+ if (!event ) {
122+ return 0 ;
123+ }
124+
125+ event -> timestamp = bpf_ktime_get_ns ();
126+ event -> pid = pid ;
127+ event -> drop_reason = args -> reason ;
128+ bpf_get_current_comm (& event -> comm , sizeof (event -> comm ));
129+ event -> stack_id = bpf_get_stackid (args , & stack_traces , 0 );
130+ event -> state = 127 ;
131+ if (sk ) {
132+ u8 state ;
133+ if (!bpf_core_read (& state , sizeof (state ), & sk -> __sk_common .skc_state )) {
134+ event -> state = state ;
135+ }
136+ }
137+
138+ if (protocol == ETH_P_IP ) {
139+ struct iphdr ip ;
140+ if (bpf_core_read (& ip , sizeof (ip ), head + network_header )) {
141+ bpf_ringbuf_discard (event , 0 );
142+ return 0 ;
143+ }
144+ if (ip .protocol != IPPROTO_TCP ) {
145+ bpf_ringbuf_discard (event , 0 );
146+ return 0 ;
147+ }
148+ struct tcphdr tcp ;
149+ if (bpf_core_read (& tcp , sizeof (tcp ), head + transport_header )) {
150+ bpf_ringbuf_discard (event , 0 );
151+ return 0 ;
152+ }
153+ event -> ip_version = 4 ;
154+ event -> saddr_v4 = ip .saddr ;
155+ event -> daddr_v4 = ip .daddr ;
156+ event -> sport = bpf_ntohs (tcp .source );
157+ event -> dport = bpf_ntohs (tcp .dest );
158+ event -> tcpflags = ((u8 * )& tcp )[13 ];
159+ } else {
160+ struct ipv6hdr ip6 ;
161+ if (bpf_core_read (& ip6 , sizeof (ip6 ), head + network_header )) {
162+ bpf_ringbuf_discard (event , 0 );
163+ return 0 ;
164+ }
165+ if (ip6 .nexthdr != IPPROTO_TCP ) {
166+ bpf_ringbuf_discard (event , 0 );
167+ return 0 ;
168+ }
169+ struct tcphdr tcp ;
170+ if (bpf_core_read (& tcp , sizeof (tcp ), head + transport_header )) {
171+ bpf_ringbuf_discard (event , 0 );
172+ return 0 ;
173+ }
174+ event -> ip_version = 6 ;
175+ bpf_core_read (& event -> saddr_v6 , sizeof (event -> saddr_v6 ), & ip6 .saddr );
176+ bpf_core_read (& event -> daddr_v6 , sizeof (event -> daddr_v6 ), & ip6 .daddr );
177+ event -> sport = bpf_ntohs (tcp .source );
178+ event -> dport = bpf_ntohs (tcp .dest );
179+ event -> tcpflags = ((u8 * )& tcp )[13 ];
180+ }
181+
182+ bpf_ringbuf_submit (event , 0 );
183+ return 0 ;
184+ }
185+
186+ char _license [] SEC ("license" ) = "Dual BSD/GPL" ;
0 commit comments