news 2026/9/14 11:34:47

Linux 内核 libbpf 编程模型:BPF 程序类型、Attach 类型与 ELF 段名完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 内核 libbpf 编程模型:BPF 程序类型、Attach 类型与 ELF 段名完整指南

Linux 内核 libbpf 编程模型:BPF 程序类型、Attach 类型与 ELF 段名完整指南

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

本文以 Linux 内核仓库中 libbpf 官方文档《Program Types and ELF Sections》为主体,系统讲解 BPF 程序类型(BPF_PROG_TYPE_*)、Attach 类型与 libbpf 所识别的 ELF 段名(SEC(...))之间的完整对应关系。读完本文,你可以准确写出任意一类 BPF 程序的SEC()段声明,理解extras命名规则(如kprobe/<function>+<offset>tracepoint/<category>/<name>)、区分可休眠(sleepable)程序,并能结合 libbpf 源码 追溯段名解析的底层实现,为 BPF 开发、加载与挂载(attach)打下坚实基础。

一、核心概念:程序类型、Attach 类型与 ELF 段名

libbpf 是一个用户态库(源码位于 tools/lib/bpf 目录),负责解析 BPF 对象文件的 ELF 段(section)、推断程序类型、并通过bpf()系统调用加载和挂载 BPF 程序。开发者在 BPF C 代码中用SEC("...")宏指定段名,libbpf 依据段名完成三件事:

  1. 推断程序类型:例如段名以xdp开头则推断为BPF_PROG_TYPE_XDP
  2. 推断 Attach 类型:例如cgroup/skb对应BPF_CGROUP_INET_INGRESS/EGRESS
  3. 执行自动挂载(auto-attach):段名中的extras部分(/之后的内容)提供如何挂载的具体细节,如SEC("tracepoint/sched/sched_switch")表示挂载到sched类别下的sched_switch追踪点。

libbpf 对段名的识别遵循两条基本规则(原文档核心内容):

  • type为精确匹配:段名必须完全等于类型名,例如SEC("socket")
  • type+表示可扩展匹配:既可以是精确的SEC("type"),也可以是良构的SEC("type/extras"),其中typeextras之间用/分隔。

当指定了extras时,它描述的是“如何自动挂载该 BPF 程序”的细节。extras的格式取决于程序类型,例如 tracepoint 为SEC("tracepoint/<category>/<name>"),USDT 探针为SEC("usdt/<path>:<provider>:<name>")。各类extras的具体格式见本文第四节。

从源码结构看段名解析

