| RFC-0184:系统网络堆栈的 POSIX 兼容性 | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 介绍了在 Fuchsia 上支持类 POSIX 网络 API 的政策。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2022-07-15 |
| 审核日期(年-月-日) | 2022-08-17 |
摘要
Fuchsia 旨在通过 fdio 和系统网络堆栈向组件公开 POSIX 兼容的网络 API。它还支持其他面向 POSIX 的操作系统中常见的一些非 POSIX 功能。
设计初衷
Fuchsia 的现有系统网络堆栈围绕着以 Linux 兼容性为目标的核心构建。由于我们正在计划替换此网络堆栈,因此用户反复提出兼容性问题。此提案要求任何系统网络堆栈都以类 POSIX API 为目标,从而解决了这些问题。
POSIX 网络接口描述了组件访问网络资源的标准方式。支持 Fuchsia 组件的 POSIX 网络子集,可让您轻松地 1) 在 Fuchsia 上重复使用现有代码,以及 2) 使用熟悉的 API 为 Fuchsia 编写新代码。
利益相关方
哪些人会受到此 RFC 是否被接受的影响?(此部分为可选,但建议填写。)
辅导员:
hjfreyer@google.com
审核者:
- abarth@google.com(RFC-0082 作者)
- brunodalbo@google.com (Netstack)
- dhobsd@google.com(广告联盟政策)
已咨询:
brunodalbo@google.com、hanjh@google.com、hjfreyer@google.com、martinjeffrey@google.com、nickbrow@google.com、tamird@google.com、wildenhain@google.com
共同化:
此 RFC 已通过 Netstack 团队的设计审核。
设计
本文档中的关键字“必须”“不得”“必需”“会”“不会”“应”“不应”“建议”“可以”和“可选”应按照 IETF RFC 2119 中的描述进行解释。
在 Fuchsia 设备上,系统网络堆栈通过公开多个 fuchsia.posix.socket FIDL 服务,为组件提供网络功能。虽然支持 FIDL 的组件可以以它们为目标平台,但我们强烈建议不要直接使用它们。相反,为 POSIX 系统调用 API 编写的组件应链接到 fdio 兼容性库,以将 libc 系统调用转换为 FIDL 服务调用。
Fuchsia 的 fdio 库充当从有限的 POSIX 子集到相应 FIDL 服务的转换层。对于网络功能,fdio 提供了许多 POSIX 调用的实现,包括 socket、setsockopt 和 getsockopt、read、write、send、recv 等。通过将 FIDL 服务与 fdio 分层,可以实现这些调用和其他调用的完整实现。
本文档的目的不是提供完整的系统调用列表,而是定义用于决定何时实现 POSIX 或对等系统定义的网络功能的标准。预期 fdio 和网络堆栈将根据需要实现系统调用和选项,主要用于第一方 Fuchsia 代码,然后用于其他应用。可以使用 fdio 提供的系统调用实现的 POSIX 函数不在本文档的讨论范围内。
请注意,虽然此提案强制要求 Fuchsia 提供与 POSIX 兼容的网络接口,但并未要求使用该接口。特别是,没有任何因素会妨碍未来规范或开发与 POSIX 一起实现的 Fuchsia 优先 API。
实现
现有的 fdio 库和系统网络堆栈已经为组件提供了一个基本与 POSIX 兼容的接口。此提案旨在将尚未正式做出的决定(即力求与类 POSIX 操作系统保持一致)编入代码,并指导未来在网络堆栈和 fdio 库方面的开发。在对系统网络堆栈和 fdio 进行更改时,应考虑以下三项原则:
POSIX 合规性
Fuchsia 的系统网络堆栈和 fdio 库旨在提供对 POSIX 指定的网络 API 的兼容性。以 POSIX 网络 API 为目标的组件在与 fdio 关联并路由适当的套接字创建功能时,应能正常运行。
与对等系统的兼容性
POSIX 规范未定义某些交互的行为,因此针对 POSIX 接口编写的组件通常会预期并考虑特定操作系统或操作系统系列的行为。如果此行为在多个类 POSIX 操作系统中定义明确且一致,则 Fuchsia 的网络子系统应与之匹配(除非在少数情况下,如下所述)。如果对等系统的行为不一致,则无法保证 Fuchsia 与任何特定对等系统的行为保持一致。
对发散行为的容忍度
Fuchsia 网络子系统可能需要实现与对等系统不同的行为。当出现以下情况时,应出现此类差异
- 对等系统的行为彼此不一致,
- 实现与对等系统一致的行为会带来安全风险,或者
- 由于 Fuchsia 的架构限制,实现一致的行为会很困难或不可能。
在这些情况下,分歧应有充分的理由、完善的文档和充分的测试。此外,组件(例如返回错误的 POSIX 系统调用)应能轻松观察到行为差异。
已知限制
POSIX 使用多个全局标识符空间,包括 UID、GID、PID 和文件路径。许多此类标识符都与内置支持一起使用,以限制对类 POSIX 系统上网络操作的访问权限。这些违规行为包括但不限于:
- 使用
SO_REUSEPORT和SO_REUSEADDR在同一地址上绑定套接字仅限于以相同 UID 运行的组件。 - 在 Linux 上,只有以
CAP_NET_RAW运行的应用才能清除SO_BINDTODEVICE套接字选项。 - 在 Linux 上,只有以
CAP_NET_RAW运行的应用才能创建原始 IP 套接字。 - 在 Linux 上,将套接字绑定到编号较低的端口需要应用具有
CAP_NET_BIND_SERVICE权限(不过在最新的 macOS 版本上,这是一项非特权操作)。
在可能的情况下,Fuchsia 将支持这些行为,但前提是能够将这些行为的功能映射到 Fuchsia 概念,并且可能需要考虑 Fuchsia 的架构限制。例如,类 POSIX 系统会隐式使用进程的 UID 来确定端口共享权限的范围。由于 Fuchsia 没有 UID,组件需要采取明确的操作来选择启用端口共享,这可能需要通过额外的 fdio 调用来实现。
性能
为了正式支持 POSIX 网络接口,Fuchsia 的网络子系统将提供该 API 的高性能实现。Fuchsia 网络堆栈和 fdio 已经拥有大量可用于测试 POSIX 接口的基准比较工具。这将用于衡量性能改进情况并检测回归。
工效学设计
通过以 POSIX(一种众所周知的通用应用接口)为目标平台,Fuchsia 可让开发者轻松移植现有代码,并提供熟悉的接口来编写新代码。虽然某些 POSIX 概念无法直接映射到 Fuchsia(例如 UID),但绝大多数网络概念都可以。以熟悉的网络接口为目标将显著改善在 Fuchsia 上开发和将代码移植到 Fuchsia 的体验。
向后兼容性
此提案并非改变原则,只是将非正式原则编入法典。由于未引入任何更改,因此向后兼容性方面的考虑因素很少。
安全注意事项
此 RFC 并未引入任何新的安全注意事项,因为它只是将一组现有的非正式原则编入法典。此外,提供 POSIX 兼容 API 的承诺并不妨碍未来对网络堆栈进行组件级隔离或分片,以解决安全问题。
隐私注意事项
此提案并未引入任何新的隐私权注意事项,因为它仅对已在使用的 POSIX API 的支持进行编纂。
测试
Fuchsia 系统网络堆栈使用现有兼容性测试套件进行测试,该套件会检查是否符合 POSIX 和 Linux 标准(尽管后者只是为了方便起见,并不意味着对 Linux 行为的隐式认可)。此测试套件通过对系统响应 POSIX 调用的预期行为进行编码,有助于防止回归并指导未来的功能开发。Fuchsia 的网络子系统与 POSIX 或类 POSIX 系统之间的有意行为差异已在测试套件中编码并记录。已知非有意差异也会被编码、记录并标记在 Fuchsia 的 bug 跟踪系统中。这种集成级测试,再加上针对系统网络堆栈内部的现有单元测试,可为 POSIX 兼容性提供足够的覆盖率。
文档
此提案需要提供两份额外的文件:
- 有关如何使用
fdioAPI 与系统网络堆栈进行通信的说明,以及 - Fuchsia 网络堆栈/
fdio与 POSIX/类 POSIX 系统行为之间存在差异的行为列表。
缺点、替代方案和未知因素
此提案要求承诺在 Fuchsia 系统网络堆栈和 fdio 库中实现 POSIX 和对等兼容行为的重要子集。由于此提案是对现有方案的正式化,因此许多功能已存在。此提案承诺 Fuchsia 将扩展现有的 API Surface,并长期支持它。
虽然 POSIX 是一个众所周知的标准,但它在设计时并未支持 Fuchsia 具有的功能或丰富的 IPC 规范机制。为了支持与类 POSIX 系统的兼容性,需要为组件提供更有限的接口(同步系统调用、无类型文件描述符),并将这些概念硬塞到 Fuchsia 原语中。此外,为 Fuchsia 组件采用类 POSIX 接口可能会阻碍开发有用的 Fuchsia 优先联网 API。
作为一种更激进的选择,Fuchsia 可以明确避开 POSIX 兼容性,转而采用 Fuchsia 优先的 API。鉴于大量 Fuchsia 系统服务代码已编写为面向类 POSIX API,这似乎既适得其反,又目光短浅。
对于未知问题,主要预期类别是 POSIX 支持方面的不完整实现,以及 Fuchsia 相对于同类操作系统的不兼容行为。这些问题需要在出现或发现时加以解决并记录在案。
在先技术和参考资料
- POSIX 2017 规范列出了 POSIX 兼容系统的要求。
- RFC-0082 介绍了 Fuchsia 在 Fuchsia 上运行未经修改的 Linux 程序的这一目标。
- gVisor 项目的网络代码构成了现有 Fuchsia 系统网络堆栈的核心。
附录:实现决策案例研究
POSIX 的 setsockopt 函数提供了一种方法,让代码可以设置影响套接字行为的选项。POSIX 定义了多个选项标志,但兼容系统可以添加自己的自定义标志。一个相当常用的选项是 SO_REUSEPORT 选项,设置该选项后,允许在完全相同的地址和端口上创建 bind 套接字。由于其语义在多个系统(包括 FreeBSD、macOS 和其他 BSD 衍生版本)中定义明确且一致,因此 Fuchsia 的网络堆栈允许组件在 UDP 套接字上设置 SO_REUSEPORT 选项。
Linux 和源自 BSD 的 SO_REUSEPORT 实现之间的一个区别是,Linux 要求绑定到同一地址的套接字属于具有相同用户 ID 的进程。由于 Fuchsia 的架构不允许使用类似的用户 ID 概念,因此 Fuchsia 中未实现此限制。
此外,Linux 对 SO_REUSEPORT 的实现会导致不一致的行为,具体取决于是在调用 bind 之前在套接字上设置该选项,然后清除该选项,还是根本不在套接字上设置该选项。对不可见的系统状态和定义不明确的行为的依赖促使我们决定不模拟 Linux 的行为。
如需了解详情,请参阅 https://fxbug.dev/42051599。