Presto:在可编程交换机上以太比特速度运行 TCP
数据中心网络已成为连接 GPU、CPU、存储设备和分布式服务的关键基础设施。随着 AI 训练、推理和分布式存储工作负载将网络带宽推向太比特每秒的范围,传统的主机端 TCP/IP 协议栈正成为系统中越来越昂贵的一部分。
这个问题通常被描述为 网络 CPU 税:主机 CPU 的很大一部分容量被消耗在简单的数据包处理上,而不是执行应用逻辑。
TCP 处理远不止移动字节。高速实现必须处理:
- 数据包解析
- 校验和
- 序列号验证
- 接收窗口管理
- 乱序重组
- ACK 生成
- 重传
- 快速重传
- 拥塞控制
- 连接状态管理
即使是内核旁路协议栈,在高包速率下也会消耗大量 CPU 资源。
这创造了一个根本的架构权衡。
ASIC 提供吞吐量、延迟和能效,但传统上牺牲了可编程性。软件协议栈提供灵活性和兼容性,但消耗 CPU 资源。
SIGCOMM ‘26 最佳论文《Presto:面向太比特时代的 Match-Action TCP 协议栈》提出了一种不同的方法:将 TCP 协议栈移入可编程交换机的数据平面。
Presto 证明了有状态的 TCP 处理可以映射到确定性的可重构 Match-Action(RMT)流水线中,同时保留标准 TCP 语义和 POSIX 套接字兼容性。
结果是一种试图结合以下优势的架构:
- ASIC 级别的线速处理
- 可编程传输逻辑
- 标准 TCP 语义
- POSIX 套接字兼容性
- 显著降低主机 CPU 消耗
⚖️ 为什么在太比特速度下 TCP 会成为 CPU 税 #
主机软件 TCP #
传统方法完全在服务器 CPU 上运行 TCP。
Linux 和内核旁路协议栈(如 TAS)提供了出色的软件灵活性和兼容性。
它们的优势包括:
- 标准 TCP 行为
- POSIX 套接字接口
- 灵活的拥塞控制
- 简单的功能开发
- 与现有应用的兼容性
问题在于可扩展性。
随着网络带宽增加,数据包处理工作量也会增加。更多的数据包意味着更多的 CPU 周期用于解析头部、维护连接状态、管理缓冲区、处理 ACK 和处理重传。
在足够高的速度下,网络处理会消耗许多原本应执行应用工作负载的 CPU 核心。
高数据包处理开销还可能导致:
- 延迟增加
- 尾延迟尖峰
- CPU 争用
- 能效低下
内核旁路减少了一些操作系统开销,但并没有消除在通用处理器上执行 TCP 逻辑的根本成本。
固定功能硬件卸载 #
相反的方法是将 TCP 处理移入专用硬件。
TCP 卸载引擎(TOE)和 RDMA 可以提供:
- 高吞吐量
- 低延迟
- 低 CPU 利用率
- 出色的能效
然而,固定功能实现难以演进。
新的拥塞控制算法、传输功能和协议扩展可能需要硬件重新设计。
RDMA 也改变了编程模型。应用不能简单地使用标准 TCP 套接字,而无需进行重大架构更改。
这使得 RDMA 对特定的 HPC 和存储工作负载非常有效,但作为 TCP 的通用替代方案吸引力较小。
SmartNIC、NPU 和 FPGA 卸载 #
可编程 SmartNIC、NPU 和 FPGA 提供了一个中间地带。
它们可以执行自定义逻辑,并在部署后更新。
然而,许多现有实现面临以下挑战:
- 大电路复杂度
- 严格的时序约束
- 显著的硬件资源消耗
- 困难的状态管理
- 吞吐量上限
- 部分而非完全卸载
一些设计仍依赖主机 CPU 完成协议栈的部分工作,限制了硬件加速的好处。
Presto 采用不同的方法,利用交换机现有的可编程数据包处理流水线。
🧩 RMT 很强大——但 TCP 本质上是有状态的 #
可重构 Match-Action(RMT)架构广泛应用于可编程交换机和下一代网络设备。
RMT 流水线由多个阶段组成。每个阶段通常执行以下部分组合:
- 匹配数据包字段。
- 执行动作。
- 读取或更新状态。
- 将数据包转发到下一阶段。
数据包以确定性方向通过流水线。
这种架构对以下工作负载非常有效:
- 路由
- ACL
- 数据包分类
- 负载均衡
- 遥测
- 头部操作
TCP 要困难得多。
一个 TCP 连接维护紧密耦合的状态,包括:
- 序列号
- 接收窗口
- 发送窗口
- ACK 状态
- 乱序数据包信息
- 重传状态
- 拥塞控制信息
传统 CPU 可以在处理一个数据包时多次读取和修改同一连接状态。
RMT 流水线无法自由执行这些操作。
数据包不能任意向后移动到早期阶段,流水线内存也不能像不受限制的软件内存一样使用。
三个根本依赖问题 #
将 TCP 映射到 RMT 流水线会产生三个主要风险。
前向读取依赖
早期阶段可能需要一个直到后期阶段才计算或验证的值。
循环写依赖
后期阶段可能确定必须修改早期阶段维护的状态。
流水线停顿
流水线理论上可以停止处理直到这些依赖解决,但这样做会破坏线速架构的吞吐量优势。
Presto 的核心贡献是一套技术,消除或转换这些依赖,而不会将交换机流水线变成串行处理器。
🚀 Presto 的三个核心设计原则 #
Presto 完全在 RMT 流水线内实现 TCP。
该架构将 TCP 操作(包括数据包重组、重传、流控制和拥塞控制强制执行)分解为可在线速执行的 match-action 操作。
三个设计原则使这成为可能。
1. 内联处理避免流水线停顿 #
正常 TCP 数据路径只将每个数据包通过流水线处理一次。
Presto 避免了:
- 数据包再循环
- 流水线内数据包缓存
- 正常路径上的多遍处理
再循环成本高,因为它消耗额外的流水线带宽并增加延迟。
缓存也有问题,因为交换机 SRAM 有限且宝贵。
相反,Presto 在 Ingress 和 Egress 流水线之间分离处理责任。
Ingress 流水线主要执行只读解析和分类。
可变的 TCP 连接状态更新放在 Egress 流水线中。
这种安排还提供了优雅的故障模型。
如果流量管理器(TM)丢弃数据包,该事件可以像普通网络数据包丢失一样处理。TCP 现有的重传机制然后提供恢复机制。
交换机不需要为每个内部故障模式构建完全独立的可靠性机制。
2. 乐观并发解决前向读取 #
当早期流水线阶段需要使用仅在后期才可用的信息做出决策时,就会发生前向依赖。
Presto 使用乐观执行。
早期阶段不需要等待下游验证,而是执行推测性状态更新。
后期阶段验证该假设。
该设计依赖于绝大多数数据包遵循正常路径的观察。
概念上:
早期流水线
│
▼
推测性状态更新
│
▼
下游验证
│
┌────┴────┐
│ │
有效 无效
│ │
▼ ▼
保留 恢复
状态 / 回滚
因此,常见情况保持完全流水线化。
只有异常数据包触发恢复。
3. 伪段注入解决循环写 #
循环写依赖更困难。
考虑一个填补之前缺失序列范围的乱序数据包。
流水线后部可以确定间隙已关闭,但必须更新的状态(如 next-seq 和 avail)可能维护在早期阶段。
流水线不能简单地向后写入。
Presto 使用伪段注入解决这个问题。
数据路径不直接修改早期状态,而是生成一个无载荷的伪段,表示新的连续序列范围。
然后将该伪段注入正常处理路径。
因为它通过同一流水线向前传播,现有 TCP 逻辑可以执行所需的状态转换。
因此,伪段将向后依赖转变为另一个前向流水线操作。
🏗️ Presto 架构 #
Presto 由三个主要组件组成:
- 控制平面
- 应用接口
- RMT 数据平面
控制平面 #
控制平面运行在主机或交换机的板载 CPU 上。
它管理:
- 连接生命周期
- 拥塞控制策略
- 更高层控制逻辑
- 恢复操作
RMT 数据路径收集必要的指标并强制执行结果速率参数。
这种划分很重要。
并非每一部分 TCP 逻辑都属于硬件。Presto 将相对复杂的策略计算保留在软件中,同时将高频数据包处理移入确定性数据路径。
应用接口 #
Presto 提供两个主要应用接口。
libPresto 暴露标准 POSIX 套接字 API。
这保留了应用兼容性,但需要用户数据通过 Presto 的发送和接收缓冲区复制。
libPresto-ZC 提供零拷贝接口。
数据密集型应用可以直接访问 Presto 管理的缓冲区,消除不必要的数据复制。
这种分离允许应用选择兼容性或最大数据路径效率。
RMT 数据平面 #
数据平面由解耦的功能块组成,它们共享同一流水线硬件。
数据路径中运行三个主要工作流:
- RX: 网络到主机接收处理
- TX: 主机到网络传输
- SYNC: 连接状态同步和信用更新
该设计在这些工作流中重用相同的硬件资源,而不是为每个 TCP 功能要求单独的流水线。
📦 数据包重组是最难的部分 #
TCP 数据包重组创建了一些最困难的状态管理问题,因为数据包可能乱序到达。
传统软件协议栈可以为任意乱序段维护动态数据结构。
RMT 流水线不能。
因此,Presto 引入了 OOO-n 模型,其中 n 表示硬件可以跟踪的乱序区间数量。
| 模式 | 能力 |
| ----- | --------------------------------------- |
| OOO-0 | 无乱序数据包缓存 |
| OOO-1 | 跟踪一个乱序区间 |
| OOO-n | 跟踪最多 `n` 个乱序区间 |
增加 n 提供更大的重组能力,但消耗额外的硬件资源。
这创建了一个明确的性能与资源权衡,而不是试图在交换机内重现不受限制的软件数据结构。
🔄 接收端重组 #
OOO-0 使用乐观并发 #
基本接收器维护两个重要状态变量:
next-seq:下一个按序期望的序列号avail:剩余接收窗口空间
传统实现可以在推进 next-seq 之前验证接收窗口。
在 RMT 流水线中,这两个变量可能位于不同阶段。
这创建了前向读取依赖。
Presto 乐观地解决它。
- 早期阶段推测性地推进
next-seq。 - 下游阶段使用
avail验证接收窗口条件。 - 有效数据包保留推测更新。
- 无效数据包触发恢复。
如果发送方违反接收窗口,违规数据包被丢弃,并通知控制平面回滚连接状态。
在恢复期间,负的 avail 值可以强制后续数据包被丢弃,同时接收器通告零窗口。
关键思想是正常情况从不需要等待下游验证。
OOO-1 使用伪段 #
OOO-1 添加:
ooo-headooo-tail
以表示单个乱序区间。
这些值维护为相对于 next-seq 的偏移量。
这种相对表示有一个重要优势:当 next-seq 推进时,乱序区间自动移位,而无需重写每个存储的序列号。
困难情况发生在传入的按序段填补间隙时。
流水线后部检测到间隙关闭,但流水线前部拥有必须推进的状态。
因此 Presto:
- 在下游检测关闭的间隙。
- 生成无载荷伪段。
- 编码新的连续序列范围。
- 将伪段注入 RX 流水线。
- 重用 OOO-0 处理来推进
next-seq。 - 更新
avail。 - 清除已完成的乱序区间。
伪段提供最终恢复 #
伪段也继承系统的数据包丢失模型。
如果伪段因拥塞被丢弃,底层乱序状态保持完整。
下一个相关真实数据包可以再次触发伪段生成。
这为状态转换提供了一种最终一致性形式,而无需伪段本身的可靠内部交付。
重叠的序列范围也可以自动修剪,防止重复字节计数。
OOO-n 扩展模型 #
同一概念可以扩展到多个乱序区间。
Presto 使用级联区间合并和批量伪段重放来关闭多个间隙。
实现维护围绕区间排序和间隙表示的关键不变量,同时避免通用排序或动态内存结构。
结果是一个硬件友好的 TCP 重组语义近似,其资源需求可以明确控制。
💾 接收端支持机制 #
数据放置 #
乱序数据包通过 DMA 直接写入主机内存。
Presto 使用接收缓冲区的双虚拟映射来处理缓冲区环绕。
这允许 DMA 操作在循环接收缓冲区跨越其物理边界时避免不必要的碎片化。
ACK 生成 #
ACK 由数据路径生成,而不是由主机 CPU 生成。
Presto 使用镜像伪段生成确认数据包。
如果 ACK 伪段丢失,结果相当于在网络中丢失 ACK,允许 TCP 现有的可靠性机制处理该条件。
出站数据包也可以在适当时捎带确认。
应用通知 #
DMA 传输包括描述哪些连续字节范围可供应用消费的通知。
当乱序间隙关闭时,通知可以立即生成,而不是等待伪段处理完成。
这减少了应用可见的延迟。
📤 发送和重传逻辑 #
基于推送的传输 #
Presto 使用推送模型进行传输。
数据路径通过 SYNC 消息定期向 libPresto 发送传输信用。
一旦主机收到信用,它主动将载荷 DMA 到数据路径进行传输。
这避免了数据路径必须反复从主机拉取数据时可能发生的额外往返延迟。
拥塞控制在硬件和软件之间分割 #
Presto 将拥塞控制分为两层。
数据路径处理高频指标,例如:
- ECN 信息
- 重复 ACK 检测
- 数据包级定时
- 速率强制执行
控制平面处理更可编程的策略逻辑。
因此,像 DCTCP 和 TIMELY 这样的算法可以保留在软件中,而数据路径强制执行结果传输速率。
这种划分避免了在复杂控制算法上消耗宝贵的流水线资源,同时保留灵活性。
SYNC 调度 #
数据路径定期生成 SYNC 消息,以传递传输信用和连接管理信息。
空闲连接可以自动减少或暂停 SYNC 活动以限制开销。
SYNC 消息还可以将基于超时的重传信号传回 libPresto。
ACK 处理和快速重传 #
传入的 ACK 更新发送方的窗口状态。
三个重复 ACK 触发快速重传。
数据路径通过 DMA 通知 libPresto,并同步调整传输信用以降低发送速率。
结果是传统 TCP 恢复行为的硬件辅助实现。
📊 实验评估 #
Presto 的原型在 Intel Tofino 2 可编程交换机上实现,并与 Linux TCP 协议栈、TAS 和 RDMA 进行了评估。
结果表明,可编程交换机 TCP 可以接近传统上与专用传输硬件相关的性能特征。
RPC 性能接近 RDMA #
在负载-延迟测试中,Presto 在 32 核服务器上达到了大约 4000 万次操作每秒(Mops)。
报告的延迟包括:
- 中位数:大约 18 μs
- 第 99.99 百分位:大约 24 μs
Presto 的性能据报告与 RDMA 几乎持平。
TAS 达到了 Presto 峰值吞吐量的大约 60%,而 Linux 在测试配置中大约落后一个数量级。
Presto 还展示了跨核心和连接的近似线性扩展,聚合流水线处理能力接近 10 亿数据包每秒。
能效释放 CPU 核心 #
FlexKVS 实验显示,Presto 达到了 TAS 最优配置大约 2 倍的吞吐量功率比。
其第 99.99 百分位尾延迟大约比 TAS 最佳情况低 5 倍。
最重要的是,TCP 处理完全从主机 CPU 数据路径中移除。
评估报告 Presto 可以释放多达 16 个 CPU 核心用于应用处理。
RMT 流水线的动态功率仅略有增加,并与吞吐量近似线性相关,大约 25 Mpps/W。
这是该架构最重要的结果之一。
目标不仅仅是增加网络吞吐量。
而是通过从通用 CPU 中消除重复的协议处理,增加每服务器瓦特的有用应用工作量。
🌊 流式传输和存储达到太比特级吞吐量 #
在单核流式测试中,Presto 达到了大约 25 Mpps 的数据包处理能力。
使用 8 KB MTU,这对应于大约 1.6 Tbps 的网络带宽。
关键点是主机 CPU 不是限制此吞吐量的因素。
交换机流水线以线速执行数据包处理工作。
在 NVMe-over-TCP 存储实验中,Presto 提供了接近 RDMA 的存储 IOPS 和延迟。
相比之下,Linux TCP 协议栈在报告测试中仅达到 Presto 吞吐量的大约四分之一。
这表明可编程 TCP 卸载可以使基于 TCP 的存储与专用传输显著更具竞争力。
🛡️ 在数据包丢失和拥塞下的鲁棒性 #
Presto 还展示了在不利网络条件下的弹性。
在大约 0.1% 的随机数据包丢失率下,Presto 在报告评估中保持了接近无损的吞吐量。
在相同测试条件下,TAS 吞吐量下降了大约一半。
在 incast 场景中(许多发送方向同一接收方同时传输),Presto 表现出比评估的软件协议栈更大的稳定性。
该架构受益于基于数据路径的快速 ACK 处理和重传信号,减少了检测与拥塞相关事件和对其做出反应之间的延迟。
🧪 可编程性是 Presto 最重要的特性 #
仅凭性能无法将 Presto 与固定功能 TOE 或 RDMA 实现区分开来。
更重要的结果是基于交换机的 TCP 协议栈保持可编程。
论文展示了几个扩展。
延迟 ACK 和 SACK #
诸如延迟确认和选择性 ACK(SACK)等功能可以通过相对较小的 P4 修改添加,在报告评估中额外功耗可忽略不计。
这证明传输实现并非永久冻结在硬件中。
TIMELY 风格的拥塞控制 #
Presto 还可以利用 Tofino 2 硬件时间戳和过滤机制来计算与 RTT 相关的指标。
例如,RTT 样本可以在数据路径中处理成指数加权移动平均(EWMA)。
控制平面然后可以使用这些测量进行拥塞控制决策。
这创建了有用的划分:
数据包到达
│
▼
硬件时间戳
│
▼
RTT 测量
│
▼
EWMA / 指标处理
│
▼
控制平面策略
│
▼
速率参数
│
▼
数据路径强制执行
因此,硬件加速高频测量路径,而软件保留对算法策略的控制。
应用与网络协同设计 #
Presto 还证明了可编程数据路径可以执行超越传统 TCP 的功能。
一个例子是共享日志的全局排序。
来自多个连接的记录可以在网络中排序,然后再写入共享日志。
这允许数据路径执行原本需要 CPU 干预的排序工作。
在报告的 32 客户端场景中,使用网络内排序,单个 CPU 核心可以饱和线速,而基于软件的解决方案需要大约五个核心。
这说明了一个更广泛的可能性:可编程网络硬件可以成为应用特定分布式系统原语的执行层,而不仅仅是更快的数据包转发器。
🔬 Presto 在架构上改变了什么 #
Presto 挑战了网络中一个长期存在的假设:
有状态协议属于 CPU,而交换机应执行简单的无状态转发。
该架构表明边界不一定是固定的。
关键不是逐条指令重现软件 TCP 实现。
相反,TCP 必须围绕硬件流水线的约束重新表述。
Presto 通过以下方式实现这一点:
- 将向后依赖转换为前向处理
- 对常见情况决策使用推测执行
- 用流水线友好结构表示状态
- 使用伪段作为内部状态转换事件
- 将控制策略与数据包级强制执行分离
- 在可能的情况下将内部数据包丢弃视为普通网络丢失
- 重用现有 TCP 可靠性机制而不是复制它们
这是一个重要的硬件-软件协同设计教训。
协议不一定需要通用处理器才能可编程。
它需要一个可以高效表达协议所需状态转换的执行模型。
⚠️ 剩余的权衡 #
Presto 并没有消除可编程交换机架构的每一个限制。
RMT 流水线有有限的:
- 流水线阶段
- SRAM
- 寄存器资源
- 元数据宽度
- 算术能力
- 数据包处理带宽
因此,复杂的 TCP 功能需要仔细映射到硬件资源上。
OOO-n 设计使这个权衡明确:支持更多同时乱序区间会消耗更多资源。
同样,将拥塞控制算法保留在控制平面保留了可编程性,但意味着并非每个决策都完全在硬件中做出。
因此,该方法最好理解为硬件-软件协同设计的 TCP,而不是简单地将传统 TCP 实现移入交换机。
🔮 Presto 指向一种新的网络架构 #
Presto 证明了软件 TCP 和固定功能硬件卸载之间的传统区别并不是唯一可用的设计空间。
可编程交换机可以潜在地提供:
- 线速数据包处理
- 硬件级能效
- 标准 TCP 兼容性
- POSIX 套接字接口
- 可编程拥塞控制
- 灵活的协议扩展
- 应用特定的网络处理
报告的结果很显著:大约 40 Mops RPC 吞吐量、1.6 Tbps 单核流式能力、最多释放 16 个 CPU 核心,以及在多个工作负载中接近 RDMA 的性能。
更重要的是,Presto 展示了如何在不放弃 TCP 软件生态系统的情况下实现这些结果。
更深层次的贡献是架构性的。
不是问如何让 CPU 更快地执行 TCP,Presto 问的是网络本身是否可以执行 TCP。
这种转变将传输处理从主机的关键路径移入可编程数据平面,将交换机从被动转发设备转变为网络协议的主动执行引擎。
随着 AI 集群、分布式存储系统和高性能数据中心继续向 800G、1.6T 乃至更高速度的网络发展,消除数据包处理的 CPU 税将变得越来越重要。
Presto 提出了一个可能的方向:
保留 TCP 的兼容性和语义,但将其热路径移到可编程硬件上。
这种组合可能成为下一代高速、CPU 高效数据中心网络的强大基础。