BPF 许可¶
背景¶
经典 BPF 采用 BSD 许可
“BPF” 最初以 BSD 数据包过滤器的形式引入,参见 http://www.tcpdump.org/papers/bpf-usenix93.pdf。 对应的指令集及其实现来自 BSD,并采用 BSD 许可。 最初的指令集现在被称为“经典 BPF”。
但是,指令集是机器语言交互的规范,类似于编程语言。 它不是代码。 因此,在某些情况下应用 BSD 许可可能会产生误导,因为指令集可能不受版权保护。
eBPF(扩展 BPF)指令集继续采用 BSD 许可
2014 年,经典 BPF 指令集得到了显著扩展。 我们通常将此指令集称为 eBPF,以将其与 cBPF 区分开来。 eBPF 指令集仍然采用 BSD 许可。
eBPF 的实现¶
使用 eBPF 指令集需要在内核空间和用户空间中都实现代码。
在 Linux 内核中¶
eBPF 解释器和各种即时编译器的参考实现是 Linux 的一部分,并采用 GPLv2 许可。 eBPF 辅助函数的实现也采用 GPLv2 许可。 解释器、JIT、辅助函数和验证器被称为 eBPF 运行时。
在用户空间中¶
在 Apache2 (https://github.com/iovisor/ubpf), MIT (https://github.com/qmonnet/rbpf) 和 BSD (https://github.com/DPDK/dpdk/blob/main/lib/librte_bpf) 许可下也有 eBPF 运行时(解释器、JIT、辅助函数)的实现。
在硬件中¶
硬件可以选择以原生方式执行 eBPF 指令,并在硬件中提供 eBPF 运行时,或者通过使用具有专有许可的固件来实现。
在其他操作系统中¶
eBPF 指令集和运行时的其他内核或用户空间实现可以具有专有许可。
在 Linux 内核中使用 BPF 程序¶
Linux 内核(虽然采用 GPLv2)允许在以下规则下链接专有内核模块:Linux 内核许可规则
加载内核模块时,linux 内核会检查它打算使用的函数。 如果任何函数被标记为“仅限 GPL”,则相应的模块或程序必须具有与 GPL 兼容的许可。
将 BPF 程序加载到 Linux 内核类似于加载内核模块。 BPF 在运行时加载,而不是静态链接到 Linux 内核。 BPF 程序加载遵循与内核模块相同的许可检查规则。 如果 BPF 程序不使用“仅限 GPL”的 BPF 辅助函数,则它们可以是专有的。
此外,截至 2021 年 8 月,一些 BPF 程序类型(Linux 安全模块 (LSM) 和 TCP 拥塞控制 (struct_ops))即使不直接使用“仅限 GPL”的辅助函数,也必须与 GPL 兼容。 Linux 内核的 LSM 和 TCP 拥塞控制模块的注册步骤是通过 EXPORT_SYMBOL_GPL 内核函数完成的。 从这个意义上讲,LSM 和 struct_ops BPF 程序隐式调用“仅限 GPL”的函数。 相同的限制适用于通过不稳定接口(也称为“kfunc”)直接调用内核函数的 BPF 程序。
将 BPF 程序与用户空间应用程序打包¶
通常,在同一软件包中,专有许可的应用程序和为 Linux 内核编写的 GPL 许可的 BPF 程序可以共存,因为它们是单独的可执行进程。 这适用于 cBPF 和 eBPF 程序。