linux内核源码包_使用eBPF过滤Linux内核中的数据包的简介

linux内核源码包

1992年,Lawrence Berkeley实验室的Steven McCanne和Van Jacobson提出了一种BSD Unix系统的解决方案,该解决方案通过实现称为Berkeley Packet Filter(BPF)的内核内数据包过滤器,将对用户空间的有害网络数据包副本最小化。 1997年,它在Linux内核版本2.1.75中引入。

BPF的目的是尽早过滤所有不需要的数据包,因此过滤机制必须从用户空间实用程序(如tcpdump)转移到内核内虚拟机。 它发送一组类似于汇编的指令,以通过系统调用bpf()过滤从用户空间到内核的必要数据包。 内核在加载程序之前会对其进行静态分析,并确保它们不会挂起或损害正在运行的系统。

BPF机

一个累加器,一个索引寄存器(x),一个暂存存储器和一个隐式程序计数器组成。 它具有少量的算术,逻辑和跳转指令。 累加器用于算术运算,而索引寄存器提供到数据包或暂存器区域的偏移量。 这是一个用BPF字节码编写的小型BPF程序的示例:


   
   
    ldh     [ 12 ]
    jeq     #ETHERTYPE_IP, l1, l2
    l1:    ret     #TRUE
    l2:    ret     #0

ldh指令从以太网数据包中的偏移量12开始向累加器加载一个半字(16位)值,该值是以太网类型的字段。 如果不是IP数据包,则将返回0 ,并且该数据包将被拒绝。

BPF即时编译器

实时(JIT)编译器于2011年引入内核 ,以加快BPF字节码的执行速度。 该编译器将BPF字节码转换为主机系统的汇编代码。 这样的编译器存在的x86-64,SPARC,PowerPC上,ARM,ARM64,MIPS和系统390,并且可以通过CONFIG_BPF_JIT启用。

eBPF机

扩展BPF(eBPF)是对BPF(现在称为cBPF,代表传统BPF)的增强,具有更多资源 ,例如10个寄存器和1-8字节加载/存储指令。 BPF有向前跳转,而eBPF有向后跳转和向前跳转,因此可以有一个循环,当然,内核可以确保正确终止。 它还包括一个称为maps的全局数据存储,并且此maps状态在事件之间保持不变。 因此,eBPF也可以用于汇总事件的统计信息。 此外,eBPF程序可以用类似于C的函数编写,可以使用GNU编译器集合(GCC)/ LLVM编译器进行编译。 eBPF被设计为具有一对一映射的JIT,因此它可以生成非常优化的代码,其执行速度与本地编译的代码一样快。

eBPF和跟踪审查

上游内核开发

Linux中传统的内置跟踪器以后期处理方式使用,它们会转储固定事件详细信息,然后,诸如perftrace-cmd之类的用户空间工具可以发布进程以获取所需的信息(例如perf stat ); 但是,eBPF可以在内核上下文中准备用户信息,并且仅将所需的信息传输到用户空间。 到目前为止,在上游内核中已经实现了对使用eBPF的kprobestracepointsperf_events过滤的支持。 Arch x86-64AArch64S390xPowerPC 64SPARC64已支持它们。

有关更多信息,请查看以下Linux内核文件:

用户空间开发

已为内核内树和内核外树开发了用户空间工具。 查看这些文件和目录,以了解更多有关eBPF使用的上游内核:

BCC是另一个内核外树工具,具有针对特定用途的高效内核跟踪程序(例如funccount ,该程序对与模式匹配的函数进行计数)。

Perf还具有一个BPF接口,可用于将eBPF对象加载到内核中。

eBPF跟踪:用户空间到内核空间的流动

BPF系统调用和BPF映射是两个可以与eBPF内核进行交互的有用实体。

BPF系统调用

用户可以使用bpf()系统调用与eBPF内核进行交互,其原型为:


int bpf ( int cmd, union bpf_attr * attr, unsigned int size ) ; 

