关于 BPF 和 eBPF 的笔记
创始人
2024-03-01 22:55:28
0

今天,我喜欢的 meetup 网站上有一篇我超爱的文章!Suchakra Sharma@tuxology 在 twitter/github)的一篇非常棒的关于传统 BPF 和在 Linux 中最新加入的 eBPF 的讨论文章,正是它促使我想去写一个 eBPF 的程序!

这篇文章就是 —— BSD 包过滤器:一个新的用户级包捕获架构

我想在讨论的基础上去写一些笔记,因为,我觉得它超级棒!

开始前,这里有个 幻灯片 和一个 pdf。这个 pdf 非常好,结束的位置有一些链接,在 PDF 中你可以直接点击这个链接。

什么是 BPF?

在 BPF 出现之前,如果你想去做包过滤,你必须拷贝所有的包到用户空间,然后才能去过滤它们(使用 “tap”)。

这样做存在两个问题:

  1. 如果你在用户空间中过滤,意味着你将拷贝所有的包到用户空间,拷贝数据的代价是很昂贵的。
  2. 使用的过滤算法很低效。

问题 #1 的解决方法似乎很明显,就是将过滤逻辑移到内核中。(虽然具体实现的细节并没有明确,我们将在稍后讨论)

但是,为什么过滤算法会很低效?

如果你运行 tcpdump host foo,它实际上运行了一个相当复杂的查询,用下图的这个树来描述它:

评估这个树有点复杂。因此,可以用一种更简单的方式来表示这个树,像这样:

然后,如果你设置 ether.type = IPip.src = foo,你必然明白匹配的包是 host foo,你也不用去检查任何其它的东西了。因此,这个数据结构(它们称为“控制流图” ,或者 “CFG”)是表示你真实希望去执行匹配检查的程序的最佳方法,而不是用前面的树。

为什么 BPF 要工作在内核中

这里的关键点是,包仅仅是个字节的数组。BPF 程序是运行在这些字节的数组之上。它们不允许有循环(loop),但是,它们 可以 有聪明的办法知道 IP 包头(IPv6 和 IPv4 长度是不同的)以及基于它们的长度来找到 TCP 端口:

x = ip_header_length
port = *(packet_start + x + port_offset) 

(看起来不一样,其实它们基本上都相同)。在这个论文/幻灯片上有一个非常详细的虚拟机的描述,因此,我不打算解释它。

当你运行 tcpdump host foo 后,这时发生了什么?就我的理解,应该是如下的过程。

  1. 转换 host foo 为一个高效的 DAG 规则
  2. 转换那个 DAG 规则为 BPF 虚拟机的一个 BPF 程序(BPF 字节码)
  3. 发送 BPF 字节码到 Linux 内核,由 Linux 内核验证它
  4. 编译这个 BPF 字节码程序为一个 原生 native 代码。例如,这是个ARM 上的 JIT 代码 以及 x86 的机器码
  5. 当包进入时,Linux 运行原生代码去决定是否过滤这个包。对于每个需要去处理的包,它通常仅需运行 100 - 200 个 CPU 指令就可以完成,这个速度是非常快的!

现状:eBPF

毕竟 BPF 出现已经有很长的时间了!现在,我们可以拥有一个更加令人激动的东西,它就是 eBPF。我以前听说过 eBPF,但是,我觉得像这样把这些片断拼在一起更好(我在 4 月份的 netdev 上我写了这篇 XDP & eBPF 的文章回复)

关于 eBPF 的一些事实是:

  • eBPF 程序有它们自己的字节码语言,并且从那个字节码语言编译成内核原生代码,就像 BPF 程序一样
  • eBPF 运行在内核中
  • eBPF 程序不能随心所欲的访问内核内存。而是通过内核提供的函数去取得一些受严格限制的所需要的内容的子集
  • 它们 可以 与用户空间的程序通过 BPF 映射进行通讯
  • 这是 Linux 3.18 的 bpf 系统调用

kprobes 和 eBPF

你可以在 Linux 内核中挑选一个函数(任意函数),然后运行一个你写的每次该函数被调用时都运行的程序。这样看起来是不是很神奇。

例如:这里有一个 名为 disksnoop 的 BPF 程序,它的功能是当你开始/完成写入一个块到磁盘时,触发它执行跟踪。下图是它的代码片断:

BPF_HASH(start, struct request *);
void trace_start(struct pt_regs *ctx, struct request *req) {
    // stash start timestamp by request ptr
    u64 ts = bpf_ktime_get_ns();
    start.update(&req, &ts);
}
...
b.attach_kprobe(event="blk_start_request", fn_name="trace_start")
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_start")

本质上它声明一个 BPF 哈希(它的作用是当请求开始/完成时,这个程序去触发跟踪),一个名为 trace_start 的函数将被编译进 BPF 字节码,然后附加 trace_start 到内核函数 blk_start_request 上。

这里使用的是 bcc 框架,它可以让你写 Python 式的程序去生成 BPF 代码。你可以在 https://github.com/iovisor/bcc 找到它(那里有非常多的示例程序)。

uprobes 和 eBPF

因为我知道可以附加 eBPF 程序到内核函数上,但是,我不知道能否将 eBPF 程序附加到用户空间函数上!那会有更多令人激动的事情。这是 在 Python 中使用一个 eBPF 程序去计数 malloc 调用的示例

附加 eBPF 程序时应该考虑的事情

  • 带 XDP 的网卡(我之前写过关于这方面的文章)
  • tc egress/ingress (在网络栈上)
  • kprobes(任意内核函数)
  • uprobes(很明显,任意用户空间函数??像带调试符号的任意 C 程序)
  • probes 是为 dtrace 构建的名为 “USDT probes” 的探针(像 这些 mysql 探针)。这是一个 使用 dtrace 探针的示例程序
  • JVM
  • 跟踪点
  • seccomp / landlock 安全相关的事情
  • 等等

这个讨论超级棒

在幻灯片里有很多非常好的链接,并且在 iovisor 仓库里有个 LINKS.md。虽然现在已经很晚了,但是我马上要去写我的第一个 eBPF 程序了!


via: https://jvns.ca/blog/2017/06/28/notes-on-bpf---ebpf/

作者:Julia Evans 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

微软向Linux内核提交全...
2025-03-22 17:20:23 作者:狼叫兽 3月22日...
2025-03-26 07:49:27
不知道列表类型的情况下进行...
在不知道列表类型的情况下进行过滤,可以使用Python的内置函数f...
2025-01-12 02:30:35
不知道键(s)的通用过滤函...
通用的过滤函数应该能够接受一个键的列表,并根据一定的条件过滤出符合...
2025-01-12 02:01:22
不知道对象中包含哪些属性,...
使用Array.filter和Array.every方法结合循环,...
2025-01-12 01:31:22
不在特定组织单位的用户的L...
要搜索不属于特定组织单位的用户,可以使用以下LDAP搜索过滤器:i...
2025-01-11 16:01:44
不要用php过滤器丢失其他...
要解决“不要用PHP过滤器丢失其他选择”的问题,可以使用其他方法来...
2025-01-11 00:31:46

热门资讯

Helix:高级 Linux ... 说到 基于终端的文本编辑器,通常 Vim、Emacs 和 Nano 受到了关注。这并不意味着没有其他...
使用 KRAWL 扫描 Kub... 用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernet...
JStock:Linux 上不... 如果你在股票市场做投资,那么你可能非常清楚投资组合管理计划有多重要。管理投资组合的目标是依据你能承受...
通过 SaltStack 管理... 我在搜索Puppet的替代品时,偶然间碰到了Salt。我喜欢puppet,但是我又爱上Salt了:)...
Epic 游戏商店现在可在 S... 现在可以在 Steam Deck 上运行 Epic 游戏商店了,几乎无懈可击! 但是,它是非官方的。...
《Apex 英雄》正式可在 S... 《Apex 英雄》现已通过 Steam Deck 验证,这使其成为支持 Linux 的顶级多人游戏之...
如何在 Github 上创建一... 学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它。你知道如何使用 git 了,你有一个 G...
2024 开年,LLUG 和你... Hi,Linuxer,2024 新年伊始,不知道你是否已经准备好迎接新的一年~ 2024 年,Lin...
什么是 KDE Connect... 什么是 KDE Connect?它的主要特性是什么?它应该如何安装?本文提供了基本的使用指南。科技日...
Opera 浏览器内置的 VP... 昨天我们报道过 Opera 浏览器内置了 VPN 服务,用户打开它可以防止他们的在线活动被窥视。不过...