11#include <vmlinux.h>
22#include <bpf/bpf_tracing.h>
3- #include <bpf/bpf_core_read.h>
43#include <bpf/usdt.bpf.h>
54#include "tracing.bpf.h"
65
7- u32 yes = true;
6+ #define MAX_STACK_DEPTH 8
7+
8+ // Skipping 3 frames off the top as they are just bpf trampoline
9+ #define SKIP_FRAMES (3 & BPF_F_SKIP_FIELD_MASK)
10+
11+ extern int LINUX_KERNEL_VERSION __kconfig ;
812
913struct stitch_span_t {
1014 struct span_base_t span_base ;
11- u32 fd ;
12- u64 addr ;
15+ u64 socket_cookie ;
1316};
1417
1518struct sock_release_span_t {
1619 struct span_base_t span_base ;
1720 u64 span_id ;
1821};
1922
20- struct skb_span_t {
23+ struct sk_span_t {
2124 struct span_base_t span_base ;
2225 u64 ksym ;
2326};
2427
25- struct file_key_t {
26- u32 tgid ;
27- u32 fd ;
28+ struct sk_error_report_span_t {
29+ struct span_base_t span_base ;
30+ u64 kstack [MAX_STACK_DEPTH ];
31+ u32 sk_err ;
2832};
2933
3034struct {
@@ -40,175 +44,143 @@ struct {
4044struct {
4145 __uint (type , BPF_MAP_TYPE_RINGBUF );
4246 __uint (max_entries , 256 * 1024 );
43- } skb_spans SEC (".maps" );
47+ } sk_spans SEC (".maps" );
4448
4549struct {
46- __uint (type , BPF_MAP_TYPE_LRU_HASH );
47- __uint (max_entries , 1024 * 10 );
48- __type (key , u32 );
49- __type (value , bool );
50- } traced_tgids SEC (".maps" );
50+ __uint (type , BPF_MAP_TYPE_RINGBUF );
51+ __uint (max_entries , 256 * 1024 );
52+ } sk_error_report_spans SEC (".maps" );
5153
5254struct {
5355 __uint (type , BPF_MAP_TYPE_LRU_HASH );
5456 __uint (max_entries , 1024 * 10 );
55- __type (key , struct sock * );
57+ __type (key , u64 );
5658 __type (value , struct span_parent_t );
57- } traced_socks SEC (".maps" );
58-
59- struct {
60- __uint (type , BPF_MAP_TYPE_LRU_HASH );
61- __uint (max_entries , 1024 * 10 );
62- __type (key , struct file_key_t );
63- __type (value , struct sock * );
64- } fd_to_sock SEC (".maps" );
65-
66- SEC ("fentry/fd_install" )
67- int BPF_PROG (fd_install , unsigned int fd , struct file * file )
68- {
69- u32 tgid = bpf_get_current_pid_tgid () >> 32 ;
70- struct file_key_t key = { .tgid = tgid , .fd = fd };
71- bool * traced = bpf_map_lookup_elem (& traced_tgids , & tgid );
72- struct sock * sk ;
73-
74- if (!traced ) {
75- return 0 ;
76- }
77-
78- sk = BPF_CORE_READ ((struct socket * ) file -> private_data , sk );
79-
80- bpf_map_update_elem (& fd_to_sock , & key , & sk , BPF_ANY );
81-
82- return 0 ;
83- }
84-
85- SEC ("fentry/close_fd" )
86- int BPF_PROG (close_fd , unsigned int fd )
87- {
88- u32 tgid = bpf_get_current_pid_tgid () >> 32 ;
89- struct file_key_t key = { .tgid = tgid , .fd = fd };
90-
91- bpf_map_delete_elem (& traced_socks , & key );
92-
93- return 0 ;
94- }
95-
96- SEC ("usdt/./tracing/demos/sock/demo:ebpf_exporter:enable_kernel_tracing" )
97- int BPF_USDT (enable_kernel_tracing )
98- {
99- u32 tgid = bpf_get_current_pid_tgid () >> 32 ;
100-
101- bpf_map_update_elem (& traced_tgids , & tgid , & yes , BPF_NOEXIST );
102-
103- return 0 ;
104- }
105-
106- SEC ("tp_btf/sched_process_exit" )
107- int BPF_PROG (sched_process_exit , struct task_struct * p )
108- {
109- u32 tgid = p -> tgid ;
110-
111- if (p -> pid != p -> tgid ) {
112- return 0 ;
113- }
114-
115- bpf_map_delete_elem (& traced_tgids , & tgid );
116-
117- return 0 ;
118- }
59+ } traced_socket_cookies SEC (".maps" );
11960
12061SEC ("usdt/./tracing/demos/sock/demo:ebpf_exporter:sock_set_parent_span" )
121- int BPF_USDT (sock_set_parent_span , int fd , u64 trace_id_hi , u64 trace_id_lo , u64 span_id )
62+ int BPF_USDT (sock_set_parent_span , u64 socket_cookie , u64 trace_id_hi , u64 trace_id_lo , u64 span_id )
12263{
123- u32 tgid = bpf_get_current_pid_tgid () >> 32 ;
12464 struct span_parent_t parent = { .trace_id_hi = trace_id_hi , .trace_id_lo = trace_id_lo , .span_id = span_id };
125- struct file_key_t key = { .tgid = tgid , .fd = fd };
126- struct sock * * sk = bpf_map_lookup_elem (& fd_to_sock , & key );
127-
128- if (!sk ) {
129- return 0 ;
130- }
13165
132- bpf_map_update_elem (& traced_socks , sk , & parent , BPF_ANY );
66+ bpf_map_update_elem (& traced_socket_cookies , & socket_cookie , & parent , BPF_ANY );
13367
134- submit_span (& stitch_spans , struct stitch_span_t , & parent , {
135- span -> fd = fd ;
136- span -> addr = (u64 ) * sk ;
137- });
68+ submit_span (& stitch_spans , struct stitch_span_t , & parent , { span -> socket_cookie = socket_cookie ; });
13869
13970 return 0 ;
14071}
14172
14273SEC ("fentry/__sock_release" )
14374int BPF_PROG (__sock_release , struct socket * sock )
14475{
145- struct sock * sk = BPF_CORE_READ (sock , sk );
146- struct span_parent_t * parent = bpf_map_lookup_elem (& traced_socks , & sk );
76+ u64 socket_cookie = bpf_get_socket_cookie (sock -> sk );
77+ struct span_parent_t * parent = bpf_map_lookup_elem (& traced_socket_cookies , & socket_cookie );
14778
14879 if (!parent ) {
14980 return 0 ;
15081 }
15182
15283 submit_span (& sock_release_spans , struct sock_release_span_t , parent , { span -> span_id = 0xdead ; });
15384
154- bpf_map_delete_elem (& traced_socks , & sk );
85+ bpf_map_delete_elem (& traced_socket_cookies , & socket_cookie );
15586
15687 return 0 ;
15788}
15889
159- static int handle_skb (struct pt_regs * ctx , struct sock * sk , struct sk_buff * skb )
90+ static int handle_sk (struct pt_regs * ctx , u64 socket_cookie )
16091{
161- struct span_parent_t * parent = bpf_map_lookup_elem (& traced_socks , & sk );
92+ struct span_parent_t * parent = bpf_map_lookup_elem (& traced_socket_cookies , & socket_cookie );
16293
16394 if (!parent ) {
16495 return 0 ;
16596 }
16697
167- submit_span (& skb_spans , struct skb_span_t , parent , { span -> ksym = PT_REGS_IP_CORE (ctx ); });
98+ submit_span (& sk_spans , struct sk_span_t , parent , {
99+ // FIXME: PT_REGS_IP_CORE(ctx) does not work for fentry, so we abuse kstack
100+ bpf_get_stack (ctx , & span -> ksym , sizeof (span -> ksym ), SKIP_FRAMES );
101+ span -> ksym -= 8 ;
102+ });
168103
169104 return 0 ;
170105}
171106
172- SEC ("kprobe /tcp_v4_do_rcv" )
107+ SEC ("fentry /tcp_v4_do_rcv" )
173108int BPF_PROG (tcp_v4_do_rcv , struct sock * sk , struct sk_buff * skb )
174109{
175- return handle_skb ((struct pt_regs * ) ctx , sk , skb );
110+ return handle_sk ((struct pt_regs * ) ctx , bpf_get_socket_cookie ( sk ) );
176111}
177112
178- SEC ("kprobe/nf_hook_slow " )
179- int BPF_PROG (nf_hook_slow , struct sk_buff * skb )
113+ SEC ("fentry/__ip_local_out " )
114+ int BPF_PROG (__ip_local_out , struct net * net , struct sock * sk , struct sk_buff * skb )
180115{
181- return handle_skb ((struct pt_regs * ) ctx , BPF_CORE_READ ( skb , sk ), skb );
116+ return handle_sk ((struct pt_regs * ) ctx , bpf_get_socket_cookie ( sk ));
182117}
183118
184- SEC ("kprobe/__ip_local_out " )
185- int BPF_PROG (__ip_local_out , struct net * net , struct sock * sk , struct sk_buff * skb )
119+ SEC ("fentry/ip_finish_output " )
120+ int BPF_PROG (ip_finish_output , struct net * net , struct sock * sk , struct sk_buff * skb )
186121{
187- return handle_skb ((struct pt_regs * ) ctx , sk , skb );
122+ return handle_sk ((struct pt_regs * ) ctx , bpf_get_socket_cookie ( sk ) );
188123}
189124
190- SEC ("kprobe/ip_finish_output" )
191- int BPF_PROG (ip_finish_output , struct net * net , struct sock * sk , struct sk_buff * skb )
125+ SEC ("fentry/__tcp_retransmit_skb" )
126+ int BPF_PROG (__tcp_retransmit_skb , struct sock * sk , struct sk_buff * skb )
127+ {
128+ return handle_sk ((struct pt_regs * ) ctx , bpf_get_socket_cookie (sk ));
129+ }
130+
131+ // Older kernels are not happy with calls to bpf_get_socket_cookie(skb->sk):
132+ //
133+ // ; return handle_sk((struct pt_regs *) ctx, bpf_get_socket_cookie(skb->sk));
134+ // 3: (85) call bpf_get_socket_cookie#46
135+ // R1 type=untrusted_ptr_ expected=sock_common, sock, tcp_sock, xdp_sock, ptr_, trusted_ptr_
136+ //
137+ // I'm not sure which is the oldest available kernel, but I know it doesn't work on v6.5
138+ // in Github Actions, but runs fine on v6.9-rc3 locally. I'm too lazy to bisect.
139+ static int handle_skb (struct pt_regs * ctx , struct sk_buff * skb )
140+ {
141+ if (LINUX_KERNEL_VERSION < KERNEL_VERSION (6 , 9 , 0 )) {
142+ return 0 ;
143+ }
144+
145+ return handle_sk (ctx , bpf_get_socket_cookie (skb -> sk ));
146+ }
147+
148+ SEC ("fentry/nf_hook_slow" )
149+ int BPF_PROG (nf_hook_slow , struct sk_buff * skb )
192150{
193- return handle_skb ((struct pt_regs * ) ctx , sk , skb );
151+ return handle_skb ((struct pt_regs * ) ctx , skb );
194152}
195153
196- SEC ("kprobe /__dev_queue_xmit" )
154+ SEC ("fentry /__dev_queue_xmit" )
197155int BPF_PROG (__dev_queue_xmit , struct sk_buff * skb )
198156{
199- return handle_skb ((struct pt_regs * ) ctx , BPF_CORE_READ ( skb , sk ), skb );
157+ return handle_skb ((struct pt_regs * ) ctx , skb );
200158}
201159
202- SEC ("kprobe /dev_hard_start_xmit" )
160+ SEC ("fentry /dev_hard_start_xmit" )
203161int BPF_PROG (dev_hard_start_xmit , struct sk_buff * skb )
204162{
205- return handle_skb ((struct pt_regs * ) ctx , BPF_CORE_READ ( skb , sk ), skb );
163+ return handle_skb ((struct pt_regs * ) ctx , skb );
206164}
207165
208- SEC ("kprobe/__tcp_retransmit_skb" )
209- int BPF_PROG (__tcp_retransmit_skb , struct sock * sk , struct sk_buff * skb )
166+ // bpf_get_socket_cookie is not available in raw_tp:
167+ // * https://github.com/torvalds/linux/blob/v6.6/kernel/trace/bpf_trace.c#L1926-L1939
168+ SEC ("fentry/sk_error_report" )
169+ int BPF_PROG (sk_error_report , struct sock * sk )
210170{
211- return handle_skb ((struct pt_regs * ) ctx , sk , skb );
171+ u64 socket_cookie = bpf_get_socket_cookie (sk );
172+ struct span_parent_t * parent = bpf_map_lookup_elem (& traced_socket_cookies , & socket_cookie );
173+
174+ if (!parent ) {
175+ return 0 ;
176+ }
177+
178+ submit_span (& sk_error_report_spans , struct sk_error_report_span_t , parent , {
179+ bpf_get_stack (ctx , & span -> kstack , sizeof (span -> kstack ), SKIP_FRAMES );
180+ span -> sk_err = sk -> sk_err ;
181+ });
182+
183+ return 0 ;
212184}
213185
214186char LICENSE [] SEC ("license" ) = "GPL" ;
0 commit comments