1
1
#include <vmlinux.h>
2
2
#include <bpf/bpf_tracing.h>
3
- #include <bpf/bpf_core_read.h>
4
3
#include <bpf/usdt.bpf.h>
5
4
#include "tracing.bpf.h"
6
5
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 ;
8
12
9
13
struct stitch_span_t {
10
14
struct span_base_t span_base ;
11
- u32 fd ;
12
- u64 addr ;
15
+ u64 socket_cookie ;
13
16
};
14
17
15
18
struct sock_release_span_t {
16
19
struct span_base_t span_base ;
17
20
u64 span_id ;
18
21
};
19
22
20
- struct skb_span_t {
23
+ struct sk_span_t {
21
24
struct span_base_t span_base ;
22
25
u64 ksym ;
23
26
};
24
27
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 ;
28
32
};
29
33
30
34
struct {
@@ -40,175 +44,143 @@ struct {
40
44
struct {
41
45
__uint (type , BPF_MAP_TYPE_RINGBUF );
42
46
__uint (max_entries , 256 * 1024 );
43
- } skb_spans SEC (".maps" );
47
+ } sk_spans SEC (".maps" );
44
48
45
49
struct {
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" );
51
53
52
54
struct {
53
55
__uint (type , BPF_MAP_TYPE_LRU_HASH );
54
56
__uint (max_entries , 1024 * 10 );
55
- __type (key , struct sock * );
57
+ __type (key , u64 );
56
58
__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" );
119
60
120
61
SEC ("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 )
122
63
{
123
- u32 tgid = bpf_get_current_pid_tgid () >> 32 ;
124
64
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
- }
131
65
132
- bpf_map_update_elem (& traced_socks , sk , & parent , BPF_ANY );
66
+ bpf_map_update_elem (& traced_socket_cookies , & socket_cookie , & parent , BPF_ANY );
133
67
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 ; });
138
69
139
70
return 0 ;
140
71
}
141
72
142
73
SEC ("fentry/__sock_release" )
143
74
int BPF_PROG (__sock_release , struct socket * sock )
144
75
{
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 );
147
78
148
79
if (!parent ) {
149
80
return 0 ;
150
81
}
151
82
152
83
submit_span (& sock_release_spans , struct sock_release_span_t , parent , { span -> span_id = 0xdead ; });
153
84
154
- bpf_map_delete_elem (& traced_socks , & sk );
85
+ bpf_map_delete_elem (& traced_socket_cookies , & socket_cookie );
155
86
156
87
return 0 ;
157
88
}
158
89
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 )
160
91
{
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 );
162
93
163
94
if (!parent ) {
164
95
return 0 ;
165
96
}
166
97
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
+ });
168
103
169
104
return 0 ;
170
105
}
171
106
172
- SEC ("kprobe /tcp_v4_do_rcv" )
107
+ SEC ("fentry /tcp_v4_do_rcv" )
173
108
int BPF_PROG (tcp_v4_do_rcv , struct sock * sk , struct sk_buff * skb )
174
109
{
175
- return handle_skb ((struct pt_regs * ) ctx , sk , skb );
110
+ return handle_sk ((struct pt_regs * ) ctx , bpf_get_socket_cookie ( sk ) );
176
111
}
177
112
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 )
180
115
{
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 ));
182
117
}
183
118
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 )
186
121
{
187
- return handle_skb ((struct pt_regs * ) ctx , sk , skb );
122
+ return handle_sk ((struct pt_regs * ) ctx , bpf_get_socket_cookie ( sk ) );
188
123
}
189
124
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 )
192
150
{
193
- return handle_skb ((struct pt_regs * ) ctx , sk , skb );
151
+ return handle_skb ((struct pt_regs * ) ctx , skb );
194
152
}
195
153
196
- SEC ("kprobe /__dev_queue_xmit" )
154
+ SEC ("fentry /__dev_queue_xmit" )
197
155
int BPF_PROG (__dev_queue_xmit , struct sk_buff * skb )
198
156
{
199
- return handle_skb ((struct pt_regs * ) ctx , BPF_CORE_READ ( skb , sk ), skb );
157
+ return handle_skb ((struct pt_regs * ) ctx , skb );
200
158
}
201
159
202
- SEC ("kprobe /dev_hard_start_xmit" )
160
+ SEC ("fentry /dev_hard_start_xmit" )
203
161
int BPF_PROG (dev_hard_start_xmit , struct sk_buff * skb )
204
162
{
205
- return handle_skb ((struct pt_regs * ) ctx , BPF_CORE_READ ( skb , sk ), skb );
163
+ return handle_skb ((struct pt_regs * ) ctx , skb );
206
164
}
207
165
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 )
210
170
{
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 ;
212
184
}
213
185
214
186
char LICENSE [] SEC ("license" ) = "GPL" ;
0 commit comments