動機
systemtap看完後就是bpf了
ebpf
- 放一台vm在kernel中當內線
- 跑verfier與自己的bytecode
- 所以會有自己的IR,過llvm轉成bytecode
- 詳細看BPF Internals (eBPF)
- 用處
- trace, profile, observe, monitor
- 這裡就與systemtap很像
- 但是現在bpf的code其實不好上手
- bpftrace整體與systemtap很像,但
- 不能透過probe去找對應的source code
- 沒有embed c, context var
- bcc是幫助開發者寫bpf的工具,但
- 現在在從bcc c/python轉移到libbpf
- 十分年輕,看commit時間,一年多一點點開始
- 但libbpf有
- BPF CO-RE: bpf的目標,邊一次到處跑
- BTF: 進化的DWARF,同時也有bpf的執行檔資訊
- libbpf: 很像compiler+linker+bootstraper
- 生vmlinux.h: 不用裝linux-header了,也不用include了
- 配合BTF與bpf的ELF設定需要的object與load bpf程式
- 提供處理kernel版本差異的方法
- extern Kconfig:
extern u32 CONFIG_HZ __kconfig;
- struct flavors: 讓relocate時用本機的struct
- extern Kconfig:
- BPF CO-RE: bpf的目標,邊一次到處跑
- libbpf的寫法十分神奇
- 現在在從bcc c/python轉移到libbpf
- bpftrace整體與systemtap很像,但
- security, network
- 可以鎖syscall,在到network stack之前就過濾封包
- trace, profile, observe, monitor
- bpf程式架構
- map
- 類似mmap, kmap的map,大塊的可以與userspace溝通的記憶體,拿來放一些資料結構
- helper
- bpf不放行直接碰kernel的變數,所以要用這個,當成syscall
- perf的ring buf
- bpf把資料傳回userspace的手段
- bytecode
- probe+action
- map
how to use
- 我只想做monitor
- bcc提供的工具
- bpftrace去跑script
- 我想開發bpf
- 看完前面兩個,再看libbpf
bcc的工具
- 出事的60秒quick check
- uptime
- dmesg -T | tail
- vmstat 1
- mpstat -P ALL 1
- pidstat 1
- iostat -xz 1
- free -m
- sar -n DEV 1
- sar -n TCP,ETCP 1
- top
- 用bcc的工具
- execsnoop: 看exec的syscal,會列ret
- ext4slower: 把file io太慢的proc列出來
- biolatency: block io in hist
- gethostlatency: call getaddrinfo/gethostbyname的延遲,抓DNS延遲
- runqlat: scheduler latency in hist
- biosnoop: 列proc使用block io的狀況,會列latency
- cachestat: 列cache成功與失敗的比率,每秒一筆
- tcpconnect: 列用tcp connect的程式(不用煩惱netstat有沒有裝了)
- tcpaccept: 列用tcp accept的程式
- profile: perf
- opensnoop: 看open的syscall,會列err
- 實際上的demo
完整工具列表
bpftrace
probe[,probe,...] /filter/ { action; ... }
- probe用
:
- systemtap用
.
- systemtap用
- filter是optional
- systemtap是用if自己做
- probe用
- probe: 括號是縮寫
BEGID
,END
- dynamic tracing
- kernel space
kprobe(k)
kprobe:function_name[+offset]
- 會有args:
arg0
,arg1
, …- 如果arg都放在stack
sarg0
,sarg1
, …
- 如果arg都放在stack
- 會有args:
kretprobe(kr)
kretprobe:function_name
retval
kfunc
&kretfunc
kfunc:function
&kretfunc:function
- 會有args:
args->name
- kretfunc會多
retval
- 可以用
bpftrace -lv
去看有什麼參數與函數
- user space
uprobe(u)
uprobe:library_name:function_name[+offset]
uprobe:library_name:address
- 會有args:
arg0
,arg1
, …
- 會有args:
uretprobe(ur)
uretprobe:library_name:function_name
retval
- kernel space
- static tracing
- kernel space
tracepoint(t)
tracepoint:name
- user space
usdt(U)
usdt:binary_path:probe_name
usdt:binary_path:[probe_namespace]:probe_name
usdt:library_path:probe_name
usdt:library_path:[probe_namespace]:probe_name
- kernel space
- else
profile(p)
: perf的抽樣profile:hz:rate
- 單位: hz, s, ms, us
- rate: 次數
software(s)
: perf的software事件man perf_event_open
software:event_name:count
orsoftware:event_name
- event
cpu-clock(cpu)
task-clock
page-faults(faults)
context-switches(cs)
cpu-migrations
minor-faults
major-faults
alignment-faults
emulation-faults
dummy
bpf-output
hardware(h)
: perf的hardware事件man perf_event_open
hardware:event_name:count
orhardware:event_name
- event
cpu-cycles(cycles)
instructions
cache-references
cache-misses
branch-instructions(branchs)
branch-misses
bus-cycles
frontend-stalls
backend-stalls
ref-cycles
interval(i)
: timerinterval:ms:rate
- 單位: hz, s, ms, us
- rate: 次數
- 可以在某些probe用wildcard,
k:vfs_*
- 還有看mem與probe的iterator在這裡
- action
- buildin function
- printf
- signal
- …
- 直接看這裡
- map function
- 語法真的很神奇
@name = map-function(val)
- 我是這樣想:
@name = map-function(@name, val)
- map function會去讀map與val產生新的map
- 我是這樣想:
- count
- hist
- min, max
- 剩下這裡
- 語法真的很神奇
- buildin var
- pid, tid, uid, gid, cpid(child pid)
- kstack, ustack: kernel, user stack
$1
,$2
…: bpftrace的參數- rand: 就是rand
- cpu, cgroup: cpu id, cgroup id
- comm: proc name
- func: function name
- probe: probe name
- nssec, elapsed: timestamp in ns, bpftrace的運行時間
- controll structrue
if (expr) {} else {}
(expr) ? expr1 : expr2;
unroll (expr) {}
(loop)- comment:
//
,/**/
- buildin function
- var
- local:
$name
- global:
@name
- 這個其實就是map,拿來放置大物件的
- buildin:
name
- 沒有struct?
- 自己寫
- include(同c)
- 生BTF
- cast(同c)
- local:
- data structrue
- array(hash)
@associative_array_name[key_name, key_name2, ...]
- tuple
$t = (expr1, expr2, ...)
$t.1; $t.2;
- array(hash)
libbpf
參考資料在?
範例在兩個地方
有說明文
- BCC to libbpf conversion guide
- 雖說是BCC到libbpf,但裡面涵蓋寫libbpf需要注意的點
- Tips and Tricks for Writing Linux BPF Applications with libbpf
- 誠如標題所示,就是tip與trick
- Building BPF applications with libbpf-bootstrap
- libbpf-bootstrap講解
主角,libbpf的code,在這裡
建議從libbpf-bootstrap開始看,下面用examples/c/krpobe來看,看看每個用libbpf都會有的東西
兩個code: userspace & bpf
現在程式分成userspace的kprobe.c
與bpf的kprobe.bpf.c
kprobe.c
: 會做跑bpf的前置工作與等bpf完成
kprobe.bpf.c
: 實際跑bpf probe的地方
userspace
header有#include "kprobe.skel.h"
libbpf生的header,裡面有與bpf溝通需要的東西與libbpf的API
libbpf_print_fn 與 bump_memlock_rlimit
libbpf_print_fn就是printk之類的,可以在裡面設定需要多燒level才print
bump_memlock_rlimit是設定bpf的mem用量
載入到執行到移除
- bootstrap_bpf__open
- 把bpf的code讀進來
- 拿到
struct bootstrap_bpf
- 可以改裡面的參數
- bootstrap_bpf__load
- 開始創map,把code丟到verifier
- bootstrap_bpf__attach
- 開始跑
- 之後就是看userspace要做什麼
- bootstrap_bpf__destroy
- 把bpf停掉
bpf
herder
#include "vmlinux.h" /* all kernel types */
#include <bpf/bpf_helpers.h> /* most used helpers: SEC, __always_inline, etc */
#include <bpf/bpf_core_read.h> /* for BPF CO-RE helpers */
#include <bpf/bpf_tracing.h> /* for getting kprobe arguments */
map
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, pid_t);
__type(value, u64);
} exec_start SEC(".maps");
- 有關的type在bpf.h
- 但struct要放什麼就要去找範例了
- 要加
SEC(".maps")
probe
SEC("tp/sched/sched_process_exec")
int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
{
//...
return 0;
}
- 在
SEC
放probe - 不同probe的函數宣告方式不一樣,像kprobe要
BPF_KPROBE(...)
這macro
- 找範例去對,現在還沒看到像樣的文件
helper
task = (struct task_struct *)bpf_get_current_task();
bpf_get_current_comm(&e->comm, sizeof(e->comm));
bpf_probe_read_str(&e->filename, sizeof(e->filename), (void *)ctx + fname_off);
這些helper都在bpf_helper_defs.h
Ref
bpftrace Cheat Sheet bpftrace Reference Guide BPF binaries: BTF, CO-RE, and the future of BPF perf tools BPF Internals (eBPF) BPF Portability and CO-RE