
一、内容简介BPFberkeley package filter技术曾经是内核中相当冷门的一项过滤网络数据包的技术然而后来随着大佬们的拓展迭代诞生了 eBPFextended berkeley package filter 现在已经成为了内核技术中最具备革命性的通用型技术由于 Linux 官方手册中并未区分 BPF 和 eBPF本文将这两个词作为同义词使用。eBPF的优点用于内核编程的方方面面然而最大的优势是——由于 eBPF 的 hook 插入与虚拟机沙箱Virtual Machine Sandbox的特点非专业内核开发者也可以使用这项技术完成自己的功能开发——不需要修改内核源码、不需要担心破坏内核不需要为跨平台而重新编译内核甚至不需要重启。eBPF 技术主要有三个应用领域网络技术安全技术监测/观测技术本篇博客将简单介绍 eBPF 以及 eBPF 在网络的应用技术——XDP主要内容eBPF hook、JIT、vertifier、map等XDP driver hook、数据包操作如重定向等二、eBPF 介绍eBPF 技术实际上是一种事件驱动的技术eBPF 程序是挂载hook在各种内核事件/应用程序事件上的程序当这些事件发生的时候先对 eBPF 字节码进行 JIT 编译再执行插入的 BPF 程序让非专业内核开发者也可以也得以进行内核编程实现功能者被称作内核可编程。不破坏内核的保证——虚拟机与验证器vertifier有人问不是说 Linux 官方手册中将这项技术视作一种内核虚拟机技术In-kernel Virtual Machine吗那为什么扯到内核可编程这里要做一个重要澄清eBPF 确实严格依照虚拟机的技术实现规范拥有自己的指令集ISP、字节码等。但是eBPF 程序执行时是 JIT 稍后有说编译的本地机器码直接在内核空间中运行的并没有虚拟化技术也没有解释运行。所以为了确保不破坏内核BPF 程序编译为 eBPF 字节码前需要先通过vertifier 的严格验证这意味着编码也不得不面临更多的限制程序保证执行完毕没有死循环没有使用未初始化变量不越界访问内存512字节的栈限制内存使用受到限制逻辑分支必须能被vertifier逐个检查确认意味着程序的复杂度受到限制跨平台的实现——eBPF 字节码与 JIT 编译器eBPF 先由 Clang/LLVM 编译器编为 eBPF 字节码跨平台再由 JITJust-in-Time编译器编为时机执行的本地机器码。目前为止我们可以用一张图串起来刚才讲解的概念图片来源https://www.infoq.com/articles/gentle-linux-ebpf-introduction/eBPF的通信机制前面我们说过了eBPF 运行在内核空间中然而我们要利用这项技术实现自己的业务那么势必面临内核程序-用户程序相互通信的问题而eBPF map 解决了 eBPF 程序的通信问题。map 的本质是键值对存储的数据结构eBPF 提供了多种选择比如数组、哈希表等等。三、XDP 介绍XDPeXpress Data Path作为现代 Linux 高性能网络的底座之一经常放在一起和 DPDK、RDMA 进行比较然而DPDK 和 RDMA 实际上都是内核旁路技术主要的思路是绕过内核。而 XDP 却基于 BPF 内核探测技术形成了与众不同的内核协作的技术范式。XDP 是 BPF 技术在网络领域的应用而 BPF 是一种 hook 在内核事件上的程序。我们要搞清楚 XDP就必须搞清楚它的 hook 点如下图所示XDP 工作在网卡 driver 这个层次在产生 sk_buffer 之前。挂载后其所在的 driver 设备每收到一个数据包可以丢弃XDP_DROP发送XDP_TX进内核协议栈XDP_PASS重定向至mapXDP_REDIRECT走重定向和内核协议栈的区别┌─────┐ ┌────────┐ ┌─────┐ XDP_PASS ┌─────────┐ │ NIC ├── Driver ├── XDP ├────────── sk_buff │ └─────┘ └────────┘ └─┬───┘ └─────────┘ │ │ XDP_REDIRECT │ ┌──▼───────┐ ┌─────────┐ │ XSK/UMEM ├────── fd_aio │ └──────────┘ └─────────┘