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

编译XDP eBPF内核程序报错,求排查与修正方案

eBPF XDP流量统计程序编译错误分析与修正

原程序代码

//This program is used to analyse network traffic (packet count, packet loss, latency and packet size). 
//The required headers 

#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <bpf/bpf_helpers.h>

BPF_HASH(packet_count, struct iphdr*, u64);
BPF_HASH(packet_size, struct iphdr*, u64);
BPF_HASH(latency, struct iphdr*, u64);
BPF_HASH(packet_loss, struct iphdr*, u64);

SEC("packet_stats")
int monitor_packets(struct xdp_md *ctx){
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct iphdr *iph = data + sizeof(struct ethhdr);  

   
if (iph + 1 > data_end) {
    return XDP_PASS;
}

// Count the number of packets
u64 *count = packet_count.lookup(&iph);
if (count) {
    *count += 1;
} else {
    packet_count.insert(&iph, &(u64){1});
}

// Track the size of packets
u64 *size = packet_size.lookup(&iph);
if (size) {
    *size += ntohs(iph->tot_len);
} else {
    packet_size.insert(&iph, &(u64){ntohs(iph->tot_len)});
}

// Track the latency of packets
u64 *ts = latency.lookup(&iph);
if (ts) {
    u64 now = bpf_ktime_get_ns();
    *ts = now - *ts;
    latency.delete(&iph);
} else {
    u64 now = bpf_ktime_get_ns();
    latency.insert(&iph, &now);
}

u64 *loss = packet_loss.lookup(&iph);
if (!value) {
        packet_loss.insert(&key, &(u64){1});
    } else {
        (*value)++;
    }

    return XDP_PASS
}
char _license[] SEC("license") = "GPL";

编译错误信息

BPF_HASH(packet_count, struct iphdr*, u64);
                       ^
xdp_pass.c:10:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
BPF_HASH(packet_count, struct iphdr*, u64);
^
xdp_pass.c:11:23: error: expected identifier
BPF_HASH(packet_size, struct iphdr*, u64);
                      ^
xdp_pass.c:11:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
BPF_HASH(packet_size, struct iphdr*, u64);
^
xdp_pass.c:12:19: error: expected identifier
BPF_HASH(latency, struct iphdr*, u64);
                  ^
xdp_pass.c:12:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
BPF_HASH(latency, struct iphdr*, u64);
^
xdp_pass.c:13:23: error: expected identifier
BPF_HASH(packet_loss, struct iphdr*, u64);
                      ^
