当前位置: 首页 > news >正文

BPF 辅助函数注册

bpf_func_protoLinux 4.17+ 内核注册 BPF 辅助函数的标准接口,直接替代了废弃的bpf_register_helper,是自定义 BPF 辅助函数的唯一正确方式

  • 作用:描述一个 BPF 辅助函数的所有信息(函数指针、参数类型、返回值、权限等)
  • 内核通过它安全校验 BPF 程序,防止越权访问
  • bpf_register_helper4.17+ 已删除
  • bpf_func_proto内核官方唯一支持的方式
  • 安全校验,防止 BPF 程序非法访问内存
  • 所有新内核(5.x/ 6.x)都必须用它;
  • 这个函数是 Linux 内核早期 BPF 接口(<5.0 版本)的 API,早已被内核官方废弃、移除

  • 内核v4.15~v4.20还保留兼容,内核v5.0 及以上彻底删除了该函数;
  • 现在的内核(包括 CentOS 7/8、Ubuntu 20.04+、Android 内核)全部不支持

结构体定义(内核标准)

struct bpf_func_proto { u64 (*func)(u64 u1, u64 u2, u64 u3, u64 u4, u64 u5); // 辅助函数本体 enum bpf_arg_type arg1_type:8; // 参数1类型 enum bpf_arg_type arg2_type:8; // 参数2类型 enum bpf_arg_type arg3_type:8; // 参数3类型 enum bpf_arg_type arg4_type:8; // 参数4类型 enum bpf_arg_type arg5_type:8; // 参数5类型 enum bpf_return_type ret_type:8; // 返回值类型 bool gpl_only; // 是否仅限 GPL 协议模块使用 bool pkt_access; // 是否允许访问数据包 u32 ctx_arg; // 上下文参数索引 };

最常用字段:

  • func:你的辅助函数指针
  • argX_type:参数类型(内核用来做安全检查)
  • ret_type:返回值类型
  • gpl_only:是否 GPL 许可

最关键的回调函数

你必须实现一个回调函数,内核会调用它来获取辅助函数的原型:

const struct bpf_func_proto *(*func_proto)(enum bpf_func_id id, const struct bpf_prog *prog);

作用:

