eBPF内核编程:从TC到XDP的全栈可观测性

eBPF内核编程:从TC到XDP的全栈可观测性

一、引言

eBPF 是 Linux 内核的"超级能力"------无需重新编译内核,动态注入安全沙箱化的程序,实现网络、安全、可观测性的全栈覆盖。Cilium/Falco/Pixie 等明星项目都构建在eBPF之上。

二、eBPF执行模型

复制代码
用户空间                    内核空间
┌──────────┐     BPF syscall     ┌────────────┐
│ eBPF程序 │ ──────────────────► │  Verifier  │ (安全检查)
│ (C/Rust) │                     │            │
└──────────┘                     └─────┬──────┘
                                       │
                              ┌────────▼──────┐
                              │  JIT Compiler │ → 原生机器码
                              └────────┬──────┘
                                       │
                    ┌──────────────────┼──────────────────┐
                    ▼                  ▼                  ▼
              ┌──────────┐     ┌──────────┐      ┌──────────┐
              │ kprobe   │     │ tracepoint│      │ XDP/TC   │
              │ 内核函数  │     │ 跟踪点    │      │ 网络钩子  │
              └──────────┘     └──────────┘      └──────────┘
                    │                  │                  │
                    └──────────────────┼──────────────────┘
                                       ▼
                              ┌──────────────┐
                              │  BPF Maps    │ (内核←→用户共享内存)
                              │  (Hash/Array)│
                              └──────┬───────┘
                                     │
                                     ▼
                              用户空间读取/可视化

三、BCC实战

python 复制代码
from bcc import BPF

# 1. 追踪所有 execve() 系统调用
prog = """
#include 

BPF_HASH(last_exec, u32, u64);  // BPF Map

int trace_execve(struct pt_regs *ctx) {
    u32 pid = bpf_get_current_pid_tgid();
    u64 ts = bpf_ktime_get_ns();
    last_exec.update(&pid, &ts);  // 记录时间戳
    return 0;
}
"""

b = BPF(text=prog)
b.attach_kprobe(event="__x64_sys_execve", fn_name="trace_execve")

# 打印追踪结果
b.trace_print()

TCP连接追踪

python 复制代码
prog = """
#include 

struct event_t {
    u32 pid;
    u32 saddr, daddr;
    u16 sport, dport;
    char comm[16];
};
BPF_PERF_OUTPUT(events);

int trace_connect(struct pt_regs *ctx, struct sock *sk) {
    struct event_t event = {};
    event.pid = bpf_get_current_pid_tgid();
    bpf_get_current_comm(&event.comm, sizeof(event.comm));
    
    // 读取源/目标IP和端口
    event.saddr = sk->__sk_common.skc_rcv_saddr;
    event.daddr = sk->__sk_common.skc_daddr;
    event.sport = sk->__sk_common.skc_num;
    event.dport = sk->__sk_common.skc_dport;
    
    events.perf_submit(ctx, &event, sizeof(event));
    return 0;
}

def print_event(cpu, data, size):
    event = b["events"].event(data)
    print(f"PID {event.pid} ({event.comm}) "
          f"{event.saddr}:{event.sport} → {event.daddr}:{event.dport}")
"""

b = BPF(text=prog)
b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect")
b["events"].open_perf_buffer(print_event)
while True:
    b.perf_buffer_poll()

四、XDP高性能网络

c 复制代码
// XDP: 网卡驱动层处理数据包(DDoS防护/负载均衡)
// 比iptables快10-100x

#include 
#include 
#include 
#include 

// 最简单的XDP DDoS防护:丢弃所有UDP包
SEC("xdp_drop")
int xdp_drop_udp(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    
    struct ethhdr *eth = data;
    if ((void*)(eth + 1) > data_end) return XDP_PASS;
    
    if (eth->h_proto == __constant_htons(ETH_P_IP)) {
        struct iphdr *ip = (void*)(eth + 1);
        if ((void*)(ip + 1) > data_end) return XDP_PASS;
        
        if (ip->protocol == IPPROTO_UDP) {
            return XDP_DROP;  // 丢弃!仅需~80ns
        }
    }
    
    return XDP_PASS;
}

五、Rust + Aya框架

rust 复制代码
use aya::{programs::Kprobe, Bpf};
use aya_log::BpfLogger;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 加载eBPF程序
    let mut bpf = Bpf::load(include_bytes_aligned!(
        "../target/bpfel-unknown-none/release/myprog"
    ))?;
    
    BpfLogger::init(&mut bpf)?;
    
    // 挂载kprobe
    let program: &mut Kprobe = bpf.program_mut("trace_openat")
        .unwrap().try_into()?;
    program.load()?;
    program.attach("do_sys_openat2", 0)?;
    
    // 持续运行
    tokio::signal::ctrl_c().await?;
    Ok(())
}

六、Cilium网络可观测

yaml 复制代码
# Cilium Hubble: 基于eBPF的服务网格可观测
# kubectl exec -n kube-system ds/cilium -- hubble observe

# 流量日志:
# default/pod-a → default/pod-b:80   FORWARDED (TCP)
# default/pod-a → external:443       FORWARDED (TLS)
# default/pod-x → 10.0.1.5:8080      DROPPED (Policy Denied)

七、eBPF安全防护

c 复制代码
// Falco: 基于eBPF的运行时安全检测
// 规则示例:检测非标准SSH端口
- rule: SSH outside standard port
  condition: >
    evt.type=connect and fd.sport!=22 and
    proc.name in (sshd, ssh)
  output: "SSH connection outside port 22 (user=%user.name)"
  priority: WARNING

八、总结

eBPF技术栈:BCC(快速原型) → bpftrace(调试) → Cilium(网络) → Falco(安全) → Aya(Rust生产)

核心价值:内核级可观测 + 零开销 + 安全沙箱 + 动态加载。

相关推荐
BingoGo3 小时前
PHP clone 之后,为什么改副本会影响原对象?
后端·php
JaguarJack3 小时前
PHP clone 之后,为什么改副本会影响原对象?
后端·php·服务端
砚凝霜3 小时前
【软考信息安全】第一章 网络安全基础、管理与法律法规
安全·web安全·php
Johny_Zhao6 小时前
网络安全等级保护测评实施方案
linux·网络·人工智能·网络安全·信息安全·云计算·等保测评·系统运维·itsm
落羽的落羽7 小时前
【AI】快速理解AI应用的相关名词概念
linux·c++·人工智能·python·计算机网络·算法
刚入门的大一新生7 小时前
Linux-进程控制
linux·运维·服务器·c++
上火的金鱼妹7 小时前
K8S基础组件作用和关系整理
linux·运维·服务器·kubernetes
Vcaker7 小时前
Linux学习25-harbor私有仓库部署
linux·运维·学习
刃神太酷啦7 小时前
Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)
linux·c语言·数据库·c++·redis·缓存·bootstrap
编程的一拳超人8 小时前
DeepSeek Harness Linux/macOS/Windows 本地下载、启动与模型配置指南
linux·windows·macos·deepseek