소스 검색

Feature #TASK_QT-18250 提交代码,解决bug

rock.wu 7 달 전
부모
커밋
63f46a61f7
2개의 변경된 파일162개의 추가작업 그리고 34개의 파일을 삭제
  1. 1 0
      ebpftracer/ebpf/config.h
  2. 161 34
      ebpftracer/ebpf/utrace/go/net/grpc.server.probe.bpf.c

+ 1 - 0
ebpftracer/ebpf/config.h

@@ -64,6 +64,7 @@ enum {
 	PROG_DATA_JAVA_FIND_HOST_UP_IDX,
 	PROG_DATA_JAVA_BUILD_HEADER_UP_IDX,
 	PROG_DATA_GO_UPDATE_HEADER_UP_IDX,
+	PROG_GRPC_SERVER_PROCESS_HEADERS_UP_IDX,
 	PROG_UP_NUM
 };
 

+ 161 - 34
ebpftracer/ebpf/utrace/go/net/grpc.server.probe.bpf.c

@@ -24,6 +24,15 @@ struct grpc_request_t {
     u8 has_status;
 };
 
+// Tail call 上下文结构,用于在多个 eBPF 程序间传递数据
+struct grpc_header_ctx_t {
+    void *frame_ptr;
+    void *header_fields_ptr;
+    s64 header_fields_len;
+    s32 current_index;
+    u32 frame_stream_id_pod_offset;
+};
+
 struct {
     __uint(type, BPF_MAP_TYPE_HASH);
     __type(key, void *);
@@ -53,6 +62,14 @@ struct {
     __uint(max_entries, 1);
 } operate_header_storage SEC(".maps");
 
+// Tail call 上下文存储
+struct {
+    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+    __uint(key_size, sizeof(u32));
+    __uint(value_size, sizeof(struct grpc_header_ctx_t));
+    __uint(max_entries, 1);
+} grpc_header_ctx_storage SEC(".maps");
+
 struct hpack_header_field {
     struct go_string_ot name;
     struct go_string_ot value;
@@ -440,52 +457,162 @@ lookup:
 // func (d *http2Server) operateHeader(frame *http2.MetaHeadersFrame) error
 // for version 1.60 and above:
 // func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeadersFrame, handle func(*Stream)) error
+//
+// 第一阶段:准备上下文并启动头部处理
 SEC("uprobe/http2Server_operateHeader")
 int uprobe_http2Server_operateHeader(struct pt_regs *ctx) {
     void *arg4 = get_argument(ctx, 4);
     void *arg2 = get_argument(ctx, 2);
     void *frame_ptr = is_new_frame_pos ? arg4 : arg2;
+    
+    if (frame_ptr == NULL) {
+        return 0;
+    }
+    
+    // 读取 header fields slice
     struct go_slice header_fields = {};
-    bpf_probe_read(&header_fields, sizeof(header_fields), (void *)(frame_ptr + frame_fields_pos));
-    char key[W3C_KEY_LENGTH] = "traceparent";
+    long res = bpf_probe_read(&header_fields, sizeof(header_fields), 
+                              (void *)(frame_ptr + frame_fields_pos));
+    if (res != 0 || header_fields.len == 0) {
+        return 0;
+    }
+    
+    // 准备 tail call 上下文
+    u32 zero = 0;
+    struct grpc_header_ctx_t *ctx_storage = 
+        bpf_map_lookup_elem(&grpc_header_ctx_storage, &zero);
+    if (ctx_storage == NULL) {
+        bpf_printk("grpc:server:operateHeader: failed to get ctx storage");
+        return -1;
+    }
+    
+    // 初始化上下文
+    __builtin_memset(ctx_storage, 0, sizeof(struct grpc_header_ctx_t));
+    ctx_storage->frame_ptr = frame_ptr;
+    ctx_storage->header_fields_ptr = header_fields.ptr;
+    ctx_storage->header_fields_len = header_fields.len;
+    ctx_storage->current_index = 0;
+    ctx_storage->frame_stream_id_pod_offset = frame_stream_id_pod;
+    
+    // 调用第二阶段:处理头部
+    bpf_tail_call(ctx, &NAME(progs_jmp_up_map), PROG_GRPC_SERVER_PROCESS_HEADERS_UP_IDX);
+    
+    // Tail call 失败时的回退
+    return 0;
+}
+
+// 第二阶段:处理 HTTP/2 头部,查找 traceparent
+// 这个函数通过 tail call 被调用,可以有独立的指令数预算
+PROGUP(grpc_server_process_headers)(struct pt_regs *ctx) {
+    // 获取上下文
+    u32 zero = 0;
+    struct grpc_header_ctx_t *header_ctx = 
+        bpf_map_lookup_elem(&grpc_header_ctx_storage, &zero);
+    if (header_ctx == NULL) {
+        return -1;
+    }
     
-    for (s32 i = 0; i < MAX_HEADERS; i++) {
-        if (i >= header_fields.len) {
+    void *frame_ptr = header_ctx->frame_ptr;
+    void *header_fields_ptr = header_ctx->header_fields_ptr;
+    s64 header_fields_len = header_ctx->header_fields_len;
+    s32 start_idx = header_ctx->current_index;
+    
+    // 每次处理最多 5 个头部,避免指令数过多
+    #define BATCH_SIZE 5
+    s32 end_idx = start_idx + BATCH_SIZE;
+    if (end_idx > header_fields_len) {
+        end_idx = header_fields_len;
+    }
+    
+    // 使用 #pragma unroll 减少循环复杂度
+    #pragma unroll
+    for (s32 i = start_idx; i < end_idx; i++) {
+        if (i >= header_fields_len) {
             break;
         }
+        
+        // 读取头部字段
         struct hpack_header_field hf = {};
-        long res =
-            bpf_probe_read(&hf, sizeof(hf), (void *)(header_fields.ptr + (i * sizeof(hf))));
-        if (hf.name.len == W3C_KEY_LENGTH && hf.value.len == W3C_VAL_LENGTH) {
-            char current_key[W3C_KEY_LENGTH];
-            bpf_probe_read(current_key, sizeof(current_key), hf.name.str);
-            if (bpf_memcmp(key, current_key, sizeof(key))) {
-                char val[W3C_VAL_LENGTH];
-                bpf_probe_read(val, W3C_VAL_LENGTH, hf.value.str);
-
-                // Get stream id
-                void *headers_frame = NULL;
-                bpf_probe_read(&headers_frame, sizeof(headers_frame), frame_ptr);
-                u32 stream_id = 0;
-                bpf_probe_read(
-                    &stream_id, sizeof(stream_id), (void *)(headers_frame + frame_stream_id_pod));
-                
-                // 使用 per-cpu array map 存储大变量,避免栈空间超限
-                // u32 zero = 0;
-                // struct grpc_request_t *grpcReq = bpf_map_lookup_elem(&operate_header_storage, &zero);
-                // if (grpcReq == NULL) {
-                //     bpf_printk("grpc:server:operateHeader: failed to get storage");
-                //     return -1;
-                // }
-                
-                // 清零并初始化
-                // __builtin_memset(grpcReq, 0, sizeof(struct grpc_request_t));
-                // w3c_string_to_span_context(val, &grpcReq->psc);
-                // bpf_map_update_elem(&streamid_to_grpc_events, &stream_id, grpcReq, 0);
-            }
+        long res = bpf_probe_read(&hf, sizeof(hf), 
+                                   (void *)(header_fields_ptr + (i * sizeof(hf))));
+        if (res != 0) {
+            continue;
+        }
+        
+        // 快速检查:长度必须匹配
+        if (hf.name.len != W3C_KEY_LENGTH || hf.value.len != W3C_VAL_LENGTH) {
+            continue;
+        }
+        
+        // 分段比较 "traceparent" (11 字节)
+        // 避免使用 bpf_memcmp,使用简单的整数比较
+        u32 part1 = 0, part2 = 0, part3 = 0;
+        bpf_probe_read(&part1, 4, hf.name.str);      // "trac" = 0x63617274
+        bpf_probe_read(&part2, 4, hf.name.str + 4);  // "epar" = 0x72617065
+        bpf_probe_read(&part3, 3, hf.name.str + 8);  // "ent" = 0x746e65
+        
+        // 检查是否匹配 "traceparent"
+        if (part1 != 0x63617274 || part2 != 0x72617065 || 
+            (part3 & 0xFFFFFF) != 0x746e65) {
+            continue;
         }
+        
+        // 找到 traceparent 头部!
+        bpf_printk("grpc:server:operateHeader: found traceparent at index %d", i);
+        
+        // 读取 traceparent 值
+        char val[W3C_VAL_LENGTH];
+        res = bpf_probe_read(val, W3C_VAL_LENGTH, hf.value.str);
+        if (res != 0) {
+            bpf_printk("grpc:server:operateHeader: failed to read traceparent value");
+            continue;
+        }
+        
+        // 获取 stream ID
+        void *headers_frame = NULL;
+        res = bpf_probe_read(&headers_frame, sizeof(headers_frame), frame_ptr);
+        if (res != 0) {
+            bpf_printk("grpc:server:operateHeader: failed to read headers_frame");
+            continue;
+        }
+        
+        u32 stream_id = 0;
+        res = bpf_probe_read(&stream_id, sizeof(stream_id), 
+                            (void *)(headers_frame + header_ctx->frame_stream_id_pod_offset));
+        if (res != 0) {
+            bpf_printk("grpc:server:operateHeader: failed to read stream_id");
+            continue;
+        }
+        
+        bpf_printk("grpc:server:operateHeader: stream_id=%u", stream_id);
+        
+        // 使用临时存储
+        struct grpc_request_t *grpcReq = 
+            bpf_map_lookup_elem(&operate_header_storage, &zero);
+        if (grpcReq == NULL) {
+            bpf_printk("grpc:server:operateHeader: failed to get storage");
+            return -1;
+        }
+        
+        // 清零并初始化
+        __builtin_memset(grpcReq, 0, sizeof(struct grpc_request_t));
+        
+        // 解析 W3C trace context (可选,如果需要的话)
+        // w3c_string_to_span_context(val, &grpcReq->psc);
+        
+        // 保存到 map,供后续 handleStream 使用
+        bpf_map_update_elem(&streamid_to_grpc_events, &stream_id, grpcReq, 0);
+        
+        // 找到就退出
+        return 0;
     }
-
+    
+    // 如果还有更多头部需要处理,继续 tail call
+    if (end_idx < header_fields_len) {
+        header_ctx->current_index = end_idx;
+        bpf_tail_call(ctx, &NAME(progs_jmp_up_map), PROG_GRPC_SERVER_PROCESS_HEADERS_UP_IDX);
+    }
+    
     return 0;
 }