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

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

介绍了为在 Fuchsia 上支持类似 POSIX 的网络 API 的政策。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-07-15
审核日期(年-月-日)2022-08-17

摘要

Fuchsia 旨在通过 fdio 和系统网络堆栈向组件公开与 POSIX 兼容的网络 API。它还支持一些在其他面向 POSIX 的操作系统中通用的非 POSIX 功能。

设计初衷

Fuchsia 的现有系统 netstack 是围绕以 Linux 兼容性为目标的核心构建的。我们计划在项目中替换此网络堆栈,因此反复出现兼容性问题。此方案要求任何系统网络堆栈以类似 POSIX 的 API 为目标,使这些 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 调用的实现,包括 socketsetsockoptgetsockoptreadwritesendrecv 等。与 fdio 分层的 FIDL 服务实现共同提供这些调用及其他调用的完整实现。

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

请注意,虽然此方案要求 Fuchsia 提供 POSIX 兼容的网络接口,但它并不需要使用它。特别是,未来规范或开发将与 POSIX 一起实现的 Fuchsia 优先 API 没有任何限制。

实现

现有的 fdio 库和系统网络堆栈已经为组件提供了大多数与 POSIX 兼容的接口。此提案旨在整理尚非正式决策,力求与类似 POSIX 的操作系统保持一致,并指导网络堆栈和 fdio 库的未来开发。更改系统 netstack 和 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 上,只有使用 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 接口的重要基准化分析工具。这将用于衡量性能改进和检测是否出现回归问题。

工效学设计

Fuchsia 以 POSIX(一个众所周知的应用通用接口)为目标,让开发者可以轻松移植现有代码,并提供用于编写新代码的熟悉接口。虽然某些 POSIX 概念不会直接映射到 Fuchsia(例如 UID),但绝大多数网络概念都可以映射到 Fuchsia。定位到熟悉的网络接口可以显著改善开发代码并将其移植到 Fuchsia 的体验。

向后兼容性

此提案并不代表对原则的变更,只是对非正式原则的编码。由于没有引入任何更改,因此向后兼容性方面的注意事项微乎其微。

安全注意事项

该 RFC 未引入任何新的安全注意事项,因为它是对一组现有的非正式原则进行了编码。此外,承诺提供与 POSIX 兼容的 API 并不会影响未来的每个组件隔离或网络堆栈分片以解决安全问题。

隐私注意事项

此方案不会引入任何新的隐私保护注意事项,因为它仅整理了对已在使用的 POSIX API 的支持。

测试

使用现有的兼容性套件测试 Fuchsia 系统 netstack,该套件会根据 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,并长期支持该 Surface。

虽然 POSIX 是一个广为人知的标准,但它在设计上不支持 Fuchsia 具备的功能或丰富的 IPC 规范机制。为了支持与类似 POSIX 的系统的兼容性,需要为组件提供更受限的接口(同步系统调用、无类型文件描述符),还需要将这些概念放入 Fuchsia 基元中。此外,为 Fuchsia 组件采用类似 POSIX 的接口可能会妨碍实用的 Fuchsia 优先网络 API 的开发。

作为一个更彻底的选择,Fuchsia 可以明确规避 POSIX 兼容性,改为使用 Fuchsia 优先的 API。鉴于针对类似 POSIX 的 API 编写了大量 Fuchsia 系统服务代码,这似乎适得其反,且目光短浅。

就未知情况而言,主要的预期类别是 POSIX 支持的不完整实现,以及 Fuchsia 相对于对等操作系统的行为不兼容。当实例出现或发现时,将需要处理和记录这些错误。

现有艺术和参考资料

  • POSIX 2017 规范列出了 POSIX 兼容系统的要求。
  • RFC-0082 描述了 Fuchsia 的目标是在 Fuchsia 上运行未经修改的 Linux 程序。
  • gVisor 项目的网络代码构成了现有 Fuchsia 系统网络堆栈的核心。

附录:实施决策案例研究

POSIX 的 setsockopt 函数为代码提供了一种方法来设置套接字上会影响其行为的选项。POSIX 定义了多个选项标志,但合规系统可以添加自己的自定义标志。一个相当常用的选项是 SO_REUSEPORT 选项,设置该选项后,系统会在完全相同的地址和端口上允许 binding 套接字。由于其语义定义明确并在多个系统(包括 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。