在 tools/lib/bpf/elf.c 中,libbpf 通过bpf_object__elf_collect()遍历 ELF 文件的各个 section,根据 section 名前缀匹配程序类型表,并设置bpf_prog结构中的prog_typeexpected_attach_typeattach_prog_name等字段。程序类型的字符串化映射表bpf_prog_type_str定义在 tools/lib/bpf/libbpf.c 附近(如[BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device"),这与 uAPI 头文件 include/uapi/linux/bpf.h 中enum bpf_prog_type的定义一一对应。

二、程序类型与 ELF 段名对照总表

下表完整继承自原文档,列出 libbpf 支持的所有程序类型、对应的 Attach 类型、ELF 段名以及是否支持可休眠(Sleepable)。

程序类型Attach 类型ELF 段名可休眠
BPF_PROG_TYPE_CGROUP_DEVICEBPF_CGROUP_DEVICEcgroup/dev
BPF_PROG_TYPE_CGROUP_SKB(无 attach 类型)cgroup/skb
BPF_CGROUP_INET_EGRESScgroup_skb/egress
BPF_CGROUP_INET_INGRESScgroup_skb/ingress
BPF_PROG_TYPE_CGROUP_SOCKOPTBPF_CGROUP_GETSOCKOPTcgroup/getsockopt
BPF_CGROUP_SETSOCKOPTcgroup/setsockopt
BPF_PROG_TYPE_CGROUP_SOCK_ADDRBPF_CGROUP_INET4_BINDcgroup/bind4
BPF_CGROUP_INET4_CONNECTcgroup/connect4
BPF_CGROUP_INET4_GETPEERNAMEcgroup/getpeername4
BPF_CGROUP_INET4_GETSOCKNAMEcgroup/getsockname4
BPF_CGROUP_INET6_BINDcgroup/bind6
BPF_CGROUP_INET6_CONNECTcgroup/connect6
BPF_CGROUP_INET6_GETPEERNAMEcgroup/getpeername6
BPF_CGROUP_INET6_GETSOCKNAMEcgroup/getsockname6
BPF_CGROUP_UDP4_RECVMSGcgroup/recvmsg4
BPF_CGROUP_UDP4_SENDMSGcgroup/sendmsg4
BPF_CGROUP_UDP6_RECVMSGcgroup/recvmsg6
BPF_CGROUP_UDP6_SENDMSGcgroup/sendmsg6
BPF_CGROUP_UNIX_CONNECTcgroup/connect_unix
BPF_CGROUP_UNIX_SENDMSGcgroup/sendmsg_unix
BPF_CGROUP_UNIX_RECVMSGcgroup/recvmsg_unix
BPF_CGROUP_UNIX_GETPEERNAMEcgroup/getpeername_unix
BPF_CGROUP_UNIX_GETSOCKNAMEcgroup/getsockname_unix
BPF_PROG_TYPE_CGROUP_SOCKBPF_CGROUP_INET4_POST_BINDcgroup/post_bind4
BPF_CGROUP_INET6_POST_BINDcgroup/post_bind6
BPF_CGROUP_INET_SOCK_CREATEcgroup/sock_create
(无 attach 类型)cgroup/sock
BPF_CGROUP_INET_SOCK_RELEASEcgroup/sock_release
BPF_PROG_TYPE_CGROUP_SYSCTLBPF_CGROUP_SYSCTLcgroup/sysctl
BPF_PROG_TYPE_EXT(无 attach 类型)freplace+
BPF_PROG_TYPE_FLOW_DISSECTORBPF_FLOW_DISSECTORflow_dissector
BPF_PROG_TYPE_KPROBE(无 attach 类型)kprobe+
kretprobe+
ksyscall+
kretsyscall+
uprobe+
uprobe.s+
uretprobe+
uretprobe.s+
usdt+
usdt.s+
BPF_TRACE_KPROBE_MULTIkprobe.multi+
kretprobe.multi+
BPF_TRACE_KPROBE_SESSIONkprobe.session+
BPF_TRACE_UPROBE_MULTIuprobe.multi+
uprobe.multi.s+
uretprobe.multi+
uretprobe.multi.s+
BPF_TRACE_UPROBE_SESSIONuprobe.session+
uprobe.session.s+
BPF_PROG_TYPE_LIRC_MODE2BPF_LIRC_MODE2lirc_mode2
BPF_PROG_TYPE_LSMBPF_LSM_CGROUPlsm_cgroup+
BPF_LSM_MAClsm+
lsm.s+
BPF_PROG_TYPE_LWT_IN(无 attach 类型)lwt_in
BPF_PROG_TYPE_LWT_OUTlwt_out
BPF_PROG_TYPE_LWT_SEG6LOCALlwt_seg6local
BPF_PROG_TYPE_LWT_XMITlwt_xmit
BPF_PROG_TYPE_NETFILTERnetfilter
BPF_PROG_TYPE_PERF_EVENTperf_event
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLEraw_tp.w+
raw_tracepoint.w+
BPF_PROG_TYPE_RAW_TRACEPOINTraw_tp+
raw_tracepoint+
BPF_PROG_TYPE_SCHED_ACTaction(已废弃)
BPF_PROG_TYPE_SCHED_CLSclassifier(已废弃)
tc(已废弃)
BPF_NETKIT_PRIMARYnetkit/primary
BPF_NETKIT_PEERnetkit/peer
BPF_TCX_INGRESStc/ingress
BPF_TCX_EGRESStc/egress
BPF_TCX_INGRESStcx/ingress
BPF_TCX_EGRESStcx/egress
BPF_PROG_TYPE_SK_LOOKUPBPF_SK_LOOKUPsk_lookup
BPF_PROG_TYPE_SK_MSGBPF_SK_MSG_VERDICTsk_msg
BPF_PROG_TYPE_SK_REUSEPORTBPF_SK_REUSEPORT_SELECT_OR_MIGRATEsk_reuseport/migrate
BPF_SK_REUSEPORT_SELECTsk_reuseport
BPF_PROG_TYPE_SK_SKBsk_skb
BPF_SK_SKB_STREAM_PARSERsk_skb/stream_parser
BPF_SK_SKB_STREAM_VERDICTsk_skb/stream_verdict
BPF_PROG_TYPE_SOCKET_FILTERsocket
BPF_PROG_TYPE_SOCK_OPSBPF_CGROUP_SOCK_OPSsockops
BPF_PROG_TYPE_STRUCT_OPSstruct_ops+
struct_ops.s+
BPF_PROG_TYPE_SYSCALLsyscall
BPF_PROG_TYPE_TRACEPOINTtp+
tracepoint+
BPF_PROG_TYPE_TRACINGBPF_MODIFY_RETURNfmod_ret+
fmod_ret.s+
BPF_TRACE_FENTRYfentry+
fentry.s+
BPF_TRACE_FEXITfexit+
fexit.s+
BPF_TRACE_FSESSIONfsession+
fsession.s+
BPF_TRACE_ITERiter+
iter.s+
BPF_TRACE_RAW_TPtp_btf+
BPF_PROG_TYPE_XDPBPF_XDP_CPUMAPxdp.frags/cpumap
xdp/cpumap
BPF_XDP_DEVMAPxdp.frags/devmap
xdp/devmap
BPF_XDPxdp.frags
xdp

表格要点解读

  1. 可休眠(Sleepable)程序:段名中带.s后缀的(如uprobe.slsm.sfentry.sstruct_ops.siter.s等)以及syscall类型程序,允许在程序体内调用会睡眠的辅助函数(如bpf_spin_lockbpf_get_stack等需要睡眠上下文的 helper)。这是原文档表格中最易被忽略的一列,直接使用fentry/<fn>而写成fentry.s/<fn>即可获得可休眠能力,代价是只能在允许睡眠的上下文中执行。
  2. 废弃的 TC 段名tcclassifieraction三类传统 TC 挂载段名已被标记废弃,官方建议使用tcx/*(如tcx/ingresstcx/egress)作为替代。SCHED_CLS类型的新程序应使用BPF_TCX_INGRESS/BPF_TCX_EGRESSBPF_NETKIT_*attach 类型。
  3. XDP 的重定向变体xdp.frags表示该 XDP 程序支持分片(fragment)skb 的 XDP 重定向;xdp.frags/devmapxdp.frags/cpumap分别声明程序输出目标为 devmap 或 cpumap,libbpf 据此在加载时正确设置attach_btf_id相关属性。
  4. raw_tpraw_tp.w:不带.w的段名映射到BPF_PROG_TYPE_RAW_TRACEPOINT(只读,不能修改原始追踪点的上下文),带.w的段名映射到BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,可在程序内修改追踪点上下文参数。

三、典型场景:从SEC()声明到自动挂载

下面以几个常见场景说明段名如何驱动 libbpf 的自动挂载行为。

3.1 挂载 kprobe 到内核函数

SEC("kprobe/tcp_v4_connect") int BPF_KPROBE(handle_connect, struct sock *sk) { return 0; }

段名kprobe/tcp_v4_connect中:kprobe精确匹配程序类型BPF_PROG_TYPE_KPROBEextrastcp_v4_connect,即要探测的内核函数名。libbpf 加载后调用bpf_program__attach_kprobe()系列 API 完成挂载。函数体内使用BPF_KPROBE宏(定义在 tools/lib/bpf/bpf_tracing.h)可自动解包PT_REGS_PARM*寄存器参数。

3.2 挂载 tracepoint

SEC("tracepoint/sched/sched_switch") int handle(struct trace_event_raw_sched_switch *ctx) { return 0; }

extras 采用<category>/<name>格式,sched/sched_switch对应内核追踪点目录中的类别与名称(可用/sys/kernel/tracing/events/查看当前系统实际存在的追踪点)。

3.3 TCX 网络分类程序

SEC("tcx/ingress") struct __sk_buff *handle_ingress(struct __sk_buff *skb) { return skb; }

段名前缀tcx/ingress会被推断为BPF_PROG_TYPE_SCHED_CLS+BPF_TCX_INGRESS,libbpf 的bpf_program__attach_tcx()会借助 netlink 将程序挂载到指定 netdev 的 tcx ingress hook 上。

3.4 加载流程与 skeleton

在 samples/bpf 中可以看到大量使用这些段名的示例(如xdp_passkprobe相关示例)。libbpf 提供的 skeleton 机制(由bpftool gen skeleton生成,核心逻辑在 tools/lib/bpf/skel_internal.h)会把每个段的类型与 attach 信息固化到 skeleton 头文件里,用户态只需调用bpf_object__load()即可完成“解析 → 加载 → 挂载”全流程。段名解析的关键入口在 tools/lib/bpf/elf.c 中的 section 类型推断函数族,程序类型到上下文类型名的映射表(如[BPF_PROG_TYPE_CGROUP_DEVICE] -> "bpf_cgroup_dev_ctx")位于 tools/lib/bpf/libbpf.c。

四、extras挂载格式详解(原文档脚注全集)

以下为原文档全部脚注对应的挂载格式规则,是编写SEC()段名时的权威依据:

程序族段名格式规则说明
fentryfentry[.s]/<function>extras 为内核函数名,.s表示可休眠
kprobekprobe/<function>[+<offset>]function的合法字符为a-zA-Z0-9_.offset必须是非负整数(如kprobe/finish_task+0
ksyscallksyscall/<syscall>extras 为系统调用名
uprobeuprobe[.s]/<path>:<function>[+<offset>]用户态二进制路径 + 函数名(或符号偏移)
uprobe.multiuprobe.multi[.s]/<path>:<function-pattern>function-pattern支持*?通配符
usdtusdt/<path>:<provider>:<name>三段式:目标二进制路径、探针 provider、探针名称
kprobe.multikprobe.multi/<pattern>支持*?通配符;合法字符为a-zA-Z0-9_.*?
lsmlsm[.s]/<hook>extras 为 LSM hook 名(如lsm/file_open),.s表示可休眠
raw_tpraw_tracepoint[.w]/<tracepoint>.w变体为可写类型
struct_opsstruct_ops[.s]/<name>name会被忽略,官方建议直接使用SEC("struct_ops")SEC("struct_ops.s");实际的挂载定义写在标注为SEC(".struct_ops[.link]")的结构体初始化器中
tracepointtracepoint/<category>/<name>类别/名称两级格式
iteriter[.s]/<struct-name>extras 为被遍历的目标结构体名(如iter/task

五、与 libbpf 文档体系的衔接

本文对应的原文档是 Documentation/bpf/libbpf/program_types.rst,它属于 libbpf 用户文档系列(总入口见 Documentation/bpf/libbpf/index.rst)。建议结合以下仓库资料进一步阅读:

  • Documentation/bpf/libbpf/libbpf_overview.rst:libbpf 的整体架构与 API 概览;
  • Documentation/bpf/libbpf/libbpf_build.rst:如何构建与安装 libbpf;
  • Documentation/bpf/libbpf/libbpf_naming_convention.rst:SEC()段命名约定的官方说明;
  • tools/lib/bpf/libbpf.h:bpf_program__attach_*系列挂载 API 的完整声明;
  • include/uapi/linux/bpf.h:bpf_prog_typebpf_attach_type枚举的权威定义;
  • samples/bpf:各类程序类型的可运行示例。

使用前提与限制说明

  1. 段名与程序类型的映射以当前仓库中 libbpf 源码(tools/lib/bpf/elf.c)支持为准;较新内核版本引入的 attach 类型(如kprobe.multiuprobe.session)同时要求运行环境的内核支持对应的bpf_attach_type能力,加载时可通过bpf_prog_attach的返回错误判断;
  2. tc/classifier/action段名仍可用但已废弃,新开发应优先采用tcx/*netkit/*
  3. 可休眠程序(.s段名)只能挂载在允许睡眠的上下文(如 LSM hook、uprobe 路径),挂载到不支持睡眠的 hook 会导致加载或挂载失败。

六、小结

libbpf 的“程序类型 + attach 类型 + ELF 段名”三元组是 BPF 开发的基础心智模型:SEC()段名是唯一入口,libbpf 依据前缀精确匹配或type+可扩展匹配推断程序类型,再解析extras决定自动挂载目标。本文完整给出了全部类型对照表、extras挂载格式规则(含可休眠变体)以及tcx替代传统tc段名的迁移建议,并指回了 tools/lib/bpf 源码中可追溯的实现位置,可作为 BPF 段名编写时的速查手册与深入源码阅读的起点。

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 11:31:39

构建 kt-kernel 时 CMake 报 “CUDA compiler not found“ 怎么修复?

构建 kt-kernel 时 CMake 报 "CUDA compiler not found" 怎么修复&#xff1f; 【免费下载链接】ktransformers A Flexible Framework for Experiencing Heterogeneous LLM Inference/Fine-tune Optimizations 项目地址: https://gitcode.com/GitHub_Trending/ktr/…

作者头像 李华
网站建设 2026/9/14 11:28:41

SpringBoot酒店预约系统开发实战与优化

1. 项目概述&#xff1a;SpringBoot酒店预约系统开发实录 去年接手的一个酒店管理系统项目让我对SpringBoot在实际业务中的应用有了全新认识。这个基于SpringBoot 2.7的酒店预约系统&#xff0c;从需求分析到上线部署共耗时三个月&#xff0c;期间踩过的坑和积累的经验值得系统…

作者头像 李华