仓库源文

.. Kenneth Lee 版权所有 2018-2020

:Authors: Kenneth Lee :Version: 1.0

讨论一下eBPF


本文是思考一个方案具体是否引入eBPF的前置思考,用这个短文建一下高层逻辑。

BPF/eBPF(下面单独谈eBPF)本质是一个受限的内核模块:出于安全,Linux/Unix系统把 系统分成了内核和用户两层,用户层再用“进程”分成多个隔间。所以内核隔间变成一个重 点攻击对象。解决方案一个是“微内核化”,把更多的功能从这个隔间里面抽出来,放到进 程隔间中。但放到进程隔间中的资源必须可以整体隔离,比如针对设备的VF,或者更轻量 级的Scalable IOV,针对内存的Page Table,针对CPU的VM/Partition等。但一旦你的控制 要跨越这些资源,数据流跨越隔间的成本就摆在那里了。动态模块本质是在打时间差:如 果你这个控制是有规律的,不依赖控制者的实时数据,我们可以写成一个“控制逻辑”,一 次送过这个隔间。这是“ko(内核模块)”,“vdso(内核提供用户动态模块)”等技术的作 用。但内核模块拥有内核的全部权限,这个又不适合直接用作控制接口。如果放一个虚拟 机呢,虚拟机本身就在代码和虚拟机之间制造了一个隔间,如果这样还不如一开始就跨越 原来的隔间。

eBPF在这个问题上进行了一次骑墙,它既不是ko,也不是虚拟机,它是一个限制了可以使 用的汇编和数据访问范围的编译器:eBPF二进制程序加载到内核中后,内核虚拟机先对这 个程序进行一次安全性检查,确认它没有使用不允许使用的指令,没有可能访问不允许访 问的数据,就完全把它当作一个ko执行(当然,并非真的是标准的.ko,只是挂入一些回调 )了。

但把一个拥有很多自由度的“外人”放到一个“秘密基地”中,虽然它被你限制了自由,都是 和很危险的。去年很多的侧信道攻击,都是通过放入这种eBFP特务到内核中,然后内外配 合攻破隔间的限制的。

这只是原始的构架,随着现在的发展,eBPF的虚拟机不仅仅是一个检查器(Verifier),也 包含了一个JIT,可以根据bfp的二进制语法动态加入代码。这更接近eBPF的“本意”:你的 目的仅仅是通过复杂的建立过程,让执行过程高效而已。JIT本质不就已经是一种Verifier 了吗?

这样,我们抽象了eBPF的两个关键特征:1. 安全问题可能永远无法完全消除;2. 主要适 用于建立一次,反复重复的逻辑。这样的东西,简单来说,就是过滤器,比如数据流分发 ,过滤,整形。数据流可以是网络(防火墙,TC,XDP,Tunnel),程序执行(cgroup, perf,trapcepoint,kprobe, uprobe),存储等等。(注1:补充1中我们放了一个例子作 为读者作为参考例子的应用场景)

第一个特征决定了我们不能把鸡蛋都放这个篮子上。它是随时可以因为安全问题被人关掉 的。也许我们应该把它看作是一种要求更严格的ko。但“更严格的ko”到底是不是需求?这 个很难判断,但如果这个框架成熟了,人们有需求的时候,还是会把它作为一种基础设施 去用。

第二个特征说明什么呢?第二个特征说明,如果我充分信任提供这个过滤器的提供者,我 也不需要eBPF。比如我们数据中心的Host设备上提供这种服务,或者我自己提供一组可选 的策略给用户挑选,我都不需要eBPF。

现在看到的一些使用方案,基本上都是Load Balancer,低价防火墙,用作DPDK,OVS等平 台的分路通路等。

eBFP现在还支持Offload(暂时应该只有Netronome支持?),在做JIT的时候,有两条分路 :

  1. bpf_int_jit_compile()

  2. bpf_prog_offload_compile()

看现在的方案这需要把程序分解在设备和CPU两端,需要有配合的接口,感觉要构成生态还 需要时间。

其他很多的信息,我不知道可以如何组织到逻辑链中,在本文的公开版本中,我们就到此 为止吧,暂时没有建立特别有效的逻辑。

补充1

为了有更直接的观感,我们放一个例子在这里作为思考后面的抽象时的一个例子:

比如你要直接把网卡的部分消息全部路由到用户态某个Socket(AF_XDP)上,可以写一个 这样的程序:::

// MyXdpFilter.c
dp_port_filter_prog(struct xdp_md *ctx) {
  u64 tcp_dp_match = tcp_port_map_lookup(dport);
    if(tcp_dp_match & TCP_PUBLIC)
        return XDP_PASS;
    return XDP_DROP;
}

编译和使用:::

    clang -O2 -target bpf -o MyXdpFilter.o -c MyXdpFilter.c
    ip link set dev my_net xdp object MyXdpFilter.o

这就是个给更高自由度的.ko,只是不像.ko那样可以放那么多资源,可以轻易把内核弄死 。这个程序也可以造成网络不正常,但因为功能有限,犯错的机会还是小得多。