Skip to content

Commit

Permalink
Add support for FastCGI protocol (#1417)
Browse files Browse the repository at this point in the history
  • Loading branch information
grcevski authored Dec 2, 2024
1 parent 4ca0c48 commit f517939
Show file tree
Hide file tree
Showing 68 changed files with 1,201 additions and 287 deletions.
2 changes: 1 addition & 1 deletion bpf/go_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ server_trace_parent(void *goroutine_addr, tp_info_t *tp, tp_info_t *found_tp) {
} else {
// If not, we then look up the information in the black-box context map - same node.
bpf_dbg_printk("Looking up traceparent for connection info");
tp_info_pid_t *tp_p = trace_info_for_connection(&conn);
tp_info_pid_t *tp_p = trace_info_for_connection(&conn, TRACE_TYPE_CLIENT);
if (!disable_black_box_cp && tp_p) {
if (correlated_request_with_current(tp_p)) {
bpf_dbg_printk("Found traceparent from trace map, another process.");
Expand Down
2 changes: 1 addition & 1 deletion bpf/go_nethttp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,7 @@ int uprobe_persistConnRoundTrip(struct pt_regs *ctx) {
// Must sort the connection info, this map is shared with kprobes which use sorted connection
// info always.
sort_connection_info(&conn);
set_trace_info_for_connection(&conn, &tp_p);
set_trace_info_for_connection(&conn, TRACE_TYPE_CLIENT, &tp_p);

// Setup information for the TC context propagation.
// We need the PID id to be able to query ongoing_http and update
Expand Down
1 change: 1 addition & 0 deletions bpf/http_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ typedef struct tp_info_pid {
tp_info_t tp;
u32 pid;
u8 valid;
u8 req_type;
} tp_info_pid_t;

// Here we keep the information that is sent on the ring buffer
Expand Down
7 changes: 4 additions & 3 deletions bpf/k_tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ int socket__http_filter(struct __sk_buff *skb) {
partial->tcp_seq = tcp.seq;
__builtin_memcpy(partial->s_addr, conn.s_addr, sizeof(partial->s_addr));

tp_info_pid_t *trace_info = trace_info_for_connection(&conn);
tp_info_pid_t *trace_info = trace_info_for_connection(&conn, TRACE_TYPE_CLIENT);
if (trace_info) {
if (cookie) { // we have an actual socket associated
bpf_map_update_elem(&tcp_connection_map, partial, &conn, BPF_ANY);
Expand All @@ -614,14 +614,15 @@ int socket__http_filter(struct __sk_buff *skb) {
connection_info_t *prev_conn = bpf_map_lookup_elem(&tcp_connection_map, partial);

if (prev_conn) {
tp_info_pid_t *trace_info = trace_info_for_connection(prev_conn);
tp_info_pid_t *trace_info =
trace_info_for_connection(prev_conn, TRACE_TYPE_CLIENT);
if (trace_info) {
if (current_immediate_epoch(trace_info->tp.ts) ==
current_immediate_epoch(bpf_ktime_get_ns())) {
//bpf_dbg_printk("Found trace info on another interface, setting it up for this connection");
tp_info_pid_t other_info = {0};
__builtin_memcpy(&other_info, trace_info, sizeof(tp_info_pid_t));
set_trace_info_for_connection(&conn, &other_info);
set_trace_info_for_connection(&conn, TRACE_TYPE_CLIENT, &other_info);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion bpf/k_tracer_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ static __always_inline void handle_buf_with_args(void *ctx, call_protocol_args_t
tp_info_pid_t *existing = bpf_map_lookup_elem(&server_traces, &t_key);
if (existing) {
__builtin_memcpy(&existing->tp, &info->tp, sizeof(tp_info_t));
set_trace_info_for_connection(&args->pid_conn.conn, existing);
set_trace_info_for_connection(
&args->pid_conn.conn, TRACE_TYPE_SERVER, existing);
} else {
bpf_dbg_printk("Didn't find existing trace, this might be a bug!");
}
Expand Down
119 changes: 112 additions & 7 deletions bpf/protocol_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,110 @@ static __always_inline http_info_t *empty_http_info() {
return value;
}

static __always_inline u32 trace_type_from_meta(http_connection_metadata_t *meta) {
if (meta->type == EVENT_HTTP_CLIENT) {
return TRACE_TYPE_CLIENT;
}

return TRACE_TYPE_SERVER;
}

static __always_inline void http_get_or_create_trace_info(http_connection_metadata_t *meta,
u32 pid,
connection_info_t *conn,
void *u_buf,
int bytes_len,
s32 capture_header_buffer) {
tp_info_pid_t *tp_p = tp_buf();

if (!tp_p) {
return;
}

tp_p->tp.ts = bpf_ktime_get_ns();
tp_p->tp.flags = 1;
tp_p->valid = 1;
tp_p->pid = pid; // used for avoiding finding stale server requests with client port reuse
tp_p->req_type = (meta) ? meta->type : 0;

urand_bytes(tp_p->tp.span_id, SPAN_ID_SIZE_BYTES);

u8 found_tp = 0;

if (meta) {
if (meta->type == EVENT_HTTP_CLIENT) {
pid_connection_info_t p_conn = {.pid = pid};
__builtin_memcpy(&p_conn.conn, conn, sizeof(connection_info_t));
found_tp = find_trace_for_client_request(&p_conn, &tp_p->tp);
} else {
//bpf_dbg_printk("Looking up existing trace for connection");
//dbg_print_http_connection_info(conn);

// For server requests, we first look for TCP info (setup by TC ingress) and then we fall back to black-box info.
found_tp = find_trace_for_server_request(conn, &tp_p->tp);
}
}

if (!found_tp) {
bpf_dbg_printk("Generating new traceparent id");
new_trace_id(&tp_p->tp);
__builtin_memset(tp_p->tp.parent_id, 0, sizeof(tp_p->tp.span_id));
} else {
bpf_dbg_printk("Using old traceparent id");
}

//unsigned char tp_buf[TP_MAX_VAL_LENGTH];
//make_tp_string(tp_buf, &tp_p->tp);
//bpf_dbg_printk("tp: %s", tp_buf);

#ifdef BPF_TRACEPARENT
// The below buffer scan can be expensive on high volume of requests. We make it optional
// for customers to enable it. Off by default.
if (!capture_header_buffer) {
if (meta) {
u32 type = trace_type_from_meta(meta);
set_trace_info_for_connection(conn, type, tp_p);
server_or_client_trace(meta->type, conn, tp_p);
}
return;
}

unsigned char *buf = tp_char_buf();
if (buf) {
int buf_len = bytes_len;
bpf_clamp_umax(buf_len, TRACE_BUF_SIZE - 1);

bpf_probe_read(buf, buf_len, u_buf);
unsigned char *res = bpf_strstr_tp_loop(buf, buf_len);

if (res) {
bpf_dbg_printk("Found traceparent %s", res);
unsigned char *t_id = extract_trace_id(res);
unsigned char *s_id = extract_span_id(res);
unsigned char *f_id = extract_flags(res);

decode_hex(tp_p->tp.trace_id, t_id, TRACE_ID_CHAR_LEN);
decode_hex((unsigned char *)&tp_p->tp.flags, f_id, FLAGS_CHAR_LEN);
if (meta && meta->type == EVENT_HTTP_CLIENT) {
decode_hex(tp_p->tp.span_id, s_id, SPAN_ID_CHAR_LEN);
} else {
decode_hex(tp_p->tp.parent_id, s_id, SPAN_ID_CHAR_LEN);
}
} else {
bpf_dbg_printk("No traceparent, making a new trace_id", res);
}
} else {
return;
}
#endif

if (meta) {
u32 type = trace_type_from_meta(meta);
set_trace_info_for_connection(conn, type, tp_p);
server_or_client_trace(meta->type, conn, tp_p);
}
}

static __always_inline u8 is_http(const unsigned char *p, u32 len, u8 *packet_type) {
if (len < MIN_HTTP_SIZE) {
return 0;
Expand Down Expand Up @@ -250,15 +354,16 @@ int protocol_http(void *ctx) {
http_connection_metadata_t *meta =
connection_meta_by_direction(&args->pid_conn, args->direction, PACKET_TYPE_REQUEST);

get_or_create_trace_info(meta,
args->pid_conn.pid,
&args->pid_conn.conn,
(void *)args->u_buf,
args->bytes_len,
capture_header_buffer);
http_get_or_create_trace_info(meta,
args->pid_conn.pid,
&args->pid_conn.conn,
(void *)args->u_buf,
args->bytes_len,
capture_header_buffer);

if (meta) {
tp_info_pid_t *tp_p = trace_info_for_connection(&args->pid_conn.conn);
u32 type = trace_type_from_meta(meta);
tp_info_pid_t *tp_p = trace_info_for_connection(&args->pid_conn.conn, type);
if (tp_p) {
info->tp = tp_p->tp;
} else {
Expand Down
65 changes: 56 additions & 9 deletions bpf/protocol_tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,56 @@ static __always_inline tcp_req_t *empty_tcp_req() {
return value;
}

static __always_inline void init_new_trace(tp_info_t *tp) {
new_trace_id(tp);
__builtin_memset(tp->parent_id, 0, sizeof(tp->span_id));
}

static __always_inline void
set_tcp_trace_info(u32 type, connection_info_t *conn, tp_info_t *tp, u32 pid) {
tp_info_pid_t *tp_p = tp_buf();

if (!tp_p) {
return;
}

tp_p->tp = *tp;
tp_p->tp.flags = 1;
tp_p->valid = 1;
tp_p->pid = pid; // used for avoiding finding stale server requests with client port reuse
tp_p->req_type = EVENT_TCP_REQUEST;

set_trace_info_for_connection(conn, type, tp_p);
bpf_dbg_printk("Set traceinfo for conn");
dbg_print_http_connection_info(conn);

server_or_client_trace(type, conn, tp_p);
}

static __always_inline void tcp_get_or_set_trace_info(tcp_req_t *req,
pid_connection_info_t *pid_conn) {
if (req->direction == TCP_SEND) { // Client
u8 found = find_trace_for_client_request(pid_conn, &req->tp);
bpf_dbg_printk("Looking up client trace info, found %d", found);
if (found) {
urand_bytes(req->tp.span_id, SPAN_ID_SIZE_BYTES);
} else {
init_new_trace(&req->tp);
}

set_tcp_trace_info(TRACE_TYPE_CLIENT, &pid_conn->conn, &req->tp, pid_conn->pid);
} else { // Server
u8 found = find_trace_for_server_request(&pid_conn->conn, &req->tp);
bpf_dbg_printk("Looking up server trace info, found %d", found);
if (found) {
urand_bytes(req->tp.span_id, SPAN_ID_SIZE_BYTES);
} else {
init_new_trace(&req->tp);
}
set_tcp_trace_info(TRACE_TYPE_SERVER, &pid_conn->conn, &req->tp, pid_conn->pid);
}
}

static __always_inline void handle_unknown_tcp_connection(pid_connection_info_t *pid_conn,
void *u_buf,
int bytes_len,
Expand All @@ -54,16 +104,11 @@ static __always_inline void handle_unknown_tcp_connection(pid_connection_info_t
task_pid(&req->pid);
bpf_probe_read(req->buf, K_TCP_MAX_LEN, u_buf);

tp_info_pid_t *server_tp = find_parent_trace(pid_conn);
req->tp.ts = bpf_ktime_get_ns();

if (server_tp && server_tp->valid && valid_trace(server_tp->tp.trace_id)) {
bpf_dbg_printk("Found existing server tp for client call");
__builtin_memcpy(
req->tp.trace_id, server_tp->tp.trace_id, sizeof(req->tp.trace_id));
__builtin_memcpy(
req->tp.parent_id, server_tp->tp.span_id, sizeof(req->tp.parent_id));
urand_bytes(req->tp.span_id, SPAN_ID_SIZE_BYTES);
}
bpf_dbg_printk("TCP request start, direction = %d, ssl = %d", direction, ssl);

tcp_get_or_set_trace_info(req, pid_conn);

bpf_map_update_elem(&ongoing_tcp_req, pid_conn, req, BPF_ANY);
}
Expand All @@ -90,6 +135,8 @@ static __always_inline void handle_unknown_tcp_connection(pid_connection_info_t
bpf_clamp_umax(off, (K_TCP_MAX_LEN / 2));
bpf_probe_read(existing->buf + off, (K_TCP_MAX_LEN / 2), u_buf);
existing->len += bytes_len;
} else {
existing->len += bytes_len;
}
}

Expand Down
Loading

0 comments on commit f517939

Please sign in to comment.