Linux内核模块与eBPF字节码程序的异同

如今eBPF正当红,迄至Linux 5.3内核,已经有24种eBPF程序类型被植入内核,后面还会继续增多。

然而,很多人并不理解eBPF的意义。最大的疑问来自于, eBPF和Linux内核模块的作用一样吗?

就功能以及性能而言,二者区别不大,而且,eBPF还远不如Linux内核模块强大,但是程序员不要总是盯着功能和性能,还要看架构。

二者的根本不同在于:

  • Linux内核模块是面向内核API编程的。
  • eBPF程序是面向BPF体系结构指令集编程的。

你可以认为eBPF运行在虚拟机中,而Linux内核中在不同的位置部署了这种虚拟机,比如Linux 5.3内核就在24个位置部署了eBPF虚拟机。

抽象来讲,Linux内核并不直接执行eBPF程序,而是启动eBPF虚拟机,由eBPF虚拟机来执行eBPF字节码。

可以这样理解eBPF字节码,即它是一种中间代码,不依赖任何体系结构,它是一种独立的体系结构,和x86_64这种是并列的,所以的eBPF虚拟机就是eBPF体系结构指令在本地平台的语义映射。

可以看下Linux内核的BPF_PROG_RUN宏,同时tcpdump -I any tcp port 1234 -dd来感受一下这种体系结构:
{ 0x15, 0, 6, 0x000086dd }
即下面的助记符:
{(001) jeq #0x86dd jt 2 jf 8}
在x86_64平台,jt,jf的语义转义就是:

if (x == true) {
	goto _2;
} else {
	goto _8;
}

这就是所谓的虚拟机。

类比一个大家都知道的例子,即Java。

我们可以把eBPF程序看成Java程序,它运行在JVM中,而JVM由本地平台启动,在这个类比中,Linux内核模块即可看作是本地平台代码,比如C语言编译成的x86_64指令序列。

所以,eBPF程序是不依赖内核的,如果Windows也部署了eBPF虚拟机,那么eBPF程序的字节码也可以在Windows上运行。

eBPF虚拟机本身就是一个沙箱,它会限制eBPF字节码永远不会离开这个沙箱,这对本地内核是极其安全的。

说到这里,性能问题是避不开的,eBPF有什么好,既然运行在虚拟机中,那肯定不如直接运行在本地啊!

eBPF对性能问题可以扯出很多的话题:

  • 限制指令条数,避免eBPF程序执行太久。
  • 限制或者禁止循环,避免eBPF程序执行太久。
  • 可以开放采用JIT转译技术。

这里说说JIT,Java也有类似的机制。即通过将中间字节码转译成本地代码来达到本地化的性能。

当然了,eBPF不仅仅可以通过JIT技术实现性能优化,还可以通过JIT技术实现Offload,比如网卡上的XDP实现。


另外一个想法是,eBPF程序既然跑在一个沙箱里,保证了安全,而沙箱又部署在Linux内核中,那么,很多本来应该由内核模块来完成的事,就可以通过eBPF程序来完成了。

这降低了 内核可编程 的实现门槛,一个人可以不懂Linux内核API也能通过内核API无关的eBPF对其进行编程,实现一些内核态的定制。

理想中的eBPF编程接口是内核API无关的,但实际中的eBPF则难免要调用一些内核的功能,这部分接口被eBPF封装后可以在eBPF程序中使用。

Linux内核程序员于是可以拒绝掉一些模块开发的需求,甩锅给业务程序员自己来用eBPF完成,而不必担心不小心一个NULL指针crash掉内核(verifier机制会阻止这种代码的加载!)。


还有一个话题。

eBPF是不是一种DSL?eBPF是不是类似SQL?


基于上述,我觉得eBPF真的就是一把瑞士军刀,我非常喜欢。然而同时,一些人也会笑着表示鄙视:

  • 它实现的功能太少…
  • 它不如内核模块强大…
  • 它限制太多…
  • 它不靠谱…

我是不想跟这些人继续聊下去的,因为当你说AK-47多么牛逼的时候,他不会听你解释AK-47为什么牛逼,而是在琢磨AK-47有什么不妥,不管想没想到,兜底的说法总是有,“AK-47不靠谱,干不过东风DF-41啊!”


浙江温州皮鞋湿,下雨进水不会胖!

发布了1550 篇原创文章 · 获赞 4786 · 访问量 1065万+

猜你喜欢

转载自blog.csdn.net/dog250/article/details/104063355
今日推荐