大家好,又见面了,我是你们的朋友全栈君。
BPF
BPF (Berkeley Packet Filter)是为捕捉和过滤符合特定规则的网络包而设计的,过滤器为运行在基于寄存器的虚拟机上的程序(用来捕捉过滤、在有寄存器的虚拟机上运行的程序)。一个eBPF程序会附加到指定的内核代码路径中,当执行该代码路径时,会执行对应的eBPF程序。 过滤(Filter): 根据外界输入的规则过滤报文; 复制(Copy):将符合条件的报文由内核空间复制到用户空间; 缺点(落后):虚拟机指令集架构(ISA)相对落后,BPF提供的一小部分RISC指令无法在现有处理器上使用
(libpcap是unix/linux平台下的网络数据包捕获函数包,大多数网络监控软件都以它为基础。Libpcap可以在绝大多数类unix平台下工作。百度百科)
位于内核之中的 BPF 模块一方面接受 tcpdump 经由 libpcap 转码而来的滤包条件(Pseudo Machine Language) ,另一方面也将符合条件的报文复制到用户空间最终经由 libpcap 发送给 tcpdump。
bpf设计
(buffer:在计算机领域,缓冲器指的是缓冲寄存器,它分输入缓冲器和输出缓冲器两种。前者的作用是将外设送来的数据暂时存放,以便处理器将它取走;后者的作用是用来暂时存放处理器送往外设的数据。有了数控缓冲器,就可以使高速工作的CPU与慢速工作的外设起协调和缓冲作用,实现数据传送的同步。由于缓冲器接在数据总线上,故必须具有三态输出功能。百度百科)
BPF 采用的报文过滤设计的全称是 CFG(Computation Flow Graph),顾名思义是将过滤器构筑于一套基于 if-else 的控制流(flow graph)之上:
eBPF
改进:更接近硬件ISA、实时编译
eBPF指令更接近硬件的ISA。其中最大的变动之一是使用了64位的寄存器,并将寄存器的数量从2提升到了10个。由于现代架构使用的寄存器远远大于10个,这样就可以像本机硬件一样将参数通过eBPF虚拟机寄存器传递给对应的函数。另外,新增的BPF_CALL指令使得调用内核函数更加便利。 寄存器: R0:一般用来表示函数返回值,包括整个 BPF 代码块(其实也可被看做一个函数)的返回值; R1~R5:一般用于表示内核预设函数的参数; R6~R9:在 BPF 代码中可以作存储用,其值不受内核预设函数影响; R10:只读,用作栈指针(SP);
将eBPF映射到本机指令有助于实时编译。对比Linux内核:需要更改内核源代码或加载内核模块,导致抽象层堆叠。eBPF 在网络、安全、应用程序分析/跟踪和性能故障排除等领域开发了全新的工具,它们不再依赖现有内核功能,而是主动重新编程运行时行为,而不影响执行效率或安全性。
(指令集架构(英语:Instruction Set Architecture,缩写为ISA),又称指令集或指令集体系,是计算机体系结构中与程序设计有关的部分,包含了基本数据类型,指令集,寄存器,寻址模式,存储体系,中断,异常处理以及外部I/O。指令集架构包含一系列的opcode即操作码(机器语言),以及由特定处理器执行的基本命令。来自维基百科)
钩子
eBPF 程序是事件驱动的,当内核或应用程序通过某个挂钩点时运行。预定义的挂钩包括系统调用、函数输入/退出、内核跟踪点、网络事件和其他几个。如果预定义的挂钩不存在特定需求,则可以创建内核探测 (kprobe) 或用户探测(uprobe) 来在内核或用户应用程序中的几乎任何位置附加 eBPF 程序。
(钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程序以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理Windows消息或特定事件。百度百科)
可以用ebpf做什么?
eBPF程序“附加”到内核中的指定代码路径,进行数据包处理。遍历代码路径时,将执行所有附加的eBPF程序。鉴于其起源,eBPF特别适合于编写网络程序,并且可以编写附加到网络套接字上的程序以过滤流量,对流量进行分类并运行网络分类器操作。甚至可以使用eBPF程序** 修改已建立的网络套接字的设置 **。该XDP项目,特别是使用eBPF通过在网络堆栈的最低级别运行eBPF程序,在接收到数据包后,立即做高性能的数据包处理。
(套接字(socket):所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。百度百科
Socket原理讲解)
eBPF对调试内核和执行性能分析也很有用。程序可以附加到跟踪点,kprobes和perf(内核调试工具)事件。由于eBPF程序可以访问内核数据结构,因此开发人员可以编写和测试新的调试代码,而不必重新编译内核。对于忙碌的工程师在运行中的系统上调试问题而言,其含义是显而易见的。甚至可以通过使用Userland静态定义的Tracepoint来使用eBPF调试用户空间程序。
eBPF的强大功能来自两个优点:快速且安全。要完全理解它,您需要了解它是如何工作的。
ebpf内核验证程序
允许用户空间代码在内核中运行存在固有的安全性和稳定性风险。因此,在加载每个eBPF程序之前,会对它们进行大量检查。 1、保证ebpf能正常结束,不会因为任何循环导致内核锁定。这是通过对程序的控制流程图(CFG)进行深度优先搜索来检查的。严格禁止无法到达的指令;包含无法访问的指令的任何程序都将无法加载。 2、校验器模拟执行ebpf程序:要求验证程序一次模拟一次eBPF程序的执行。每次指令执行前后校验虚拟机状态,保证寄存器和栈的状态都是有效的。严禁越界(代码)跳跃、访问越界数据。 简化检验:越过已经检查过的程序的子集 校验器安全模式:禁止指针运算,确保不会将内核地址泄露给非特权用户,不会将指针写入内存。没启用安全模式,仅允许在执行检查之后进行指针运算。? 无法读取包含未初始化内容(从未写过内容)的寄存器,读取会导致加载失败。寄存器R0-R5的内容通过存储特殊值来捕获未初始化寄存器的所有读取,从而在函数调用中标记为不可读。进行了类似的检查以读取堆栈上的变量,并确保没有指令写入只读帧指针寄存器。? 3、检验者使用eBPF程序类型(稍后介绍)来限制可以从eBPF程序调用哪些内核功能以及可以访问哪些数据结构。例如,某些程序类型被允许直接访问网络数据包数据。
eBPF map
用于在内核或内核和空间用户传递数据
eBPF实现:BCC(bpf compiler collection)
BCC & libbpf
- C编写
- libbpf
- clang前端编译—>中间代码
- llvm后端—>优化(pass)、ebpf字节码
- BPF系统调用—>内核—>验证代码安全性—>JIT—>machine code
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/190874.html原文链接:https://javaforall.cn