BPF (Berkeley Packet Filter)的简单介绍(一)

      1. 介绍   

        过去在UNIX 系统上提供一种为监控网络而设计的用户层工具,他需要将数据包从kernel 拷贝到user 空间,由于监控工具需要抓取的目标数据大部分时候不是所有数据,这就需要一个将拷贝数据最小化的内核代理包过滤器(Packet Filter),最初在SunOS 上采用NIT(Network Interface Tap), 它是一种RISC CPU上基于内存栈的次最优过滤器,后面BPF 采用了一种基于寄存器的过滤器,其过滤计算效率比基于协议栈的方式提高了20倍,并且其采用了直接buffer 策略,使得其在相同CPU 下的效率相较于NIT提高了100倍。

由于网络问题的处理需要一种允许用户层工具直接访问原始数据流的机制,但是效率一直是困扰包括NIT、CSPF(CMU/Stanford packet filter)在内的工具的有效使用。因此BPF 应运而生,其达效率到了NIT 的10-100倍,CSPF的1.5-20倍。

2. 网络TAP(Traffic Access Point)

        BPF 有两个重要组成部分,一是网络TAP,二是包过滤器(Packet Filter), 网络TAP从网络设备驱动搜集数据包的拷贝并传递给用户层应用,比如tcpdump、bpftrace 等; 过滤器决定一个数据包是否需要接收,如果接收又要copy 多少给监听的应用。

        一般情况下,当数据包到达一个网口时,链路层驱动会把数据包传送给上层网络协议栈,但当有BPF 监听这个网口时,链路层驱动首先调用BPF,BPF 填喂每一个参与处理 包过滤器,这些用户定义的包过滤器决定了一个包是否被接受,以及需要保存多少字节,对于每个接受这个数据包的filter,BPF 拷贝请求大小的数据到对应filter 关联的buffer。然后网络驱动重新获得控制权,如果目的地址不是本机将直接返回丢弃,如果目的地址是本机将按正常的将数据包传递给上层网络协议栈处理。

       

当一个进程需要查看一个网络上很多数据包时,由于数据包到来的间隔特别短,用户层监听应用不可能每个数据包都系统调用去读取,所以BPF必须收集多个数据包然后以数据块单元的形式在应用请求时返回给应用。为了保证每个数据包的边界,BPF以带有时间戳,长度,和偏移量的头封装抓取到的数据包

    2.1 包过滤(Packet Filtering)

        因为网络监控经常只需要某一部分的网络数据流,在中断上下文(interrupt context) 过滤掉不需要的数据包,最小化内存流量,可以获得巨大的性能提升。所以包过滤必须是现场过滤(比如在网口DMA 引擎数据数据获取处直接过滤),而不是将其拷贝到kernel 其它buffer 再去过滤,这时如果数据包不被接受,那么消耗内存也仅仅是处理过滤引用少部分内存。

下面两幅图是NIT 和BPF 在全接收和全拒收两种情况下效率对比图。可以看出不管是全接收还是全拒绝的情况下BPF的CPU 时间开销都低于NIT。

3. 过滤器模型(Filter model)

        上面讲的BPF buffer模型主导了接收数据包的开销 ,过滤模型决定了拒绝数据包的开销。

包过滤简单讲就是包的布尔函数,如果函数值为True 那么内核将数据包传递给监控应用,如果函数值为False 就直接忽略。

        历史上,对于过滤器有两种抽象方法,一种是Boolean表达树(比如CSPF 用的就是boolean expression tree),另一种就是直接非循环控制流图(directed acyclic control flow graph--CFG), BPF 使用的就是CFG,对于两种抽象方法他们都可以互相替代达到相同的功能,但是其实现方式却大有不同。

  3.1 CSPF(Boolean Tree)

        CSPF 基于操作数堆栈,将常数和数据包压栈,执行对顶部两个元素布尔或者位操作,然后根据结果决定接收或者拒绝包。

         CSPF 有两个显著的弱点

                       首先,CSPF采用操作数堆栈实现,模拟栈的指针加减,其实是对内存的读写,内存是现代计算机性能一大瓶颈,所以BPF 基于寄存器的方式很好的优化了此问题。

                        其次,由于布尔树存在冗余的计算的,比如下图中的两个节点只要有一个为true 就已经肯定可以成立,但它仍然会计算另一个节点,虽然这个问题可以通过"短路"条件进行规避,但包的各级协议是分层的,这会导致每个节点都要解析一次数据包,进而造成大量冗余计算,在BPF 的CFG 模型中可以实现一次解析流图表示多层使用,避免了冗余的计算,节约了计算资源。

                        虽然CSPF 有这么多缺点,但它却给包过滤提供一个优秀的idea,就是在内核中引入一个虚拟机语言解释器为描述和实现包过滤提供了一个很好的抽象。BPF 继承了CSPF的优点,并避免了CSPF的缺点。
 

