Skip to content

Commit 1b6970a

Browse files
committed
wip: trace-log correlation initial iteration
Signed-off-by: Mattia Meleleo <[email protected]>
1 parent fcf99ae commit 1b6970a

File tree

20 files changed

+899
-136
lines changed

20 files changed

+899
-136
lines changed

bpf/common/iov_iter.h

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#pragma once
5+
6+
#include <bpfcore/vmlinux.h>
7+
#include <bpfcore/bpf_helpers.h>
8+
#include <bpfcore/bpf_core_read.h>
9+
#include <bpfcore/utils.h>
10+
11+
#include <logger/bpf_dbg.h>
12+
13+
enum { k_iovec_max_len = 8192 };
14+
15+
#pragma clang diagnostic push
16+
#pragma clang diagnostic ignored "-Wpadded"
17+
18+
struct iov_iter___dummy {
19+
unsigned int type; // for co-re support, use iter_type instead
20+
u8 iter_type;
21+
void *ubuf;
22+
const struct iovec *iov;
23+
const struct iovec *__iov;
24+
unsigned long nr_segs;
25+
};
26+
27+
#pragma clang diagnostic pop
28+
29+
typedef struct iov_iter___dummy iovec_iter_ctx;
30+
31+
enum iter_type___dummy { ITER_UBUF };
32+
33+
// extracts kernel specific iov_iter information into a iovec_iter_ctx instance
34+
static __always_inline void get_iovec_ctx(iovec_iter_ctx *ctx, struct iov_iter___dummy *iov_iter) {
35+
ctx->ubuf = NULL;
36+
ctx->iov = NULL;
37+
if (bpf_core_field_exists(iov_iter->type)) {
38+
// clear the direction bit when reading iovec_iter::type to end up
39+
// with the original enumerator value (the direction bit is the LSB
40+
// and is either 0 (READ) or 1 (WRITE)).
41+
ctx->iter_type = BPF_CORE_READ(iov_iter, type) & 0xfe;
42+
} else {
43+
ctx->iter_type = BPF_CORE_READ(iov_iter, iter_type);
44+
}
45+
46+
if (bpf_core_field_exists(iov_iter->ubuf)) {
47+
ctx->ubuf = BPF_CORE_READ(iov_iter, ubuf);
48+
}
49+
50+
if (bpf_core_field_exists(iov_iter->iov)) {
51+
ctx->iov = BPF_CORE_READ(iov_iter, iov);
52+
} else if (bpf_core_field_exists(iov_iter->__iov)) {
53+
ctx->iov = BPF_CORE_READ(iov_iter, __iov);
54+
}
55+
56+
ctx->nr_segs = BPF_CORE_READ(iov_iter, nr_segs);
57+
}
58+
59+
static __always_inline int read_iovec_ctx(iovec_iter_ctx *ctx, unsigned char *buf, size_t max_len) {
60+
if (max_len == 0) {
61+
return 0;
62+
}
63+
64+
bpf_clamp_umax(max_len, k_iovec_max_len);
65+
66+
bpf_dbg_printk("iter_type=%u", ctx->iter_type);
67+
bpf_dbg_printk("nr_segs=%lu, iov=%p, ubuf=%p", ctx->nr_segs, ctx->iov, ctx->ubuf);
68+
69+
// ITER_UBUF only exists in kernels >= 6.0 - earlier kernels use ITER_IOVEC
70+
if (bpf_core_enum_value_exists(enum iter_type___dummy, ITER_UBUF)) {
71+
const int iter_ubuf = bpf_core_enum_value(enum iter_type___dummy, ITER_UBUF);
72+
73+
// ITER_UBUF is never a bitmask, and can be 0, so we perform a proper
74+
// equality check rather than a bitwise and like we do for ITER_IOVEC
75+
if (ctx->ubuf != NULL && ctx->iter_type == iter_ubuf) {
76+
bpf_clamp_umax(max_len, k_iovec_max_len);
77+
return bpf_probe_read(buf, max_len, ctx->ubuf) == 0 ? max_len : 0;
78+
}
79+
}
80+
81+
const int iter_iovec = bpf_core_enum_value(enum iter_type, ITER_IOVEC);
82+
83+
if (ctx->iter_type != iter_iovec) {
84+
return 0;
85+
}
86+
87+
u32 tot_len = 0;
88+
89+
enum { max_segments = 16 };
90+
91+
bpf_clamp_umax(ctx->nr_segs, max_segments);
92+
93+
// Loop couple of times reading the various io_vecs
94+
for (unsigned long i = 0; i < ctx->nr_segs && i < max_segments; i++) {
95+
struct iovec vec;
96+
97+
if (bpf_probe_read_kernel(&vec, sizeof(vec), &ctx->iov[i]) != 0) {
98+
break;
99+
}
100+
101+
// bpf_dbg_printk("iov[%d]=%llx", i, &ctx->iov[i]);
102+
// bpf_dbg_printk("base %llx, len %d", vec.iov_base, vec.iov_len);
103+
104+
if (!vec.iov_base || !vec.iov_len) {
105+
continue;
106+
}
107+
108+
const u32 remaining = k_iovec_max_len > tot_len ? (k_iovec_max_len - tot_len) : 0;
109+
u32 iov_size = vec.iov_len < max_len ? vec.iov_len : max_len;
110+
iov_size = iov_size < remaining ? iov_size : remaining;
111+
bpf_clamp_umax(tot_len, k_iovec_max_len);
112+
bpf_clamp_umax(iov_size, k_iovec_max_len);
113+
114+
// bpf_dbg_printk("tot_len=%d, remaining=%d", tot_len, remaining);
115+
116+
if (tot_len + iov_size > max_len) {
117+
break;
118+
}
119+
120+
bpf_probe_read(&buf[tot_len], iov_size, vec.iov_base);
121+
122+
// bpf_dbg_printk("iov_size=%d, buf=%s", iov_size, buf);
123+
124+
tot_len += iov_size;
125+
}
126+
127+
return tot_len;
128+
}

