译自:https://jvns.ca/blog/2017/06/28/notes-on-bpf---ebpf/
作者: Julia Evans
原创:LCTT https://linux.cn/article-9630-1.html
译者: qhwdw
今天,我喜欢的 meetup 网站上有一篇我超爱的文章!Suchakra Sharma(@tuxology 在 twitter/github)的一篇非常棒的关于传统 BPF 和在 Linux 中最新加入的 eBPF 的讨论文章,正是它促使我想去写一个 eBPF 的程序!
这篇文章就是 —— BSD 包过滤器:一个新的用户级包捕获架构
我想在讨论的基础上去写一些笔记,因为,我觉得它超级棒!
开始前,这里有个 幻灯片 和一个 pdf。这个 pdf 非常好,结束的位置有一些链接,在 PDF 中你可以直接点击这个链接。
在 BPF 出现之前,如果你想去做包过滤,你必须拷贝所有的包到用户空间,然后才能去过滤它们(使用 “tap”)。
这样做存在两个问题:
问题 #1 的解决方法似乎很明显,就是将过滤逻辑移到内核中。(虽然具体实现的细节并没有明确,我们将在稍后讨论)
但是,为什么过滤算法会很低效?
如果你运行 tcpdump host foo
,它实际上运行了一个相当复杂的查询,用下图的这个树来描述它:
评估这个树有点复杂。因此,可以用一种更简单的方式来表示这个树,像这样:
然后,如果你设置 ether.type = IP
和 ip.src = foo
,你必然明白匹配的包是 host foo
,你也不用去检查任何其它的东西了。因此,这个数据结构(它们称为“控制流图” ,或者 “CFG”)是表示你真实希望去执行匹配检查的程序的最佳方法,而不是用前面的树。
这里的关键点是,包仅仅是个字节的数组。BPF 程序是运行在这些字节的数组之上。它们不允许有循环(loop),但是,它们 可以 有聪明的办法知道 IP 包头(IPv6 和 IPv4 长度是不同的)以及基于它们的长度来找到 TCP 端口:
x = ip_header_length
port = *(packet_start + x + port_offset)
(看起来不一样,其实它们基本上都相同)。在这个论文/幻灯片上有一个非常详细的虚拟机的描述,因此,我不打算解释它。
当你运行 tcpdump host foo
后,这时发生了什么?就我的理解,应该是如下的过程。
host foo
为一个高效的 DAG 规则毕竟 BPF 出现已经有很长的时间了!现在,我们可以拥有一个更加令人激动的东西,它就是 eBPF。我以前听说过 eBPF,但是,我觉得像这样把这些片断拼在一起更好(我在 4 月份的 netdev 上我写了这篇 XDP & eBPF 的文章回复)
关于 eBPF 的一些事实是:
bpf
系统调用你可以在 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 找到它(那里有非常多的示例程序)。
因为我知道可以附加 eBPF 程序到内核函数上,但是,我不知道能否将 eBPF 程序附加到用户空间函数上!那会有更多令人激动的事情。这是 在 Python 中使用一个 eBPF 程序去计数 malloc 调用的示例。
在幻灯片里有很多非常好的链接,并且在 iovisor 仓库里有个 LINKS.md。虽然现在已经很晚了,但是我马上要去写我的第一个 eBPF 程序了!
via: https://jvns.ca/blog/2017/06/28/notes-on-bpf---ebpf/
作者:Julia Evans 译者:qhwdw 校对:wxy