以下是这些论点的摘要; 有关更多详细信息,请参见手册页BPF

  • cmd可以是任何已定义的枚举bpf_cmd ,它告诉内核有关地图区域的管理(例如,创建,更新,删除,查找元素,附加或分离程序等)。
  • attr可以是用户定义的结构,可由其各自的命令使用。
  • sizeattr的大小。

BPF地图

eBPF跟踪计算内核域本身中的统计信息。 我们将需要内核中某种类型的内存/数据结构来创建此类统计信息。 映射是一种通用的数据结构,以键值对的形式存储不同类型的数据。 它们允许在eBPF内核程序之间以及内核和用户空间应用程序之间共享数据。

地图的重要属性包括:

  • 类型(map_type)
  • 最大元素数(max_entries)
  • 密钥大小,以字节为单位(key_size)
  • 值大小(以字节为单位)(value_size)

根据使用或需要选择不同类型的映射(例如,哈希,数组,程序数组等)。 例如,如果键是字符串(或者不是整数序列),则可以使用哈希映射来加快查找速度; 但是,如果键像索引一样,则数组映射将提供最快的查找方法。

键不能大于key_size ,不能存储大于value_size的值,并且max_entries是可在映射中存储的键-值对的最大数量。

这是要注意的两个重要命令:

  • BPF_PROG_LOAD:以下是该程序的重​​要属性:

prog_type :对跟踪有用的程序类型:

BPF_PROG_TYPE_KPROBE
BPF_PROG_TYPE_TRACEPOINT
BPF_PROG_TYPE_PERF_EVENT

insns :指向结构bpf_insn的指针,该结构具有由内核BPF虚拟机执行的BPF指令

insn_cntinsns上存在的指令总数

license:string ,必须与GPL兼容才能调用标记为gpl_only的帮助函数

kern_version :内核树的版本

  • BPF_MAP_CREATE:接受BPF映射部分中讨论的属性,创建一个新的映射,然后返回引用该映射的新文件描述符。 返回的map_fd可用于查找或通过诸如BPF_MAP_LOOKUP_ELEMBPF_MAP_UPDATE_ELEMBPF_MAP_DELETE_ELEM 或BPF_MAP_GET_NEXT_KEY之类的命令更新地图元素。 这些map-manipulation命令接受带有map_fd ,key和value的属性。

要了解其工作原理,请在GitHub上查看此独立的eBPF演示 ; 它不需要任何其他eBPF库代码。 它有一个小的库,用于加载BPF内核代码的不同部分( bpf_load.c ),然后在bpf()系统调用( bpf.c )之上包装函数,以操作映射并加载内核BPF代码。 编译此代码时,我们得到两个可执行文件: memcpy_kprobememcpy_stat

  • memcpy_kprobe:对于每个应用程序,我们都有一个_kern文件和另一个_user文件。 _kern文件具有int bpf_prog1(struct pt_regs * ctx)函数 。 此函数在内核中执行,因此可以访问内核变量和函数。 Memcpy_kprobe_kern.c分别具有针对程序,许可证和版本的三个部分映射。 这些部分中的数据是系统调用bpf(BPF_PROG_LOAD,...)属性的一部分,然后内核根据prog_type属性执行已加载的BPF指令。 所以,在memcpy_kprobe_kern.c BPF代码将当kprobe仪器在内核的memcpy的条目()执行的是命中。 执行此BPF代码时,它将读取memcpy()的第三个参数,例如副本的大小,然后在跟踪缓冲区中打印一个有关memcpy大小的语句。 Memcpy_kprobe_user.c加载内核程序并继续读取跟踪缓冲区,以显示正在将什么内核eBPF程序写入其中。
  • memcpy_stat:这将在内核本身中准备memcpy()复制大小的统计信息。 Memcpy_stat_kern.c还有另外一部分,如地图。 bpf_prog1()读取memcpy()的大小并更新映射表。 相应的用户空间程序memcpy_stat_user.c每两秒钟读取一次映射表,并在控制台上打印统计信息。

这些简单的示例说明了如何编写内核eBPF代码以进行内核跟踪和统计信息准备。

如果您使用过eBPF并希望分享建议,请在评论中留下注释。

翻译自: https://opensource.com/article/17/9/intro-ebpf

linux内核源码包

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值