bpf/generictracer/iovec_len.h

Lines changed: 0 additions & 6 deletions
This file was deleted.

bpf/generictracer/k_tracer.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <common/common.h>
1111
#include <common/connection_info.h>
12+
#include <common/iov_iter.h>
1213
#include <common/msg_buffer.h>
1314
#include <common/dns.h>
1415
#include <common/pin_internal.h>
@@ -708,7 +709,8 @@ static __always_inline void setup_recvmsg(u64 id, struct sock *sk, struct msghdr
708709
.sock_ptr = (u64)sk,
709710
};
710711

711-
get_iovec_ctx((iovec_iter_ctx *)&args.iovec_ctx, msg);
712+
struct iov_iter___dummy *iov_iter = (struct iov_iter___dummy *)&msg->msg_iter;
713+
get_iovec_ctx((iovec_iter_ctx *)&args.iovec_ctx, iov_iter);
712714

713715
bpf_map_update_elem(&active_recv_args, &id, &args, BPF_ANY);
714716
}

bpf/generictracer/k_unix_sock.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <bpfcore/vmlinux.h>
77
#include <bpfcore/bpf_helpers.h>
88

9+
#include <common/iov_iter.h>
910
#include <common/http_types.h>
1011
#include <common/tc_common.h>
1112
#include <common/tracing.h>
@@ -146,7 +147,8 @@ int BPF_KPROBE(obi_kprobe_unix_stream_recvmsg,
146147
.sock_ptr = (u64)sk,
147148
};
148149

149-
get_iovec_ctx((iovec_iter_ctx *)&args.iovec_ctx, msg);
150+
struct iov_iter___dummy *iov_iter = (struct iov_iter___dummy *)&msg->msg_iter;
151+
get_iovec_ctx((iovec_iter_ctx *)&args.iovec_ctx, iov_iter);
150152

151153
bpf_map_update_elem(&active_recv_args, &id, &args, BPF_ANY);
152154

