Linux 内核 BPF 子系统开发实战指南:缺陷报告、补丁提交、Stable 回合与测试工具链全流程
Linux 内核 BPF 子系统开发实战指南缺陷报告、补丁提交、Stable 回合与测试工具链全流程【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文基于内核树中 Documentation/bpf/bpf_devel_QA.rstHOWTO interact with BPF subsystem整理并扩充面向希望参与 BPF 子系统开发的工程师读完你将掌握 BPF 的缺陷报告渠道、补丁从自测到进入 mainline 的完整流转路径bpf/bpf-next → net/net-next → mainline、BPF selftests 的运行方法与配置要点以及 BPF JIT/LLVM 协同开发中的关键约定-mcpuprobe、--targetbpf等从而具备独立向 BPF 社区提交补丁并完成验证的全部能力。一、总览BPF 开发的协作入口BPFeBPF内核开发、bpftool 以及 iproute2 BPF loader 的开发统一通过bpf 内核邮件列表bpfvger.kernel.org进行。通用补丁提交规范请参阅 Documentation/process/submitting-patches.rst本文只补充 BPF 特有的约定。从源码结构看当前仓库的 MAINTAINERS 文件将 BPF 细分为多个维护条目可据此定位各方向的负责人条目说明关键路径BPF [CORE]verifier、syscall 等核心kernel/bpf/verifier.c、kernel/bpf/syscall.cBPF [GENERAL]BPF 总维护含 selftests、libbpf、samplestools/testing/selftests/bpf/、tools/bpf/、samples/bpf/、arch/*/net/*BPF [JIT for X86/ARM/ARM64/RISC-V/…]各架构 JITarch/arch/net/BPF [TOOLING] (bpftool)用户态调试工具tools/bpf/bpftool/BPF [LIBRARY] (libbpf)用户态库tools/lib/bpf/BPF [SELFTESTS]测试基础设施tools/testing/selftests/bpf/BPF [GENERAL]条目MAINTAINERS中列出的维护者包括 Alexei Starovoitov、Daniel Borkmann、Andrii Nakryiko、Eduard Zingerman、Kumar Kartikeya Dwivedi 等并给出了 patchwork 队列netdevbpf 项目的 bpf delegate以及bpf/bpf-next两棵 git 树与文档正文描述完全一致。二、如何报告 BPF 缺陷所有BPF 内核代码问题包括 XDP、BPF tracing 等都发到bpfvger.kernel.org。由于 netdev 列表流量巨大报告中务必 Cc BPF 维护者可从内核 MAINTAINERS 文件确认Alexei Starovoitov astkernel.orgDaniel Borkmann danieliogearbox.net如果已经定位到有问题的提交还需把该提交的作者也加入 Cc可通过内核 git 树查询。重要约定请勿把 BPF 问题提交到 bugzilla——文档明确警告这样做基本保证问题会被忽视。三、补丁提交流程3.1 发送前在 BPF CI 上自测BPF CI 基于 GitHub托管在 kernel-patches 组织的bpf仓库中。文档以 UI 工作流为主步骤如下在自己的 GitHub 账号中 fork 该仓库一次性操作本地 clone 自己的 fork检出跟踪bpf-next或bpf分支的新分支并把待测补丁叠加其上把本地分支推送到自己的 fork并向bpf_next_base或bpf_base分支分别对应上游 bpf-next 与 bpf发起 Pull Request。PR 创建后不久 CI 工作流即会运行。注意两点CI 容量与上游提交者共享按排队情况运行时间可能较长bpf-next_base与bpf_base会随上游分支推进而更新因此你的补丁集会被自动尝试 rebase到新基线这可能导致当前 CI 运行被中止并以新基线重启。tools/testing/selftests/bpf/README.rst 进一步说明CI 系统对系列中的每个补丁运行 selftests并在多种架构上执行内核配置由 selftests 目录下通用与架构相关的配置片段如 tools/testing/selftests/bpf/config 与config.x86_64等推导而来测试结果会反馈到 patchwork失败会像 checkpatch 违例一样被高亮显示。3.2 补丁发往哪个邮件列表BPF 补丁提交到bpfvger.kernel.org。若补丁横跨多个子系统网络、tracing、security 等务必同时 Cc 相应子系统的邮件列表与维护者以便他们审查并给出Acked-by。3.3 在哪里查看正在讨论的补丁Cc 到 netdev 的补丁都会进入 patchwork 的netdevbpf项目队列目标为 BPF 的补丁会被分配给 bpf delegate 由 BPF 维护者处理对应 MAINTAINERS 中Q:字段登记的 netdevbpf delegate 队列。补丁状态含义AcceptedBPF 社区审查通过、维护者批准补丁已应用到 bpf 或 bpf-next 之一提交者会收到邮件通知Changes Requested需要修改重发补丁被移出当前审查队列被拒绝或不适用于 BPF 树的补丁同样会被清除。3.4 补丁如何进入 Linux 主线BPF 维护两棵内核 git 树bpf与bpf-next均只有 master 一个分支简化 rebase 目标选择bpf仅接收修复bpf-next接收新功能、清理与其他改进next 型内容。这与网络子系统的 net / net-next 类比。两棵树累积的补丁会定期以 pull request 形式并入由 David S. Miller 维护的net / net-next树再从中进入 Linus Torvalds 维护的 mainline。net/net-next 的合入机制见 Documentation/process/maintainer-netdev.rst。偶尔为规避合并冲突BPF 维护者会向其他树如 tracing发送只含少量补丁的 pull request但 net / net-next 始终是主要合入目标。pull request 带高层摘要可在 netdev 列表中按主题行搜索yyyy-mm-dd为日期pull-request: bpf yyyy-mm-dd pull-request: bpf-next yyyy-mm-dd如何指定目标树流程与 netdev 文档Documentation/process/maintainer-netdev.rst一致关键在主题行修复最终走 bpf → netgit format-patch --subject-prefixPATCH bpf start..finish功能/改进最终走 bpf-next → net-nextgit format-patch --subject-prefixPATCH bpf-next start..finish若不确定该进 bpf 还是 net、bpf-next 还是 net-next主题行写 net / net-next 也没关系维护者会负责分配。若明确目标为 bpf / bpf-next请先对相应树做 rebase 以减少冲突。第二轮及以后的修订版本必须在主题前缀中加版本号例如git format-patch --subject-prefixPATCH bpf-next v2 start..finish收到修改意见后必须重新发送完整补丁系列吸收反馈后而不是在旧系列上只发个别 diff。3.5 补丁被应用到 bpf / bpf-next 意味着什么意味着从 BPF 角度看该补丁适合进入主线但这不是最终裁决补丁进入 net / net-next 前bpf 列表上任何时间点都可能出现新的 review。若讨论结论是无法按原样合入维护者会追加后续修复或干脆从树中移除并保留在必要时rebase 整棵树的权利。树的存在目的有二i) 累积并暂存 BPF 补丁以便向 net / net-next 集成 ii) 在补丁继续前进之前对其运行完整的 BPF 测试套件与 workload。当 David S. Miller 接受 BPF pull request 后补丁进入 net / net-next再进一步流向 mainline合入频率等细节见 netdev 文档。3.6 反馈与 pull request 的节奏反馈延迟维护者尽量压低延迟通常23 个工作日视改动复杂度与补丁负载浮动pull request 频率为避免积累过多补丁会较频繁发送经验法则是每周末每棵树一次视负载与紧急程度也可能在周中加发merge window 期间合入窗口开启时 bpf-next 停止处理与 net-next 类似细节见 Documentation/process/maintainer-netdev.rst。这两周内维护者可能要求你在 bpf-next 重新开放后重发补丁系列Linus 在合入窗口后发布v*-rc1bpf-next 处理即恢复。非邮件列表订阅者可参考 David S. Miller 维护的 net-next 状态页获取指引。3.7 Verifier 改动必须附带 selftests如果补丁改变了 verifier 行为必须向 BPF 内核 selftests 增加测试用例若缺失且维护者认为必要会在接受改动前要求补充。tools/testing/selftests/bpf/test_verifier.c 追踪了大量 BPF 测试用例包括 LLVM BPF 后端从受限 C 代码可能生成的诸多 corner case因此未被 test_verifier.c 追踪的 verifier 行为未来存在被变更的可能。3.8 selftests 还是 samples/bpf总体优先向 BPF 内核 selftests 添加因为 selftests 会被各类机器人定期运行以捕获内核回归——用例越多覆盖越好意外破坏的概率越低selftests 本身也可以演示特性用法。分工建议samples/bpf/适合入门级的简单功能演示selftests功能测试与 corner case 测试如果你的sample看起来像测试用例请放进 selftests。3.9 何时扩展 bpftoolbpftool源码位于tools/bpf/bpftool/的核心定位是内核中活跃 BPF 程序与 map 的统一用户态调试/内省工具。如果 BPF 相关 UAPI 变更允许 dump 出程序或 map 的更多信息应当同步扩展 bpftool 支持这些 dump。3.10 何时扩展 iproute2 的 BPF loaderXDP 或 tc 层如cls_bpf对应源码 net/sched/cls_bpf.c的 UAPI 变更约定要在用户态一侧同步加入 iproute2 BPF loader 的支持——这既有利于 UAPI 本身被设计得真正可用也能让主流下游发行版用户及时受益。iproute2 BPF loader 的补丁规则发送到netdevvger.kernel.org不由 BPF 内核维护者处理但请保留他们在 Cc 以便 reviewiproute2 官方 git 仓库由 Stephen Hemminger 维护主题前缀为[PATCH iproute2 master]或[PATCH iproute2 net-next]内核改动进了 net-next则对应的 iproute2 改动进其 net-next 分支否则进 masteriproute2 的 net-next 分支在当前 master 版本发布后合入 master与 BPF 相同补丁进入 netdev 项目的 patchwork 并委派给 shemminger 处理。3.11 提交前最低要求充分自测是硬性要求绝不仓促提交进入bpf树的修复必须带Fixes:标签目标为 bpf-next 且受影响提交在 net-next或个别情况在 bpf-next中的修复同样需要Fixes:——它用于识别后续提交并极大帮助 backport 人员缺一不可不接受空提交信息。高质量 commit message 至关重要一个月后看代码的其他开发者需要理解为什么这样改、原分析中是否有缺陷因此必须给出充分理由与用例描述超过 1 个补丁的系列必须有 cover letter给出系列高层描述——它会进入 BPF 维护者的 merge commit从而可从 git log 中长期检索。3.12 涉及 BPF JIT 和/或 LLVM 的新特性维护者努力保持所有 BPF JIT 同步更新保证不同架构上运行 BPF 程序时体验一致避免程序在内核 JIT 开启时降级到低效的解释器。注意事项若你无法自行实现/测试某架构的 JIT 改动请尽早与该架构的 BPF JIT 开发者协作从源码结构看各架构 JIT 代码位于arch/*/net/可结合 git log 找到合适的协作者MAINTAINERS 中每个架构均有独立的 BPF JIT 条目为新指令始终添加 BPF 测试用例如test_bpf.c与test_verifier.c以获得广泛测试覆盖并帮助运行时测试各 JIT新 BPF 指令被内核接受后还要实现 LLVM BPF 后端的相应支持见下文 LLVM 部分。3.13BPF_INTERNAL符号命名空间以BPF_INTERNAL方式导出的符号只能被 BPF 基础设施如带轻量 skeleton 的 preload 内核模块使用BPF_INTERNAL之外的大多数符号同样不应被 BPF 之外的代码使用。某些符号缺少该标注可能是因为它们早于命名空间机制或属于疏漏。四、Stable 内核回合4.1 需要某个 BPF 修复进入 stable先在 stable 仓库linux-stable.git 的linux-*.y分支确认该提交是否已经存在。若不存在给 BPF 维护者发邮件并在 Cc 中加入netdevvger.kernel.org请求排队该修复。整体流程与 netdev 一致见 Documentation/process/maintainer-netdev.rst。4.2 会回合到已停止维护的内核吗不会。需要 BPF 提交进入当前不再由 stable 维护者维护的内核需要自行处理。当前 stable 与 LTS 内核清单以 kernel.org 官方列表为准。4.3 自己的补丁需要进 stable 怎么办规则与 netdev 补丁提交一致。永远不要在补丁描述里加Cc: stablevger.kernel.org而应请 BPF 维护者代为排队可以在补丁中---之后不会进入 git log 的部分加一段说明也可以直接用邮件单独请求。4.4 在哪里查看已排队的 stable 补丁修复关键缺陷的补丁进入 bpf 树后会先排入 patchwork 的 BPF stable bundlebpf/stablestate*。这些补丁至少保留到对应提交进入 mainline经过更广泛曝光后才由 BPF 维护者正式提交给 stable 维护者。五、如何测试补丁运行 BPF selftests启动新编译的内核后从 git 树根目录进入 selftests 目录$ cd tools/testing/selftests/bpf/ $ make运行 verifier 测试$ sudo ./test_verifierverifier 测试会打印当前执行的每一项检查末尾给出通过/失败汇总例如Summary: 418 PASSED, 0 FAILED运行全部 BPF selftests$ sudo make run_tests细节参见 Documentation/dev-tools/kselftest/ 下的 kernel selftest 文档。从源码结构看几个文档中提到的构建行为均可在 tools/testing/selftests/bpf/Makefile 中得到印证为尽量让测试全部通过被测内核的.config应尽可能贴近 selftests 目录下的配置片段tools/testing/selftests/bpf/config 及config.x86_64、config.aarch64等架构片段若无法做到构建时设置BPF_STRICT_BUILD0Makefile 中BPF_STRICT_BUILD ? 1PERMISSIVE : $(filter 0,$(BPF_STRICT_BUILD))即可容忍个别编译失败并继续构建其余测试而不是把每个失败都当作致命错误。此外tools/testing/selftests/bpf/README.rst 提供了两条实用补充DENYLIST 机制部分架构不支持全部 BPF 特性如 s390x 的 BPF trampoline此时DENYLIST与DENYLIST.arch文件用于阻止测试在该架构运行三列测试名、失败报错、原因摘要vmtest.shtools/testing/selftests/bpf/vmtest.sh 可在虚拟机中以接近维护者 CI 的环境运行 selftests——使用树内内核配置、下载 CI 使用的 VM 用户态镜像、重新编译并运行 BPF selftests默认运行test_progs结果默认保存在~/.bpf_selftests依赖 clang建议源码构建、pahole、qemu、docutilsrst2man与 libcap-devel。pahole 依赖为支持最新的 BPF Type Format 特性讨论见 Documentation/bpf/btf.rst以CONFIG_DEBUG_INFO_BTFy构建内核时要求pahole 1.16dwarves 包或从 dwarves 项目源码构建。pahole 自 v1.13 起提交 21507cd3e97bpahole: add libbpf as submodule under lib/bpf开始使用 libbpf 的定义与 API用 git 仓库构建时git submodule update --init --recursive会同步 libbpf 子模块但默认发布的源码包不含 libbpf 子模块源码会引发构建问题kernel.org 上的 pahole tarball 同样如此应改用附带 libbpf 子模块源码的 tarball。部分发行版如 Fedora、Gentoo已打包 pahole 1.16。selftests 版本匹配运行内核xyz就应运行内核xyz自带的 BPF selftests不要指望最新 mainline 树的 selftests 永远全绿。尤其test_bpf.c其用例已迁入 selftests 框架的prog_tests/组织与test_verifier.c用例量大且持续更新既新增 BPF 测试序列也会随 verifier 变聪明而调整既有用例。六、LLVM 工具链6.1 哪里获得带 BPF 支持的 LLVMLLVM 的 BPF 后端自LLVM 3.7.1起已在上游主流发行版均提供带 BPF 后端的 LLVM 包多数场景直接安装发行版软件包即可无需手工编译。用llc --version检查目标列表确认 BPF 目标在册$ llc --version LLVM (http://llvm.org/): LLVM version 10.0.0 Optimized build. Default target: x86_64-unknown-linux-gnu Host CPU: skylake Registered Targets: aarch64 - AAArch64 (little endian) bpf - BPF (host endian) bpfeb - BPF (big endian) bpfel - BPF (little endian) x86 - 32-bit X86: Pentium-Pro and above x86-64 - 64-bit X86: EM64T and AMD64为使用 LLVM BPF 后端的新特性建议开发者跟踪最新 LLVM 发布——新 BPF 内核特性如指令集扩展的 LLVM 支持往往与内核侧同步开发。6.2 手工构建 LLVM追求最快增量构建的开发者推荐使用 Ninja包管理器中一般为ninja或ninja-build。需要 ninja、cmake 与 g。从 git 仓库构建最新 LLVM/Clang$ git clone https://github.com/llvm/llvm-project.git $ mkdir -p llvm-project/llvm/build $ cd llvm-project/llvm/build $ cmake .. -G Ninja -DLLVM_TARGETS_TO_BUILDBPF;X86 \ -DLLVM_ENABLE_PROJECTSclang \ -DCMAKE_BUILD_TYPERelease \ -DLLVM_BUILD_RUNTIMEOFF $ ninja产物位于build/bin/可将PATH指向该目录。-DLLVM_TARGETS_TO_BUILD设为你需要的目标完整列表见llvm-project/llvm/lib/Target。6.3 报告 LLVM BPF 后端问题LLVM BPF 后端与内核侧 verifier 深度耦合任一侧的问题都需要排查修复。发现LLVM 生成的代码被 verifier 拒绝或 BPF 代码生成缺陷时应当到 netdev 邮件列表提出并 Cc 内核与 LLVM 两侧的开发者Yonghong Song、Alexei Starovoitov、Daniel Borkmann。LLVM 的 issue tracker 中也能检索 BPF 相关 bug但文档建议优先走邮件列表并 Cc 维护者。6.4 新 BPF 指令的内核/LLVM 集成LLVM 的 BPF 后端提供-mcpu选择器以挑选指令集扩展版本LLVM 20 之前默认generic基础指令集v1自 LLVM 20 起默认处理器目标改为指令集v3。-mcpuprobe会让 LLVM 探测宿主内核支持的扩展并自动选择最优集合。交叉编译时可手动指定版本$ llc -march bpf -mcpuhelp Available CPUs for this target: generic - Select the generic processor. probe - Select the probe processor. v1 - Select the v1 processor. v2 - Select the v2 processor. [...]向内核新增 BPF 指令必须遵循同一方案提升指令集版本并实现相应的 probing使-mcpuprobe用户在升级内核后能透明获得优化。若你无法自行实现 LLVM 支持请向 BPF 开发者求助。顺带一提BPF 内核 selftests 使用-mcpuprobe运行以获得更好的测试覆盖——从源码结构看tools/testing/selftests/bpf/Makefile 确实按 clang 支持情况以-mcpuv2/-mcpuv3/-mcpuv4分档编译测试对象例如探测到 v4 支持时启用相应路径。6.5--targetbpf还是默认宿主架构目标尽管 LLVM IR 生成与优化力求架构无关--targetarch仍会影响生成代码BPF 程序可能递归包含带文件作用域内联汇编的宿主头文件默认宿主目标能正确处理而bpf目标在 BPF 后端汇编器不识别这些宿主汇编时会失败大多数情况如此不带-g编译时默认目标可能在目标文件中产生.eh_frame、.rela.eh_frame等额外 ELF 段bpf目标则不会默认目标可能把 C switch 语句优化为跳转表switch table跳转表位于全局只读段会导致 BPF 程序加载失败bpf目标不做该优化。可用-fno-jump-tables关闭跳转表生成--targetbpf保证pointer、long/unsigned long恒为 64 位无论 clang 二进制/默认目标/内核是 32 位还是 64 位而原生目标按宿主架构惯例编译这些类型——在 32 位架构上BPF context 结构中的指针/long 将是 32 位宽而 BPF LLVM 后端始终按 64 位运行。何时用默认目标程序包含最终拉入宿主文件作用域汇编的头文件例如 ptrace.h也可叠加-fno-jump-tables规避跳转表问题。何时必须用bpf目标程序使用含pointer/long/unsigned long字段并与 BPF helper 或 context 数据结构交互的结构体——verifier 会校验对这些结构的访问若宿主架构与 BPF 架构如 64 位不对齐就会校验失败。文档给出的明确例子是BPF_PROG_TYPE_SK_MSG必须使用--targetbpf。原生目标的主要用途是 tracing 中遍历pt_regs或其他依赖 CPU 寄存器宽度的内核结构。除此之外一般推荐clang --targetbpf。结语BPF 子系统的开发协作可以概括为一条清晰的主线bpf 邮件列表是唯一入口bpf/bpf-next 两棵树承担累积与测试patchwork 状态反映审查进度net/net-next 是通向 mainline 的主通道stable 队列由维护者统一代管。开发者的自我要求则是三件事改动 verifier 就补 selftests改动 UAPI 就同步 bpftool 或 iproute2 loader改动指令集就同步所有 JIT 与 LLVM 后端并遵循指令集版本探测方案。做到这些即可按 Documentation/bpf/bpf_devel_QA.rst 的约定顺利参与 BPF 开发——Happy BPF hacking!【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考