RFC-0184:系统 Netstack 的 POSIX 兼容性

RFC-0184:系统网络堆栈的 POSIX 兼容性
状态已接受
区域
  • 外部 ABI 兼容性
  • Netstack
说明

介绍在 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

Reviewers:

  • abarth@google.com(RFC-0082 作者)
  • brunodalbo@google.com(网络栈)
  • 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 调用的实现,包括 socketsetsockoptgetsockoptreadwritesendrecv 等。与 fdio 叠加的 FIDL 服务实现共同提供这些调用及其他调用的完整实现。

本文档的目标不是提供系统调用的完整列表,而是定义用于确定何时实现 POSIX 或对等系统定义的网络功能的标准。预计 fdio 和网络堆栈将根据需要实现系统调用和选项,主要针对第一方 Fuchsia 代码,然后在其他应用需要时实现。本文档不涵盖可通过使用 fdio 提供的系统调用实现的 POSIX 函数。

请注意,虽然此提案要求 Fuchsia 提供与 POSIX 兼容的网络接口,但并不要求使用该接口。具体而言,我们未来可以制定或开发优先使用 Fuchsia 的 API,并将其与 POSIX 一起实现。

实现

现有的 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_REUSEPORTSO_REUSEADDR 将套接字绑定到同一地址仅限于使用相同 UID 运行的组件。
  • 在 Linux 上,清除 SO_BINDTODEVICE 套接字选项的功能仅限于使用 CAP_NET_RAW 运行的应用。
  • 在 Linux 上,创建原始 IP 套接字的功能仅限于使用 CAP_NET_RAW 运行的应用。
  • 在 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 兼容性提供足够的覆盖率。

文档

此提案需要另外提供两项文件:

  1. 有关如何使用 fdio API 与系统网络堆栈通信的说明,以及
  2. Fuchsia netstack/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 选项。

SO_REUSEPORT 的 Linux 实现与 BSD 派生实现之间的一个区别是,Linux 要求绑定到同一地址的套接字属于具有相同用户 ID 的进程。由于 Fuchsia 的架构不支持类似的用户 ID 概念,因此 Fuchsia 中未实现此约束条件。

此外,Linux 对 SO_REUSEPORT 的实现会导致行为不一致,具体取决于是在调用 bind 之前在套接字上设置该选项,然后在之后清除该选项,还是根本未在套接字上设置该选项。由于依赖于不可见的系统状态和定义不清的行为,因此我们决定不模拟 Linux 的行为。

如需了解详情,请访问 https://fxbug.dev/42051599。