基于libbpf与eBPF tracepoint提取UDP数据包负载的问题排查
内核4.19下通过
netif_receive_skb tracepoint提取UDP负载的问题排查 我在接收端尝试用tracepoint netif_receive_skb提取UDP数据包负载并发送到用户态处理,但三种方法均出现问题:
方法1:直接定位负载打印,末尾数据缺失
通过以下代码定位UDP负载:
unsigned char *payload = (unsigned char *)(udph + 1); bpf_printk("%s", payload);
实际打印时发现负载末尾部分数据缺失。
方法2:映射自定义结构体触发内存访问错误
尝试将负载存入自定义结构体并发送事件,收到BPF验证器的R8 invalid mem access 'inv'错误。当前场景中skb->data_len为0(线性数据包),理论上可完整获取数据,但观察到skb->end与skb->tail的值小于data和head,存在疑问。
相关代码片段
struct custom_data { __u32 val1; __u32 val2; __u32 val3; __u32 val4; }; SEC("tp/net/netif_receive_skb") int net_netif_receive_skb(struct trace_event_raw_consume_skb *args) { struct sk_buff *skb = (struct sk_buff *)BPF_CORE_READ(args, skbaddr); // 数据包解析步骤(省略) unsigned char *data_end = BPF_CORE_READ(skb, data) + BPF_CORE_READ(skb, len); if ((unsigned char *)(udph + 1) > data_end) return -1; struct custom_data *custom_data= (struct custom_data *)(udph + 1); if ((unsigned char *)(custom_data + 1) > data_end) return -1; __u32 val1 = custom_data ->val1; bpf_printk("port: %d", bpf_htons(port2_real_dst)); // 注释掉bpf_printk后,代码可正常加载!
验证器错误信息
; unsigned char *data_end = BPF_CORE_READ(skb, data) + BPF_CORE_READ(skb, len); 189: (61) r1 = *(u32 *)(r10 -32) ; unsigned char *data_end = BPF_CORE_READ(skb, data) + BPF_CORE_READ(skb, len); 190: (0f) r8 += r1 ; if ((unsigned char *)(udph + 1) > data_end) 191: (3d) if r8 >= r7 goto pc+124 from 191 to 316: frame1: R0_w=invP(id=0) R1_w=invP(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R6_w=invP(id=22) R7=invP(id=21) R8_w=invP(id=0) R9=invP61 R10=fp0 fp-32=mmmmmmmm fp-40=00000000 fp-48=00000000 fp-56=000mmmmm fp-64=mmmmmmmm fp-72=00000000 fp-80=mmmmmmmm fp-88=invP61 ; if ((unsigned char *)(telemetry_data + 1) > data_end) 316: (bf) r1 = r7 317: (07) r1 += 28 ; if ((unsigned char *)(telemetry_data + 1) > data_end) 318: (3d) if r8 >= r1 goto pc+71 from 318 to 390: frame1: R0=invP(id=0) R1=invP(id=0) R6=invP(id=22) R7=invP(id=21) R8=invP(id=0) R9=invP61 R10=fp0 fp-32=mmmmmmmm fp-40=00000000 fp-48=00000000 fp-56=000mmmmm fp-64=mmmmmmmm fp-72=00000000 fp-80=mmmmmmmm fp-88=invP61 ; __u16 port2_real_dst = telemetry_data->port2_real_dst; 390: (71) r1 = *(u8 *)(r7 +26) R7 invalid mem access 'inv'
方法3:bpf_probe_read_kernel读取不完整,含垃圾值
使用bpf_probe_read_kernel(data, sizeof(*custom_data), udph + 1);从内核内存读取负载,仅能获取部分数据,且包含垃圾值。
疑问与求助
是否遗漏了关键步骤?有没有其他基于libbpf库读取UDP数据包负载的可行方法?当前使用内核版本为4.19。
内容的提问来源于stack exchange,提问作者hundredmiles
相关产品推荐
相关产品推荐

