请在使用站内资源的同时不要恶意进行爬取或倒链等行为,感谢支持!
相关文档:
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 。