  • 根据func_id返回对应的bpf_func_proto
  • 不认识的 ID 统一返回bpf_base_func_proto(id)

完整可编译示例

步骤 1:实现自定义辅助函数

// 真正的辅助函数逻辑 static u64 bpf_helper_add(u64 a, u64 b, u64 unused3, u64 unused4, u64 unused5) { return a + b; }

步骤 2:定义函数原型

static const struct bpf_func_proto add_func_proto = { .func = bpf_helper_add, .gpl_only = false, .ret_type = RET_INTEGER, .arg1_type = ARG_ANYTHING, .arg2_type = ARG_ANYTHING, };

步骤 3:实现查询回调

static const struct bpf_func_proto * my_bpf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { switch (func_id) { case BPF_FUNC_my_add: // 自定义函数ID return &add_func_proto; default: return bpf_base_func_proto(func_id); // 其他用内核默认 } }

步骤 4:绑定到 BPF 程序类型

static struct bpf_prog_type my_prog_type __read_mostly = { .name = "my_bpf_prog", .func_proto = my_bpf_func_proto, // 绑定回调 };

步骤 5:注册 / 卸载

// 模块初始化 static int __init my_init(void) { return register_bpf_prog_type(&my_prog_type); } // 模块退出 static void __exit my_exit(void) { unregister_bpf_prog_type(&my_prog_type); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");

常用参数类型(arg_type)

你必须正确填写,否则 BPF 校验器会拒绝加载程序:

ARG_ANYTHING // 任意值 ARG_PTR_TO_MEM // 指向内存的指针 ARG_CONST_SIZE // 常量大小 ARG_PTR_TO_CTX // 指向上下文 ARG_DONTCARE // 不关心

常用返回值:

RET_INTEGER // 返回整数 RET_PTR_TO_MEM // 返回内存指针 RET_VOID // 无返回

BPF_CALL_*宏:BPF 辅助函数标准写法

BPF_CALL_0 / BPF_CALL_1 / BPF_CALL_2 ... BPF_CALL_5Linux 内核定义 BPF 辅助函数的官方标准宏必须配合bpf_func_proto使用,也是替代bpf_register_helper的核心。

  • 内核定义的辅助函数声明宏
  • 数字代表参数个数
    • BPF_CALL_0:0 个参数
    • BPF_CALL_1:1 个参数
    • ...
    • BPF_CALL_5:5 个参数(BPF 最大支持)
  • 作用:统一封装 BPF 辅助函数的参数和返回值格式
  • 所有内核自带 BPF 辅助函数(如bpf_trace_printk)都用它

强制统一 BPF 辅助函数签名

BPF 规定辅助函数必须是:

u64 (*func)(u64, u64, u64, u64, u64);

BPF_CALL_*帮你自动写好,不会写错。

示例 1:2 个参数 → 用BPF_CALL_2

// 辅助函数:a + b BPF_CALL_2(bpf_my_add, u64, a, u64, b) { return a + b; }

示例 2:0 个参数 → 用BPF_CALL_0

BPF_CALL_0(bpf_get_pid) { return (u64)current->tgid; }

示例 3:3 个参数

BPF_CALL_3(bpf_test, u64, a, u64, b, u64, c) { return a + b + c; }

struct bpf_verifier_ops 与bpf程序

struct bpf_verifier_ops= BPF 程序的规则手册 + 裁判

BPF 程序 = 运动员

  • 内核加载 BPF 程序时
  • 必须先找它绑定的bpf_verifier_ops
  • 用里面的函数来校验 BPF 代码是否合法
  • 其中最重要的函数
    const struct bpf_func_proto *(*func_proto)(...);
    它决定了这个 BPF 程序能调用哪些辅助函数!

每一种 BPF 程序(如 XDP、tracepoint、fentry、socket)都绑定一个固定的struct bpf_verifier_ops

例如:

BPF_PROG_TYPE_XDP → xdp_verifier_ops BPF_PROG_TYPE_TRACEPOINT → tracepoint_verifier_ops BPF_PROG_TYPE_TRACING → tracing_verifier_ops <-- 我们用这个 BPF_PROG_TYPE_SOCKET_FILTER → sock_filter_ops

当你加载一个 BPF 程序:

  1. 内核看你是什么程序类型(TRACING / XDP...)
  2. 找到对应的struct bpf_verifier_ops
  3. 调用ops->func_proto(func_id)
  4. 返回函数是否可用 + 函数指针

这就是:

BPF 程序能调用哪些辅助函数,完全由 verifier_ops 决定!

最简洁的关系图

BPF 程序类型 ↓ (绑定) struct bpf_verifier_ops ↓ (包含) func_proto() <-- 你要改的就是这个 ↓ (查询) struct bpf_func_proto ↓ (指向) BPF_CALL_* 定义的辅助函数

struct bpf_verifier_ops是 BPF 程序与辅助函数之间的唯一桥梁

想给 BPF 程序加自定义函数 → 必须修改它的 verifier_ops

  • 每种 BPF 程序都有一个 verifier_ops
  • func_proto 决定能调用哪些辅助函数
  • 5.15 注册辅助函数 = 替换 func_proto
http://www.jsqmd.com/news/495308/

相关文章:

  • java毕业设计基于springboot+Java兰州市出租车服务管理系统
  • 2026年南京口碑好的纸箱定制定制生产排名,推荐的纸箱定制厂商有哪些 - 工业品网
  • 闭眼入! 更贴合开源免费需求的降AI率网站,千笔·降AIGC助手 VS 万方智搜AI
  • 极简Prometheus监控实战指南
  • 2026年 挂具厂家推荐排行榜:氧化挂具/喷涂挂具/电镀挂具/涂装挂具/钛合金挂具,专业定制与耐用品质深度解析 - 品牌企业推荐师(官方)
  • 2026年 钢筋桁架焊接机厂家推荐排行榜,全自动钢筋网焊接机,桥梁钢筋网焊接机,预制构件钢筋网焊接机,精准高效焊接设备深度解析 - 品牌企业推荐师(官方)
  • 〘 8-2 〙软考高项 | 第15章:项目风险管理(下)
  • 高性价比AI写教材指南:低查重且高效的操作技巧分享
  • 网站增加可允许上传文件类型,例如webp、mov等文件格式扩展
  • 打印机共享、连接
  • 2026年闭眼入!万众偏爱的降AIGC平台 —— 千笔
  • IT 卷不动了?转网安才是真香!零网安基础入门到精通,收藏这篇就够了!
  • 计算机视觉中的多模态融合:技术原理与工业实践
  • 基于语音识别的智能家居设计(有完整资料)
  • 2026年选购优质轻集料混凝土批发厂商的实用攻略,目前轻集料混凝土厂商嘉贤诚信务实提供高性价比服务 - 品牌推荐师
  • 计算机毕业设计之springboot毕业生学历证明系统
  • 请问PBOOTCMS网站安装后,首页打开 404 NOT FOUND的处理方式是怎么回事
  • 2026年3月市场口碑好的危废暂存间公司都在这份分析分析里,危废间/防爆危废间/危废暂存间,危废暂存间实力厂家推荐 - 品牌推荐师
  • SpringBoot实现各种参数校验,写得太好了,建议收藏!
  • AI时代岗位发展前景
  • 全球半导体及集成电路博览会攻略:新手参展不踩坑,高效对接资源 - 品牌2025
  • IF 开环启动切龙伯格观测器 Matlab/simulink 仿真探索
  • 2026年期货量化软件扩展性排名_二次开发能力对比
  • 【数据结构与算法】死磕排序算法:面试官最爱问的那些排序(下篇)
  • 2026年质量好的铠装控制电缆工厂推荐:护套控制电缆/阻燃屏蔽控制电缆稳定供应商推荐 - 行业平台推荐
  • 瑞祥商联卡回收攻略:快速变现的秘密都在这里! - 团团收购物卡回收
  • 【开题答辩全过程】以 基于python 的图书借阅管理系统为例,包含答辩的问题和答案
  • 城市内涝预警系统怎么做?城市内涝积水监测技术解析
  • [网络安全提高篇] 一二三.恶意样本分类之基于API序列和深度学习的恶意家族分类详解
  • CAD制图出图比例应该如何正确设置?(一)