1 前言
根据BPF程序的主要目的,可以将其分为两类。一类是跟踪,一类是网络。本文将总结常见的BPF程序类型,并予以简单介绍,具体使用将在后续文章中逐步分享,感谢阅读。
跟踪
跟踪类程序可以提供系统行为和系统硬件的直接信息。它们可以访问特定内存区域,从运行进程中提取执行跟踪信息。还可以直接访问为每个特定进程分配的资源,包括文件描述符、CPU和内存。
网络
网络类程序可以检测和控制系统的网络流量。它们可以对网络接口的数据包进行过滤,甚至可以完全拒绝数据包。可以将BPF程序附加到网络驱动程序接受数据包的网络事件上,也可以将BPF程序附加到数据包传递给用户空间的网络事件上。
2. BPF程序类型简介
2.1 kprobe程序
BPF kprobe程序类型允许使用BPF程序作为kprobe的处理程序,当被检测内核函数触发时,执行BPF程序,程序类型被定义为BPF_PROG_TYPE_KPROBE。kprobe 是动态附加到内核调用点的函数,编写附加到kprobe模块上的BPF程序时,需要确定BPF程序的执行时机,也就是确定BPF程序是在内核函数调用开始时执行,还是内核函数调用结束返回时执行。
- 如果是在内核函数调用开始时执行BPF程序,我们可以设置BPF程序的SEC为:
SEC("kprobe/内核函数")
- 如果是在内核函数调用结束返回时执行BPF程序,我们可以设置BPF程序的SEC为:
SEC("kretprobe/内核函数")
2.2 tracepoint程序
Tracepoint 程序是内核代码的静态标记,允许注入跟踪和调试相关的任意代码,它会附加到内核提供的跟踪点处理程序上,程序类型被定义为BPF_PROG_TYPE_TRACEPOINT。因为tracepoint需要在内核中预先定义,所以灵活性不如kprobe,但是tracepoint引入内核后,可以保证稳定性,而且调试内核时,可以提供更高的可预测性。
系统中所有的跟踪点都定义在/sys/kernel/debug/traceing/events
目录中:
2.3 XDP 程序
XDP程序定义了一些对数据包控制的操作,用于决定如何处理数据包。当网络包到达内核时,XDP程序会在早期被执行,程序类型被定义为BPF_PROG_TYPE_XDP。数据包控制情况:
- 数据包传递到内核下一个子系统,XDP程序返回XDP_PASS;
- 数据包被内核忽略,不做处理,XDP程序返回XDP_DROP;
- 数据包转发回原来收到数据包的网卡,XDP程序返回XDP_TX。
2.4 perf事件程序
Perf事件程序将BPF代码附加到perf事件上,当perf产生分析数据时,执行BPF程序,程序类型定义为BPF_PROG_TYPE_PERF_EVENT。Perf是内核的内部分析器,可以产生硬件和软件的性能数据事件,我们可以用perf事件程序监控系统很多信息。
2.5 cgroup 套接字BPF程序
cgroup 套接字BPF程序可以将BPF逻辑附加到控制组(cgroup)上,该程序允许cgroup在其包含的进程中控制网络流量,程序类型定义为BPF_PROG_TYPE_CGROUP_SKB。该类型的BPF程序附加到cgroup上对于容器环境很有用,在容器环境中,容器进程组收到cgroup限制,可以对所有容器进程使用相同策略,无需单独识别每个进程。
2.6 cgroup 打开套接字BPF程序
cgroup打开套接字BPF程序允许cgroup内的任何进程打开网络套接字时执行代码,它不是访问网络数据包,而是进程打开新套接字时进行控制,程序类型定义为BPF_PROG_CGROUP_SOCK。该类型的BPF程序可以对打开套接字的程序组提供访问控制和增加安全性,而不必单独限制每个进程的功能。
2.7 套接字选项BPF程序
套接字选项BPF程序在数据包通过内核网络栈的多个阶段中转时,允许运行时修改套接字连接选项,它可以在套接字连接的生命周期中被多次调用,程序类型定义为BPF_PROG_TYPE_SOCK_OPS。当创建该类型的BPF程序时,函数调用会收到op参数,该参数表示内核在套接字连接上将执行的操作。通过这个参数,可以知道程序被调用时发生在连接生命周期的哪个阶段,进而可以访问网络IP地址和连接端口号等数据,还可以修改连接选项、设置超时、更改给定数据包的往返延时时间等。
2.8 套接字映射BPF程序
套接字映射BPF程序可以访问套接字映射和套接字重定向,该类型定义为BPF_PROG_TYPE_SK_SKB。该类型BPF程序可以实现负载平衡功能,通过跟踪多个套接字,可以在内核空间多个套接字之间转发网络数据包,还可以控制网络流量。
2.9 cgroup 设备BPF程序
cgroup设备BPF程序可以决定是否能在给定设备商执行cgroup操作,类型定义为BPF_PROG_TYPPE_CGROUP_DEVICE。可以编写该类型BPF程序,从而更加灵活地设置权限。
2.10 套接字消息传递BPF程序
套接字消息传递BPF程序可以控制是否将消息发送到套接字,程序类型定义为BPF_PROG_TYPE_SK_MSG。
- 内核将消息发送到套接字,程序返回SK_PASS;
- 内核不将消息传递给套接字,程序返回SK_DROP。
2.11 原始跟踪点BPF程序
原始跟踪点以内核原始格式访问跟踪点参数,这种格式提供了内核正在执行任务的更多详细信息,但它会有少许性能开销,程序类型定义为BPF_PROG_TYPE_RAW_TRACE。
2.12 cgroup 套接字地址BPF程序
cgroup 套接字地址BPF程序允许操作cgroup控制的用户空间程序的IP地址和端口号,程序类型定义为BPF_PROG_CGROUP_SOCK_ADDR。
2.13 套接字重用端口BPF程序
内核中有个选项叫做SO_REUSEPORT,它允许相同主机上多个进程绑定相同的端口。该选项可以使可接受的网络连接提高,从而获得较高的性能。 套接字重用端口BPF程序挂钩到内核用来确定是否要重用端口,该类型定义为BPF_PROG_TYPE_SK_REUSEPORT。BPF程序逻辑修改重用端口情况:
- 防止程序重用同一端口,BPF程序返回SK_DROP;
- 通知内核启动端口重用,BPF程序返回SK_PASS。
2.14 流量解析BPF程序
内核中有个组件叫做流量解析器,用于跟踪网络数据包经过的不同层,从网络数据包到达系统再到网络数据包发送给用户空间程序,它允许使用不同分类方法对数据包进行控制。 流量解析BPF程序将程序逻辑挂钩到流量解析路径上,提供内核解析器没有的安全保证,可以修改内核网络数据包流,类型定义为BPF_PROG_TYPE_FLOW_DISSECTOR。
2.15 其它BPF程序
网络分类BPF程序: BPF_PROG_TYPE_SCHED_CLS和BPF_PROG_TYPE_SCHED_ACT这两类BPF程序允许对网络流量进行分类,并修改套接字缓冲区中数据包某些属性。 还有轻量级隧道BPF程序、红外设备BPF程序等。
3. 总结
本文简单总结了常见的BPF程序类型,并予以简单介绍,那么这些类型的BPF程序在BPF进行跟踪和网络方面具体该如何使用呢?后面的文章将会逐步介绍,感谢阅读。
参考资料:《Linux 内核观测技术BPF》