You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 16:14:52