Linux 内核 libbpf 编程模型:BPF 程序类型、Attach 类型与 ELF 段名完整指南 📅 发布时间:2026/9/14 11:34:53 👁 浏览次数: 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/functionoffset、tracepoint/category/name、区分可休眠sleepable程序并能结合 libbpf 源码 追溯段名解析的底层实现为 BPF 开发、加载与挂载attach打下坚实基础。一、核心概念程序类型、Attach 类型与 ELF 段名libbpf 是一个用户态库源码位于 tools/lib/bpf 目录负责解析 BPF 对象文件的 ELF 段section、推断程序类型、并通过bpf()系统调用加载和挂载 BPF 程序。开发者在 BPF C 代码中用SEC(...)宏指定段名libbpf 依据段名完成三件事推断程序类型例如段名以xdp开头则推断为BPF_PROG_TYPE_XDP推断 Attach 类型例如cgroup/skb对应BPF_CGROUP_INET_INGRESS/EGRESS执行自动挂载auto-attach段名中的extras部分/之后的内容提供如何挂载的具体细节如SEC(tracepoint/sched/sched_switch)表示挂载到sched类别下的sched_switch追踪点。libbpf 对段名的识别遵循两条基本规则原文档核心内容type为精确匹配段名必须完全等于类型名例如SEC(socket)type表示可扩展匹配既可以是精确的SEC(type)也可以是良构的SEC(type/extras)其中type与extras之间用/分隔。当指定了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_type、expected_attach_type与attach_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/devBPF_PROG_TYPE_CGROUP_SKB无 attach 类型cgroup/skbBPF_CGROUP_INET_EGRESScgroup_skb/egressBPF_CGROUP_INET_INGRESScgroup_skb/ingressBPF_PROG_TYPE_CGROUP_SOCKOPTBPF_CGROUP_GETSOCKOPTcgroup/getsockoptBPF_CGROUP_SETSOCKOPTcgroup/setsockoptBPF_PROG_TYPE_CGROUP_SOCK_ADDRBPF_CGROUP_INET4_BINDcgroup/bind4BPF_CGROUP_INET4_CONNECTcgroup/connect4BPF_CGROUP_INET4_GETPEERNAMEcgroup/getpeername4BPF_CGROUP_INET4_GETSOCKNAMEcgroup/getsockname4BPF_CGROUP_INET6_BINDcgroup/bind6BPF_CGROUP_INET6_CONNECTcgroup/connect6BPF_CGROUP_INET6_GETPEERNAMEcgroup/getpeername6BPF_CGROUP_INET6_GETSOCKNAMEcgroup/getsockname6BPF_CGROUP_UDP4_RECVMSGcgroup/recvmsg4BPF_CGROUP_UDP4_SENDMSGcgroup/sendmsg4BPF_CGROUP_UDP6_RECVMSGcgroup/recvmsg6BPF_CGROUP_UDP6_SENDMSGcgroup/sendmsg6BPF_CGROUP_UNIX_CONNECTcgroup/connect_unixBPF_CGROUP_UNIX_SENDMSGcgroup/sendmsg_unixBPF_CGROUP_UNIX_RECVMSGcgroup/recvmsg_unixBPF_CGROUP_UNIX_GETPEERNAMEcgroup/getpeername_unixBPF_CGROUP_UNIX_GETSOCKNAMEcgroup/getsockname_unixBPF_PROG_TYPE_CGROUP_SOCKBPF_CGROUP_INET4_POST_BINDcgroup/post_bind4BPF_CGROUP_INET6_POST_BINDcgroup/post_bind6BPF_CGROUP_INET_SOCK_CREATEcgroup/sock_create无 attach 类型cgroup/sockBPF_CGROUP_INET_SOCK_RELEASEcgroup/sock_releaseBPF_PROG_TYPE_CGROUP_SYSCTLBPF_CGROUP_SYSCTLcgroup/sysctlBPF_PROG_TYPE_EXT无 attach 类型freplaceBPF_PROG_TYPE_FLOW_DISSECTORBPF_FLOW_DISSECTORflow_dissectorBPF_PROG_TYPE_KPROBE无 attach 类型kprobekretprobeksyscallkretsyscalluprobeuprobe.s是uretprobeuretprobe.s是usdtusdt.s是BPF_TRACE_KPROBE_MULTIkprobe.multikretprobe.multiBPF_TRACE_KPROBE_SESSIONkprobe.sessionBPF_TRACE_UPROBE_MULTIuprobe.multiuprobe.multi.s是uretprobe.multiuretprobe.multi.s是BPF_TRACE_UPROBE_SESSIONuprobe.sessionuprobe.session.s是BPF_PROG_TYPE_LIRC_MODE2BPF_LIRC_MODE2lirc_mode2BPF_PROG_TYPE_LSMBPF_LSM_CGROUPlsm_cgroupBPF_LSM_MAClsmlsm.s是BPF_PROG_TYPE_LWT_IN无 attach 类型lwt_inBPF_PROG_TYPE_LWT_OUTlwt_outBPF_PROG_TYPE_LWT_SEG6LOCALlwt_seg6localBPF_PROG_TYPE_LWT_XMITlwt_xmitBPF_PROG_TYPE_NETFILTERnetfilterBPF_PROG_TYPE_PERF_EVENTperf_eventBPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLEraw_tp.wraw_tracepoint.wBPF_PROG_TYPE_RAW_TRACEPOINTraw_tpraw_tracepointBPF_PROG_TYPE_SCHED_ACTaction已废弃BPF_PROG_TYPE_SCHED_CLSclassifier已废弃tc已废弃BPF_NETKIT_PRIMARYnetkit/primaryBPF_NETKIT_PEERnetkit/peerBPF_TCX_INGRESStc/ingressBPF_TCX_EGRESStc/egressBPF_TCX_INGRESStcx/ingressBPF_TCX_EGRESStcx/egressBPF_PROG_TYPE_SK_LOOKUPBPF_SK_LOOKUPsk_lookupBPF_PROG_TYPE_SK_MSGBPF_SK_MSG_VERDICTsk_msgBPF_PROG_TYPE_SK_REUSEPORTBPF_SK_REUSEPORT_SELECT_OR_MIGRATEsk_reuseport/migrateBPF_SK_REUSEPORT_SELECTsk_reuseportBPF_PROG_TYPE_SK_SKBsk_skbBPF_SK_SKB_STREAM_PARSERsk_skb/stream_parserBPF_SK_SKB_STREAM_VERDICTsk_skb/stream_verdictBPF_PROG_TYPE_SOCKET_FILTERsocketBPF_PROG_TYPE_SOCK_OPSBPF_CGROUP_SOCK_OPSsockopsBPF_PROG_TYPE_STRUCT_OPSstruct_opsstruct_ops.s是BPF_PROG_TYPE_SYSCALLsyscall是BPF_PROG_TYPE_TRACEPOINTtptracepointBPF_PROG_TYPE_TRACINGBPF_MODIFY_RETURNfmod_retfmod_ret.s是BPF_TRACE_FENTRYfentryfentry.s是BPF_TRACE_FEXITfexitfexit.s是BPF_TRACE_FSESSIONfsessionfsession.s是BPF_TRACE_ITERiteriter.s是BPF_TRACE_RAW_TPtp_btfBPF_PROG_TYPE_XDPBPF_XDP_CPUMAPxdp.frags/cpumapxdp/cpumapBPF_XDP_DEVMAPxdp.frags/devmapxdp/devmapBPF_XDPxdp.fragsxdp表格要点解读可休眠Sleepable程序段名中带.s后缀的如uprobe.s、lsm.s、fentry.s、struct_ops.s、iter.s等以及syscall类型程序允许在程序体内调用会睡眠的辅助函数如bpf_spin_lock、bpf_get_stack等需要睡眠上下文的 helper。这是原文档表格中最易被忽略的一列直接使用fentry/fn而写成fentry.s/fn即可获得可休眠能力代价是只能在允许睡眠的上下文中执行。废弃的 TC 段名tc、classifier、action三类传统 TC 挂载段名已被标记废弃官方建议使用tcx/*如tcx/ingress、tcx/egress作为替代。SCHED_CLS类型的新程序应使用BPF_TCX_INGRESS/BPF_TCX_EGRESS或BPF_NETKIT_*attach 类型。XDP 的重定向变体xdp.frags表示该 XDP 程序支持分片fragmentskb 的 XDP 重定向xdp.frags/devmap与xdp.frags/cpumap分别声明程序输出目标为 devmap 或 cpumaplibbpf 据此在加载时正确设置attach_btf_id相关属性。raw_tp与raw_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_KPROBEextras为tcp_v4_connect即要探测的内核函数名。libbpf 加载后调用bpf_program__attach_kprobe()系列 API 完成挂载。函数体内使用BPF_KPROBE宏定义在 tools/lib/bpf/bpf_tracing.h可自动解包PT_REGS_PARM*寄存器参数。3.2 挂载 tracepointSEC(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_CLSBPF_TCX_INGRESSlibbpf 的bpf_program__attach_tcx()会借助 netlink 将程序挂载到指定 netdev 的 tcx ingress hook 上。3.4 加载流程与 skeleton在 samples/bpf 中可以看到大量使用这些段名的示例如xdp_pass、kprobe相关示例。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()段名时的权威依据程序族段名格式规则说明fentry族fentry[.s]/functionextras 为内核函数名.s表示可休眠kprobe族kprobe/function[offset]function的合法字符为a-zA-Z0-9_.offset必须是非负整数如kprobe/finish_task0ksyscall族ksyscall/syscallextras 为系统调用名uprobe族uprobe[.s]/path:function[offset]用户态二进制路径 函数名或符号偏移uprobe.multi族uprobe.multi[.s]/path:function-patternfunction-pattern支持*与?通配符usdt族usdt/path:provider:name三段式目标二进制路径、探针 provider、探针名称kprobe.multi族kprobe.multi/pattern支持*与?通配符合法字符为a-zA-Z0-9_.*?lsmlsm[.s]/hookextras 为 LSM hook 名如lsm/file_open.s表示可休眠raw_tpraw_tracepoint[.w]/tracepoint.w变体为可写类型struct_opsstruct_ops[.s]/namename会被忽略官方建议直接使用SEC(struct_ops)或SEC(struct_ops.s)实际的挂载定义写在标注为SEC(.struct_ops[.link])的结构体初始化器中tracepointtracepoint/category/name类别/名称两级格式iteriter[.s]/struct-nameextras 为被遍历的目标结构体名如iter/task五、与 libbpf 文档体系的衔接本文对应的原文档是 Documentation/bpf/libbpf/program_types.rst它属于 libbpf 用户文档系列总入口见 Documentation/bpf/libbpf/index.rst。建议结合以下仓库资料进一步阅读Documentation/bpf/libbpf/libbpf_overview.rstlibbpf 的整体架构与 API 概览Documentation/bpf/libbpf/libbpf_build.rst如何构建与安装 libbpfDocumentation/bpf/libbpf/libbpf_naming_convention.rstSEC()段命名约定的官方说明tools/lib/bpf/libbpf.hbpf_program__attach_*系列挂载 API 的完整声明include/uapi/linux/bpf.hbpf_prog_type、bpf_attach_type枚举的权威定义samples/bpf各类程序类型的可运行示例。使用前提与限制说明段名与程序类型的映射以当前仓库中 libbpf 源码tools/lib/bpf/elf.c支持为准较新内核版本引入的 attach 类型如kprobe.multi、uprobe.session同时要求运行环境的内核支持对应的bpf_attach_type能力加载时可通过bpf_prog_attach的返回错误判断tc/classifier/action段名仍可用但已废弃新开发应优先采用tcx/*与netkit/*可休眠程序.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),仅供参考