Page tree

如需转载请标注内容地址为: https://wiki.shileizcc.com/confluence/display/bpf/BPFTool

Skip to end of metadata
Go to start of metadata

请在使用站内资源的同时不要恶意进行爬取或倒链等行为,感谢支持!

BPFTool

Install

安装,由于 bpftool 不会默认安装,并且需要对应内核版本进行编译安装获取,步骤如下:

安装依赖:

$ apt install libelf-dev libbfd-dev libcap-dev clang make gcc

编译

$ git clone -b v5.11 --depth 1 https://github.com/torvalds/linux
$ cd linux/tools/bpf/bpftool/
$ make && make install

获取版本:

$ bpftool --version
bpftool v5.11.0
features:

特征查看

可以访问系统的 BPF 特征:

$ bpftool feature

查看是否开启 JIT:

$ cat /proc/sys/net/core/bpf_jit_enable

Perf

perf 子命令显示那些 BPF 程序通过 perf_event_open() 进行挂载,比如:

$ bpftool perf
pid 302822  fd 5: prog_id 1540  uprobe  filename /proc/self/exe  offset 515536
pid 302822  fd 7: prog_id 1541  uprobe  filename /proc/self/exe  offset 515520
pid 302822  fd 12: prog_id 1542  tracepoint  sys_enter_open
pid 302822  fd 14: prog_id 1543  tracepoint  sys_enter_openat
pid 302822  fd 16: prog_id 1544  tracepoint  sys_exit_open
pid 302822  fd 18: prog_id 1545  tracepoint  sys_exit_openat

offset 字段显示了被插桩对象的偏移量。

prog_id 是 BPF 的 ID,可以使用下面的命令进行打印。

检查 BPF 程序

可以查看 BPF 程序相关的直接信息。

$ bpftool prog show
...
817: sched_cls  tag 7c82c5731d7e274e  gpl
	loaded_at 2021-12-20T14:32:55+0800  uid 0
	xlated 9944B  jited 5920B  memlock 12288B  map_ids 102,88,98,99,94,126,86,101,95
818: sched_cls  tag 6dab058777b21a42  gpl
	loaded_at 2021-12-20T14:32:55+0800  uid 0
	xlated 1528B  jited 923B  memlock 4096B  map_ids 88,126
819: sched_cls  tag 054161765f3787f6  gpl
	loaded_at 2021-12-20T14:32:55+0800  uid 0
	xlated 12824B  jited 7300B  memlock 16384B  map_ids 98,102,88,126,99,95,94,125,96

可以通过 json 格式查看:

$ bpftool prog show --json id 817 | jq
{
  "id": 817,
  "type": "sched_cls",
  "tag": "7c82c5731d7e274e",
  "gpl_compatible": true,
  "loaded_at": 1639981975,
  "uid": 0,
  "bytes_xlated": 9944,
  "jited": true,
  "bytes_jited": 5920,
  "bytes_memlock": 12288,
  "map_ids": [
    102,
    88,
    98,
    99,
    94,
    126,
    86,
    101,
    95
  ]
}

自定义格式化输出:

$ bpftool prog show --json id 817 | jq -c '[.id, .type, .loaded_at]'
[817,"sched_cls",1639981975]

当知道标识符后,还可以使用 BPFTool 获取整个程序的数据。当你需要调试由编译器生成的 BPF 字节码时,这会很方面:

$ bpftool prog dump xlated id 817
...
 1226: (bf) r2 = r10
 1227: (07) r2 += -56
 1228: (bf) r3 = r10
 1229: (07) r3 += -200
 1230: (18) r1 = map[id:88]
 1232: (b4) w4 = 0
 1233: (85) call htab_percpu_map_update_elem#149408
 1234: (18) r6 = map[id:126]
 1236: (79) r7 = *(u64 *)(r10 -208)
 1237: (bf) r1 = r7
 1238: (bf) r2 = r6
 1239: (b7) r3 = 1
 1240: (85) call bpf_tail_call#12
 1241: (b4) w0 = 2
 1242: (05) goto pc-57

可以在末尾加上 linum 修饰符增加源代码文件和行信息。

如果使用 opcodes 修饰符可以在输出中包含 BPF 指令的 opcode(用黑体标记)。

可以图形展示:

$ bpftool prog dump xlated id 817 visual &> output.out
# apt install graphviz
$ dot -Tpng output.out -o visual-graph.png

如果是 5.1 以上内核版本,可以访问到程序运行时的系统信息。统计信息能告诉我们内核在 BPF 程序上花费的时长。默认情况下,系统中关闭此功能。为了让内核记录相关数据,可以运行以下命令:

