Linux eBPF 深度实战:从内核可编程到零侵入可观测性革命

eBPF 正在彻底改变 Linux 内核的可观测性、安全和网络领域。一文深入理解其架构设计、编程模型与生产实践。

引言:为什么 eBPF 如此重要?

在传统 Linux 系统中,内核态与用户态之间存在一道清晰的边界。想要观察内核行为,要么修改内核源码重新编译(开发成本高、部署周期长),要么使用有限功能的系统调用和 procfs(粒度粗、性能差)。eBPF(Extended Berkeley Packet Filter)打破了这一限制——它允许用户编写小程序,经安全验证后直接在内核态执行,无需修改内核模块。

从 3.18 内核首次引入到如今的 6.x 时代,eBPF 已从一个简单的数据包过滤器演进为通用内核虚拟机,催生了 Cilium、Falco、Tetragon、Pixie 等一系列革命性产品。

一、eBPF 架构总览

1.1 核心组件

eBPF 运行时包含三个关键部分:


┌──────────────────────────────────────────────────┐
│                  用户态程序                        │
│  ┌─────────┐  ┌──────────┐  ┌─────────────────┐ │
│  │bpf()系统 │  │  Map 读写 │  │  环形缓冲区消费   │ │
│  │调用加载   │  │          │  │                 │ │
│  └────┬────┘  └─────┬────┘  └────────┬────────┘ │
├───────┼─────────────┼────────────────┼──────────┤
│       ▼             ▼                ▼          │
│              内 核 态                              │
│  ┌──────────────────────────────────────────┐    │
│  │           eBPF Verifier                   │    │
│  │  (类型检查/边界检查/循环检测/可达性分析)    │    │
│  └──────────────────┬───────────────────────┘    │
│                     ▼                            │
│  ┌──────────────────────────────────────────┐    │
│  │         eBPF JIT 编译器                    │    │
│  │    (将字节码编译为原生机器指令)              │    │
│  └──────────────────┬───────────────────────┘    │
│                     ▼                            │
│  ┌──────────────────────────────────────────┐    │
│  │        eBPF 字节码执行沙箱                  │    │
│  │    (512字节栈 / 禁止无限循环 / 安全内存)     │    │
│  └──────────────────┬───────────────────────┘    │
│                     ▼                            │
│  ┌─────────┐ ┌──────────┐ ┌─────────────────┐   │
│  │ kprobe  │ │ tracepoint│ │   XDP / TC       │   │
│  │ uprobe  │ │  perf_ev  │ │   Socket Filter  │   │
│  └─────────┘ └──────────┘ └─────────────────┘   │
└──────────────────────────────────────────────────┘

1.2 程序生命周期

