当前位置:首页>Linux>Linux 内核 eBPF 程序挂载点与执行分析

Linux 内核 eBPF 程序挂载点与执行分析

  • 2026-06-27 16:40:29
Linux 内核 eBPF 程序挂载点与执行分析

本文总结内核中各种 eBPF 程序类型的挂载点 (attach point)、执行入口、核心调用流程。


    1. 总体架构概览

    eBPF 程序的挂载和执行在 Linux 内核中遵循一个统一的模式:

    用户态工具 (bpftool / libbpf) 
        │
        │ BPF_PROG_LOAD (加载 & 验证)
        ▼
      BPF syscall (kernel/bpf/syscall.c)
        │
        │ link_create() / BPF_RAW_TRACEPOINT_OPEN / perf_event_open
        ▼
      Attach Logic (根据 prog_type 分发到不同子系统)
        │
        ├── bpf_tracing_prog_attach()     → trampoline (fentry/fexit/lsm)
        ├── cgroup_bpf_link_attach()      → cgroup BPF array
        ├── bpf_xdp_link_attach()         → net_device XDP prog
        ├── bpf_perf_link_attach()        → perf_event / kprobe
        ├── bpf_kprobe_multi_link_attach()→ fprobe
        ├── bpf_nf_link_attach()          → netfilter hook
        ├── tcx_link_attach()             → TC ingress/egress
        ├── netns_bpf_link_create()       → netns (sk_lookup/flow_dissector)
        ├── bpf_struct_ops_link_create()  → struct_ops map
        └── sock_map_link_create()        → sockmap
        │
        ▼
      Runtime Execution (内核执行流触发)
        │
        ├── bpf_prog_run() / __bpf_prog_run()          → 直接执行 JIT/解释器
        ├── bpf_prog_run_array()                       → 遍历 prog 数组执行
        ├── trampoline (__bpf_prog_enter + call)       → fentry/fexit/lsm
        └── bpf_prog_run_pin_on_cpu()                  → 绑定 CPU 执行

    2. eBPF 程序类型与挂载类型映射表

    2.1 程序类型定义

    内核中定义了十几种 bpf_prog_type 和几十种 bpf_attach_type。

    // include/uapi/linux/bpf.h: 1040-1074
    enum bpf_prog_type {
        BPF_PROG_TYPE_UNSPEC,              // 0
        BPF_PROG_TYPE_SOCKET_FILTER,       // 1  经典 socket filter
        BPF_PROG_TYPE_KPROBE,              // 2  kprobe / kprobe_multi
        BPF_PROG_TYPE_SCHED_CLS,           // 3  TC cls/act, TCX, Netkit
        BPF_PROG_TYPE_SCHED_ACT,           // 4  TC action (已废弃,合并到 SCHED_CLS)
        BPF_PROG_TYPE_TRACEPOINT,          // 5  静态 tracepoint
        BPF_PROG_TYPE_XDP,                 // 6  XDP: native/offload/generic
        BPF_PROG_TYPE_PERF_EVENT,          // 7  perf_event (uprobe/uretprobe)
        BPF_PROG_TYPE_CGROUP_SKB,          // 8  cgroup ingress/egress
        BPF_PROG_TYPE_CGROUP_SOCK,         // 9  cgroup sock_create/sock_release
        BPF_PROG_TYPE_LWT_IN,              // 10 轻量级隧道 ingress
        BPF_PROG_TYPE_LWT_OUT,             // 11 轻量级隧道 egress
        BPF_PROG_TYPE_LWT_XMIT,            // 12 轻量级隧道 transmit
        BPF_PROG_TYPE_SOCK_OPS,            // 13 TCP sock ops
        BPF_PROG_TYPE_SK_SKB,              // 14 sockmap stream parser/verdict
        BPF_PROG_TYPE_CGROUP_DEVICE,       // 15 cgroup device 访问控制
        BPF_PROG_TYPE_SK_MSG,              // 16 sockmap message verdict/redirect
        BPF_PROG_TYPE_RAW_TRACEPOINT,      // 17 raw tracepoint
        BPF_PROG_TYPE_CGROUP_SOCK_ADDR,    // 18 cgroup bind/connect/sendmsg/recvmsg
        BPF_PROG_TYPE_LWT_SEG6LOCAL,       // 19 SRv6 local endpoint
        BPF_PROG_TYPE_LIRC_MODE2,          // 20 红外遥控
        BPF_PROG_TYPE_SK_REUSEPORT,        // 21 SO_REUSEPORT 选择/迁移
        BPF_PROG_TYPE_FLOW_DISSECTOR,      // 22 flow dissector
        BPF_PROG_TYPE_CGROUP_SYSCTL,       // 23 cgroup sysctl
        BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, // 24 可写 raw tracepoint
        BPF_PROG_TYPE_CGROUP_SOCKOPT,      // 25 cgroup getsockopt/setsockopt
        BPF_PROG_TYPE_TRACING,             // 26 fentry/fexit/fmod_ret
        BPF_PROG_TYPE_STRUCT_OPS,          // 27 struct_ops (TCP CC 等)
        BPF_PROG_TYPE_EXT,                 // 28 freplace (程序替换)
        BPF_PROG_TYPE_LSM,                 // 29 Linux Security Module
        BPF_PROG_TYPE_SK_LOOKUP,           // 30 socket lookup 重定向
        BPF_PROG_TYPE_SYSCALL,             // 31 可在 BPF 中调用 syscall
        BPF_PROG_TYPE_NETFILTER,           // 32 netfilter hook
        __MAX_BPF_PROG_TYPE
    };

    2.2 挂载类型定义

    // include/uapi/linux/bpf.h: 1077-1136
    enum bpf_attach_type {
        BPF_CGROUP_INET_INGRESS,           // cgroup ingress
        BPF_CGROUP_INET_EGRESS,            // cgroup egress
        BPF_CGROUP_INET_SOCK_CREATE,       // cgroup socket create
        BPF_CGROUP_SOCK_OPS,               // cgroup sock ops
        BPF_SK_SKB_STREAM_PARSER,          // sockmap stream parser
        BPF_SK_SKB_STREAM_VERDICT,         // sockmap stream verdict
        BPF_CGROUP_DEVICE,                 // cgroup device
        BPF_SK_MSG_VERDICT,                // sk_msg verdict
        BPF_CGROUP_INET4_BIND,             // cgroup IPv4 bind
        BPF_CGROUP_INET6_BIND,             // cgroup IPv6 bind
        BPF_CGROUP_INET4_CONNECT,          // cgroup IPv4 connect
        BPF_CGROUP_INET6_CONNECT,          // cgroup IPv6 connect
        BPF_CGROUP_INET4_POST_BIND,        // cgroup IPv4 post-bind
        BPF_CGROUP_INET6_POST_BIND,        // cgroup IPv6 post-bind
        BPF_CGROUP_UDP4_SENDMSG,           // cgroup UDPv4 sendmsg
        BPF_CGROUP_UDP6_SENDMSG,           // cgroup UDPv6 sendmsg
        BPF_LIRC_MODE2,                    // LIRC
        BPF_FLOW_DISSECTOR,                // flow dissector
        BPF_CGROUP_SYSCTL,                 // cgroup sysctl
        BPF_CGROUP_UDP4_RECVMSG,           // cgroup UDPv4 recvmsg
        BPF_CGROUP_UDP6_RECVMSG,           // cgroup UDPv6 recvmsg
        BPF_CGROUP_GETSOCKOPT,             // cgroup getsockopt
        BPF_CGROUP_SETSOCKOPT,             // cgroup setsockopt
        BPF_TRACE_RAW_TP,                  // raw tracepoint
        BPF_TRACE_FENTRY,                  // fentry
        BPF_TRACE_FEXIT,                   // fexit
        BPF_MODIFY_RETURN,                 // fmod_ret
        BPF_LSM_MAC,                       // LSM MAC hook
        BPF_TRACE_ITER,                    // BPF iterator
        BPF_CGROUP_INET4_GETPEERNAME,      // cgroup getpeername
        BPF_CGROUP_INET6_GETPEERNAME,
        BPF_CGROUP_INET4_GETSOCKNAME,      // cgroup getsockname
        BPF_CGROUP_INET6_GETSOCKNAME,
        BPF_XDP_DEVMAP,                    // XDP devmap 程序
        BPF_CGROUP_INET_SOCK_RELEASE,      // cgroup sock release
        BPF_XDP_CPUMAP,                    // XDP cpumap 程序
        BPF_SK_LOOKUP,                     // sk_lookup
        BPF_XDP,                           // XDP 程序
        BPF_SK_SKB_VERDICT,                // sk_skb verdict (sockmap)
        BPF_SK_REUSEPORT_SELECT,           // reuseport select
        BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,// reuseport migrate
        BPF_PERF_EVENT,                    // perf_event (kprobe/uprobe 传统方式)
        BPF_TRACE_KPROBE_MULTI,            // kprobe_multi
        BPF_LSM_CGROUP,                    // LSM cgroup
        BPF_STRUCT_OPS,                    // struct_ops
        BPF_NETFILTER,                     // netfilter
        BPF_TCX_INGRESS,                   // TCX ingress
        BPF_TCX_EGRESS,                    // TCX egress
        BPF_TRACE_UPROBE_MULTI,            // uprobe_multi
        BPF_CGROUP_UNIX_CONNECT,           // cgroup UNIX connect
        BPF_CGROUP_UNIX_SENDMSG,           // cgroup UNIX sendmsg
        BPF_CGROUP_UNIX_RECVMSG,           // cgroup UNIX recvmsg
        BPF_CGROUP_UNIX_GETPEERNAME,       // cgroup UNIX getpeername
        BPF_CGROUP_UNIX_GETSOCKNAME,       // cgroup UNIX getsockname
        BPF_NETKIT_PRIMARY,                // Netkit primary
        BPF_NETKIT_PEER,                   // Netkit peer
        BPF_TRACE_KPROBE_SESSION,          // kprobe session
        BPF_TRACE_UPROBE_SESSION,          // uprobe session
    };

    2.3 程序类型与挂载点/执行入口完整对应表

    prog_type
    attach_type
    挂载 / 执行入口
    关键文件
    KPROBEPERF_EVENTperf_event_create_kernel_counter
     → BPF callback
    kernel/events/core.c
    KPROBETRACE_KPROBE_MULTI
    fprobe → kprobe_multi_link_handler()
    kernel/trace/bpf_trace.c
    KPROBETRACE_KPROBE_SESSION
    fprobe + session cookie
    kernel/trace/bpf_trace.c
    KPROBETRACE_UPROBE_MULTI
    uprobe_multi link handler
    kernel/trace/bpf_trace.c
    PERF_EVENTPERF_EVENT
    perf_event callback / perf_trace_run_bpf_submit()
    kernel/events/core.c
    include/trace/perf.h
    TRACEPOINTPERF_EVENTtrace_call_bpf()
     / perf_trace_run_bpf_submit()
    kernel/trace/bpf_trace.c
    RAW_TRACEPOINTTRACE_RAW_TPbpf_trace_runX()
     宏展开 → __bpf_trace_run()
    kernel/trace/bpf_trace.c
    TRACINGTRACE_FENTRY
    trampoline: __bpf_prog_enter → prog→bpf_func
    kernel/bpf/trampoline.c
    arch/x86/net/bpf_jit_comp.c
    TRACINGTRACE_FEXIT
    trampoline: fentry_progs + orig_func + fexit_progs
    同上
    TRACINGMODIFY_RETURN
    trampoline: modify return value of target func
    同上
    EXT
    (fentry/fexit)
    通过 trampoline 替换/扩展已有 BPF prog
    kernel/bpf/trampoline.c
    LSMLSM_MAC
    trampoline → LSM static_call hooks
    security/security.c
    kernel/bpf/bpf_lsm.c
    LSMLSM_CGROUP
    cgroup BPF array + bpf_prog_run_array_cg()
    kernel/bpf/cgroup.c
    STRUCT_OPSSTRUCT_OPS
    内核 struct 函数指针(如 tcp_congestion_ops
    kernel/bpf/bpf_struct_ops.c
    net/ipv4/bpf_tcp_ca.c
    XDPXDP
    驱动 NAPI → bpf_prog_run_xdp() / bpf_prog_run_generic_xdp()
    include/net/xdp.h
    net/core/dev.c
    XDPXDP_DEVMAP
    devmap redirect → BPF prog on target dev
    kernel/bpf/devmap.c
    XDPXDP_CPUMAP
    cpumap redirect to per-CPU processing
    kernel/bpf/cpumap.c
    SCHED_CLSTCX_INGRESSsch_handle_ingress()
     → tcx_run()
    net/core/dev.c
    SCHED_CLSTCX_EGRESSsch_handle_egress()
     → tcx_run()
    net/core/dev.c
    SCHED_CLSNETKIT_PRIMARY/PEER
    netkit virtual device egress
    drivers/net/netkit.c
    CGROUP_SKBINET_INGRESS__cgroup_bpf_run_filter_skb(sk, skb, CGROUP_INET_INGRESS)net/core/filter.c:150
    CGROUP_SKBINET_EGRESS__cgroup_bpf_run_filter_skb(sk, skb, CGROUP_INET_EGRESS)net/ipv4/ip_output.c:320
    CGROUP_SOCKINET_SOCK_CREATE
    创建 socket 时调用 BPF_CGROUP_RUN_PROG_INET_SOCK()
    net/ipv4/af_inet.c
    CGROUP_SOCKINET_SOCK_RELEASE
    socket 释放时调用
    cgroup attach framework
    CGROUP_SOCK_ADDRINET4_BIND
     等
    bind/connect/sendmsg/recvmsg/get{peer,sock}name 调用点
    各网络协议栈文件
    CGROUP_SOCKOPTGETSOCKOPT/SETSOCKOPT__cgroup_bpf_run_filter_{get,set}sockopt()kernel/bpf/cgroup.c
    SOCK_OPSCGROUP_SOCK_OPS
    TCP 状态机各阶段 → BPF_CGROUP_RUN_PROG_SOCK_OPS()
    net/ipv4/tcp_input.c:177
    CGROUP_SYSCTLCGROUP_SYSCTL
    sysctl 读写时 __cgroup_bpf_run_filter_sysctl()
    kernel/bpf/cgroup.c
    CGROUP_DEVICECGROUP_DEVICE
    设备访问时 __cgroup_bpf_run_filter_dev()
    kernel/bpf/cgroup.c
    SOCKET_FILTER
    (n/a)
    sk_filter_trim_cap()
     → bpf_prog_run_save_cb()
    net/core/filter.c:134
    SK_SKBSTREAM_PARSER/VERDICT
    sockmap: 数据流入流出时触发
    net/core/skmsg.c
    net/core/sock_map.c
    SK_MSGSK_MSG_VERDICT
    sockmap: sendmsg 触发
    net/core/skmsg.c
    SK_LOOKUPSK_LOOKUPbpf_sk_lookup_run_v4/v6()
     → __inet_lookup_listener() 等
    include/linux/filter.h:1664
    SK_REUSEPORTREUSEPORT_SELECTreuseport_select_sock()
     → run_bpf_filter()
    net/core/sock_reuseport.c:568
    FLOW_DISSECTORFLOW_DISSECTOR__skb_flow_dissect()
     → BPF prog
    net/core/flow_dissector.c
    NETFILTERNETFILTERnf_hook_run_bpf()
     → netfilter hook
    net/netfilter/nf_bpf_link.c:11
    LWT_IN/OUT/XMIT
    (n/a)
    轻量级隧道 ingress/egress/xmit
    net/core/lwt_bpf.c
    SYSCALL
    (n/a)
    在 BPF 中通过 bpf_sys_bpf() helper 执行
    kernel/bpf/syscall.c
     (helper)

    3. 核心执行引擎

    所有 eBPF 程序的最终执行都经过以下几个核心函数。

    3.1 __bpf_prog_run —— 最底层执行入口

    // include/linux/filter.h: 697-721
    // 所有 bpf_prog_run* 函数的共同底层
    static __always_inline u32 __bpf_prog_run(const struct bpf_prog *prog,
    constvoid *ctx,
                                              bpf_dispatcher_fn dfunc)
    {
        u32 ret;
        cant_migrate();
    if (static_branch_unlikely(&bpf_stats_enabled_key)) {
    structbpf_prog_stats *stats;
            u64 duration, start = sched_clock();
            ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
            duration = sched_clock() - start;
            stats = this_cpu_ptr(prog->stats);
    // ... update stats ...
        } else {
            ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
        }
    return ret;
    }

    关键点prog->bpf_func 是 JIT 编译后的二进制代码入口;若未 JIT 则走解释器路径。dfunc 是分发器函数(bpf_dispatcher_nop_func 或 BPF_DISPATCHER_FUNC)。

    3.2 bpf_prog_run —— 最常用的程序执行接口

    // include/linux/filter.h: 723-726
    static __always_inline u32 bpf_prog_run(const struct bpf_prog *prog, constvoid *ctx)
    {
    return __bpf_prog_run(prog, ctx, bpf_dispatcher_nop_func);
    }

    3.3 bpf_prog_run_array —— 遍历多个程序顺序执行

    // include/linux/bpf.h: 2271-2298
    static __always_inline u32
    bpf_prog_run_array(const struct bpf_prog_array *array,
    constvoid *ctx, bpf_prog_run_fn run_prog)

    {
    conststructbpf_prog_array_item *item;
    conststructbpf_prog *prog;
    structbpf_run_ctx *old_run_ctx;
    structbpf_trace_run_ctxrun_ctx;
        u32 ret = 1;

        RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "no rcu lock held");
    if (unlikely(!array))
    return ret;

        migrate_disable();
        old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
        item = &array->items[0];
    while ((prog = READ_ONCE(item->prog))) {
            run_ctx.bpf_cookie = item->bpf_cookie;
            ret &= run_prog(prog, ctx);      // 结果按位与!
            item++;
        }
        bpf_reset_run_ctx(old_run_ctx);
        migrate_enable();
    return ret;
    }

    典型用法:

    ret = bpf_prog_run_array(rcu_dereference(&bpf_prog_array), ctx, bpf_prog_run);

    此函数是 cgroup、tracepoint、kprobe_multi 等多个子系统的核心调度函数。所有程序的返回值做按位与(ret &= run_prog(...))处理——只要有一个程序返回 0,最终结果就是 0。

    3.4 Trampoline 执行引擎 —— fentry / fexit / lsm / modify_return

    Trampoline 是最复杂的执行路径,它动态生成汇编代码,在目标函数前后插入 BPF 程序的调用。

    // kernel/bpf/trampoline.c: 886-893
    /* The logic is similar to bpf_prog_run(), but with an explicit
     * rcu_read_lock() and migrate_disable() which are required
     * for the trampoline. The macro is split into
     * call __bpf_prog_enter
     * call prog->bpf_func
     * call __bpf_prog_exit
     *
     * __bpf_prog_enter returns:
     * 0 - skip execution of the bpf prog
     * 1 - execute bpf prog
     * [2..MAX_U64] - execute bpf prog and record execution time.
     */

    FENTRY trampoline 汇编结构 (x86):

    push rbp
    mov rbp, rsp
    sub rsp, frame_size       // 分配栈帧,保存 ctx 参数
    push rbx
    // 保存原始函数参数到栈上

    // === 每个 fentry prog 执行 ===
    call __bpf_prog_enter     // rcu_read_lock + migrate_disable
    mov rbx, rax              // 保存 start_time
    test rax, rax             // 检查是否应该跳过
    je skip_prog              // 重入检测失败 → 跳过
    lea rdi, [rbp - frame_size]  // R1 = ctx
    call prog->bpf_func       // 调用 JIT 后的 BPF 程序
    call __bpf_prog_exit      // rcu_read_unlock + migrate_enable + stats
    // === prog 执行结束 ===

    // ==== 调用原始函数 ====
    call original_func+5      // 跳过 ftrace nop,调用被 hook 的函数体

    // === 每个 fexit prog 执行 === (结构同上)
    // ...

    leave
    ret

    同步保护机制:trampoline 对每个程序提供三种 enter 策略:

    // kernel/bpf/trampoline.c: 1065-1078
    bpf_trampoline_enter_tbpf_trampoline_enter(const struct bpf_prog *prog)
    {
    if (bpf_prog_check_recur(prog))
    return sleepable ? __bpf_prog_enter_sleepable_recur :
                __bpf_prog_enter_recur;   // 可重入程序:带 recursion counter

    if (resolve_prog_type(prog) == BPF_PROG_TYPE_LSM &&
            prog->expected_attach_type == BPF_LSM_CGROUP)
    return __bpf_prog_enter_lsm_cgroup;  // LSM cgroup 特殊路径

    return sleepable ? __bpf_prog_enter_sleepable : __bpf_prog_enter;
    // sleepable 使用 rcu_read_lock_trace(),否则使用 rcu_read_lock()
    }

    4. 分类一:Tracing 类

    追踪类 BPF 程序覆盖内核的观测/调试/性能分析场景。

    4.1 KPROBE / KPROBE_MULTI

    挂载路径

    // kernel/bpf/syscall.c: 5608-5617 (link_create 中的分发)
    case BPF_PROG_TYPE_KPROBE:
    if (attr->link_create.attach_type == BPF_PERF_EVENT)
            ret = bpf_perf_link_attach(attr, prog);          // 传统 perf kprobe
    elseif (attr->link_create.attach_type == BPF_TRACE_KPROBE_MULTI ||
                 attr->link_create.attach_type == BPF_TRACE_KPROBE_SESSION)
            ret = bpf_kprobe_multi_link_attach(attr, prog);   // kprobe_multi
    elseif (attr->link_create.attach_type == BPF_TRACE_UPROBE_MULTI ||
                 attr->link_create.attach_type == BPF_TRACE_UPROBE_SESSION)
            ret = bpf_uprobe_multi_link_attach(attr, prog);   // uprobe_multi
    break;

    执行入口 1 —— 传统 perf_event kprobe

    kprobe ftrace callback → perf_trace_buf_submit() → trace_call_bpf()
    // kernel/trace/bpf_trace.c: 110-140
    unsignedinttrace_call_bpf(struct trace_event_call *call, void *ctx)
    {
    unsignedint ret;
        cant_sleep();
    if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1)) {
    // 同一 CPU 已有 BPF 程序在运行,跳过(防止无限递归)
            rcu_read_lock();
            bpf_prog_inc_misses_counters(rcu_dereference(call->prog_array));
            rcu_read_unlock();
            ret = 0;
    goto out;
        }
    // 通过 perf_trace_buf_submit 调用
    // ...
    }

    执行入口 2 —— kprobe_multi (基于 fprobe)

    // kernel/trace/bpf_trace.c: 2752-2764
    staticintkprobe_multi_link_handler(struct fprobe *fp, unsignedlong fentry_ip,
    unsignedlong ret_ip, struct ftrace_regs *fregs,
    void *data)

    {
    structbpf_kprobe_multi_link *link;
        link = container_of(fp, struct bpf_kprobe_multi_link, fp);
    // ...
        err = kprobe_multi_link_prog_run(link, ftrace_get_entry_ip(fentry_ip), ...);
    // ...
    }

    // kernel/trace/bpf_trace.c: 2715-2749
    staticintkprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
    unsignedlong entry_ip, ...)

    {
    structbpf_kprobe_multi_run_ctxrun_ctx = { ... };
    // ...
        migrate_disable();
        rcu_read_lock();
        regs = ftrace_partial_regs(fregs, bpf_kprobe_multi_pt_regs_ptr());
        old_run_ctx = bpf_set_run_ctx(&run_ctx.session_ctx.run_ctx);
        err = bpf_prog_run(link->link.prog, regs);   // ctx = pt_regs
        bpf_reset_run_ctx(old_run_ctx);
        rcu_read_unlock();
        migrate_enable();
    return err;
    }

    性能优势: kprobe_multi 基于 fprobe(批量 ftrace hook),一次注册可以挂载到多个函数,比逐个注册 perf_event kprobe 效率更高。

    调用流程 (kprobe)

    内核函数入口指令
      │
      │ ftrace (nop → call)
      ▼
    ftrace 回调
      │
      ├─[传统 kprobe]
      │   kprobe 处理 → kretprobe_handler / pre_handler
      │     └─ perf_trace_buf_submit(perf_call_bpf_enter)
      │         └─ trace_call_bpf(call, regs)
      │             └─ bpf_prog_run_array(array, regs, bpf_prog_run)
      │
      └─[kprobe_multi]
          fprobe → kprobe_multi_link_handler(fentry_ip, fregs)
            └─ kprobe_multi_link_prog_run(link, entry_ip, fregs)
                └─ bpf_prog_run(prog, ftrace_partial_regs(fregs))

    4.2 TRACEPOINT / RAW_TRACEPOINT

    执行入口 —— 静态 tracepoint

    trace_xxx() 宏展开
      │
      │ if (static_key_false(&xxx.key))
      ▼
    __DO_TRACE() → trace_xxx 回调数组
      │
      │ 如果有 BPF program_array
      ▼
    trace_call_bpf(call, entry)       // kernel/trace/bpf_trace.c:110
      └─ bpf_prog_run_array(prog_array, entry, bpf_prog_run)

    执行入口 —— raw tracepoint

    // kernel/trace/bpf_trace.c: 2289-2296
    // 通过宏展开为 bpf_trace_run1 ~ bpf_trace_run12
    void bpf_trace_run#
    #x(struct bpf_raw_tp_link *link, ...) {
        u64 args[x];
    // 收集参数
        __bpf_trace_run(link, args);
    }
    EXPORT_SYMBOL_GPL(bpf_trace_run##x)

    // kernel/trace/bpf_trace.c: 2241
    void __bpf_trace_run(struct bpf_raw_tp_link *link, u64 *args)
    {
    structbpf_trace_run_ctxrun_ctx;
    // ...
        bpf_prog_run(link->link.prog, args);  // args 直接作为 ctx
    }

    4.3 PERF_EVENT (BPF_PROG_TYPE_PERF_EVENT)

    // kernel/events/core.c
    // perf_event_create_kernel_counter → event->prog = prog
    // 当 perf event 触发时:
    //   perf_event_overflow → perf_event_output_forward → bpf_overflow_handler
    //     └─ bpf_prog_run(event->prog, &ctx)  // ctx = bpf_perf_event_data_kern

    4.4 TRACING (fentry / fexit / fmod_ret) —— Trampoline 架构

    这是内核中最精妙的 BPF 挂载机制。通过动态生成 trampoline 代码,在目标函数的前/后插入 BPF 程序。

    挂载流程

    bpf(BPF_LINK_CREATE, { prog_fd, target_fd, attach_type=BPF_TRACE_FENTRY })
      │
      │ link_create()  →  kernel/bpf/syscall.c:5524
      │   case BPF_PROG_TYPE_TRACING:
      │     if (expected_attach_type == BPF_TRACE_FENTRY/FEXIT/MODIFY_RETURN)
      │       └─ bpf_tracing_prog_attach()   // syscall.c:3452
      │           │
      │           ├─ bpf_check_attach_target()  // 验证目标函数签名
      │           ├─ bpf_trampoline_get(key, &tgt_info)  // 获取或创建 trampoline
      │           │     │
      │           │     ├─ bpf_trampoline_lookup(key)   // 查找已有 trampoline
      │           │     └─ 如不存在,创建新 trampoline 分配 executable memory
      │           │
      │           ├─ bpf_trampoline_link_prog(&link->link, tr)  // 链接到 trampoline
      │           │     │
      │           │     ├─ 根据 attach_type 决定 tr->progs_hlist 分组:
      │           │     │   BPF_TRACE_FENTRY → BPF_TRAMP_FENTRY slot
      │           │     │   BPF_TRACE_FEXIT  → BPF_TRAMP_FEXIT slot
      │           │     │   BPF_MODIFY_RETURN → BPF_TRAMP_MODIFY_RETURN slot
      │           │     │
      │           │     └─ bpf_trampoline_update(tr)   // 调用 ++
      │           │           └─ arch_prepare_bpf_trampoline()
      │           │               │
      │           │               │  // x86: arch/x86/net/bpf_jit_comp.c:3066
      │           │               │  __arch_prepare_bpf_trampoline()
      │           │               │   生成如下汇编结构:
      │           │               │   ┌─────────────────────────────────┐
      │           │               │   │ 保存原函数参数到栈                │
      │           │               │   │ for each FENTRY prog:            │
      │           │               │   │   call __bpf_prog_enter          │
      │           │               │   │   je skip                        │
      │           │               │   │   call prog->bpf_func            │
      │           │               │   │   call __bpf_prog_exit           │
      │           │               │   │ call original_func+X86_PATCH_SIZE│
      │           │               │   │ for each FEXIT prog:             │
      │           │               │   │   call __bpf_prog_enter          │
      │           │               │   │   je skip                        │
      │           │               │   │   call prog->bpf_func            │
      │           │               │   │   call __bpf_prog_exit           │
      │           │               │   │ 恢复返回值 & 返回                 │
      │           │               │   └──────────────────────────────────┘
      │           │               │
      │           │               └─ register_ftrace_direct_multi()
      │           │                   将目标函数开头的 5 字节 nop 替换为
      │           │                   call <trampoline>
      │           │
      │           └─ bpf_link_prime → 返回 link fd 给用户

    关键源码注释:x86 汇编生成

    // arch/x86/net/bpf_jit_comp.c: 3010-3065
    // 注释详细描述了生成的汇编结构:
    /*
     * push rbp
     * mov rbp, rsp
     * sub rsp, 16                     // space for skb and dev
     * push rbx                        // temp regs to pass start time
     * mov qword ptr [rbp - 16], rdi   // save skb pointer to stack
     * mov qword ptr [rbp - 8], rsi    // save dev pointer to stack
     * call __bpf_prog_enter           // rcu_read_lock and preempt_disable
     * mov rbx, rax                    // remember start time
     * lea rdi, [rbp - 16]             // R1==ctx of bpf prog
     * call addr_of_jited_FENTRY_prog
     * ...
     * call __bpf_prog_exit            // rcu_read_unlock, preempt_enable
     * ...
     * call eth_type_trans+5           // execute body of eth_type_trans
     * ...
     * call addr_of_jited_FEXIT_prog   // bpf prog can access return value
     * ...
     * ret                             // return to original caller
     */

    MODIFY_RETURN 特殊处理

    // kernel/bpf/trampoline.c: 891
    // fmod_ret 的 trampoline 不使用 fexit,而是在原始函数返回后
    // 调用 fmod_ret 程序,用其返回值替换原函数的返回值。
    // 对应的 trampoline flags:
    //    flags = BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_SKIP_FRAME

    5. 分类二:网络类 —— XDP/TC

    5.1 XDP (BPF_PROG_TYPE_XDP)

    挂载

    // kernel/bpf/syscall.c: 5590-5592
    case BPF_PROG_TYPE_XDP:
        ret = bpf_xdp_link_attach(attr, prog);
    break;

    bpf_xdp_link_attach() 在 net/core/dev.c:10443,将程序挂载到 net_device 的 XDP hook 上。

    执行入口 —— 三种模式

    模式
    执行位置
    调用链
    Native XDP
    驱动 NAPI poll 内,收包后立即执行
    驱动 → bpf_prog_run_xdp(prog, xdp_buff) (在 include/net/xdp.h:650)
    Generic XDPnetif_receive_skb_core()
     之后的软件路径
    bpf_prog_run_generic_xdp(skb, xdp, prog)
     → bpf_prog_run_xdp(prog, xdp) (在 net/core/dev.c:5232)
    Offload XDP
    智能网卡硬件
    网卡芯片(硬件)执行,不经过内核 CPU

    Native XDP 执行

    // include/net/xdp.h: 650-665
    static __always_inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog,
                                                struct xdp_buff *xdp)

    {
    /* Driver XDP hooks are invoked within a single NAPI poll cycle and thus
         * under local_bh_disable(), which provides the needed RCU protection
         * for accessing map entries.
         */

        u32 act = __bpf_prog_run(prog, xdp, BPF_DISPATCHER_FUNC(xdp));
    if (static_branch_unlikely(&bpf_master_redirect_enabled_key)) {
    if (act == XDP_TX && netif_is_bond_slave(xdp->rxq->dev))
                act = xdp_master_redirect(xdp);
        }
    return act;
    }

    关键点: XDP 在 NAPI poll 上下文(软中断)中执行,已有 local_bh_disable() 保护,所以不需要显式的 rcu_read_lock();但不同于其他路径,这里需要使用 BPF_DISPATCHER_FUNC 分发器以支持 map 查找的优化路径。

    返回值含义

    返回值
    含义
    后续处理
    XDP_PASS
    放行,交给内核协议栈
    skb 构造 → netif_receive_skb
    XDP_DROP
    丢弃
    直接释放
    XDP_TX
    从同一网卡发出
    xdp_do_redirect
     回环
    XDP_REDIRECT
    重定向到其他网卡/CPU
    xdp_do_redirect()
    XDP_ABORTED
    错误(仅用于调试)
    打印 trace 信息

    Generic XDP (非驱动支持的 fallback)

    // net/core/dev.c: 5232-5280
    u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp,
                                  struct bpf_prog *xdp_prog)

    {
    // ... 调整 skb 指针、设置 data_hard_start ...
        act = bpf_prog_run_xdp(xdp_prog, xdp);
    // 根据 act 做相应处理
    }

    调用链:netif_receive_skb_core() → do_xdp_generic() → bpf_prog_run_generic_xdp()

    5.2 TC / TCX (BPF_PROG_TYPE_SCHED_CLS)

    挂载

    // kernel/bpf/syscall.c: 5593-5598
    case BPF_PROG_TYPE_SCHED_CLS:
    if (attr->link_create.attach_type == BPF_TCX_INGRESS ||
            attr->link_create.attach_type == BPF_TCX_EGRESS)
            ret = tcx_link_attach(attr, prog);     // TCX
    else
            ret = netkit_link_attach(attr, prog);  // Netkit

    执行入口 —— TCX ingress

    // net/core/dev.c: 4330-4372
    static __always_inline enum tcx_action_base
    tcx_run(const struct bpf_mprog_entry *entry, struct sk_buff *skb,
    constbool needs_mac)

    {
    conststructbpf_mprog_fp *fp;
    conststructbpf_prog *prog;
    int ret = TCX_NEXT;
    if (needs_mac) __skb_push(skb, skb->mac_len);
        bpf_mprog_foreach_prog(entry, fp, prog) {
            bpf_compute_data_pointers(skb);
            ret = bpf_prog_run(prog, skb);  // ctx = sk_buff
    if (ret != TCX_NEXT) break;     // 直到有程序返回非 TCX_NEXT
        }
    if (needs_mac) __skb_pull(skb, skb->mac_len);
    return tcx_action_code(skb, ret);
    }

    // 调用者:
    // sch_handle_ingress() → tcx_run(entry, skb, true)
    // sch_handle_egress()  → tcx_run(entry, skb, false)

    执行入口 —— 经典 TC cls_bpf / act_bpf (legacy)

    // net/sched/cls_bpf.c: 101
    filter_res = bpf_prog_run(prog->filter, skb);

    // net/sched/act_bpf.c:
    // tc action 执行: bpf_prog_run(prog, skb)

    6. 分类三:网络类 —— Cgroup/Socket

    6.1 CGROUP_SKB (ingress/egress)

    挂载

    // kernel/bpf/syscall.c: 5551-5552 (link_create)
    case BPF_PROG_TYPE_CGROUP_SKB:
        ret = cgroup_bpf_link_attach(attr, prog);
    break;

    执行入口

    // kernel/bpf/cgroup.c: 1562-1620
    int __cgroup_bpf_run_filter_skb(struct sock *sk, struct sk_buff *skb,
    enum cgroup_bpf_attach_type atype)
    {
    // ...
        cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
        bpf_compute_and_save_data_end(skb, &saved_data_end);

    if (atype == CGROUP_INET_EGRESS) {
            ret = bpf_prog_run_array_cg(&cgrp->bpf, atype, skb,
                                        __bpf_prog_run_save_cb, 0, &flags);
    // 返回值转换: 1→keep, 0→drop, 2/3→带 CN 标记
        } else { // CGROUP_INET_INGRESS
            ret = bpf_prog_run_array_cg(&cgrp->bpf, atype, skb,
                                        bpf_prog_run_save_cb, 0NULL);
    // 非 1 表示拒绝
        }
    }

    调用位置(内核协议栈触发点)

    attach_type
    调用位置
    文件
    CGROUP_INET_INGRESSsk_filter_trim_cap()
     之后
    net/core/filter.c:150
    CGROUP_INET_EGRESS__ip_local_out()
     / __ip6_local_out() / ip_output()
    net/ipv4/ip_output.c:320
    // net/core/filter.c: 150
    // 在 socket filter 之后立即执行 cgroup ingress BPF
    err = BPF_CGROUP_RUN_PROG_INET_INGRESS(sk, skb);

    // net/ipv4/ip_output.c: 320
    // 在 IP 层输出路径执行 cgroup egress BPF
    ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);

    6.2 CGROUP_SOCK / CGROUP_SOCK_ADDR

    // kernel/bpf/cgroup.c: 1640-1648
    int __cgroup_bpf_run_filter_sk(struct sock *sk, enum cgroup_bpf_attach_type atype)
    {
    structcgroup *cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
    return bpf_prog_run_array_cg(&cgrp->bpf, atype, sk, bpf_prog_run, 0NULL);
    }
    attach_type
    内核调用点
    说明
    CGROUP_INET_SOCK_CREATE__inet_create()
     / inet6_create()
    socket 创建时
    CGROUP_INET4_BINDinet_bind()
    IPv4 bind
    CGROUP_INET6_BINDinet6_bind()
    IPv6 bind
    CGROUP_INET4_CONNECT__inet_stream_connect()
     / inet_dgram_connect()
    IPv4 connect
    CGROUP_INET4_POST_BINDinet_bind()
     之后
    bind 完成后的后置处理
    CGROUP_UDP4_SENDMSGudp_sendmsg()
    UDP 发送
    CGROUP_UDP4_RECVMSGudp_recvmsg()
    UDP 接收
    BPF_CGROUP_INET_SOCK_RELEASE
    socket release 路径
    socket 释放时

    6.3 SOCK_OPS (BPF_PROG_TYPE_SOCK_OPS)

    // kernel/bpf/cgroup.c: 1732
    return bpf_prog_run_array_cg(&cgrp->bpf, atype, sock_ops, bpf_prog_run, 0NULL);

    调用点分散在 TCP 状态机各处:

    // net/ipv4/tcp_input.c: 177, 196 等
    BPF_CGROUP_RUN_PROG_SOCK_OPS(&sock_ops);

    支持的操作阶段包括(通过 BPF_SOCK_OPS_* 枚举):

    • BPF_SOCK_OPS_TCP_CONNECT_CB
    • BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB
    • BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB
    • BPF_SOCK_OPS_STATE_CB
    • BPF_SOCK_OPS_RTT_CB
    • BPF_SOCK_OPS_WRITE_HDR_OPT_CB 等

    6.4 SK_LOOKUP (BPF_PROG_TYPE_SK_LOOKUP)

    挂载

    // kernel/bpf/syscall.c: 5581-5583
    case BPF_PROG_TYPE_FLOW_DISSECTOR:
    case BPF_PROG_TYPE_SK_LOOKUP:
        ret = netns_bpf_link_create(attr, prog);
    break;

    程序挂载在网络命名空间(struct net)上。

    执行入口

    // include/linux/filter.h: 1631-1701
    // BPF_PROG_SK_LOOKUP_RUN_ARRAY 宏 —— 特殊的遍历逻辑
    #define BPF_PROG_SK_LOOKUP_RUN_ARRAY(array, ctx, func)  \
        ({  \
    // ... 遍历所有程序

    // 特殊逻辑: 每个程序可以选择 selected_sk
    // SK_PASS + selected_sk → 使用选择的 socket
    // SK_DROP → 拒绝连接
    // ...
             _all_pass || _selected_sk ? SK_PASS : SK_DROP;  \
         })

    // include/linux/filter.h: 1664 - 具体执行封装
    staticinlineboolbpf_sk_lookup_run_v4(...)
    {
        run_array = rcu_dereference(net->bpf.run_array[NETNS_BPF_SK_LOOKUP]);
    if (run_array) {
    structbpf_sk_lookup_kernctx = { .family = AF_INET, ... };
            act = BPF_PROG_SK_LOOKUP_RUN_ARRAY(run_array, ctx, bpf_prog_run);
    if (act == SK_PASS) {
                selected_sk = ctx.selected_sk;  // BPF 程序选中的 socket
            }
        }
        *psk = selected_sk;
    return no_reuseport;
    }

    调用位置

    在 __inet_lookup_listener() 和 inet6_lookup_listener() 中,在 socket 查找过程中被调用,允许 BPF 程序重定向连接到其他 socket 或直接拒绝。

    6.5 SK_REUSEPORT (BPF_PROG_TYPE_SK_REUSEPORT)

    // net/core/sock_reuseport.c: 497-525
    static struct sock *run_bpf_filter(struct sock_reuseport *reuse, u16 socks,
                                        struct bpf_prog *prog, struct sk_buff *skb,
                                        u32 hdr_len)

    {
    structsk_buff *nskb = NULL;
        u32 index;
    // 如果需要完整的 L4 header,push skb
    if (hdr_len) nskb = skb_clone(skb, GFP_ATOMIC);
        index = bpf_prog_run_save_cb(prog, nskb ?: skb);
    // 根据 index 选择对应的 socket
    if (index >= socks) returnNULL;
    return reuse->socks[index];
    }

    // 调用位置: reuseport_select_sock()  →  net/core/sock_reuseport.c:568
    struct sock *reuseport_select_sock(struct sock *sk, u32 hash,
                                        struct sk_buff *skb, u32 hdr_len)

    {
    // ...
    if (prog)
            sk2 = run_bpf_filter(reuse, socks, prog, skb, hdr_len);
    else
            sk2 = reuseport_select_sock_by_hash(reuse, hash, socks);
    // ...
    }

    7. 分类四:安全类 —— LSM

    7.1 LSM BPF (BPF_PROG_TYPE_LSM)

    挂载

    // kernel/bpf/syscall.c: 5561-5579
    case BPF_PROG_TYPE_LSM:
    if (attr->link_create.attach_type != prog->expected_attach_type)
            ret = -EINVAL;
    if (prog->expected_attach_type == BPF_LSM_CGROUP)
            ret = cgroup_bpf_link_attach(attr, prog);   // 挂载到 cgroup
    else
            ret = bpf_tracing_prog_attach(prog, ...);   // 挂载到 trampoline

    LSM_MAC 执行路径 —— 通过 Trampoline + static_call

    LSM BPF 宏挂载模式采用了一个精巧的集成方案:

    1. 内核模块注册 LSM hooks 时使用 static_call 机制
    2. BPF LSM 程序通过 trampoline 注册到对应的 static_call 槽位
    3. 安全子系统调用 LSM hook 时,通过 static_call 直接跳转到 BPF trampoline

    内核中的 LSM hook 调用宏:

    // security/security.c: 961-978
    #define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...)  \
    do {  \
    if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) {  \
            R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__);  \
    if (R != LSM_RET_DEFAULT(HOOK)) goto LABEL;  \
        }  \
    } while (0);


    #define call_int_hook(HOOK, ...)  \
    ({  \
        int RC = LSM_RET_DEFAULT(HOOK);  \
        LSM_LOOP_UNROLL(__CALL_STATIC_INT, RC, HOOK, OUT, __VA_ARGS__);  \
    OUT:  \
        RC;  \
    })

    所以完整的 LSM BPF 执行流程为:

    内核代码调用 security_xxx() LSM hook
      │
      │ 展开为 call_int_hook(xxx, ...)
      ▼
    static_call(LSM_STATIC_CALL(xxx, N))(...)
      │
      │ 如果该 slot 被 BPF LSM 程序占用
      ▼
    bpf_lsm_xxx trampoline (通过 lsm_trampoline 生成)
      │
      ├─ __bpf_prog_enter_lsm_cgroup(prog, run_ctx)  // LSM_CGROUP 走此路径
      │   └─ rcu_read_lock() + 获取 cgroup bpf prog
      │
      ├─ call prog->bpf_func(ctx)    // 执行 BPF LSM 程序
      │   ctx = 原始 LSM hook 的参数
      │   返回值: 0=允许, -EPERM=拒绝
      │
      └─ __bpf_prog_exit(...)       // rcu_read_unlock + enable

    LSM_CGROUP 执行路径

    对于 BPF_LSM_CGROUP 挂载类型,LSM 程序运行在 cgroup 上下文中,使用 bpf_prog_run_array_cg() 遍历 cgroup 层级中的所有 LSM 程序。

    7.2 Netfilter BPF (BPF_PROG_TYPE_NETFILTER)

    // net/netfilter/nf_bpf_link.c: 11-21
    staticunsignedintnf_hook_run_bpf(void *bpf_prog, struct sk_buff *skb,
    const struct nf_hook_state *s)

    {
    conststructbpf_prog *prog = bpf_prog;
    structbpf_nf_ctxctx = {
            .state = s,
            .skb = skb,
        };
    return bpf_prog_run_pin_on_cpu(prog, &ctx);
    }

    通过 nf_register_net_hook() 注册到 netfilter hook 链中,与其他 netfilter 模块(iptables 等)并列执行。


    8. 分类五:Struct_Ops 类

    8.1 BPF_PROG_TYPE_STRUCT_OPS

    Struct_Ops 允许用 BPF 程序替换/实现内核中的结构体函数指针。最典型的例子是 TCP 拥塞控制算法。

    挂载

    // kernel/bpf/syscall.c: 5532-5533
    if (attr->link_create.attach_type == BPF_STRUCT_OPS)
    return bpf_struct_ops_link_create(attr);

    注册与执行 —— 以 TCP CC 为例

    // net/ipv4/bpf_tcp_ca.c: 311-338
    // 1. 定义一个 tcp_congestion_ops 实例,其函数指针指向 trampoline 入口
    staticstructtcp_congestion_ops __bpf_ops_tcp_congestion_ops = {
        .ssthresh = bpf_tcp_ca_ssthresh,   // trampoline stub
        .cong_avoid = bpf_tcp_ca_cong_avoid,
        .set_state = bpf_tcp_ca_set_state,
    // ...
    };

    // 2. 注册为 struct_ops
    staticstructbpf_struct_opsbpf_tcp_congestion_ops = {
        .verifier_ops = &bpf_tcp_ca_verifier_ops,
        .reg = bpf_tcp_ca_reg,          // 注册到内核: tcp_register_congestion_control()
        .unreg = bpf_tcp_ca_unreg,      // 注销
        .update = bpf_tcp_ca_update,    // 更新 CFI stubs
        .init_member = bpf_tcp_ca_init_member,
        .name = "tcp_congestion_ops",
        .cfi_stubs = &__bpf_ops_tcp_congestion_ops,
    };

    执行流程

    BPF 用户态加载 struct_ops BPF 程序
      │
      │ bpf(BPF_MAP_CREATE) → BPF_MAP_TYPE_STRUCT_OPS
      │ bpf(BPF_LINK_CREATE, attach_type=BPF_STRUCT_OPS)
      ▼
    bpf_struct_ops_link_create()
      │
      ├─ 为每个成员函数生成 trampoline (通过 cfistubs)
      ├─ st_ops->reg() → tcp_register_congestion_control()
      │     └─ 将 BPF 实现的 tcp_congestion_ops 注册到内核
      │
      └─ 内核调用 TCP 拥塞控制回调时:
            tcp_congestion_ops→ssthresh(sk)
              │
              │ 实际指向 CFI stub
              ▼
            bpf_tcp_ca_ssthresh (trampoline)
              └─ __bpf_prog_enter → call prog->bpf_func → __bpf_prog_exit

    关键点cfi_stubs 是内核为每个 BPF struct_ops 创建的 trampoline,实现 CFI (Control Flow Integrity) 保护,同时负责 rcu_read_lock/migrate_disable 等上下文保护。


    9. 分类六:其他类型

    9.1 CGROUP_DEVICE

    // kernel/bpf/cgroup.c
    // 在用户空间访问设备文件时触发:
    // __cgroup_bpf_run_filter_dev(cgrp, dev, access_type)
    //   └─ bpf_prog_run_array_cg(&cgrp->bpf, CGROUP_DEVICE, ...)

    9.2 CGROUP_SYSCTL

    // kernel/bpf/cgroup.c
    int __cgroup_bpf_run_filter_sysctl(struct ctl_table_header *head,
                                        struct ctl_table *table, int write, ...)
    {
    // ...
        ret = bpf_prog_run_array_cg(&cgrp->bpf, atype, &ctx, bpf_prog_run, 0NULL);
    // 返回值 0 = 拒绝修改, 1 = 允许
    }

    调用位置:/proc/sys/ 的读写操作路径上。

    9.3 CGROUP_SOCKOPT

    // kernel/bpf/cgroup.c
    int __cgroup_bpf_run_filter_setsockopt(struct sock *sock, int *level, int *optname, ...)
    int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level, int optname, ...)

    调用位置:do_sock_setsockopt() / do_sock_getsockopt() 之前。

    9.4 SOCKET_FILTER (BPF_PROG_TYPE_SOCKET_FILTER)

    // net/core/filter.c: 134
    intsk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsignedint cap)
    {
    structsk_filter *filter;
    // ...
        filter = rcu_dereference(sk->sk_filter);
    if (filter) {
            pkt_len = bpf_prog_run_save_cb(filter->prog, skb);
    // ...
        }
    }

    调用链:sock_queue_rcv_skb() → 协议层接收 → sk_filter_trim_cap()

    9.5 SK_SKB / SK_MSG (sockmap)

    通过 sockmap 将 socket 和 BPF 程序关联。程序在数据流入/流出 sockmap 管理的 socket 时触发。

    9.6 FLOW_DISSECTOR

    // kernel/bpf/syscall.c: 5581-5583
    case BPF_PROG_TYPE_FLOW_DISSECTOR:
        ret = netns_bpf_link_create(attr, prog);

    执行位置:__skb_flow_dissect() 在解析数据包 flow 信息时调用 BPF 程序。

    9.7 SYSCALL (BPF_PROG_TYPE_SYSCALL)

    // include/uapi/linux/bpf.h: 1072
    BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */

    这是一个特殊类型,不能像其他 BPF 程序那样 attach 到内核 hook 点。它只能通过 bpf_sys_bpf() helper 在另一个 BPF 程序中被调用,允许 BPF 程序安全地执行 syscall。


    10. 核心调用流程图

    10.1 统一挂载流程图

    用户态: bpftool prog load / bpftool link pin / libbpf
      │
      │ bpf(BPF_LINK_CREATE, {prog_fd, attach_type, ...})
      ▼
    link_create()                              // kernel/bpf/syscall.c:5524
      │
      ├─ prog = bpf_prog_get(prog_fd)          // 获取已验证的程序
      ├─ bpf_prog_attach_check_attach_type()   // 验证 attach_type 兼容性
      │
      └─ switch (prog->type):
           │
           ├─ CGROUP_SKB/SOCK/SOCK_ADDR/SOCK_OPS/DEVICE/SYSCTL/SOCKOPT
           │    └─ cgroup_bpf_link_attach(attr, prog)   →  挂载到 cgroup bpf array
           │
           ├─ EXT / TRACING (FENTRY/FEXIT/MODIFY_RETURN)
           │    └─ bpf_tracing_prog_attach(prog, target_fd, btf_id, ...)
           │         ├─ bpf_check_attach_target()       →  验证目标函数
           │         ├─ bpf_trampoline_get()            →  获取/创建 trampoline
           │         ├─ bpf_trampoline_link_prog()      →  链接程序
           │         │    └─ bpf_trampoline_update()    →  生成并安装 trampoline
           │         │         └─ arch_prepare_bpf_trampoline()
           │         │              └─ register_ftrace_direct_multi()
           │         └─ bpf_link_prime()               →  返回 link fd
           │
           ├─ LSM (LSM_MAC)
           │    └─ bpf_tracing_prog_attach() (同上 trampoline 路径)
           │
           ├─ LSM (LSM_CGROUP)
           │    └─ cgroup_bpf_link_attach()            →  cgroup 路径
           │
           ├─ TRACING (RAW_TP)
           │    └─ bpf_raw_tp_link_attach()            →  raw tracepoint
           │
           ├─ TRACING (ITER)
           │    └─ bpf_iter_link_attach()              →  iterator
           │
           ├─ KPROBE (PERF_EVENT)
           │    └─ bpf_perf_link_attach(attr, prog)    →  perf_event kprobe
           │
           ├─ KPROBE (KPROBE_MULTI/KPROBE_SESSION)
           │    └─ bpf_kprobe_multi_link_attach()      →  fprobe
           │
           ├─ KPROBE (UPROBE_MULTI/UPROBE_SESSION)
           │    └─ bpf_uprobe_multi_link_attach()      →  fprobe
           │
           ├─ PERF_EVENT / TRACEPOINT
           │    └─ bpf_perf_link_attach()              →  perf_event
           │
           ├─ XDP
           │    └─ bpf_xdp_link_attach()               →  挂载到 net_device
           │
           ├─ SCHED_CLS (TCX_INGRESS/EGRESS)
           │    └─ tcx_link_attach()                   →  挂载到 net_device
           │
           ├─ SCHED_CLS (NETKIT)
           │    └─ netkit_link_attach()                →  挂载到 netkit 设备
           │
           ├─ NETFILTER
           │    └─ bpf_nf_link_attach()                →  挂载到 netfilter hook
           │
           ├─ FLOW_DISSECTOR / SK_LOOKUP
           │    └─ netns_bpf_link_create()             →  挂载到 net namespace
           │
           ├─ STRUCT_OPS
           │    └─ bpf_struct_ops_link_create()        →  注册 struct_ops 到子系统
           │
           └─ SK_MSG / SK_SKB
                └─ sock_map_link_create()              →  挂载到 sockmap

    10.2 统一运行时执行流程

    内核执行流到达 hook 点
      │
      ├───[Trampoline 类] (fentry/fexit/lsm/modify_ret)
      │    │
      │    │ 目标函数开头 5-byte nop 已被替换为 call <trampoline>
      │    ▼
      │   trampoline asm code (动态生成)
      │    ├─ 保存寄存器 & 参数到栈
      │    ├─ for each fentry prog:
      │    │   ├─ call __bpf_prog_enter(prog, run_ctx)
      │    │   │   ├─ rcu_read_lock() / rcu_read_lock_trace() (sleepable)
      │    │   │   ├─ migrate_disable()
      │    │   │   ├─ 检查重入保护 (per-CPU prog->active counter)
      │    │   │   └─ return start_time or 0 (skip)
      │    │   ├─ if (start_time != 0): call prog->bpf_func(ctx)
      │    │   │   └─ ctx = 原始函数参数 / pt_regs 等
      │    │   └─ __bpf_prog_exit(prog, start_time, run_ctx)
      │    │       ├─ bpf_reset_run_ctx()
      │    │       ├─ update_prog_stats()
      │    │       ├─ migrate_enable()
      │    │       └─ rcu_read_unlock()
      │    ├─ call 原始函数体 (fentry only)
      │    ├─ for each fexit / fmod_ret prog: (同上)
      │    └─ 恢复寄存器 & ret
      │
      ├───[Array Dispatch 类] (cgroup, tracepoint, kprobe_multi, etc.)
      │    │
      │    ▼
      │   bpf_prog_run_array_cg() / bpf_prog_run_array()
      │    ├─ rcu_read_lock()
      │    ├─ migrate_disable()
      │    ├─ bpf_set_run_ctx()
      │    ├─ for each prog in array:
      │    │   └─ run_prog(prog, ctx)     // bpf_prog_run() or __bpf_prog_run_save_cb()
      │    │       └─ __bpf_prog_run(prog, ctx, dispatcher)
      │    │           └─ dispensher(ctx, insnsi, prog->bpf_func)
      │    │               ├─ JIT'd: 直接调用 prog->bpf_func 机器码
      │    │               └─ 解释器: BPF_PROG_RUN() 宏
      │    ├─ bpf_reset_run_ctx()
      │    ├─ migrate_enable()
      │    └─ rcu_read_unlock()
      │
      ├───[Direct Run 类] (socket filter, reuseport, XDP, TCX, etc.)
      │    │
      │    ▼
      │   bpf_prog_run(prog, ctx) / bpf_prog_run_save_cb(prog, skb) / bpf_prog_run_xdp(prog, xdp)
      │    └─ __bpf_prog_run(prog, ctx, dispatcher)
      │        └─ (同上)
      │
      └───[Struct_Ops 类]
           │
           ▼
          内核调用 struct 函数指针 (如 tcp_congestion_ops->ssthresh(sk))
           └─ cfi_stub (trampoline)
               └─ __bpf_prog_enter → call prog->bpf_func → __bpf_prog_exit

    11. 关键数据结构速查

    结构
    定义位置
    说明
    bpf_proginclude/linux/filter.h:535+
    BPF 程序核心结构,包含 insnsi (指令), bpf_func (JIT 入口), aux (辅助信息)
    bpf_prog_arrayinclude/linux/bpf.h:2184
    RCU 保护的程序指针数组,用于 cgroup/tracepoint 等
    bpf_prog_array_iteminclude/linux/bpf.h:2176
    数组元素,包含 prog 指针 + cookie
    bpf_trampolineinclude/linux/bpf.h:1330+
    trampoline 对象,管理 fentry/fexit/fmod_ret 程序
    bpf_tramp_linkkernel/bpf/trampoline.c
    每个 BPF 程序对 trampoline 的链接
    bpf_tramp_imageinclude/linux/bpf.h:1345+
    trampoline 生成的二进制 images
    bpf_tramp_run_ctxkernel/bpf/trampoline.c
    trampoline 运行时上下文
    bpf_trace_run_ctxinclude/linux/bpf.h
    trace 类运行时上下文(含 bpf_cookie)
    bpf_prog_statsinclude/linux/filter.h
    每个 prog 的运行时统计(调用次数/耗时)
    cgroup_bpfinclude/linux/bpf-cgroup-defs.h
    cgroup 内嵌的 BPF 数组结构
    bpf_mprog_entryinclude/linux/bpf_mprog.h
    TCX 使用的多程序入口

    附录 A:源码关键文件索引

    文件路径
    说明
    include/uapi/linux/bpf.h
    prog_type / attach_type 枚举定义
    include/linux/bpf.hbpf_prog_run_array
    bpf_prog_array 等核心结构
    include/linux/filter.h__bpf_prog_run
    bpf_prog_runBPF_PROG_SK_LOOKUP_RUN_ARRAY
    kernel/bpf/syscall.clink_create()
     — 挂载分发入口
    kernel/bpf/trampoline.c
    trampoline 管理:enter/exit/trampoline_update
    arch/x86/net/bpf_jit_comp.c
    x86 trampoline 汇编生成
    kernel/bpf/cgroup.c
    cgroup BPF attach/run
    kernel/trace/bpf_trace.c
    kprobe/kprobe_multi/tracepoint/raw_tp 执行
    kernel/bpf/bpf_lsm.c
    LSM BPF hook 注册与验证
    security/security.c
    LSM hook 调用宏 (call_int_hook)
    net/core/dev.c
    XDP generic / TCX 执行
    include/net/xdp.hbpf_prog_run_xdp
    net/core/filter.c
    socket filter / cgroup ingress
    net/core/sock_reuseport.c
    reuseport BPF
    net/netfilter/nf_bpf_link.c
    netfilter BPF hook
    kernel/bpf/bpf_struct_ops.c
    struct_ops 管理
    net/ipv4/bpf_tcp_ca.c
    TCP CC struct_ops 示例

    附录 B:安全执行模型

    所有 BPF 程序在执行时都受到以下安全保护:

    1. verifier 验证: 所有 BPF 程序必须先通过 bpf_check() 验证器(kernel/bpf/verifier.c),确保无越界访问、循环有界、类型安全等
    2. CFI (Control Flow Integrity): struct_ops 使用 cfi_stubs 防止控制流劫持
    3. RCU 保护: 所有 BPF 程序执行在 RCU read-side critical section 中,map 访问天然安全
    4. migrate_disable: 防止程序执行期间被迁移到其他 CPU,保证 per-CPU 数据一致性
    5. 重入保护: kprobe/tracepoint 使用 per-CPU bpf_prog_active 计数器防止无限递归
    6. JIT 加固: x86 JIT 生成的代码都设置内存为 RO+X,防止修改
    7. Spectre 防护: 对数组索引等边界操作使用 array_index_nospec() 等缓解措施

    本文基于linux-master源码

    最新文章

    随机文章

    基本 文件 流程 错误 SQL 调试
    1. 请求信息 : 2026-07-03 03:47:13 HTTP/2.0 GET : https://f.mffb.com.cn/a/499047.html
    2. 运行时间 : 0.115451s [ 吞吐率:8.66req/s ] 内存消耗:4,847.87kb 文件加载:140
    3. 缓存信息 : 0 reads,0 writes
    4. 会话信息 : SESSION_ID=f49f7ffd618ab1ed6220e0f9c59a4f12
    1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
    2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
    3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
    4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
    5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
    6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
    7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
    8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
    9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
    10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
    11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
    12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
    13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
    14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
    15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
    16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
    17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
    18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
    19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
    20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
    21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
    22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
    23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
    24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
    25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
    26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
    27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
    28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
    29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
    30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
    31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
    32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
    33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
    34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
    35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
    36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
    37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
    38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
    39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
    40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
    41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
    42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
    43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
    44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
    45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
    46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
    47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
    48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
    49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
    50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
    51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
    52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
    53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
    54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
    55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
    56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
    57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
    58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
    59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
    60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
    61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
    62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
    63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
    64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
    65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
    66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
    67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
    68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
    69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
    70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
    71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
    72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
    73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
    74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
    75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
    76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
    77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
    78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
    79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
    80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
    81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
    82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
    83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
    84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
    85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
    86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
    87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
    88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
    89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
    90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
    91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
    92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
    93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
    94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
    95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
    96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
    97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
    98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
    99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
    100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
    101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
    102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
    103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
    104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
    105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
    106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
    107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
    108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
    109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
    110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
    111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
    112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
    113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
    114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
    115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
    116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
    117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
    118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
    119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
    120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
    121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
    122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
    123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
    124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
    125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
    126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
    127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
    128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
    129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
    130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
    131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
    132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
    133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
    134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
    135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
    136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
    137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
    138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
    139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
    140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
    1. CONNECT:[ UseTime:0.000626s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
    2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000895s ]
    3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000356s ]
    4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000275s ]
    5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000503s ]
    6. SELECT * FROM `set` [ RunTime:0.000201s ]
    7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000552s ]
    8. SELECT * FROM `article` WHERE `id` = 499047 LIMIT 1 [ RunTime:0.000616s ]
    9. UPDATE `article` SET `lasttime` = 1783021633 WHERE `id` = 499047 [ RunTime:0.009505s ]
    10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000268s ]
    11. SELECT * FROM `article` WHERE `id` < 499047 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000495s ]
    12. SELECT * FROM `article` WHERE `id` > 499047 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000432s ]
    13. SELECT * FROM `article` WHERE `id` < 499047 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001080s ]
    14. SELECT * FROM `article` WHERE `id` < 499047 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.013020s ]
    15. SELECT * FROM `article` WHERE `id` < 499047 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.016925s ]
    0.117024s