$ sysctl -w kernel.bpf_stats_enabled=1

BPFTool 不仅允许检查程序的运行情况,还允许将新程序加载到内核中,并将它们附加到套接字和 cgroup。例如,可以使用如下命令加载前面的程序并将其冲就滑到 BPF 文件系统:

$ bpftool prog load bpf_prog.o /sys/fs/bpf/bpf_prog

BPF 映射

可以访问正在使用的 BPF 映射。

$ bpftool map show
...
123: hash  flags 0x1
	key 8B  value 24B  max_entries 16384  memlock 524288B
124: prog_array  flags 0x0
	key 4B  value 4B  max_entries 25  memlock 4096B
	owner_prog_type sched_cls  owner jited
125: hash  flags 0x1
	key 8B  value 24B  max_entries 16384  memlock 524288B
126: prog_array  flags 0x0
	key 4B  value 4B  max_entries 25  memlock 4096B
	owner_prog_type sched_cls  owner jited

还可以创建和更新映射,以及列出映射中的所有元素。创建新映射需要提供的信息,与程序初始化映射要提供的信息相同。也需要制定要创建哪种类型的映射、键和值的大小映射名。因为不在程序初始化时初始化映射,所以需要持久化到 BPF 文件系统中,以便稍后使用:

$ bpftool map create /sys/fs/bpf/counter type array key 4 value 4 entries 5 name counter

创建出来的映射:

$ bpftool map show
...
183: array  name counter  flags 0x0
	key 4B  value 4B  max_entries 5  memlock 4096B

当创建映射后,可以对映射的元素进行更新和删除。

记住不能从固定大小的数组中删除元素,只能更新它们。但是可以从其他类型的映射中删除元素,例如哈希映射。

如果将新添加到映射或者更新现有元素,可以通过 map update 命令:

$ bpftool map update id 183 key 1 0 0 0 value 0 0 0 0

如果使用无效值更新元素,效果如下:

$ bpftool map update id 183 key 1 0 0 0 value 0 0 0
Error: value expected 4 bytes got 3

查看映射的值,当创建固定大小的数组映射时,可以看到 BPF 将所有元素初始化为空值:

$ bpftool map dump id 183
key: 00 00 00 00  value: 00 00 00 00
key: 01 00 00 00  value: 00 00 00 00
key: 02 00 00 00  value: 00 00 00 00
key: 03 00 00 00  value: 00 00 00 00
key: 04 00 00 00  value: 00 00 00 00
Found 5 elements

查看复杂到特定接口的程序

BPF 可以加载运行在 cgroup、Pref 时间和网络数据包的程序,反过来,BPFTool 子命令 cgroup、pref 和 net 可以查看跟踪这些接口上的附加程序。

BPFTool 的 pref 子命令可以列出系统中附加到跟踪点的所有程序,例如 BPFTool 和 perf 子命令可以列出附加到 kprobes、uprobes 和跟踪点上的所有程序。

BPFTool 的 net 子命令可以列出附加到 XDP 和流量控制的程序。对于其他的像套接字过滤器和端口重用程序的附加程序,只能通过使用 iproute2 得到。与查看其他 BPF 对象一样,可以通过命令:

$ bpftool net show

列出附加到 XDP 和 TC 的程序。

最后,BPFTool 的 cgroup 子命令可以列出附加到 cgroups 的所有程序。这个子命令与看到的其他命令有些不同。命令:

$ bpftool cgroup show

需要加上查看的 cgroup 路径。如果想要列出系统中所有 cgroup 上的附加程序,需要使用命令

$ bpftool cgroup tree

例如:

$ bpftool cgroup tree
CgroupPath
ID       AttachType      AttachFlags     Name
/sys/fs/cgroup/unified
756      connect4
752      connect6
758      sendmsg4
754      sendmsg6
759      recvmsg4
755      recvmsg6
757      getpeername4
753      getpeername6
/sys/fs/cgroup/unified/system.slice/systemd-udevd.service
    1289     ingress
    1288     egress
/sys/fs/cgroup/unified/system.slice/systemd-journald.service
    1293     ingress
    1292     egress
/sys/fs/cgroup/unified/system.slice/systemd-logind.service
    1291     ingress
    1290     egress

BPFTool 提供对 cgroups、Perf 和网络接口便捷查看,可以验证程序是否成功地附加到内核中的任何接口上。

文档创建于 , 最后一次更新于 , 文档当前的状态 正式版 , 当前编写页面的版本 V1.3.1 。

  • No labels