3.2  BPF 过滤模型

             3.2.1 上面说过BPF 使用的控制流图(CFG)方法最大优点是CFG 图可以实现数据包一次解析多层协议使用的优点,极大的减少了CPU 时间的消耗。从下图可以看出CFG 图保存了解析的数据包信息,当知道需要到达某个节点的遍历路径后只需利用原始计算的结果就可以。

        从上图可以看出控制流图方法最长的遍历路径长度是6,平均是3,也就意味着平均经过三次对比就可以确定是否要接收某个包,但是布尔树方式如下图,就需要完整完成7次布尔运算才能确定是否需要接收某个包。

        3.2.2  虚拟机设计

                使用数据流图的方式是一种高效的处理方式,但这还远远不够,它必须借助CSPF 的idea 设计一个运行在内核高效的虚拟机。虚拟机的设计必须遵循以下几个原则。

                一、它必须是跟协议无关的,引入新的协议无需做任何修改。

                二、它必须是通用的,指令集合足够丰富以便支持不可预见处理

                三、数据包引用应该尽可能少

                四、指令的Decode 应该在单条C Switch 语句完成

                五、抽象寄存器应该有物理寄存器与之相对应

3.3   BPF 虚拟机

        BPF 虚拟机的抽象包括:一个累加器、一个索引寄存器、一个暂存器(scratch memory store)、一个隐式程序计数器。对这些元素的操作可以有以下几种

        1. 加载指令 (Load Instructions)copy 一个值到累加器或者索引寄存器,来源可以是立即数、固定或者变化偏移量的包数据、包长度、暂存器。

        2. 存储指令 (Store Instructions)将累加器或者索引寄存器copy到暂存器。

        3.  累加器指令 (ALU Instructions)使用索引寄存器或者常量在累加器上执行算术或逻辑运算

        4. 分支指令 (Branch Instructions)基于常量、索引寄存器或者累加器的对比测试改变控制流的指令

        5. 返回指令 (Return Instructions)终止过滤器并决定包的哪部分需要保存并传递给user application,如果不需要任何保存,返回0

        6. 混合指令(Miscellaneous Instruction)其它的所有指令,比如寄存器转移指令

固定长度的指令如下图

其中opcode 表示指令类型和地址模式

        jt表示jump true 意思是在条件跳转指令中如果true需要跳转到吓一条指令的偏移量

        jf表示jump false 意思是在条件跳转指令中如果false需要跳转到下一条指令的偏移量

        k 是通用目的的区域

表一 是所有BPF 的指令集合采用汇编语法表示其意思,其实在真是代码中他是采用C语言宏表示

表二是地址模式的语义解释                                                                                                    

        

 

 BPF 的原始论文

参考:

[1] [译]使用 bcc/BPF 分析 go 程序
[2] 动态追踪技术(四):基于 Linux bcc/BPF 实现 Go 程序动态追踪 - 简书
[3] Golang bcc/BPF Function Tracing
[4] 动态追踪技术漫谈 - OpenResty 官方博客
[5] https://www.kernel.org/doc/Documentation/networking/filter.txt
[6] tc-bpf(8) - Linux manual page
[7] https://www.kernel.org/doc/Documentation/userspace-api/seccomp_filter.rst
[8] seccomp(2) - Linux manual page
[9] http://www.tcpdump.org/papers/bpf-usenix93.pdf
[10] bpfc(8) - Linux manual page
[11] netsniff-ng toolkit

参考blog:

BPF漫谈_weixin_30835933的博客-CSDN博客                     

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值