eBPF 是一项革命性技术,它能在内核中运行沙箱程序(sandbox programs), 而无需修改内核源码或者加载内核模块。
eBPF的一个重要特性是能够使用高级语言(如C)来实现程序。LLVM有一个eBPF后端,用于编辑包含eBPF指令的ELF文件,前端(如clang)可以用于生成程序。
在一个后端转换为字节码后,使用bpf()系统调用加载bpf程序,并校验安全性。JIT会将字节码编译进CPU架构中,并将该程序附加到内核对象上,当这些对象发生事件时会触发程序的执行(例如,当从一个网络接口发送报文时)。
eBPF work flow
eBPF MAP
eBPF map是用户空间和内核空间之间的数据交换、信息传递的桥梁。本质上是以「键/值」方式存储在内核中的数据结构,它们可以被任何知道它们的BPF程序访问。在内核空间的程序创建BPF Map并返回对应的文件描述符,在用户空间运行的程序就可以通过这个文件描述符来访问并操作BPF Map,这就是为什么BPF Map在BPF世界中是桥梁的存在了。
网络数据收发原理
1.数据包达到物理网卡(RX FIFO),通过DMA到内存中。内存指的是网卡的接收的Ring Buffer。
2.并且拷贝成一个一个的sk_buffer.
3.触发硬中断,通知CPU,已经有数据来了,CPU根据注册的中断函数,中断函数调用驱动程序,驱动先禁用网卡的中断,目的下次再来数据就直接处理就可以,就不再通知CPU的硬中断。
4.弥补硬中断处理时间问题,需要启用一个软中断。(主要是弥补硬中断处理时间不及的问题)
5.数据单元的sk_buffer然后再交给我们的协议栈处理。实际上就是交给网络层和传输层来处理。[被ip层协议和传输层协议处理]
6.去处掉网络层和传输层的头以后,CPU就把数据Copy到用户空间的应用程序。
内核单元层级关系
网络相关的(子系统),但对于存储和其他系统,问题都是类似的。图中列出了对这些子系统进行操作所需的工具。例如:
配置以太网驱动或者网络设备需要使用 ethtool 命令;
配置路由使用 ip 命令;
配置过滤使用 seccom 命令;
配置 IP 防火墙使用 iptables 命令,但如果你使用的是 raw sockets,那有很多地方都 会 bypass,因此这并不是一个完整的防火墙;
配置流量整形使用 tc 命令;
抓包使用 tcpdump 命令,但同样的,它并没有展示出全部信息,因为它只关注了一层;
如果有虚拟交换机,那使用 brctl 或 ovsctl;
所以我们看到,每个子系统都有自己的 API,这意味着如果要自动化这些东西,必须单独的使用这些工具。有一些工具这样做了,但这种方式意味着我们需要了解其中的每一层。
eBPF work point
需要弄清楚netfilter所处的位置:
BPF XDP ---> sk_buffer ---> TC[network stack Dividing Line] ---> IPv4 And IPv6 ---> Netfilter ---> TCP UDP RAW
XDP (eXpress Data Path)
XDP 代表 eXpress Data Path,提供了 BPF 框架,可在 Linux 内核中实现高性能可编程数据包处理。它在软件中尽早运行 BPF 程序,即在网络驱动程序收到数据包时。
在XDP中,驱动程序只是从ring buff中接收数据包,而没有执行任何其他的操作,例如分配 skb 将数据包进一步推入网络堆栈,也没有将数据包推入 GRO 引擎因此,XDP BPF 程序在 CPU 处理时最早执行。
XDP 中传递给 BPF 程序的数据包表示形式为 BPF 上下文如下所示:
struct xdp_buff {
void *data;
void *data_end;
void *data_meta;
void *data_hard_start;
struct xdp_rxq_info *rxq;
};
处理后返回状态:
enum xdp_action {
XDP_ABORTED = 0,
XDP_DROP,
XDP_PASS,
XDP_TX,
XDP_REDIRECT,
};
XDP_DROP:在驱动层丢弃报文,通常用于实现DDos或防火墙
XDP_PASS:允许报文上送到内核网络栈,同时处理该报文的CPU会分配并填充一个skb,将其传递到GRO引擎。之后的处理与没有XDP程序的过程相同。
XDP_TX:BPF程序通过该选项可以将网络报文从接收到该报文的NIC上发送出去。例如当集群中的部分机器实现了防火墙和负载均衡时,这些机器就可以作为hairpinned模式的负载均衡,在接收到报文,经过XDP BPF修改后将该报文原路发送出去。
XDP_REDIRECT:与XDP_TX类似,但是通过另一个网卡将包发出去。另外, XDP_REDIRECT 还可以将包重定向到一个 BPF cpumap,即,当前执行 XDP 程序的 CPU 可以将这个包交给某个远端 CPU,由后者将这个包送到更上层的内核栈,当前 CPU 则继续在这个网卡执行接收和处理包的任务。这和 XDP_PASS 类似,但当前 CPU 不用去做将包送到内核协议栈的准备工作(分配 skb,初始化等等),这部分开销还是很大的。
XDP_ABORTED:表示程序产生了异常,其行为和 XDP_DROP相同,但 XDP_ABORTED 会经过 trace_xdp_exception tracepoint,因此可以通过 tracing 工具来监控这种非正常行为。
TC (traffic control)
除了XDP之外,BPF 还可以工作在网络数据路径中的内核 TC(流量控制)层。 XDP BPF 程序与 tc BPF 的主要区别:
tc BPF 程序可以在ingress方向触发,也可以网络数据路径中的egress方向触发。
没有eBPF处理丢包的网络包路径:
netfilter 丢包处理的网络包路径:
tc 丢包处理的网络包路径:
XDP 丢包处理的网络包路径:
下面是一张不同的网络包处理技术在处理路径图: