
关注「Raymond运维」公众号,并设为「星标」,也可以扫描底部二维码加入群聊,第一时间获取最新内容,不再错过精彩内容。
eBPF(extended Berkeley Packet Filter)是Linux内核3.18引入的革命性技术,它允许在内核空间运行用户定义的沙盒程序,无需修改内核代码或加载内核模块。传统的内核观测手段(如SystemTap、kprobe)需要编译内核模块,存在系统崩溃风险且灵活性差。eBPF通过JIT编译和验证器机制,在保证安全性的前提下,实现了动态、高性能的内核可编程能力。从网络包过滤到性能分析,从安全审计到容器网络,eBPF正在重新定义系统可观测性的边界。
# 检查内核版本uname -r# 检查eBPF支持grep CONFIG_BPF /boot/config-$(uname -r)# 应输出: CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_JIT=y# 检查BTF支持(CO-RE需要)ls /sys/kernel/btf/vmlinuxUbuntu/Debian:
# 更新系统sudo apt update && sudo apt upgrade -y# 安装编译工具链sudo apt install -y \ build-essential \ clang \ llvm \ libelf-dev \ linux-headers-$(uname -r) \ linux-tools-$(uname -r) \ linux-tools-common# 安装BCC工具集(快速上手)sudo apt install -y bpfcc-tools python3-bpfcc# 或安装libbpf开发库(生产环境推荐)sudo apt install -y libbpf-devCentOS/RHEL:
# 安装依赖sudo yum install -y \ clang \ llvm \ elfutils-libelf-devel \ kernel-devel-$(uname -r) \ bcc-tools# 安装内核调试符号sudo debuginfo-install kernel-$(uname -r)# 测试bpftoolsudo bpftool prog list# 测试BCC工具sudo /usr/share/bcc/tools/execsnoop# 检查map类型支持bpftool feature probe | grep "map_type"说明:如果bpftool prog list返回空,说明当前没有加载eBPF程序,这是正常的。execsnoop应能实时显示系统中执行的命令。
hello_world.py:
#!/usr/bin/env python3# hello_world.py - BCC入门示例from bcc import BPF# eBPF程序(C代码)bpf_program = """#include <uapi/linux/ptrace.h>int hello(struct pt_regs *ctx) { bpf_trace_printk("Hello, eBPF!\\n"); return 0;}"""# 加载eBPF程序b = BPF(text=bpf_program)# 将hello函数attach到sys_clone系统调用b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="hello")print("eBPF程序已加载,按Ctrl+C退出...")try: b.trace_print()except KeyboardInterrupt:print("\n程序退出")运行示例:
sudo python3 hello_world.py# 在另一个终端执行命令触发clone系统调用ls /tmp# 输出:# <...>-12345 [001] .... 123456.789012: 0: Hello, eBPF!trace_execve.bpf.c(内核态代码):
// trace_execve.bpf.c#include<linux/bpf.h>#include<bpf/bpf_helpers.h>#include<bpf/bpf_tracing.h>char LICENSE[] SEC("license") = "GPL";struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024);} events SEC(".maps");structevent {int pid;char comm[16];};SEC("tracepoint/syscalls/sys_enter_execve")inttrace_execve(struct trace_event_raw_sys_enter* ctx){structevent *e; e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);if (!e)return0; e->pid = bpf_get_current_pid_tgid() >> 32; bpf_get_current_comm(&e->comm, sizeof(e->comm)); bpf_ringbuf_submit(e, 0);return0;}trace_execve.c(用户态代码):
// trace_execve.c#include<stdio.h>#include<unistd.h>#include<signal.h>#include<bpf/libbpf.h>#include"trace_execve.skel.h"structevent {int pid;char comm[16];};staticvolatilebool exiting = false;staticvoidsig_handler(int sig){ exiting = true;}staticinthandle_event(void *ctx, void *data, size_t data_sz){conststructevent *e = data;printf("PID %-6d COMM %-16s\n", e->pid, e->comm);return0;}intmain(int argc, char **argv){structring_buffer *rb =NULL;structtrace_execve_bpf *skel;int err; signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler);// 打开并加载eBPF程序 skel = trace_execve_bpf__open_and_load();if (!skel) {fprintf(stderr, "Failed to open and load BPF skeleton\n");return1; }// 附加tracepoint err = trace_execve_bpf__attach(skel);if (err) {fprintf(stderr, "Failed to attach BPF skeleton\n");goto cleanup; }// 创建ring buffer rb = ring_buffer__new(bpf_map__fd(skel->maps.events), handle_event, NULL, NULL);if (!rb) { err = -1;fprintf(stderr, "Failed to create ring buffer\n");goto cleanup; }printf("%-10s %-16s\n", "PID", "COMM");while (!exiting) { err = ring_buffer__poll(rb, 100);if (err == -EINTR) { err = 0;break; }if (err < 0) {fprintf(stderr, "Error polling ring buffer: %d\n", err);break; } }cleanup: ring_buffer__free(rb); trace_execve_bpf__destroy(skel);return err < 0 ? -err : 0;}编译和运行:
# 编译eBPF程序clang -O2 -g -target bpf -D__TARGET_ARCH_x86_64 \ -c trace_execve.bpf.c -o trace_execve.bpf.o# 生成skeleton头文件bpftool gen skeleton trace_execve.bpf.o > trace_execve.skel.h# 编译用户态程序clang -O2 -g trace_execve.c -o trace_execve -lbpf -lelf -lz# 运行sudo ./trace_execve# 追踪所有execve调用sudo execsnoop-bpfcc# 追踪TCP连接sudo tcpconnect-bpfcc# 分析系统调用延迟sudo funclatency-bpfcc sys_read# 统计VFS操作sudo vfsstat-bpfcc 1# 查看加载的eBPF程序sudo bpftool prog show# 查看eBPF Mapssudo bpftool map show# 导出Map内容sudo bpftool map dump id <MAP_ID># 查看程序性能统计sudo bpftool prog profile预期输出:
# bpftool prog show12: tracepoint name trace_execve tag abc123def456 loaded_at 2025-01-15T10:30:00+0800 uid 0 xlated 256B jited 180B memlock 4096Bxdp_drop_tcp.bpf.c:
// XDP程序: 丢弃目标端口为4040的TCP包#include<linux/bpf.h>#include<linux/if_ether.h>#include<linux/ip.h>#include<linux/tcp.h>#include<bpf/bpf_helpers.h>SEC("xdp")intxdp_drop_tcp_4040(struct xdp_md *ctx){void *data_end = (void *)(long)ctx->data_end;void *data = (void *)(long)ctx->data;// 解析以太网头structethhdr *eth = data;if ((void *)(eth + 1) > data_end)return XDP_PASS;// 只处理IP包if (eth->h_proto != __constant_htons(ETH_P_IP))return XDP_PASS;// 解析IP头structiphdr *ip = (void *)(eth + 1);if ((void *)(ip + 1) > data_end)return XDP_PASS;// 只处理TCP协议if (ip->protocol != IPPROTO_TCP)return XDP_PASS;// 解析TCP头structtcphdr *tcp = (void *)ip + (ip->ihl * 4);if ((void *)(tcp + 1) > data_end)return XDP_PASS;// 丢弃目标端口4040的包if (tcp->dest == __constant_htons(4040)) { bpf_printk("Dropped TCP packet to port 4040\n");return XDP_DROP; }return XDP_PASS;}char LICENSE[] SEC("license") = "GPL";加载XDP程序:
# 编译clang -O2 -g -target bpf -c xdp_drop_tcp.bpf.c -o xdp_drop_tcp.bpf.o# 加载到网卡eth0sudo ip linkset dev eth0 xdp obj xdp_drop_tcp.bpf.o sec xdp# 测试(在另一台机器)nc -zv <目标IP> 4040 # 应该超时# 卸载sudo ip linkset dev eth0 xdp offsyscall_audit.bpf.c:
// 审计危险系统调用(execve, unlink, rmdir)#include<linux/bpf.h>#include<bpf/bpf_helpers.h>#include<bpf/bpf_tracing.h>char LICENSE[] SEC("license") = "GPL";structsyscall_event { __u32 pid; __u32 uid;char comm[16];char syscall[16];};struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); __uint(key_size, sizeof(__u32)); __uint(value_size, sizeof(__u32));} events SEC(".maps");static __always_inline inttrace_syscall(void *ctx, constchar *name){structsyscall_eventevent = {}; __u64 pid_tgid = bpf_get_current_pid_tgid(); __u64 uid_gid = bpf_get_current_uid_gid(); event.pid = pid_tgid >> 32; event.uid = uid_gid & 0xFFFFFFFF; bpf_get_current_comm(&event.comm, sizeof(event.comm)); bpf_probe_read_kernel_str(&event.syscall, sizeof(event.syscall), name); bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));return0;}SEC("tracepoint/syscalls/sys_enter_execve")inttrace_execve(struct trace_event_raw_sys_enter* ctx){return trace_syscall(ctx, "execve");}SEC("tracepoint/syscalls/sys_enter_unlink")inttrace_unlink(struct trace_event_raw_sys_enter* ctx){return trace_syscall(ctx, "unlink");}SEC("tracepoint/syscalls/sys_enter_rmdir")inttrace_rmdir(struct trace_event_raw_sys_enter* ctx){return trace_syscall(ctx, "rmdir");}用户态程序(Python + BCC):
#!/usr/bin/env python3from bcc import BPFimport ctypes as ct# 定义事件结构classSyscallEvent(ct.Structure): _fields_ = [ ("pid", ct.c_uint32), ("uid", ct.c_uint32), ("comm", ct.c_char * 16), ("syscall", ct.c_char * 16), ]# 加载eBPF程序b = BPF(src_file="syscall_audit.bpf.c")# 附加tracepointsb.attach_tracepoint(tp="syscalls:sys_enter_execve", fn_name="trace_execve")b.attach_tracepoint(tp="syscalls:sys_enter_unlink", fn_name="trace_unlink")b.attach_tracepoint(tp="syscalls:sys_enter_rmdir", fn_name="trace_rmdir")# 回调函数defprint_event(cpu, data, size): event = ct.cast(data, ct.POINTER(SyscallEvent)).contentsprint(f"[AUDIT] PID={event.pid} UID={event.uid} COMM={event.comm.decode()} SYSCALL={event.syscall.decode()}")# 打开perf bufferb["events"].open_perf_buffer(print_event)print("监控危险系统调用中,按Ctrl+C退出...")whileTrue:try: b.perf_buffer_poll()except KeyboardInterrupt:breakprofile_oncpu.bpf.c(CPU火焰图数据采集):
// 采集on-CPU时间,用于生成火焰图#include<linux/bpf.h>#include<bpf/bpf_helpers.h>#include<bpf/bpf_tracing.h>char LICENSE[] SEC("license") = "GPL";#define MAX_STACK_DEPTH 50struct { __uint(type, BPF_MAP_TYPE_STACK_TRACE); __uint(key_size, sizeof(__u32)); __uint(value_size, MAX_STACK_DEPTH * sizeof(__u64)); __uint(max_entries, 10000);} stack_traces SEC(".maps");struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(key_size, sizeof(__u32)); __uint(value_size, sizeof(__u64)); __uint(max_entries, 10000);} counts SEC(".maps");SEC("perf_event")intdo_sample(struct bpf_perf_event_data *ctx){ __u32 key = 0; __u64 *val, one = 1;// 获取内核栈 key = bpf_get_stackid(ctx, &stack_traces, 0);if ((int)key < 0)return0; val = bpf_map_lookup_elem(&counts, &key);if (val) __sync_fetch_and_add(val, 1);else bpf_map_update_elem(&counts, &key, &one, BPF_NOEXIST);return0;}用户态采集脚本(使用bcc):
#!/usr/bin/env python3from bcc import BPFimport signalimport sysbpf_program = """#include <uapi/linux/ptrace.h>BPF_STACK_TRACE(stack_traces, 10000);BPF_HASH(counts, u32, u64);int do_sample(struct bpf_perf_event_data *ctx) { u32 key = 0; u64 *val, one = 1; key = stack_traces.get_stackid(&ctx->regs, 0); if ((int)key < 0) return 0; val = counts.lookup(&key); if (val) (*val)++; else counts.update(&key, &one); return 0;}"""b = BPF(text=bpf_program)b.attach_perf_event(ev_type=PerfType.SOFTWARE, ev_config=PerfSWConfig.CPU_CLOCK, fn_name="do_sample", sample_freq=49)print("采集CPU profile,按Ctrl+C结束...")try:whileTrue: sleep(1)except KeyboardInterrupt:passcounts = b["counts"]stack_traces = b["stack_traces"]# 输出folded格式(供flamegraph.pl使用)for k, v insorted(counts.items(), key=lambda x: x[1].value, reverse=True): stack = list(stack_traces.walk(k.value)) symbols = []for addr in stack: sym = b.sym(addr, -1) symbols.append(sym.decode('utf-8', 'replace'))print(f"{';'.join(reversed(symbols))}{v.value}")场景描述:Kubernetes集群中某服务响应慢,需要分析容器网络栈延迟。
实现代码:
# 使用BCC工具tcplife追踪TCP连接生命周期sudo tcplife-bpfcc -p $(pgrep -f "myapp")# 输出示例PID COMM LADDR LPORT RADDR RPORT TX_KB RX_KB MS12345 myapp 10.244.1.5 8080 10.244.2.10 34567 0.5 2.3 125深度分析:
#!/usr/bin/env python3# tcp_latency.py - 分析TCP connect延迟from bcc import BPFbpf_text = """#include <uapi/linux/ptrace.h>#include <net/sock.h>#include <bcc/proto.h>BPF_HASH(start, u32);int trace_connect_entry(struct pt_regs *ctx, struct sock *sk){ u32 pid = bpf_get_current_pid_tgid() >> 32; u64 ts = bpf_ktime_get_ns(); start.update(&pid, &ts); return 0;}int trace_connect_return(struct pt_regs *ctx){ u32 pid = bpf_get_current_pid_tgid() >> 32; u64 *tsp, delta_us; tsp = start.lookup(&pid); if (tsp == 0) return 0; delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; bpf_trace_printk("PID %d connect latency: %lld us\\n", pid, delta_us); start.delete(&pid); return 0;}"""b = BPF(text=bpf_text)b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_entry")b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_return")print("追踪TCP connect延迟...")b.trace_print()运行结果:
myapp-12345 [001] .... 123456.789012: PID 12345 connect latency: 1234 us场景描述:数据库服务器IOPS高,需要定位频繁读写的文件。
实现方案:
# 使用filetop实时统计文件读写sudo filetop-bpfcc -C# 输出示例Tracing... Output every 1 secs. Hit Ctrl-C to endTID COMM READS WRITES R_Kb W_Kb T FILE1234 mysqld 1205 523 96400 41840 R data/ibdata11234 mysqld 523 0 41840 0 R data/ib_logfile05678 redis-server 89 156 712 1248 R dump.rdb详细追踪:
#!/usr/bin/env python3# vfs_trace.py - 追踪VFS层读写from bcc import BPFbpf_program = """#include <uapi/linux/ptrace.h>#include <linux/fs.h>BPF_HASH(counts, struct dentry *);int trace_vfs_read(struct pt_regs *ctx, struct file *file){ struct dentry *dentry = file->f_path.dentry; u64 *val, one = 1; val = counts.lookup(&dentry); if (val) (*val)++; else counts.update(&dentry, &one); return 0;}"""b = BPF(text=bpf_program)b.attach_kprobe(event="vfs_read", fn_name="trace_vfs_read")print("统计VFS读操作,10秒后输出结果...")time.sleep(10)counts = b["counts"]for k, v insorted(counts.items(), key=lambda x: x[1].value, reverse=True)[:20]:# 解析dentry获取文件名 dentry_ptr = k.value filename = b.get_dentry_name(dentry_ptr)print(f"{filename.decode('utf-8', 'replace')}: {v.value} reads")场景描述:应用进程内存持续增长,怀疑有内存泄露。
实现步骤:
# 使用memleak工具追踪内存分配sudo memleak-bpfcc -p $(pgrep myapp) -t# 输出示例(显示调用栈和分配次数)[10:30:00]addr = 0x7f8a4c0010 size = 4096 [unknown] [unknown] malloc+0x28 myapp_alloc+0x45 [myapp] process_request+0x123 [myapp] 120 allocs, 0 frees自定义内存追踪:
// memleak_trace.bpf.c#include<linux/bpf.h>#include<bpf/bpf_helpers.h>structalloc_info { __u64 size; __u64 timestamp; __u32 stack_id;};struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 10240); __type(key, __u64); // address __type(value, struct alloc_info);} allocs SEC(".maps");struct { __uint(type, BPF_MAP_TYPE_STACK_TRACE); __uint(key_size, sizeof(__u32)); __uint(value_size, 127 * sizeof(__u64)); __uint(max_entries, 1024);} stack_traces SEC(".maps");SEC("uprobe/malloc")inttrace_malloc(struct pt_regs *ctx){ __u64 size = PT_REGS_PARM1(ctx);// 保存参数,在uretprobe中使用 __u64 pid_tgid = bpf_get_current_pid_tgid(); bpf_map_update_elem(&sizes, &pid_tgid, &size, BPF_ANY);return0;}SEC("uretprobe/malloc")inttrace_malloc_return(struct pt_regs *ctx){ __u64 addr = PT_REGS_RC(ctx); __u64 pid_tgid = bpf_get_current_pid_tgid(); __u64 *size = bpf_map_lookup_elem(&sizes, &pid_tgid);if (!size || addr == 0)return0;structalloc_infoinfo = { .size = *size, .timestamp = bpf_ktime_get_ns(), .stack_id = bpf_get_stackid(ctx, &stack_traces, BPF_F_USER_STACK), }; bpf_map_update_elem(&allocs, &addr, &info, BPF_ANY); bpf_map_delete_elem(&sizes, &pid_tgid);return0;}SEC("uprobe/free")inttrace_free(struct pt_regs *ctx){ __u64 addr = PT_REGS_PARM1(ctx); bpf_map_delete_elem(&allocs, &addr);return0;}char LICENSE[] SEC("license") = "GPL";// 不推荐(高频场景)bpf_trace_printk("count: %d\n", count);// 推荐bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &data, sizeof(data));struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, 1); __type(key, __u32); __type(value, __u64);} stats SEC(".maps");#pragma unroll或bounded loops#pragma unrollfor (int i = 0; i < 10; i++) {// 循环体}# 启用unprivileged eBPFsudo sysctl kernel.unprivileged_bpf_disabled=0# 限制map访问(需要内核5.13+)bpf_map__set_map_flags(map, BPF_F_RDONLY_PROG);# 临时提升限制ulimit -l unlimited# 永久配置 /etc/security/limits.conf* hard memlock unlimited* soft memlock unlimited# 检查程序是否被卸载if ! bpftool prog show id <PROG_ID>; thenecho"eBPF program lost, reloading..." reload_ebpf_programfistruct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 100000); // 根据实际负载调整} my_map SEC(".maps");# 发送到Elasticsearchfrom elasticsearch import Elasticsearches = Elasticsearch(['http://localhost:9200'])defhandle_event(cpu, data, size): event = parse_event(data) es.index(index="ebpf-events", document=event)ethtool -i <interface>/sys/kernel/debug/tracing/events |
# 查看eBPF程序加载日志sudo dmesg | grep -i bpf# 查看verifier拒绝原因sudo bpftool prog load program.o /sys/fs/bpf/myprog 2>&1# 查看trace_pipe输出(bpf_trace_printk)sudocat /sys/kernel/debug/tracing/trace_pipe# 查看perf eventssudo perf record -e 'bpf:*' -a sleep 10sudo perf script问题一:程序加载失败,提示"back-edge from insn X to Y"
# 查看详细错误sudo bpftool prog load program.o /sys/fs/bpf/test 2>&1 | less解决方案:
#pragma unroll展开循环问题二:XDP程序无法附加到网卡
# 检查驱动支持ethtool -i eth0 | grep driver# 检查XDP模式ip link show eth0 | grep xdp解决方案:
ip link set dev eth0 xdpgeneric obj program.o问题三:性能开销过高
bpftool prog profile查看程序执行开销sample_period = 1000# 开启eBPF JIT调试echo 2 | sudotee /proc/sys/net/core/bpf_jit_enablesudo dmesg | tail -100 # 查看JIT编译的汇编代码# 使用llvm-objdump查看字节码llvm-objdump -S program.bpf.o# 使用bpftool查看已加载程序的字节码sudo bpftool prog dump xlated id <PROG_ID># 查看JIT后的汇编sudo bpftool prog dump jited id <PROG_ID># 监控eBPF程序执行时间sudo bpftool prog profile id <PROG_ID># 监控map内存使用sudo bpftool map show# 计算内存占用: max_entries * (key_size + value_size)# 监控系统整体eBPF开销perf stat -e 'bpf:*' -a sleep 10使用Prometheus导出指标:
#!/usr/bin/env python3from prometheus_client import start_http_server, Gaugeimport subprocessimport time# 定义指标ebpf_prog_count = Gauge('ebpf_programs_total', 'Total eBPF programs loaded')ebpf_map_memory = Gauge('ebpf_map_memory_bytes', 'Memory used by eBPF maps')defcollect_metrics():# 统计程序数量 prog_count = subprocess.check_output(['sudo', 'bpftool', 'prog', 'list']).decode().count('\n') ebpf_prog_count.set(prog_count)# 统计map内存(简化计算)# 实际应解析bpftool map show输出 ebpf_map_memory.set(1024 * 1024) # 示例值if __name__ == '__main__': start_http_server(9101)whileTrue: collect_metrics() time.sleep(15)# Prometheus告警规则groups:-name:ebpf_alertsinterval:30srules:-alert:eBPFProgramMissingexpr:ebpf_programs_total{job="critical"}==0for:5mlabels:severity:criticalannotations:summary:"关键eBPF程序丢失"description:"检查程序是否被卸载或崩溃"-alert:eBPFMapMemoryHighexpr:ebpf_map_memory_bytes>2*1024*1024*1024for:10mlabels:severity:warningannotations:summary:"eBPF Maps内存占用过高"description:"当前占用 {{ $value | humanize }}B"-alert:eBPFHighCPUexpr:rate(bpf_prog_run_time_ns[5m])>0.15for:5mlabels:severity:warningannotations:summary:"eBPF程序CPU开销过高"#!/bin/bash# ebpf_backup.sh - 备份eBPF程序配置BACKUP_DIR="/data/backups/ebpf"DATE=$(date +%Y%m%d)mkdir -p $BACKUP_DIR# 导出已加载的程序列表sudo bpftool prog show > $BACKUP_DIR/programs_$DATE.txt# 导出map内容(示例)for map_id in $(sudo bpftool map list | grep -oP '^\d+'); dosudo bpftool map dump id$map_id > $BACKUP_DIR/map_${map_id}_$DATE.jsondone# 备份源代码和编译产物tar -czf $BACKUP_DIR/ebpf_src_$DATE.tar.gz /opt/ebpf_programs/# 清理30天前备份find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete# 卸载所有eBPF程序for prog_id in $(sudo bpftool prog list | grep -oP '^\d+'); dosudo bpftool prog detach id$prog_iddone# 解压源代码tar -xzf /data/backups/ebpf/ebpf_src_20250115.tar.gz -C /opt/# 重新编译和加载cd /opt/ebpf_programsmake clean && make./load_programs.sh# 检查程序是否加载sudo bpftool prog list# 检查map是否创建sudo bpftool map list# 测试功能sudocat /sys/kernel/debug/tracing/trace_pipe# eBPF程序管理sudo bpftool prog list # 列出所有程序sudo bpftool prog show id <ID> # 查看程序详情sudo bpftool prog dump xlated id <ID> # 导出字节码sudo bpftool prog dump jited id <ID> # 导出JIT汇编sudo bpftool prog pin id <ID> /sys/fs/bpf/myprog # 固定程序# Map管理sudo bpftool map list # 列出所有mapssudo bpftool map dump id <ID> # 导出map内容sudo bpftool map update id <ID> key 0x01 value 0x02 # 更新mapsudo bpftool map delete id <ID> key 0x01 # 删除entry# 编译和加载clang -O2 -g -target bpf -c program.bpf.c -o program.bpf.osudo ip linkset dev eth0 xdp obj program.bpf.o sec xdp # XDPsudo tc filter add dev eth0 egress bpf obj program.bpf.o # TC# 调试sudocat /sys/kernel/debug/tracing/trace_pipe # 查看printk输出echo 1 | sudotee /sys/kernel/debug/tracing/tracing_on # 开启tracingMap类型选择:
BPF_MAP_TYPE_HASH:哈希表,适合kv存储,查找O(1)BPF_MAP_TYPE_ARRAY:数组,索引访问,性能最优BPF_MAP_TYPE_PERCPU_HASH/ARRAY:per-CPU版本,避免竞争BPF_MAP_TYPE_RINGBUF:环形缓冲区,替代perf_event,内核5.8+BPF_MAP_TYPE_LRU_HASH:LRU哈希表,自动淘汰旧数据BPF_MAP_TYPE_STACK_TRACE:存储内核/用户栈,用于火焰图XDP返回值:
XDP_PASS:继续内核协议栈处理XDP_DROP:丢弃数据包(DDoS防护)XDP_TX:从相同网卡发送回去(负载均衡)XDP_REDIRECT:重定向到其他网卡(路由)XDP_ABORTED:异常,丢弃并记录微
信
群
WeChat group
为了方便大家更好的交流运维等相关技术问题,创建了微信交流群,需要加群的小伙伴们可以扫一扫下面的二维码加我为好友拉您进群(备注:加群)。

代
码
仓
库
| 代码仓库 | 网址 |
| Github | https://github.com/raymond999999 |
| Gitee | https://gitee.com/raymond9 |
博
客
Blog
| 博客 | 网址 |
| https://blog.csdn.net/qq_25599925 | |
| 稀土掘金 | https://juejin.cn/user/4262187909781751 |
| 知识星球 | https://wx.zsxq.com/group/15555885545422 |
| 阿里云社区 | https://developer.aliyun.com/profile/snzh3xpxaf6sg |
| 腾讯云社区 | https://cloud.tencent.com/developer/user/11823619 |
| 华为云社区 | https://developer.huaweicloud.com/usercenter/mycommunity/dynamics |
访问博客网站,查看更多优质原创内容。