Board logo

标题: eBPF 简史(4) [打印本页]

作者: look_w    时间: 2017-12-8 08:57     标题: eBPF 简史(4)

本帖最后由 look_w 于 2017-12-8 08:58 编辑

新的指令集eBPF 对于既有 cBPF 令集的改动量之大,以至于基本上不能认为两者还是同一种语言了。个中变化,我们可以通过反汇编清单 4 的源代码(llvm-objdump                --disassemble)略知一二:
清单 6 Disassemble of                    sockex1_kern.o
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sockex1_kern.o: file format ELF64-BPF
Disassembly of section socket1:
bpf_prog1:
0: bf 16 00 00 00 00 00 00 r6 = r1
1: 30 00 00 00 17 00 00 00 r0 = *(u8 *)skb[23]
2: 63 0a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r0
3: 61 61 04 00 00 00 00 00 r1 = *(u32 *)(r6 + 4)
4: 55 01 08 00 04 00 00 00 if r1 != 4 goto 8
5: bf a2 00 00 00 00 00 00 r2 = r10
6: 07 02 00 00 fc ff ff ff r2 += -4
7: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0ll
9: 85 00 00 00 01 00 00 00 call 1
10: 15 00 02 00 00 00 00 00 if r0 == 0 goto 2
11: 61 61 00 00 00 00 00 00 r1 = *(u32 *)(r6 + 0)
12: db 10 00 00 00 00 00 00 lock *(u64 *)(r0 + 0) += r1
LBB0_3:
13: b7 00 00 00 00 00 00 00 r0 = 0
14: 95 00 00 00 00 00 00 00 exit




我们不用管这段汇编写了点儿什么,先跟清单 2 开头的那段 cBPF 代码对比一下两者的异同:
至于 eBPF 具体的指令表,因为过于庞杂这里笔者就不作文抄公了。不过 eBPF 中的几个寄存器的利用规则这里还是可以有的,否则要读懂清单 6                中的代码略有困难:
In-kernel                Verifier其实结合前面那么多的内容看下来不难发现 eBPF                其实近似于一种改头换面后的内核模块,只不过它比内核模块更短小精干,实现的功能也更新颖一些罢了,但无论是什么样的架构,只要存在注入的代码就会有安全隐患,eBPF                也不外如是——毕竟注入的代码是要在内核中运行的。
为了最大限度的控制这些隐患,cBPF 时代就开始加入了以防止不规范的注入代码;到了 eBPF 时代则在载入程序(bpf_load_program())时加入了更复杂的,在运行注入程序之前,先进行一系列的安全检查,最大限度的保证系统的安全。具体来说,verifier                机制会对注入的程序做两轮检查:
Overview: eBPF                的架构诚然,eBPF 设计的复杂程度已是超越 cBPF                太多太多,笔者罗里吧嗦了大半天,其实也就是将将领着大家入门的程度而已,为了便于读者们能够把前文所述的碎片知识串到一起,这里笔者将 eBPF                的大体架构草绘一番,如下图所示,希望能帮助大家对 eBPF 构建一个整体的认识。
图 5.                Architecture of eBPF追求极简:BPF Compiler Collection(BCC)现在让我们将目光聚焦到 eBPF 的使用——相信这是大部分读者最感兴趣的部分,毕竟绝大多数人其实并没有多少机会参与 eBPF 的开发——重新回到清单                3&4 中的 sockex1:说句良心话,虽然现在可以用 C 来实现 BPF,但编译出来的却仍然是 ELF                文件,开发者需要手动析出真正可以注入内核的代码。这部分工作多少有些麻烦,如果可以有一个通用的方案一步到位的生成出 BPF                代码就好了,开发者的注意力应该放在其他更有价值的地方,不是吗?
于是就有人设计了 BPF Compiler Collection(BCC),BCC 是一个 python 库,但是其中有很大一部分的实现是基于 C 和                C++的,python 只不过实现了对 BCC 应用层接口的封装而已。
使用 BCC 进行 BPF 的开发仍然需要开发者自行利用 C 来设计 BPF 程序——但也仅此而已,余下的工作,包括编译、解析 ELF、加载 BPF                代码块以及创建 map 等等基本可以由 BCC 一力承担,无需多劳开发者费心。
限于篇幅关于 BCC 笔者不再过多展开,文章的最后笔者再给出一个基于 BCC 实现的 sockex1 的例子,读者可以感受一下使用 BCC                带给开发者们的便利性:
清单 7 A sample of                BCC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from bcc import BPF
# 和清单 2 一样,篇幅所限,这里只贴一部分源码,完全版请移步
interface="ens160"
# BCC 可以接受直接将 BPF 代码嵌入 python code 之中
# 为了方便展示笔者使用了这一功能
# 注意:prog 中的中文注释是由于笔者需要写作之故加入,如果读者想尝试运行这段代码,
# 则请将中文全部删除,因为目前 BCC 还不支持在内嵌 C 代码中使用中文注释
prog = """
#include <net/sock.h>
#include <bcc/proto.h>
// BCC 中专门为 map 定义了一系列的宏,以方便使用
// 宏中的 struct 下还定义了相应的函数,让开发者可以如 C++一般操作 map
// 这里笔者定义了一个 array 类型的 map,名为 my_map1
BPF_ARRAY(my_map1, long);
// BCC 下的 BPF 程序中不再需要定义把函数或变量专门放置于某个 section 下了
int bpf_prog1(struct __sk_buff *skb)
{
    // ……
    struct ethernet_t *eth = cursor_advance(cursor, sizeof(*eth));
    // ……
    struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
    int index = ip->nextp;
    long zero = 0; // BCC 下的 bpf 书写还是有很多坑的
    // 例如,这里如果不去定义一个局部变量 zero,
    // 而是直接用常量 0 作为 lookup_or_init()的变量就会报错
    // map 类下的各个方法的具体细节可以参照 reference_guide.md
    value = my_map1.lookup_or_init(&index, &zero);
    if (value)
        __sync_fetch_and_add(value, skb->len);
    return 0;
}
"""
bpf = BPF(text=prog, debug = 0)
# 注入 bpf_prog1 函数
function = bpf.load_func("bpf_prog1", BPF.SOCKET_FILTER)
# 这是一段 SOCKET_FILTER 类型的 BPF,所以需要挂载到某一个 interface 上
BPF.attach_raw_socket(function, interface)
# 利用 map 机制获取进出 interface 的各个协议的报文总长
bpf_map = bpf["my_map1"]
while 1:
    print ("TCP : {}, UDP : {}, ICMP: {}".format(
bpf_map[socket.IPPROTO_TCP].value,
# …




结束语本文从 BPF 的源头开始,一路讲到了近年来刚刚杀青的 eBPF,虽说拘泥于篇幅,大多内容只能蜻蜓点水、浅尝辄止,但文中 BPF                的原理、设计、实现和应用均有所涉猎,勉强也能拿来入个门了。加之近年来基于 eBPF                的应用层出不穷,希望本文能激发读者们的奇思妙想,从而设计出更多基于 BPF 的优秀应用来。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0