bpf/generictracer/maps/iovec_mem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <bpfcore/vmlinux.h>
77
#include <bpfcore/bpf_helpers.h>
88

9-
#include <generictracer/iovec_len.h>
9+
#include <common/iov_iter.h>
1010

1111
struct {
1212
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);

bpf/generictracer/protocol_common.h

Lines changed: 3 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
#include <bpfcore/vmlinux.h>
77
#include <bpfcore/bpf_helpers.h>
88

9+
#include <common/iov_iter.h>
910
#include <common/sock_port_ns.h>
1011
#include <common/http_types.h>
1112
#include <common/pin_internal.h>
1213
#include <common/ringbuf.h>
1314

14-
#include <generictracer/iovec_len.h>
15-
1615
#include <generictracer/maps/connection_meta_mem.h>
1716
#include <generictracer/maps/iovec_mem.h>
1817
#include <generictracer/maps/listening_ports.h>
@@ -97,129 +96,15 @@ static __always_inline http_connection_metadata_t *connection_meta_by_direction(
9796
return meta;
9897
}
9998

100-
#pragma clang diagnostic push
101-
#pragma clang diagnostic ignored "-Wpadded"
102-
103-
struct iov_iter___dummy {
104-
unsigned int type; // for co-re support, use iter_type instead
105-
u8 iter_type;
106-
void *ubuf;
107-
const struct iovec *iov;
108-
const struct iovec *__iov;
109-
unsigned long nr_segs;
110-
};
111-
112-
#pragma clang diagnostic pop
113-
114-
typedef struct iov_iter___dummy iovec_iter_ctx;
115-
116-
enum iter_type___dummy { ITER_UBUF };
117-
118-
// extracts kernel specific iov_iter information into a iovec_iter_ctx instance
119-
static __always_inline void get_iovec_ctx(iovec_iter_ctx *ctx, struct msghdr *msg) {
120-
ctx->ubuf = NULL;
121-
ctx->iov = NULL;
122-
if (bpf_core_field_exists(((struct iov_iter___dummy *)&msg->msg_iter)->type)) {
123-
// clear the direction bit when reading iovec_iter::type to end up
124-
// with the original enumerator value (the direction bit is the LSB
125-
// and is either 0 (READ) or 1 (WRITE)).
126-
ctx->iter_type = BPF_CORE_READ((struct iov_iter___dummy *)&msg->msg_iter, type) & 0xfe;
127-
} else {
128-
ctx->iter_type = BPF_CORE_READ((struct iov_iter___dummy *)&msg->msg_iter, iter_type);
129-
}
130-
131-
if (bpf_core_field_exists(((struct iov_iter___dummy *)&msg->msg_iter)->ubuf)) {
132-
ctx->ubuf = BPF_CORE_READ((struct iov_iter___dummy *)&msg->msg_iter, ubuf);
133-
}
134-
135-
if (bpf_core_field_exists(((struct iov_iter___dummy *)&msg->msg_iter)->iov)) {
136-
ctx->iov = BPF_CORE_READ((struct iov_iter___dummy *)&msg->msg_iter, iov);
137-
} else if (bpf_core_field_exists(((struct iov_iter___dummy *)&msg->msg_iter)->__iov)) {
138-
ctx->iov = BPF_CORE_READ((struct iov_iter___dummy *)&msg->msg_iter, __iov);
139-
}
140-
141-
ctx->nr_segs = BPF_CORE_READ((struct iov_iter___dummy *)&msg->msg_iter, nr_segs);
142-
}
143-
144-
static __always_inline int read_iovec_ctx(iovec_iter_ctx *ctx, unsigned char *buf, size_t max_len) {
145-
if (max_len == 0) {
146-
return 0;
147-
}
148-
149-
bpf_clamp_umax(max_len, k_iovec_max_len);
150-
151-
bpf_dbg_printk("iter_type=%u", ctx->iter_type);
152-
bpf_dbg_printk("nr_segs=%lu, iov=%p, ubuf=%p", ctx->nr_segs, ctx->iov, ctx->ubuf);
153-
154-
// ITER_UBUF only exists in kernels >= 6.0 - earlier kernels use ITER_IOVEC
155-
if (bpf_core_enum_value_exists(enum iter_type___dummy, ITER_UBUF)) {
156-
const int iter_ubuf = bpf_core_enum_value(enum iter_type___dummy, ITER_UBUF);
157-
158-
// ITER_UBUF is never a bitmask, and can be 0, so we perform a proper
159-
// equality check rather than a bitwise and like we do for ITER_IOVEC
160-
if (ctx->ubuf != NULL && ctx->iter_type == iter_ubuf) {
161-
bpf_clamp_umax(max_len, k_iovec_max_len);
162-
return bpf_probe_read(buf, max_len, ctx->ubuf) == 0 ? max_len : 0;
163-
}
164-
}
165-
166-
const int iter_iovec = bpf_core_enum_value(enum iter_type, ITER_IOVEC);
167-
168-
if (ctx->iter_type != iter_iovec) {
169-
return 0;
170-
}
171-
172-
u32 tot_len = 0;
173-
174-
enum { max_segments = 16 };
175-
176-
bpf_clamp_umax(ctx->nr_segs, max_segments);
177-
178-
// Loop couple of times reading the various io_vecs
179-
for (unsigned long i = 0; i < ctx->nr_segs && i < max_segments; i++) {
180-
struct iovec vec;
181-
182-
if (bpf_probe_read_kernel(&vec, sizeof(vec), &ctx->iov[i]) != 0) {
183-
break;
184-
}
185-
186-
// bpf_dbg_printk("iov[%d]=%llx", i, &ctx->iov[i]);
187-
// bpf_dbg_printk("base %llx, len %d", vec.iov_base, vec.iov_len);
188-
189-
if (!vec.iov_base || !vec.iov_len) {
190-
continue;
191-
}
192-
193-
const u32 remaining = k_iovec_max_len > tot_len ? (k_iovec_max_len - tot_len) : 0;
194-
u32 iov_size = vec.iov_len < max_len ? vec.iov_len : max_len;
195-
iov_size = iov_size < remaining ? iov_size : remaining;
196-
bpf_clamp_umax(tot_len, k_iovec_max_len);
197-
bpf_clamp_umax(iov_size, k_iovec_max_len);
198-
199-
// bpf_dbg_printk("tot_len=%d, remaining=%d", tot_len, remaining);
200-
201-
if (tot_len + iov_size > max_len) {
202-
break;
203-
}
204-
205-
bpf_probe_read(&buf[tot_len], iov_size, vec.iov_base);
206-
207-
// bpf_dbg_printk("iov_size=%d, buf=%s", iov_size, buf);
208-
209-
tot_len += iov_size;
210-
}
211-
212-
return tot_len;
213-
}
214-
21599
static __always_inline int read_msghdr_buf(struct msghdr *msg, unsigned char *buf, size_t max_len) {
216100
if (max_len == 0) {
217101
return 0;
218102
}
219103

220104
iovec_iter_ctx ctx;
221105

222-
get_iovec_ctx(&ctx, msg);
106+
struct iov_iter___dummy *iov_iter = (struct iov_iter___dummy *)&msg->msg_iter;
107+
get_iovec_ctx(&ctx, iov_iter);
223108

224109
return read_iovec_ctx(&ctx, buf, max_len);
225110
}

bpf/generictracer/protocol_http2.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
#include <bpfcore/vmlinux.h>
77
#include <bpfcore/bpf_helpers.h>
88

9+
#include <common/iov_iter.h>
910
#include <common/http_buf_size.h>
1011
#include <common/pin_internal.h>
1112
#include <common/ringbuf.h>
1213

1314
#include <generictracer/http2_grpc.h>
14-
#include <generictracer/iovec_len.h>
1515
#include <generictracer/k_tracer_tailcall.h>
1616
#include <generictracer/protocol_common.h>
1717
#include <generictracer/types/http2_conn_info_data.h>

0 commit comments

Comments
 (0)