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

使用BPF_MAP_TYPE_CPUMAP时调用bpf_map_update_elem报ENOMEM(Cannot allocate memory)错误的排查与解决

BPF_MAP_TYPE_CPUMAP时调用bpf_map_update_elem报ENOMEM(Cannot allocate memory)错误的排查与解决

我仔细啃了你的代码和报错信息,这个ENOMEM错误其实是几个小问题叠加出来的,咱们一步步拆解解决:

1. 最核心的坑:update元素的标志用错了

你现在调用bpf_map_update_elem时用了BPF_EXIST标志——这个标志的意思是只有当key已经存在时才允许更新,但刚load完的cpumap是空的,根本没有cpu=0这个条目。

理论上这种情况应该返回ENOENT(条目不存在),但某些内核版本在处理逻辑上有个小问题:它会先尝试为队列分配内存,发现条目不存在后再释放内存,但错误码却返回成了ENOMEM,直接把我们带偏了。

解决办法:把标志改成BPF_ANY(存在则更新,不存在则创建)或者BPF_NOEXIST(仅当不存在时创建),推荐用BPF_ANY更稳妥:

ret = bpf_map_update_elem(cpu_map_fd, &cpu, &val, BPF_ANY);

2. 队列qsize可能设置过大

你给qsize设了1024,cpumap的每个条目对应内核要为该CPU创建一个长度为1024的skb队列,这个队列需要占用不少内存。如果系统剩余内存吃紧,或者内核的内存限制比较严格,就会触发ENOMEM。

解决办法:先把qsize改小测试,比如64或者128,验证成功后再根据业务需求调整:

struct bpf_cpumap_val val = {
    .qsize = 64,  // 从小值开始试,稳了再调大
    .bpf_prog.fd = just_pass_fd,
};

3. 代码逻辑的小疏漏:update成功后直接return

你在update elem成功后直接return 0了,后面挂载xdp主程序到lo接口的代码根本没机会执行!哪怕update成功了,你的主xdp程序也没挂上,完全起不到转发UDP包的作用。

解决办法:把这个多余的return删掉,让程序继续执行到挂载步骤:

} else {
    fprintf(stderr, "Successfully updated cpu_map\n");
    // 这里别return 0!让程序往下走
}

4. 硬编码网卡index的隐患

你直接把LO_IFINDEX设为1,虽然大部分系统的lo接口index是1,但也有例外情况。最好用动态获取的方式更保险:

#include <net/if.h>  // 记得加这个头文件

int LO_IFINDEX = if_nametoindex("lo");
if (LO_IFINDEX == 0) {
    fprintf(stderr, "Failed to get lo interface index\n");
    goto end_destroy;
}

最后验证步骤

改完代码后,按以下步骤验证:

  1. 确保内核版本≥4.19(CPUMAP是4.19内核引入的)
  2. 用root权限编译运行(eBPF程序需要root权限)
  3. 用bpftool map list查看cpumap是否成功创建并添加了cpu=0的条目
  4. 发送UDP包测试(比如nc -u localhost 1234),然后用cat /sys/kernel/debug/tracing/trace_pipe查看bpf_printk的输出,验证just_pass程序是否正常运行

备注:内容来源于stack exchange,提问作者Chasing1020

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 03:08:01