Skip to content

Commit 3c58e66

Browse files
authored
Merge pull request #381 from cloudflare/ivan/sock-trace-cookies
Rewrite sock trace with socket cookies
2 parents d8ca7b1 + 34aea78 commit 3c58e66

File tree

4 files changed

+131
-135
lines changed

4 files changed

+131
-135
lines changed

examples/sock-trace.bpf.c

+86-114
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
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

913
struct stitch_span_t {
1014
struct span_base_t span_base;
11-
u32 fd;
12-
u64 addr;
15+
u64 socket_cookie;
1316
};
1417

1518
struct 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

3034
struct {
@@ -40,175 +44,143 @@ struct {
4044
struct {
4145
__uint(type, BPF_MAP_TYPE_RINGBUF);
4246
__uint(max_entries, 256 * 1024);
43-
} skb_spans SEC(".maps");
47+
} sk_spans SEC(".maps");
4448

4549
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");
5153

5254
struct {
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

12061
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)
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

14273
SEC("fentry/__sock_release")
14374
int 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")
173108
int 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")
197155
int 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")
203161
int 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

214186
char LICENSE[] SEC("license") = "GPL";

examples/sock-trace.yaml

+36-7
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@ tracing:
2323
size: 8
2424
decoders:
2525
- name: uint
26-
- name: fd
27-
size: 8
28-
decoders:
29-
- name: uint
30-
- name: addr_bytes # will look weird in little endian
26+
- name: socket_cookie
3127
size: 8
3228
decoders:
3329
- name: hex
@@ -55,8 +51,8 @@ tracing:
5551
size: 8
5652
decoders:
5753
- name: uint
58-
- name: skb
59-
ringbuf: skb_spans
54+
- name: sk_spans
55+
ringbuf: sk_spans
6056
service: kernel
6157
labels:
6258
- name: trace_id
@@ -83,3 +79,36 @@ tracing:
8379
size: 8
8480
decoders:
8581
- name: ksym
82+
- name: sk_error_report
83+
ringbuf: sk_error_report_spans
84+
service: kernel
85+
labels:
86+
- name: trace_id
87+
size: 16
88+
decoders:
89+
- name: hex
90+
- name: parent_span_id
91+
size: 8
92+
decoders:
93+
- name: hex
94+
- name: span_id
95+
size: 8
96+
decoders:
97+
- name: hex
98+
- name: span_monotonic_timestamp_ns
99+
size: 8
100+
decoders:
101+
- name: uint
102+
- name: span_duration_ns
103+
size: 8
104+
decoders:
105+
- name: uint
106+
- name: kstack
107+
size: 64
108+
decoders:
109+
- name: kstack
110+
- name: sk_err
111+
size: 4
112+
decoders:
113+
- name: uint
114+
- name: errno

tracing/demos/sock/main.go

-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
)
1313

1414
func main() {
15-
enableKernelTracing()
16-
1715
processor, err := demos.SetupTracing()
1816
if err != nil {
1917
log.Fatalf("Error setting up tracing: %v", err)

0 commit comments

Comments
 (0)