3

从 bpf 手册页:

eBPF 程序可以用受限的 C 语言编写,该 C 语言被编译(使用 clang 编译器)成 eBPF 字节码。这个受限制的 C 语言省略了各种特性,例如循环、全局变量、可变参数函数、浮点数以及作为函数参数传递的结构。

AFAIK 手册页未更新。我想知道在使用受限 C 编写 eBPF 程序时究竟禁止什么?手册页所说的仍然正确吗?

4

2 回答 2

5

这并不是 ELF 文件本身“允许”什么的问题。这句话意味着一旦编译成 eBPF 指令,你的 C 代码可能会生成会被验证者拒绝的代码。例如,BPF 程序中的循环长期以来一直在 BPF 程序中被拒绝,因为无法保证它们会终止(唯一的解决方法是在编译时展开它们)。

因此,您基本上可以在 C 中使用几乎任何您想要的东西并成功生成 ELF 目标文件。但是你希望它通过验证者。哪些组件肯定会导致验证者抱怨?让我们看一下手册页中的列表:

  • 循环:Linux 5.3 版引入了对有界循环的支持,因此循环现在可以在一定程度上起作用。“有界循环”是指验证者有办法告诉它们最终将完成的循环:通常,一种for (i = 0; i < CONSTANT; i++)类型的循环应该工作(假设i在块中没有修改)。

  • 全局变量:最近有一些工作支持全局变量,但是它们以特定的方式处理(作为单条目映射)并且我没有真正尝试过它们,所以我不知道这有多透明以及是否您可以简单地在程序中定义全局变量。随意尝试:)。

  • 可变参数函数:很确定这不受支持,目前我不知道它在 eBPF 中会如何转换。

  • 浮点数:仍然不支持。

  • 将结构作为函数参数传递:不支持,尽管我认为传递指向结构的指针应该可以工作。

如果你对这个级别的细节感兴趣,你真的应该看看Cilium 关于 BPF 的文档。它不是完全最新的(仅缺少非常新的功能),但比手册页更完整和准确。特别是,LLVM 部分列出了在编译为 eBPF 的 C 程序中应该或不应该工作的项目。除了上述项目外,他们还引用了:

  • (所有函数都需要内联,没有函数调用)-> 这个已经过时了,BPF 有函数调用。

  • 没有共享库调用:这是真的。您不能调用标准库中的函数或其他 BPF 程序中定义的函数。您只能调用在相同 BPF 程序中定义的函数,或在内核中实现的 BPF 助手,或执行“尾调用”。

  • 例外:memset()///的 LLVM 内置函数可用(我认为它们几乎是您可以调用的唯一函数,除了 BPF 助手和其他 BPF 函数)。memcpy()memmove()memcmp()

  • 不允许使用 const 字符串或数组(因为它们在 ELF 文件中的处理方式):我认为这在今天仍然有效吗?

  • BPF 程序堆栈被限制为 512 字节,因此您的 C 程序不得导致尝试使用更多字节的可执行文件。

列出了其他允许或需要了解的项目。我只能鼓励你潜入其中!

于 2019-08-28T09:13:36.697 回答
2

让我们来看看这些:

  • 可变参数函数、浮点数和作为函数参数传递结构仍然是不可能的。据我所知,没有正在进行的工作来支持这些。
  • 由于Daniel Borkmann 最近的补丁集,内核 >=5.2 应该支持全局变量
  • 无限循环仍然不受支持。在内核 >=5.3 中对有界循环的支持有限。我在这里使用“有限”,因为如果循环太大,一个小程序仍然可能被拒绝。

了解最新版本的 Linux 允许什么的最好方法是阅读验证者的代码和/或关注bpf 邮件列表(您可能还想关注 netdev 邮件列表,因为一些补丁集可能仍然在那里)。我还发现检查补丁非常有效,因为它更清楚地概述了每个补丁集的状态。

于 2019-08-28T09:02:39.587 回答