eBPF(extended Berkeley Packet Filter, 可扩展伯克利包过滤器) 对内核进行动态编程,以实现高效联网、可观察性、可追踪性和安全性
介绍
- eBPF是从- BPF(也称 cBPF:classic Berkeley Packet Filter)发展而来的,- BPF专门用来过滤网络数据包
- eBPF允许程序在不修改内核源代码,或添加额外的内核模块情况下运行
- 特征
- 无侵入特性:观测成本极低,应用无需修改任何代码和重启进程
- 动态可编程性:无需重启探针,动态下发 eBPF 脚本即可修改探针侧的逻辑
- 高性能:自带 JIT 编译,使探针能够获得内核本地运行的效率
- 安全:verifier 机制限制了 eBPF 脚本能够访问的内核函数,保证内核运行的稳定
 
eBPF 架构
    
     
    
    
转自
- 用户态
- 用户编写 eBPF程序,可以使用eBPF汇编或者eBPF特有的 C 语言来编写
- 使用 LLVM/CLang编译器,将eBPF程序编译成eBPF字节码
- 调用 bpf()系统调用把eBPF字节码加载到内核
 
- 内核态
- 当用户调用 bpf()系统调用把eBPF字节码加载到内核时,内核先会对eBPF字节码进行安全验证
- 使用 JIT(Just In Time)技术将eBPF字节编译成本地机器码(Native Code)
- 根据 eBPF程序的功能,将eBPF机器码挂载到内核的不同运行路径上
- 如用于跟踪内核运行状态的 eBPF程序将会挂载在kprobes的运行路径上
 
- 当内核运行到这些路径时,会触发执行相应路径上的 eBPF机器码
 
 
    
    
上图转载自
eBPF 挂载点
    
     
    
    
bpftrace_probes 参考
相关链接
持续剖析
- 持续剖析(Continuous Profiling)是通过动态实时采集应用程序 CPU、内存等资源申请的堆栈信息,帮助检测和定位应用程序的性能瓶颈,实现包括- 
- eBPF
- jstack
- 火焰图(Flame Graph)- 
- 分析 CPU 占用、内存分配、内存泄漏、墙中热点、网络 IO、文件 IO、锁竞争、异常
- 实现包括:广义火焰图、冰柱状火焰图
 
 
eBPF 使用
BCC 工具
BCC 工具支持使用 Python 和 C 语言组合来编写 eBPF 程序,参考
# ubuntu
sudo apt-get install bcc bpfcc-tools linux-headers-$(uname -r)
$ bcc -v
bcc: version 0.16.17
Usage: bcc [-ansi] [-options] [-o output] file [files].
hello world
- C语言编写- eBPF- 内核态程序:- hello.c
int hello_world(void *ctx)
{
    bpf_trace_printk("Hello, World!");
    return 0;
}
- Python开发- 用户态程序:- hello.py
#!/usr/bin/env python3
from bcc import BPF
# 加载 eBPF 内核态程序
b = BPF(src_file="hello.c")
# 将 eBPF 程序挂载到内核探针 kprobe
# do_sys_openat2() 是系统调用 openat() 在内核中的实现
b.attach_kprobe(event="do_sys_openat2", fn_name="hello_world")
# 读取并且打印 eBPF 内核态程序输出的数据
b.trace_print()
$ sudo python3 hello.py
b'           <...>-2111    [000] ...21   239.916342: bpf_trace_printk: Hello, World!'
b'      irqbalance-962     [001] ...21   242.346380: bpf_trace_printk: Hello, World!'
b'      irqbalance-962     [001] ...21   242.346886: bpf_trace_printk: Hello, World!'
...
- bpf_trace_printk()会将信息写入- /sys/kernel/debug/tracing/trace_pipe中
相关教程