ebpf 的受限 C 中不允许什么?
What is not allowed in restricted C for ebpf?
来自 bpf 手册页:
eBPF programs can be written in a restricted C that is compiled
(using the clang compiler) into eBPF bytecode. Various features are
omitted from this restricted C, such as loops, global variables,
variadic functions, floating-point numbers, and passing structures as
function arguments.
据我所知,手册页未更新。我想知道在使用受限 C 编写 eBPF 程序时究竟禁止什么?手册页所说的仍然正确吗?
让我们回顾一下这些:
- 可变参数函数、浮点数和传递结构作为函数参数仍然是不可能的。据我所知,没有正在进行的工作来支持这些。
- 全局变量 应该在 >=5.2 的内核中得到支持,感谢 recent patchset by Daniel Borkmann.
- 无限循环 仍然不受支持。有limited support for bounded loops in kernels >=5.3。我在这里使用“有限”是因为如果循环太大,小程序仍然可能被拒绝。
了解 Linux 的最新版本允许什么的最好方法是阅读 the verifier's code and/or to follow the bpf mailing list (you might also want to follow the netdev mailing list as some patchsets may still land there). I've also found checking patchwork 非常有效,因为它更清楚地概述了每个补丁集的状态。
ELF 文件本身“允许”什么并不是真正的问题。这句话意味着一旦编译成 eBPF 指令,你的 C 代码可能会产生被验证者拒绝的代码。例如,BPF 程序中的循环在 BPF 程序中长期以来一直被拒绝,因为无法保证它们会终止(唯一的解决方法是在编译时展开它们)。
所以你基本上可以在 C 中使用几乎任何你想要的东西,并成功地生成一个 ELF 目标文件。但是你希望它通过验证器。哪些组件肯定会导致验证者抱怨?让我们看看手册页中的列表:
循环:Linux 5.3 版引入了对有界循环的支持,因此循环现在可以在一定程度上起作用。 “有界循环”是指验证者有办法告诉它们最终会完成的循环:通常,for (i = 0; i < CONSTANT; i++)
类循环应该可以工作(假设 i
未在块中修改)。
全局变量:最近有一些支持全局变量的工作,但是它们以特定的方式处理(如单项映射),我还没有真正试验过它们,所以我不知道这有多透明,是否可以简单地在程序中定义全局变量。随意尝试 :).
可变参数函数:很确定这是不支持的,我现在不知道在 eBPF 中如何转换。
浮点数:仍不支持。
将结构作为函数参数传递:不支持,但我认为将指针传递给结构应该可行。
如果您对这个级别的细节感兴趣,您真的应该看看 Cilium's documentation on BPF. It is not completely up-to-date (only the very new features are missing), but much more complete and accurate than the man page. In particular, the LLVM section 有一个列表,列出了在编译为 eBPF 的 C 程序中应该或不应该工作的项目。除了上述项目外,他们还引用:
(所有函数都需要内联,没有函数调用) -> 这个已经过时了,BPF有函数调用。
没有共享库调用:这是事实。您不能调用标准库中的函数,或其他 BPF 程序中定义的函数。您只能调用在相同 BPF 程序中定义的函数,或在内核中实现的 BPF 助手,或执行“尾调用”。
异常:memset()
/memcpy()
/memmove()
/memcmp()
的 LLVM 内置函数可用(我认为它们很漂亮除了 BPF 助手和其他 BPF 函数之外,您可以调用的函数很多。
不允许使用 const 字符串或数组(因为它们在 ELF 文件中的处理方式):我认为这在今天仍然有效?
BPF 程序堆栈限制为 512 字节,因此您的 C 程序不得生成试图使用更多字节的可执行文件。
列出了其他允许的或众所周知的项目。我只能鼓励你投入其中!
来自 bpf 手册页:
eBPF programs can be written in a restricted C that is compiled (using the clang compiler) into eBPF bytecode. Various features are omitted from this restricted C, such as loops, global variables, variadic functions, floating-point numbers, and passing structures as function arguments.
据我所知,手册页未更新。我想知道在使用受限 C 编写 eBPF 程序时究竟禁止什么?手册页所说的仍然正确吗?
让我们回顾一下这些:
- 可变参数函数、浮点数和传递结构作为函数参数仍然是不可能的。据我所知,没有正在进行的工作来支持这些。
- 全局变量 应该在 >=5.2 的内核中得到支持,感谢 recent patchset by Daniel Borkmann.
- 无限循环 仍然不受支持。有limited support for bounded loops in kernels >=5.3。我在这里使用“有限”是因为如果循环太大,小程序仍然可能被拒绝。
了解 Linux 的最新版本允许什么的最好方法是阅读 the verifier's code and/or to follow the bpf mailing list (you might also want to follow the netdev mailing list as some patchsets may still land there). I've also found checking patchwork 非常有效,因为它更清楚地概述了每个补丁集的状态。
ELF 文件本身“允许”什么并不是真正的问题。这句话意味着一旦编译成 eBPF 指令,你的 C 代码可能会产生被验证者拒绝的代码。例如,BPF 程序中的循环在 BPF 程序中长期以来一直被拒绝,因为无法保证它们会终止(唯一的解决方法是在编译时展开它们)。
所以你基本上可以在 C 中使用几乎任何你想要的东西,并成功地生成一个 ELF 目标文件。但是你希望它通过验证器。哪些组件肯定会导致验证者抱怨?让我们看看手册页中的列表:
循环:Linux 5.3 版引入了对有界循环的支持,因此循环现在可以在一定程度上起作用。 “有界循环”是指验证者有办法告诉它们最终会完成的循环:通常,
for (i = 0; i < CONSTANT; i++)
类循环应该可以工作(假设i
未在块中修改)。全局变量:最近有一些支持全局变量的工作,但是它们以特定的方式处理(如单项映射),我还没有真正试验过它们,所以我不知道这有多透明,是否可以简单地在程序中定义全局变量。随意尝试 :).
可变参数函数:很确定这是不支持的,我现在不知道在 eBPF 中如何转换。
浮点数:仍不支持。
将结构作为函数参数传递:不支持,但我认为将指针传递给结构应该可行。
如果您对这个级别的细节感兴趣,您真的应该看看 Cilium's documentation on BPF. It is not completely up-to-date (only the very new features are missing), but much more complete and accurate than the man page. In particular, the LLVM section 有一个列表,列出了在编译为 eBPF 的 C 程序中应该或不应该工作的项目。除了上述项目外,他们还引用:
(所有函数都需要内联,没有函数调用) -> 这个已经过时了,BPF有函数调用。
没有共享库调用:这是事实。您不能调用标准库中的函数,或其他 BPF 程序中定义的函数。您只能调用在相同 BPF 程序中定义的函数,或在内核中实现的 BPF 助手,或执行“尾调用”。
异常:
memset()
/memcpy()
/memmove()
/memcmp()
的 LLVM 内置函数可用(我认为它们很漂亮除了 BPF 助手和其他 BPF 函数之外,您可以调用的函数很多。不允许使用 const 字符串或数组(因为它们在 ELF 文件中的处理方式):我认为这在今天仍然有效?
BPF 程序堆栈限制为 512 字节,因此您的 C 程序不得生成试图使用更多字节的可执行文件。
列出了其他允许的或众所周知的项目。我只能鼓励你投入其中!