跳转至

Is it Still Possible to Extend TCP?

这是 MPTCP 设计团队做的测量工作,是 NSDI12-MPTCP 的前作。本文中的结论直接影响了 MPTCP 的标准化设计.

  • 本文(IMC11-MPTCP): 测量结果
  • NSDI12-MPTCP: 标准化设计

一、核心问题与结论

问题:IP options 早已因路由器慢路径处理而无法使用。TCP 的官方扩展机制是 TCP options,它是否也被中间盒(middlebox,例如 NAT、防火墙、性能增强代理 PEP、流量规整器)"僵化"了?如果还能用,新扩展的设计会受到哪些约束?

结论:TCP 仍然可以扩展,但设计空间很窄

新扩展必须满足三点:

  1. 在 SYN 握手中协商
  2. 容忍 options 被剥离并回退到普通 TCP
  3. 不依赖序列号的绝对值、序列空间的连续性和报文段边界

至少 25% 的路径存在超出普通防火墙的 Layer4 (传输层) 干预

二、测量方法

工具 TCPExposure:

客户端(发起方,约 3000 行 Python)由志愿者运行,服务器(响应方,约 500 行)部署在作者自己运营的、没有中间盒的网络 sfc.wide.ad.jp

两端都可控,这是本文相对于 Padhye/Floyd、Medina 等"仅客户端"测量的关键优势:只有在两端同时抓包,才能判断选项是否被删、序列号是否被改、报文段是否被重新分段

响应方是无状态的:

它的回复只依赖收到的报文段(收到 SYN 就回 SYN/ACK,ACK 号取收到序列的末尾)。这样便于推理,因为没有隐藏的服务器状态。但这也带来一个局限:无法区分选项是在 SYN 中被剥离,还是在 SYN/ACK 中被剥离

控制命令(放在载荷里):

  • just ack:默认命令,响应方回一个纯 ACK
  • echo headers:响应方把收到的头部和自己回复的头部都放进载荷返回,客户端据此逐字段比对
  • don't advance ack:响应方不推进 ACK,只用于重传测试

参数:

两端 MSS 都设为 512,以避免意外分片。测试三个端口:80、443,以及未分配的 34343,因为中间盒的行为与端口相关

三、各项测试与结果

测试 测什么 关键结果(端口 34343 / 80 / 443) 对扩展设计的启示
4.1 选项 SYN 和数据段中的未知选项(MP_CAPABLE / MP_DATA)、已知选项(TIMESTAMP) SYN 中未知选项被删的比例为 4% / 14% / 6%。没有任何路径因为选项而丢弃 SYN。凡是在 SYN 中放行未知选项的路径,在数据段中也会放行 在 SYN 中协商就足以判断后续能否使用该选项。必须容忍 SYN/ACK 中的选项被剥离
4.2 序列号改写 双向 ISN 是否被改 序列号未变的比例为 93% / 82% / 90%。原因是防火墙为弥补可预测 ISN 而重新随机化。部分改写序列号的路径仍然放行未知选项(34343:5/9;80:7/26;443:7/14) 不能在选项中嵌入绝对序列号,应改用相对连接起点的字节偏移
4.3 序列空洞 Data-first:中间盒看到空洞两侧的数据;Ack-first:先看到越过未见数据的 ACK(proactive ack) Data-first 通过率 97% / 85% / 95%,失败表现为无响应或重复 ACK。Ack-first 通过率只有 76% / 67% / 74%,约 20% 无响应,另有 ACK 被"修正"、中间盒自行重传等情况。约 10% 的家庭网络在 Ack-first 中无响应,尽管这些网络都不剥离选项 不能在单条流中留下序列空洞
4.4 代理确认 Proxy SYN/ACK(依据 ISN、窗口、MSS、窗口缩放因子的特征值)和 Proxy Data ACK 两类测试识别出的路径集合完全一致,说明存在完整的 split-TCP 代理 代理会剥离选项,扩展会自然回退到普通 TCP
4.5 不一致重传 重传时使用不同的载荷(等长、少 16 字节、多 16 字节) 大多数路径放行(99% / 87% / 97%)。少数路径缓存原始段并重发,即 ACK 推进了但头部没有被回显。端口 80 有一条路径直接 RST 基本可用,但扩展不能依赖"到达的是原始数据还是新数据"
4.6 重分段 拆分(发送满长度段,响应方 MSS 为 512);合并(顺序发送,以及先制造空洞迫使中间盒排队) 拆分只在代理路径上出现(1 / 9 / 4 条),且都不保留选项。没有任何中间盒在放行选项的同时进行重分段。有一条非代理路径只在不带选项时才合并 选项放行时,可以认为它仍然绑定在原来的报文段上
4.7 智能网卡 4 个厂商的 12 款支持 TSO 的网卡,以及 Intel 82598EB 的 LRO TSO 会把选项复制到每个拆分后的段。LRO 只合并选项值相同的段,合并后只保留一份选项 选项会被重复或合并,不能用选项出现的次数做信令

四、三个案例分析

第 5 节

(1) MPTCP: 设计几乎完全由中间盒的行为决定

  • 协商:在 SYN 中携带 MP_CAPABLE
    • 如果第一个 RTT 内数据段上的选项没有通过,就回退到普通 TCP
  • 每个子流使用独立的序列空间
    • 因为跨路径条带化会造成序列空洞(数据空洞的不通过率为 2–10%,ACK 空洞约 25%)
    • 因此需要额外的数据层序列号(DSN)
  • DSN 放在 TCP Options 而不是载荷里
    • 放在载荷里需要 TLV 分块,会引入不一致重传的风险,也会迫使中间盒解析载荷
  • 采用显式映射(数据序列号起点、子流序列号起点、长度),而不是"每段一个 DSN"
    • 以兼容 TSO 的选项复制和 LRO 的合并
  • 子流序列号使用相对值,以应对 ISN 改写
  • DSN 映射带校验和
    • 用来防范 FTP/SIP 等应用层网关改写载荷
    • 必要时回退到单路径
  • 重传时总是发送原始数据
  • 使用显式的数据层 ACK,不从子流 ACK 推断,以防范 proactive ack

(2) TCP Long Option [扩展选项空间]: 按现有形式不安全

  • TSO 会让每个拆分段看起来都带有长选项,因此需要像 MPTCP 那样显式标明扩展选项的位置
  • 同样需要相对序列号和校验和
  • 如果 SACK 放在扩展空间里,会改写序列号的中间盒看不到它,也就无法同步修正
  • 重传时扩展选项内容变化,在缓存段的中间盒看来就是不一致重传,可能导致连接失败
XXX is Not an Option 这句话很常见!

笔者见过好多次这类表达, 比如:

(1) Fonseca、Porter、Katz、Shenker、Stoica 2005 年的 Berkeley 技术报告《IP options are not an option》

(2) HotNets'18:《Delay is Not an Option: Low Latency Routing in Space》

(3) 一句更有名的话 "Failure is not an option"。这句话出自电影《阿波罗 13 号》(1995)

这个句式表示: "XXX 不是一个可行的选择"

  • 看 (1): 带 IP options 的包会被路由器送进慢路径(由 CPU 软件处理,而不是硬件转发),甚至直接被丢弃。所以这个扩展机制实际上已废
  • 看 (2): "对 LEO 星座来说,高时延是不可接受的"。呼应了论文的核心卖点:低轨卫星加上星间激光链路,长距离时延可以低于地面光纤

当你想表示: XXX 已经过时了 / XXX 需要rethinking / ... 就可以采用这个方式! 🚀