一个 eBPF 程序从编写到执行的完整流程:

  1. 编写:使用 C(或 Rust)编写受限的 eBPF 程序
  2. 编译:用 clang/LLVM 编译为 eBPF ELF 字节码
  3. 加载:通过 bpf() 系统调用加载进内核
  4. 验证:内核 Verifier 执行静态分析,确保安全
  5. JIT:JIT 编译为原生 CPU 指令
  6. 挂载:attach 到 hook 点(kprobe/tracepoint/XDP 等)
  7. 执行:hook 触发时运行目标函数
  8. 通信:通过 Maps 和 Ring Buffer 与用户态交换数据
  9. 二、eBPF 编程模型详解

    2.1 第一个 eBPF 程序:跟踪 execve 系统调用

    
    // execve_tracker.bpf.c
    #include "vmlinux.h"
    #include <bpf/bpf_helpers.h>
    #include <bpf/bpf_tracing.h>
    
    // 定义 Perf 事件 Map,用于向用户态推送事件
    struct {
        __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
        __uint(key_size, sizeof(u32));
        __uint(value_size, sizeof(u32));
    } events SEC(".maps");
    
    // 定义要记录的数据结构
    struct event {
        u32 pid;
        u32 uid;
        char comm[16];
        char filename[256];
    };
    
    // 挂载点:在 execve 进入时触发
    SEC("tracepoint/syscalls/sys_enter_execve")
    int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter *ctx)
    {
        struct event e = {};
        
        // 获取当前进程信息
        e.pid = bpf_get_current_pid_tgid() >> 32;
        e.uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
        bpf_get_current_comm(&e.comm, sizeof(e.comm));
        
        // 读取 execve 的第一个参数即文件路径
        bpf_probe_read_user_str(&e.filename, sizeof(e.filename), 
                                (void *)ctx->args[0]);
        
        // 推送到用户态
        bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, 
                              &e, sizeof(e));
        
        return 0;
    }
    
    char _license[] SEC("license") = "GPL";
    

    2.2 BPF Maps:内核态与用户态的数据桥梁

    Maps 是 eBPF 程序存储状态和与用户态通信的核心数据结构:

    
    // 1. Hash Map:用于计数和缓存 lookup
    struct {
        __uint(type, BPF_MAP_TYPE_HASH);
        __uint(max_entries, 10240);
        __type(key, u32);    // PID
        __type(value, u64);  // syscall 计数
    } syscall_count SEC(".maps");
    
    // 2. Per-CPU Array:高性能 per-CPU 计数器
    struct {
        __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
        __uint(max_entries, 1);
        __type(key, u32);
        __type(value, struct counters);
    } cpu_stats SEC(".maps");
    
    // 3. LRU Hash:有界缓存
    struct {
        __uint(type, BPF_MAP_TYPE_LRU_HASH);
        __uint(max_entries, 65536);
        __type(key, struct flow_key);
        __type(value, struct flow_stats);
    } flows SEC(".maps");
    
    // 4. Ring Buffer:高性能事件流(推荐替代 perf_event)
    struct {
        __uint(type, BPF_MAP_TYPE_RINGBUF);
        __uint(max_entries, 256 * 1024); // 256KB
    } rb SEC(".maps");
    
    // 5. Perf Event Array:按 CPU 分发事件
    struct {
        __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
        __uint(key_size, sizeof(u32));
        __uint(value_size, sizeof(u32));
    } events SEC(".maps");
    

    选型指南:

    • 需要持久化计数 → BPF_MAP_TYPE_HASH
    • 高并发 per-CPU 统计 → BPF_MAP_TYPE_PERCPU_HASH
    • 流式事件通知到用户态 → BPF_MAP_TYPE_RINGBUF(首选)或 BPF_MAP_TYPE_PERF_EVENT_ARRAY
    • LRU 缓存(有界) → BPF_MAP_TYPE_LRU_HASH
    • 数组索引查找 → BPF_MAP_TYPE_ARRAY

    2.3 Helper 函数:eBPF 与内核的交互接口

    eBPF 通过一组受限的 helper 函数与内核交互(不同挂载类型可用的 helper 不同):

    
    // 常用 Helper 函数
    bpf_map_lookup_elem()     // 查找 Map 元素
    bpf_map_update_elem()     // 更新 Map 元素
    bpf_probe_read()          // 从内核地址读取数据
    bpf_probe_read_user_str() // 安全读取用户态字符串
    bpf_ktime_get_ns()        // 获取当前纳秒时间戳
    bpf_get_current_pid_tgid()// 获取当前 PID/TGID
    bpf_get_current_comm()    // 获取进程名
    bpf_perf_event_output()   // 输出到 perf 环形缓冲区
    bpf_ringbuf_output()      // 输出到 ring buffer
    bpf_printk()              // 调试打印(通过 trace_pipe)
    bpf_tail_call()           // 尾调用另一个 eBPF 程序
    bpf_get_stackid()         // 获取内核/用户态调用栈
    

    2.4 用户态加载骨架(libbpf)

    
    // loader.c
    #include <bpf/libbpf.h>
    #include <stdio.h>
    #include "execve_tracker.skel.h"
    
    static int handle_event(void *ctx, void *data, size_t len)
    {
        struct event *e = data;
        printf("PID=%u UID=%u COMM=%s FILE=%s\n",
               e->pid, e->uid, e->comm, e->filename);
        return 0;
    }
    
    int main(int argc, char **argv)
    {
        struct execve_tracker_bpf *skel;
        struct ring_buffer *rb;
        int err;
        
        // 1. 打开并加载 eBPF skeleton
        skel = execve_tracker_bpf__open_and_load();
        if (!skel) {
            fprintf(stderr, "Failed to load BPF skeleton\n");
            return 1;
        }
        
        // 2. Attach 到 tracepoint
        err = execve_tracker_bpf__attach(skel);
        if (err) {
            fprintf(stderr, "Failed to attach BPF program\n");
            goto cleanup;
        }
        
        // 3. 创建 ring buffer 轮询
        rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), 
                              handle_event, NULL, NULL);
        
        printf("Trace execve syscalls... Ctrl-C to stop\n");
        while (ring_buffer__poll(rb, 100) >= 0) {}
        
    cleanup:
        ring_buffer__free(rb);
        execve_tracker_bpf__destroy(skel);
        return err;
    }
    

    构建命令:

    
    # 编译 BPF 程序(目标为 eBPF ELF)
    clang -O2 -g -target bpf -c execve_tracker.bpf.c -o execve_tracker.bpf.o
    
    # 生成 skeleton 头文件
    bpftool gen skeleton execve_tracker.bpf.o > execve_tracker.skel.h
    
    # 编译用户态 loader
    clang -O2 -g loader.c -o loader -lbpf -lelf -lz
    

    三、Hook 点全景:eBPF 能挂在哪里

    3.1 内核函数跟踪

    
    // kprobe:动态挂载到任意内核函数入口
    SEC("kprobe/do_sys_openat2")
    int BPF_KPROBE(trace_do_sys_openat2, int dfd, const char *filename)
    {
        // 通过 PT_REGS_PARM 宏访问参数
        bpf_printk("openat: %s\n", filename);
        return 0;
    }
    
    // kretprobe:挂载到函数返回点
    SEC("kretprobe/do_sys_openat2")
    int BPF_KRETPROBE(trace_openat2_ret, long ret)
    {
        bpf_printk("openat returned: %ld\n", ret);
        return 0;
    }
    
    // fentry/fexit(推荐,性能更好,需要 BTF)
    SEC("fentry/do_sys_openat2")
    int BPF_PROG(trace_openat2_entry, int dfd, const char *filename)
    {
        bpf_printk("fentry: %s\n", filename);
        return 0;
    }
    

    3.2 用户态跟踪

    
    // uprobe:挂载到用户态函数入口
    SEC("uprobe//usr/bin/bash:readline")
    int trace_uprobe_readline(struct pt_regs *ctx)
    {
        char buf[64];
        bpf_probe_read_user(buf, sizeof(buf), (void *)PT_REGS_PARM1(ctx));
        bpf_printk("bash readline: %s\n", buf);
        return 0;
    }
    

    3.3 Tracepoint:稳定的内核 instrumentation

    
    // mmap 系统调用入口
    SEC("tracepoint/syscalls/sys_enter_mmap")
    int trace_mmap_enter(struct trace_event_raw_sys_enter *ctx)
    {
        struct mmap_event e = {};
        e.pid = bpf_get_current_pid_tgid() >> 32;
        e.addr = (unsigned long)ctx->args[0];
        e.len = (size_t)ctx->args[1];
        e.prot = (int)ctx->args[2];
        ring_buffer_output(&rb, &e, sizeof(e), 0);
        return 0;
    }
    

    3.4 XDP:网络数据包的最前线

    
    SEC("xdp")
    int xdp_drop_port(struct xdp_md *ctx)
    {
        void *data_end = (void *)(long)ctx->data_end;
        void *data = (void *)(long)ctx->data;
        
        struct ethhdr *eth = data;
        if ((void *)(eth + 1) > data_end) return XDP_PASS;
        
        if (eth->h_proto != bpf_htons(ETH_P_IP))
            return XDP_PASS;
        
        struct iphdr *ip = (void *)(eth + 1);
        if ((void *)(ip + 1) > data_end) return XDP_PASS;
        
        // 丢弃目的端口 9999 的 TCP 流量
        if (ip->protocol == IPPROTO_TCP) {
            struct tcphdr *tcp = (void *)(ip + 1);
            if ((void *)(tcp + 1) > data_end) return XDP_PASS;
            if (bpf_ntohs(tcp->dest) == 9999)
                return XDP_DROP;
        }
        
        return XDP_PASS;
    }
    

    XDP 的几种动作:

    动作 含义
    XDP_PASS 放行,交给内核网络栈处理
    XDP_DROP 直接丢弃(在网卡驱动层)
    XDP_TX 从接收网卡原路发送回去
    XDP_REDIRECT 重定向到另一个网卡或 CPU
    XDP_ABORTED 异常丢弃(触发 tracepoint)

    3.5 Socket Filter 与 Socket 操作

    
    // 用于 socket 过滤(传统 BPF 的扩展)
    SEC("sockfilter")
    int socket_filter(struct __sk_buff *skb)
    {
        // 只允许 HTTP/HTTPS 流量
        if (skb->protocol == bpf_htons(ETH_P_IP)) {
            // 解析并决策...
        }
        return skb->len; // 返回允许的字节数
    }
    

    3.6 LSM(Linux Security Module)

    
    // 使用 BPF LSM 实现安全策略(需要 CONFIG_BPF_LSM=y)
    SEC("lsm/file_open")
    int BPF_PROG(file_open_lsm, struct file *file, int ret)
    {
        // ret 是之前 LSM hook 的返回值,返回 0 表示允许
        char comm[16];
        bpf_get_current_comm(comm, sizeof(comm));
        
        // 禁止特定程序访问敏感文件
        if (file->f_path.dentry->d_name.len == 14 &&
            bpf_strncmp(file->f_path.dentry->d_name.name, 14, "shadow") == 0) {
            if (bpf_strncmp(comm, 4, "curl") == 0)
                return -EPERM; // 禁止 curl 读取 shadow
        }
        return 0;
    }
    

    四、实战案例:构建生产级系统调用追踪器

    4.1 需求与架构

    目标:构建一个生产级系统调用延迟观测工具,要求:

    • 追踪 read/write/send/recv 四个 IO 类系统调用的延迟分布
    • 使用直方图统计(P25/P50/P75/P99/最大)
    • 零侵入,无需修改目标进程
    • 性能开销 < 1%

    架构设计:

    
    用户态进程                   内核态
    ┌──────────────┐          ┌──────────────────┐
    │ 聚合统计线程  │          │                  │
    │   (低负载)   │定期读取  │  eBPF 程序       │
    │              │◄─────────│  (kprobe/        │
    │ 展示直方图   │   Map    │   kretprobe)     │
    └──────────────┘          │  记录时间差       │
                              └──────────────────┘
    

    4.2 BPF 核心代码

    
    // syscall_latency.bpf.c
    #include "vmlinux.h"
    #include <bpf/bpf_helpers.h>
    #include <bpf/bpf_tracing.h>
    #include <bpf/bpf_core_read.h>
    
    #define MAX_ENTRIES 10240
    #define MAX_SLOTS 36
    
    // 用于在读系统调用入口记录时间戳
    struct {
        __uint(type, BPF_MAP_TYPE_HASH);
        __uint(max_entries, MAX_ENTRIES);
        __type(key, u64);   // pid_tgid
        __type(value, u64); // start time ns
    } start SEC(".maps");
    
    // 2 的对数直方图:用于统计延迟分布(单位:微秒)
    struct {
        __uint(type, BPF_MAP_TYPE_HASH);
        __uint(max_entries, 4); // 4 种 syscall 各一个
        __type(key, u32);       // syscall_nr
        __type(value, u64[MAX_SLOTS]);
    } hist SEC(".maps");
    
    static __always_inline u64 log2l(u64 v)
    {
        u64 r = 0;
        while (v >>= 1) r++;
        return r;
    }
    
    // 通用的进入处理函数
    static __always_inline int trace_enter(syscall_t sys_nr)
    {
        u64 pid_tgid = bpf_get_current_pid_tgid();
        u64 ts = bpf_ktime_get_ns();
        bpf_map_update_elem(&start, &pid_tgid, &ts, BPF_ANY);
        return 0;
    }
    
    // 通用的返回处理函数(计算延迟并更新直方图)
    static __always_inline int trace_exit(syscall_t sys_nr)
    {
        u64 pid_tgid = bpf_get_current_pid_tgid();
        u64 *startp = bpf_map_lookup_elem(&start, &pid_tgid);
        if (!startp) return 0;
        
        u64 duration_ns = bpf_ktime_get_ns() - *startp;
        bpf_map_delete_elem(&start, &pid_tgid);
        
        // 转换为微秒
        u64 duration_us = duration_ns / 1000;
        if (duration_us < 1) return 0;
        
        // 计算对数直方图槽位
        u32 slot = log2l(duration_us);
        if (slot >= MAX_SLOTS) slot = MAX_SLOTS - 1;
        
        // 更新直方图
    u64 *h = bpf_map_lookup_elem(&hist, &sys_nr);
        if (h) {
            __sync_fetch_and_add(&h[slot], 1);
        }
        
        return 0;
    }
    
    // 四个系统调用的 enter/exit handler
    SEC("tracepoint/syscalls/sys_enter_read")
    int enter_read(struct trace_event_raw_sys_enter *ctx) 
    { return trace_enter(0); }
    
    SEC("tracepoint/syscalls/sys_exit_read")
    int exit_read(struct trace_event_raw_sys_exit *ctx) 
    { return trace_exit(0); }
    
    SEC("tracepoint/syscalls/sys_enter_write")
    int enter_write(struct trace_event_raw_sys_enter *ctx) 
    { return trace_enter(1); }
    
    SEC("tracepoint/syscalls/sys_exit_write")
    int exit_write(struct trace_event_raw_sys_exit *ctx) 
    { return trace_exit(1); }
    
    SEC("tracepoint/syscalls/sys_enter_sendto")
    int enter_sendto(struct trace_event_raw_sys_enter *ctx) 
    { return trace_enter(2); }
    
    SEC("tracepoint/syscalls/sys_exit_sendto")
    int exit_sendto(struct trace_event_raw_sys_exit *ctx) 
    { return trace_exit(2); }
    
    SEC("tracepoint/syscalls/sys_enter_recvfrom")
    int enter_recvfrom(struct trace_event_raw_sys_enter *ctx) 
    { return trace_enter(3); }
    
    SEC("tracepoint/syscalls/sys_exit_recvfrom")
    int exit_recvfrom(struct trace_event_raw_sys_exit *ctx) 
    { return trace_exit(3); }
    
    char LICENSE[] SEC("license") = "GPL";
    

    4.3 结果输出

    
    # 通过 bpftool 读取直方图数据
    $ sudo bpftool map dump name hist
    
    key: 0  value: ...  # read 延迟分布(微秒)
    slot count
    0    1523      # < 1us
    1    2841      # 1-2us
    2    4102      # 2-4us
    3    3567      # 4-8us
    4    1890      # 8-16us
    5    723       # 16-32us
    6    312       # 32-64us
    ...
    30   1         # 1073741824-2147483648us
    

    五、CO-RE(Compile Once, Run Everywhere)

    5.1 问题背景

    传统 eBPF 编译需要目标机器的内核头文件,这在异构环境中是噩梦。BTF(BPF Type Format)解决了这个问题。

    5.2 CO-RE 工作流程

    
    ┌──────────────┐     ┌──────────┐     ┌──────────────┐
    │ 开发机器      │     │ 编译产物  │     │ 目标机器      │
    │              │     │          │     │              │
    │ vmlinux.h    │────►│ .o 文件   │────►│ libbpf 运行时 │
    │ (BTF 生成)   │     │ + BTF    │     │ 重定位字段    │
    │              │     │ relocs   │     │ (BTF CO-RE)  │
    └──────────────┘     └──────────┘     └──────────────┘
    

    5.3 实践

    
    # 1. 生成 vmlinux.h(从内核 BTF 信息)
    bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
    
    # 2. 编译(加上 -g 以记录 BTF reloc 信息)
    clang -O2 -g -target bpf -D__TARGET_ARCH_x86_64 \
        -I/usr/include/bpf \
        -c program.bpf.c -o program.bpf.o
    
    # 3. 在任何有 BTF 的内核上运行(5.4+ 基本都支持)
    

    使用 vmlinux.h 后,通过 BPF_CORE_READ 宏可以跨内核版本安全访问字段:

    
    // 传统方式:硬编码偏移(脆弱)
    u64 pid = *(u64 *)(task + 0x4D8);
    
    // CO-RE 方式:安全重定位(稳定)
    u64 pid = BPF_CORE_READ(task, pid);
    

    六、性能开销与优化策略

    6.1 量化开销

    操作 开销 说明
    Map lookup (hash) ~50ns 内核中单次读取
    Map update (hash) ~80ns 写入
    Ring buffer output ~70ns 推送到用户态
    Perf event output ~120ns + 拷贝开销
    BPF 程序执行 ~10ns 简单 prog
    bpf() syscall 加载 ~100μs 一次性
    JIT 编译 ~1-5ms 一次性

    6.2 优化策略

    
    // 使用 Per-CPU Map 减少缓存行竞争
    struct {
        __uint(type, BPF_MAP_TYPE_PERCPU_HASH);
        __uint(max_entries, 1024);
        __type(key, u32);
        __type(value, u64);
    } percpu_stats SEC(".maps");
    
    // Ring Buffer 优于 Perf events(零拷贝、更低延迟)
    // 在 BPF 程序中尽量使用 BPF CO-RE 避免运行时计算
    // BPF to BPF 调用减少代码重复(inline 之后无额外开销)
    
    // Tail call 拆分大型程序(突破指令数限制)
    struct {
        __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
        __uint(max_entries, 8);
        __type(key, u32);
        __type(value, u32);
    } progs SEC(".maps");
    
    SEC("xdp")
    int xdp_main(struct xdp_md *ctx)
    {
        bpf_tail_call(ctx, &progs, 0);
        return XDP_PASS;
    }
    

    6.3 Benchmark 参考

    在 8 核 Intel Xeon 上,单核极限场景:

    • XDP_DROP:~24M pps(每秒 2400 万包)
    • kprobe:~5M events/s
    • tracepoint:~8M events/s
    • uprobe:~3M events/s
    • Ring Buffer 消费:~20M events/s

    七、eBPF 生态系统与工具链

    7.1 开发工具

    工具 用途
    bpftool 查看/操作 BPF 程序、Map、BTF
    libbpf 加载和管理 BPF 程序(CO-RE 支持)
    BCC Python 快速原型开发框架
    BPFtrace 一行脚本完成简单追踪
    eunomia-bpf 在线部署与 WebAssembly 混合
    Hookdrop 基于 eBPF 的系统加固
    corge Rust + Aya 框架开发

    7.2 生产级项目

    • Cilium:基于 eBPF 的 CNI,替代 kube-proxy,提供 L3-L7 网络策略
    • Tetragon:安全可观测性运行时,实时监控进程/网络/文件行为
    • Falco:异常行为检测,云原生运行时安全
    • Pixie:Kubernetes 应用可观测性,零侵入采集遥测数据
    • Katran:Meta 的 4/7 层负载均衡器,XDP +一致性哈希
    • Kube-OVN:OVN + eBPF 替代 Open vSwitch

    八、限制与注意事项

    8.1 指令数限制

    默认 100 万条指令(5.2+ 内核),Verifier 会模拟执行每条路径。

    8.2 循环限制

    禁止无限循环。有限循环需满足:

    
    #pragma unroll
    for (int i = 0; i < 8; i++) {  // 编译期确定的迭代次数
        ...
    }
    

    8.3 栈空间限制

    BPF 栈仅 512 字节,大数据结构必须使用 Map。

    8.4 GPL 兼容

    调用 GPL-only helper 函数的 eBPF 程序必须声明 SEC("license") = "GPL"。

    8.5 内存安全

    所有内存访问必须经过 verifier 验证边界,直接指针解引用会被拒绝。

    九、总结与展望

    eBPF 的核心价值总结:

    1. 安全沙箱:Verifier 确保用户程序不会导致内核崩溃
    2. 原生性能:JIT 编译后等同内核原生代码
    3. 零侵入:无需修改目标进程或内核代码
    4. 实时性:事件驱动,毫秒级响应
    5. 生态丰富:工具链成熟,社区活跃
    6. 未来趋势:

      • BPF Typed Pins(持久化 BPF 对象)
      • BPF For BPF(更丰富的跨程序调用)
      • ARM64/PPC/RISC-V 的支持日益完善
      • 与 io_uring 的深度融合(异步 BPF 运行时)
      • BPF LSM 的广泛应用(可编程安全策略)

      引用:eBPF 不是一项技术,而是一场正在发生的范式革命—它将 Linux 内核从一个静态的黑盒变成了一个动态可编程的平台,让每一个人都能以前所未有的方式观察、保护和优化自己的系统。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿
网站二维码

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部
/* 跳过导航链接 (无障碍) */ position: absolute; top: -100px; left: 15px; z-index: 99999; padding: 8px 16px; background: #007bff; color: #fff; font-size: 14px; border-radius: 0 0 4px 4px; text-decoration: none; transition: top 0.2s; } top: 0; outline: 3px solid #0056b3; }