xdp_pass.c:13:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
BPF_HASH(packet_loss, struct iphdr*, u64);
^
xdp_pass.c:22:13: warning: comparison of distinct pointer types ('struct iphdr *' and 'void *') [-Wcompare-distinct-pointer-types]
if (iph + 1 > data_end) {
    ~~~~~~~ ^ ~~~~~~~~
xdp_pass.c:27:1: error: use of undeclared identifier 'u64'
u64 *count = packet_count.lookup(&iph);
^
xdp_pass.c:27:6: error: use of undeclared identifier 'count'
u64 *count = packet_count.lookup(&iph);
     ^
xdp_pass.c:27:14: error: use of undeclared identifier 'packet_count'
u64 *count = packet_count.lookup(&iph);
             ^
xdp_pass.c:28:5: error: use of undeclared identifier 'count'
if (count) {
    ^
xdp_pass.c:29:6: error: use of undeclared identifier 'count'
    *count += 1;
     ^
xdp_pass.c:31:5: error: use of undeclared identifier 'packet_count'
    packet_count.insert(&iph, &(u64){1});
    ^
xdp_pass.c:31:33: error: use of undeclared identifier 'u64'
    packet_count.insert(&iph, &(u64){1});
                                ^
xdp_pass.c:35:1: error: use of undeclared identifier 'u64'
u64 *size = packet_size.lookup(&iph);
^
xdp_pass.c:35:6: error: use of undeclared identifier 'size'
u64 *size = packet_size.lookup(&iph);
     ^
xdp_pass.c:35:13: error: use of undeclared identifier 'packet_size'
u64 *size = packet_size.lookup(&iph);
            ^
xdp_pass.c:36:5: error: use of undeclared identifier 'size'
if (size) {
    ^
xdp_pass.c:37:14: warning: implicit declaration of function 'ntohs' is invalid in C99 [-Wimplicit-int]
    *size += ntohs(iph->tot_len);
             ^
xdp_pass.c:37:6: error: use of undeclared identifier 'size'
    *size += ntohs(iph->tot_len);
     ^
xdp_pass.c:39:5: error: use of undeclared identifier 'packet_size'
    packet_size.insert(&iph, &(u64){ntohs(iph->tot_len)});
    ^
xdp_pass.c:39:32: error: use of undeclared identifier 'u64'
    packet_size.insert(&iph, &(u64){ntohs(iph->tot_len)});
                               ^
xdp_pass.c:43:1: error: use of undeclared identifier 'u64'
u64 *ts = latency.lookup(&iph);
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
6 warnings and 20 errors generated.

问题分析与修正点

1. 缺少必要头文件与类型定义

  • u64 类型未定义:需包含 <linux/types.h> 引入内核标准类型
  • ntohs 函数未声明:添加 <linux/byteorder/generic.h>,适配eBPF环境的字节序转换

2. BPF哈希表键类型错误

原代码用 struct iphdr* 作为哈希表键,这是错误的:

  • 内核态指针是虚拟地址,不同CPU/上下文地址不唯一,无法作为唯一标识
  • 应使用数据包的源IP地址(__be32 类型)作为键,确保统计的是同一IP的流量

3. 指针越界检查类型不匹配

iph + 1 是 struct iphdr* 类型,data_end 是 void* 类型,直接比较会触发类型警告,需将 iph + 1 强制转换为 void*

4. 哈希表操作参数错误

原代码调用 lookup(&iph) 传递的是指针的地址(struct iphdr**),但哈希表的键是IP地址,应直接传递 &iph->saddr 作为键值

5. 丢包统计逻辑与变量错误

  • 原代码使用未定义变量 value、key,需改为对应变量名 loss
  • 原丢包逻辑无效:XDP层统计丢包需跟踪被丢弃的包(如返回 XDP_DROP 的情况),可通过统计总包数和丢弃包数计算丢包率

6. 语法错误

  • return XDP_PASS 末尾缺少分号

修正后的完整代码

// 统计入站网络包:包数量、包大小、双向延迟、丢包情况
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/types.h>
#include <linux/byteorder/generic.h>
#include <bpf/bpf_helpers.h>

// 用源IP地址作为哈希表键,统计各IP的数据包信息
BPF_HASH(packet_count, __be32, u64);
BPF_HASH(packet_size, __be32, u64);
// 存储包的接收时间戳,用于计算双向延迟
BPF_HASH(packet_ts, __be32, u64);
// 统计总处理包数和丢弃包数
BPF_ARRAY(total_packets, u64, 1);
BPF_ARRAY(dropped_packets, u64, 1);

SEC("xdp_stats")
int monitor_packets(struct xdp_md *ctx) {
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth = data;
    struct iphdr *iph;

    // 检查以太网头部完整性
    if (eth + 1 > data_end) {
        return XDP_PASS;
    }

    // 仅处理IPv4包
    if (eth->h_proto != __constant_htons(ETH_P_IP)) {
        return XDP_PASS;
    }

    iph = (struct iphdr *)(eth + 1);
    // 检查IP头部完整性
    if ((void *)(iph + 1) > data_end) {
        return XDP_PASS;
    }

    __be32 src_ip = iph->saddr;
    u64 *total = total_packets.lookup(&((u32){0}));
    if (total) {
        (*total)++;
    } else {
        u64 init = 1;
        total_packets.update(&((u32){0}), &init);
    }

    // 统计包数量
    u64 *count = packet_count.lookup(&src_ip);
    if (count) {
        (*count)++;
    } else {
        u64 init = 1;
        packet_count.update(&src_ip, &init);
    }

    // 统计包大小(转换为主机字节序)
    u16 pkt_size = __ntohs(iph->tot_len);
    u64 *size = packet_size.lookup(&src_ip);
    if (size) {
        (*size) += pkt_size;
    } else {
        packet_size.update(&src_ip, &((u64){pkt_size}));
    }

    // 计算双向延迟:如果是回应包,计算与请求包的时间差
    u64 *ts = packet_ts.lookup(&src_ip);
    if (ts) {
        u64 now = bpf_ktime_get_ns();
        bpf_printk("Latency for IP %x: %llu ns", src_ip, now - *ts);
        packet_ts.delete(&src_ip);
    } else {
        // 记录请求包的时间戳
        u64 now = bpf_ktime_get_ns();
        packet_ts.update(&src_ip, &now);
    }

    // 模拟丢包统计:包大小超过100字节则丢弃(示例逻辑)
    if (pkt_size > 100) {
        u64 *dropped = dropped_packets.lookup(&((u32){0}));
        if (dropped) {
            (*dropped)++;
        } else {
            u64 init = 1;
            dropped_packets.update(&((u32){0}), &init);
        }
        return XDP_DROP;
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

编译命令

使用原命令即可编译:

clang -O2 -target bpf -c demo.c -o demo.o

内容的提问来源于stack exchange,提问作者Anvay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 04:45:33