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

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

描述了在 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(网络堆栈)
  • 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 经过了网络堆栈团队的设计审核。

设计

本文档中的关键字“MUST”“MUST NOT”“REQUIRED”“SHALL”“SHALL NOT”“SHOULD” “SHOULD NOT”“RECOMMENDED”“MAY”和“OPTIONAL”应 按照 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 兼容的网络接口,但并不要求使用该接口。特别是,没有任何内容会阻止未来指定或开发与 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_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 网络堆栈/fdio 与 POSIX/类似 POSIX 的系统行为之间的差异行为列表。

缺点、替代方案和未知因素

此提案要求在 Fuchsia 系统网络堆栈和 fdio 库中实现 POSIX 和对等兼容行为的重要子集。由于此提案是对现有计划的正式化,因此大部分功能已经存在。此提案承诺 Fuchsia 将扩展现有 API 表面,并长期支持它。

虽然 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。