RFC 8684 具有多个地址的多路径操作的 TCP 扩展

摘要

TCP/IP 通信目前仅限于每个连接的单个路径,但对等点之间通常存在多个路径。将这些多条路径同时用于 TCP/IP 会话将提高网络内的资源使用率,从而通过更高的吞吐量和更好的网络故障恢复能力来改善用户体验。

多路径 TCP 提供了在对等点之间同时使用多条路径的能力。本文档介绍了一组对传统 TCP 的扩展,以支持多路径操作。该协议为应用程序提供与 TCP 相同类型的服务(即可靠的字节流),并且它提供了在可能不相交的路径上建立和使用多个 TCP 流所必需的组件。

本文档通过主要由部署经验驱动的澄清和修改,指定了多路径 TCP 的 v1,淘汰了 RFC 6824 中指定的 v0。

本备忘录的状态

这是一份 Internet 标准跟踪文档。

本文档是 Internet 工程任务组 (IETF) 的产品。它代表了 IETF 社区的共识。它已接受公众审查,并已获互联网工程指导小组 (IESG) 批准出版。有关 Internet 标准的更多信息,请参见 RFC 7841 的第 2 节

有关本文档当前状态、任何勘误表以及如何提供反馈的信息,请访问 https://www.rfc-editor.org/info/rfc8684。

版权声明

版权所有 (c) 2020 IETF Trust 和文件作者。版权所有。

本文件受 BCP 78 和 IETF 信托关于 IETF 文件的法律规定 ( https://trustee.ietf.org/license-info ) 的约束,该条款在本文件发布之日生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文档中提取的代码组件必须包含 Trust Legal Provisions 第 4.e 节中所述的简化 BSD 许可文本,并且按照简化 BSD 许可中的说明在不保证的情况下提供。

、简介

多路径 TCP (MPTCP) 是对常规 TCP [ RFC0793 ]的一组扩展,以提供多路径 TCP 服务[ RFC6182 ],它使传输连接能够同时跨多个路径运行。本文档介绍了向 TCP 添加多路径功能所需的协议更改——特别是用于信令和设置多路径(“子流”)、管理这些子流、数据重组和会话终止的协议更改。然而,这并不是创建多路径 TCP 实现所需的唯一信息。本文档由其他三个补充:

  • [ RFC6182 ](MPTCP 体系结构),它解释了多路径 TCP 背后的动机,包含对此设计所基于的高级设计决策的讨论,并提供了对可以开发可扩展 MPTCP 实现的功能分离的解释。
  • [ RFC6356 ](拥塞控制),它提出了一种安全的拥塞控制算法,用于耦合多条路径的行为,以“不伤害”其他网络用户。
  • [ RFC6897 ](应用程序注意事项),其中讨论了 MPTCP 将对应用程序产生什么影响,应用程序将希望使用 MPTCP 做什么,以及由于这些因素,MPTCP 实现应该提供哪些 API 扩展。

本文档废弃了 Multipath TCP [ RFC6824 ]的 v0 规范。本文档指定 MPTCP v1,它不向后兼容 MPTCP v0。该文档还为支持这两个版本的实现定义了版本协商程序。

1.1。设计假设

为了限制潜在的巨大设计空间,MPTCP 工作组对本文档中介绍的多路径 TCP 设计施加了两个关键约束:

  • 它必须向后兼容当前的常规 TCP,以增加其部署的机会。
  • 可以假设一台或两台主机是多宿主和多地址的。

为了简化设计,我们假设主机上存在多个地址就足以表明存在多个路径。这些路径不必完全不相交:它们之间可以共享一个或多个路由器。即使在这种情况下,使用多条路径也是有益的,可以提高资源利用率和对部分节点故障的恢复能力。[ RFC6356 ]中定义的拥塞控制算法确保使用多条路径不会产生不利影响。此外,在某些情况下,单个主机上的不同 TCP 端口可能会提供不相交的路径(例如通过某些等价多路径 (ECMP) 实现[ RFC2992 ]),因此 MPTCP 设计还支持在路径标识符中使用端口。

上面列出的向后兼容性有三个方面(在[ RFC6182 ]中有更详细的讨论):

  • 外部约束:

    该协议必须通过绝大多数现有的中间设备(如 NAT、防火墙和代理)运行,因此必须尽可能地在线上类似于现有的 TCP。此外,协议不能假设它在线路上发送的段未经修改地到达目的地:它们可能被拆分或合并;TCP 选项可能会被删除或复制。

  • 应用约束:

    该协议必须在不改变使用通用 TCP API 的现有应用程序的情况下可用(尽管并非所有功能都可用于此类遗留应用程序是合理的)。此外,该协议必须向应用程序提供与常规 TCP 相同的服务模型。

  • 倒退:

    该协议应该能够在不受用户干扰的情况下回退到标准 TCP,以便能够与旧主机通信。

补充应用注意事项文档[ RFC6897 ]讨论了 API 的必要特性以提供向后兼容性,以及 API 扩展以在与常规单路径 TCP 等效的控制和信息级别传达 MPTCP 的行为。

MPTCP 体系结构文档[ RFC6182 ]和[ howhard ]中给出了对设计约束和相关设计决策的进一步讨论。

1.2. 网络堆栈中的多路径 TCP

MPTCP 在传输层运行,旨在对更高层和更低层都透明。它是标准 TCP 之上的一组附加功能;图 1说明了这种分层。MPTCP 旨在为遗留应用程序使用而无需更改;在[ RFC6897 ]中给出了它与应用程序交互的详细讨论。

1
2
3
4
5
6
7
8
9
                             +-------------------------------+
| Application |
+---------------+ +-------------------------------+
| Application | | MPTCP |
+---------------+ + - - - - - - - + - - - - - - - +
| TCP | | Subflow (TCP) | Subflow (TCP) |
+---------------+ +-------------------------------+
| IP | | IP | IP |
+---------------+ +-------------------------------+

图 1标准 TCP 和 MPTCP 协议栈的比较

1.3. 术语

本文档使用了一些特定于 MPTCP 或在 MPTCP 上下文中具有定义含义的术语,如下所示:

  • 小路:

    发送者和接收者之间的链接序列,在此上下文中由源和目标地址/端口对的 4 元组定义。

  • 子流:

    在单个路径上运行的 TCP 段流,它构成更大的 MPTCP 连接的一部分。子流的启动和终止与常规 TCP 连接类似。

  • (MPTCP) 连接:

    一组一个或多个子流,应用程序可以通过这些子流在两个主机之间进行通信。连接和应用程序套接字之间存在一对一的映射。

  • 数据级:

    有效载荷数据名义上通过连接传输,而连接又通过子流传输。因此,术语“数据级”与“连接级”同义,与“子流级”相反,后者指的是单个子流的属性。

  • 代币:

    主机赋予多路径连接的本地唯一标识符。也可以称为“连接 ID”。

  • 主持人:

    运行 MPTCP 实现并启动或接受 MPTCP 连接的终端主机。

除了这些术语,请注意 MPTCP 对常规单路径 TCP 语义的解释和影响在第 4 节中讨论。

1.4. MPTCP 概念

本节提供了 MPTCP 正常操作的高级摘要;这种类型的场景 如图 2 所示。MPTCP 如何运作的详细描述在第 3 节中给出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
         Host A                               Host B
------------------------ ------------------------
Address A1 Address A2 Address B1 Address B2
---------- ---------- ---------- ----------
| | | |
| (initial connection setup) | |
|----------------------------------->| |
|<-----------------------------------| |
| | | |
| (additional subflow setup) |
| |--------------------->| |
| |<---------------------| |
| | | |
| | | |

图 2示例 MPTCP 使用场景

  • 对于不支持 MPTCP 的应用程序,MPTCP 的行为与普通 TCP 相同。扩展的 API 可以为支持 MPTCP 的应用程序提供额外的控制[ RFC6897 ]。应用程序首先以正常方式打开 TCP 套接字。MPTCP 信令和操作由 MPTCP 实现处理。
  • MPTCP 连接的开始类似于常规 TCP 连接。这在图 2中进行了说明,其中分别在主机 A 和 B 上的地址 A1 和 B1 之间建立了 MPTCP 连接。
  • 如果有额外的路径可用,则会在这些路径上创建额外的 TCP 会话(称为 MPTCP“子流”),并与现有会话组合,该会话继续显示为与两端应用程序的单个连接。附加 TCP 会话的创建在主机 A 上的地址 A2 和主机 B 上的地址 B1 之间进行了说明。
  • MPTCP 通过主机上存在的多个地址来识别多条路径。这些多个地址的组合等同于附加路径。在该示例中,可以设置的其他潜在路径是 A1<->B2 和 A2<->B2。尽管此附加会话显示为从 A2 发起,但它同样可以从 B1 或 B2 发起。
  • 额外子流的发现和设置将通过路径管理方法实现;本文档描述了一种机制,通过该机制,主机可以通过使用自己的附加地址或通过向其他主机发送其可用地址来启动新的子流。
  • MPTCP 添加连接级序列号以允许对到达具有不同网络延迟的多个子流的段进行重组。
  • 子流通过四次 FIN 握手作为常规 TCP 连接终止。MPTCP 连接由连接级 FIN 终止。

1.5。需求语言

关键词“必须”、“不得”、“要求”、“”、“不得”、“应该”、“不应”、“推荐”、“不推荐”、“可以”和“可选”当且仅当它们以全部大写字母出现时,本文档中的 “ 将按照 BCP 14 [ RFC2119 ] [ RFC8174 ]中的描述进行解释,如此处所示。

、经营概况

本节参照协议操作对常见的 MPTCP 操作进行单一描述。这是对关键功能的高级概述;完整的规范在第 3 节中。此处不讨论可扩展性和协商功能。在本节中大量引用了 MPTCP 选项的符号名称——这些是 IANA 分配的 MPTCP 选项的子类型(参见第 7 节),它们的格式在第 3 节提供的详细协议规范中定义。

多路径 TCP 连接在两个主机之间提供双向字节流,就像普通 TCP 一样进行通信,因此不需要对应用程序进行任何更改。但是,多路径 TCP 使主机能够使用具有不同 IP 地址的不同路径来交换属于 MPTCP 连接的数据包。多路径 TCP 连接看起来就像一个应用程序的普通 TCP 连接。然而,对于网络层来说,每个 MPTCP 子流看起来就像一个常规的 TCP 流,其段带有一个新的 TCP 选项类型。多路径 TCP 管理这些子流的创建、删除和利用以发送数据。在多路径 TCP 连接中管理的子流数量不是固定的,并且在多路径 TCP 连接的生命周期内可能会波动。

所有 MPTCP 操作都使用 TCP 选项发出信号——MPTCP 的单一数字类型,每个 MPTCP 消息都有“子类型”。以下是这些信息的目的和基本原理的摘要。

2.1。启动 MPTCP 连接

这与启动正常 TCP 连接的信令相同,但 SYN、SYN/ACK 和初始 ACK(和数据)数据包也带有 MP_CAPABLE 选项。此选项具有可变长度并有多种用途。首先验证远程主机是否支持Multipath TCP;其次,此选项允许主机交换一些信息以验证其他子流的建立。更多细节在第 3.1 节中给出。

1
2
3
4
5
6
7
8
Host A                                  Host B
------ ------
MP_CAPABLE ->
[flags]
<- MP_CAPABLE
[B's key, flags]
ACK + MP_CAPABLE (+ data) ->
[A's key, B's key, flags, (data-level details)]

如果不知道它是否已被接收,则可能发生 ACK + MP_CAPABLE 的重传。下图显示了初始子流设置的所有可能交换,以确保这种可靠性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Host A (with data to send immediately)  Host B
------ ------
MP_CAPABLE ->
[flags]
<- MP_CAPABLE
[B's key, flags]
ACK + MP_CAPABLE + data ->
[A's key, B's key, flags, data-level details]


Host A (with data to send later) Host B
------ ------
MP_CAPABLE ->
[flags]
<- MP_CAPABLE
[B's key, flags]
ACK + MP_CAPABLE ->
[A's key, B's key, flags]

ACK + MP_CAPABLE + data ->
[A's key, B's key, flags, data-level details]


Host A Host B (sending first)
------ ------
MP_CAPABLE ->
[flags]
<- MP_CAPABLE
[B's key, flags]
ACK + MP_CAPABLE ->
[A's key, B's key, flags]

<- ACK + DSS + data
[data-level details]

2.2. 将新子流与现有 MPTCP 连接相关联

MP_CAPABLE 握手中的密钥交换提供了可用于在设置新子流时对端点进行身份验证的材料。其他子流以启动正常 TCP 连接的相同方式开始,但 SYN、SYN/ACK 和 ACK 数据包也带有 MP_JOIN 选项。

主机 A 在其地址之一和主机 B 的地址之一之间启动新的子流。由密钥生成的令牌用于识别它正在加入的 MPTCP 连接,并且基于哈希的消息身份验证代码 (HMAC) 用于身份验证。HMAC 使用在 MP_CAPABLE 握手中交换的密钥和在这些 MP_JOIN 选项中交换的随机数(随机数)。MP_JOIN 还包含标志和地址 ID,可用于引用源地址,而发送者无需知道它是否已被 NAT 更改。更多细节在第 3.2 节中给出。

1
2
3
4
5
6
7
8
9
10
11
12
Host A                                  Host B
------ ------
MP_JOIN ->
[B's token, A's nonce,
A's Address ID, flags]
<- MP_JOIN
[B's HMAC, B's nonce,
B's Address ID, flags]
ACK + MP_JOIN ->
[A's HMAC]

<- ACK

2.3. 通知其他主机另一个潜在地址

与多宿主主机关联的 IP 地址集可能会在 MPTCP 连接的生命周期内发生变化。MPTCP 支持在主机上隐式和显式地添加和删除地址。如果主机 A 已经建立了从地址⁠/端口对 IP#-A1 开始的子流,并且想要打开从地址⁠/端口对 IP#-A2 开始的第二个子流,它只需启动子流的建立,如上所述。然后将隐含地通知远程主机有关新地址的信息。

在某些情况下,主机可能希望在不建立新子流的情况下向远程主机通告地址的可用性——例如,当 NAT 阻止在一个方向上进行设置时。在下面的示例中,主机 A 通知主机 B 它的备用 IP 地址⁠/端口对 (IP#-A2)。主机 B 稍后可能会向这个新地址发送一个 MP_JOIN。ADD_ADDR 选项包含一个 HMAC,用于验证地址是从连接的发起者发送的。此选项的接收者将其回显给客户端以指示成功接收。更多细节在第 3.4.1 节中给出。

1
2
3
4
5
6
7
8
9
10
11
12
13
Host A                                 Host B
------ ------
ADD_ADDR ->
[Echo-flag=0,
IP#-A2,
IP#-A2's Address ID,
HMAC of IP#-A2]

<- ADD_ADDR
[Echo-flag=1,
IP#-A2,
IP#-A2's Address ID,
HMAC of IP#-A2]

有一个用于地址删除的相应信号,使用在 ADD_ADDR 握手中发出的地址 ID。更多细节在第 3.4.2 节中给出。

1
2
3
4
Host A                                 Host B
------ ------
REMOVE_ADDR ->
[IP#-A2's Address ID]

2.4. 使用 MPTCP 进行数据传输

为了确保通过可能随时出现和消失的子流可靠、有序地传递数据,MPTCP 使用 64 位数据序列号 (DSN) 对通过 MPTCP 连接发送的所有数据进行编号。每个子流都有自己的 32 位序列号空间,利用常规 TCP 序列号标头,并且 MPTCP 选项将子流序列空间映射到数据序列空间。这样,在发生故障时,可以在不同的子流(映射到同一个 DSN)上重新传输数据。

数据序列信号(DSS)承载数据序列映射。数据序列映射由该映射有效的子流序列号、数据序列号和长度组成。该选项还可以携带接收到的 DSN 的连接级确认(“数据 ACK”)。

使用 MPTCP,所有子流共享相同的接收缓冲区并通告相同的接收窗口。MPTCP 中有两个级别的确认。在每个子流上使用常规 TCP 确认来确认接收到通过子流发送的分段,而与它们的 DSN 无关。此外,还有数据序列空间的连接级确认。这些确认跟踪字节流的进展并滑动接收窗口。

更多细节在第 3.3 节中给出。

1
2
3
4
5
6
Host A                                 Host B
------ ------
DSS ->
[Data Sequence Mapping]
[Data ACK]
[Checksum]

2.5. 请求更改路径的优先级

主机可以在初始子流设置时指示他们是否希望将子流用作常规路径或备用路径——仅当没有可用的常规路径时才使用备用路径。在连接期间,主机 A 可以通过 MP_PRIO 信号向主机 B 请求更改子流的优先级。更多细节在第 3.3.8 节中给出。

1
2
3
Host A                                 Host B
------ ------
MP_PRIO ->

2.6. 关闭 MPTCP 连接

当主机想要关闭现有子流而不是整个连接时,它可以启动常规 TCP FIN/ACK 交换。

当主机 A 想要通知主机 B 它没有更多数据要发送时,它会将此“数据 FIN”作为 DSS 的一部分发出信号(见上文)。它具有与常规 TCP FIN 相同的语义和行为,但在连接级别。一旦成功接收到 MPTCP 连接上的所有数据,就会在连接级别使用数据 ACK 确认此消息。更多细节在第 3.3.3 节中给出。

1
2
3
4
5
6
Host A                                 Host B
------ ------
DSS ->
[Data FIN]
<- DSS
[Data ACK]

还有一种连接关闭的附加方法,称为“快速关闭”,类似于使用 RST 信号关闭单路径 TCP 连接。MP_FASTCLOSE 信号用于向对端指示连接将被突然关闭,不再接受任何数据。这可以用于 ACK(确保信号的可靠性)或 RST(不能)。下图显示了这两个示例。更多细节在第 3.5 节中给出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Host A                                 Host B
------ ------
ACK + MP_FASTCLOSE ->
[B's key]

[RST on all other subflows] ->

<- [RST on all subflows]


Host A Host B
------ ------
RST + MP_FASTCLOSE ->
[B's key] [on all subflows]

<- [RST on all subflows]

2.7. 显着特点

值得强调的是,MPTCP 的信令在设计时考虑了几个关键要求:

  • 为了应对路径上的 NAT,地址由地址 ID 引用,以防 IP 数据包的源地址被 NAT 更改。如果 SYN 的接收者在 NAT 之后,则无法建立新的 TCP 流;为了允许在任一端位于 NAT 之后时创建子流,MPTCP 使用 ADD_ADDR 消息。
  • 如果无法进行 MPTCP 操作,则 MPTCP 会回退到普通 TCP——例如,如果一台主机不支持 MPTCP,或者如果中间盒更改了有效负载。这将在第 3.7 节中讨论。
  • 为了解决[ RFC6181 ]中确定的威胁,采取以下步骤: 在 MP_CAPABLE 消息中以明文形式发送密钥;MP_JOIN 消息使用这些密钥通过 HMAC-SHA256([ RFC2104 ]使用[ RFC6234 ]中的算法)进行保护;并对其他消息进行标准 TCP 有效性检查(确保序列号在窗口内[ RFC5961 ])。在[ RFC7430 ]中确定了对 MPTCP v0 的残余威胁,以及影响协议的那些(即,对 ADD_ADDR 的修改)已包含在本文档中。安全性的进一步讨论可以在第 5 节中找到。

3. MPTCP 操作:概述

本节介绍 MPTCP 的操作。下面的小节讨论了协议操作的每个关键部分。

所有 MPTCP 操作都使用可选的 TCP 标头字段发出信号。IANA 为 MPTCP 分配了一个 TCP 选项编号(“Kind”)(参见第 7 节),然后各个消息将由“子类型”确定,其值也存储在 IANA 注册表中(并且是也在第 7 节中列出)。与所有 TCP 选项一样,长度字段以字节为单位指定,包括类型和长度 2 个字节。

在整个文档中,当通过符号名称引用 MPTCP 选项时,例如“MP_CAPABLE”,这是指具有单个 MPTCP 选项类型的 TCP 选项,并且具有第 7 节中定义的符号名称的子类型值。该子类型是一个 4 位字段——选项有效载荷的前 4 位,如图 3所示。MPTCP 消息在以下部分中定义。

1
2
3
4
5
6
7
8
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------- --------------+
| 种类 | 长度 |子类型| |
+---------------+---------------+-------+ |
| 亚型特定数据 |
| (可变长度) |
+-------------------------------------------------- --------------+

图 3MPTCP 选项格式

与子流启动相关的那些 MPTCP 选项用于设置了 SYN 标志的数据包。此外,还有一个 MPTCP 选项用于信令元数据,以确保可以重新组合分段数据以交付给应用程序。

然而,其余选项是不需要在特定数据包上的信号,例如用于发送附加地址的信号。虽然实现可能希望尽快发送 MPTCP 选项,但可能无法在单个数据包上组合所有需要的选项(MPTCP 和常规 TCP 的选项,例如 SACK(选择性确认) [ RFC2018 ] )。因此,实现可以选择发送包含附加信令信息的重复 ACK。这改变了重复 ACK 的语义;这些通常仅作为丢失段的信号发送[ RFC5681 ]在常规 TCP 中。因此,接收到包含 MPTCP 选项的重复 ACK 的 MPTCP 实现不得其视为拥塞信号。此外,MPTCP 实现不应该为了单独发送 MPTCP 选项而连续发送两个以上的重复 ACK,以确保没有中间盒将其误解为拥塞的标志。

此外,标准 TCP 有效性检查(例如确保序列号和确认号在窗口内)必须在处理任何 MPTCP 信号之前进行,如[ RFC5961 ]中所述,并且应该根据建议生成初始子流序列号在[ RFC6528 ]中。

3.1。连接启动

连接启动以单条路径上的 SYN、SYN/ACK、ACK 交换开始。每个数据包都包含 Multipath Capable (MP_CAPABLE) MPTCP 选项(图 4)。此选项声明其发送方能够执行多路径 TCP 并希望在此特定连接上这样做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------+- --------------+
| 种类 | 长度 |子类型|版本|A|B|C|D|E|F|G|H|
+---------------+---------------+-------+--------+- --------------+
| 选项发件人密钥(64 位)|
| (如果选项长度> 4)|
| |
+-------------------------------------------------- --------------+
| 选项接收方密钥(64 位)|
| (如果选项长度> 12)|
| |
+-------------------------------+------------------ --------------+
| 数据级长度(16 位)| 校验和(16 位,可选) |
+-------------------------------+------------------ --------------+

图 4支持多路径 (MP_CAPABLE) 选项

本规范 (v1) 中的 MP_CAPABLE 交换与 v0 中指定的不同。如果主机支持多个版本的 MPTCP,则 MP_CAPABLE 选项的发送者应该发送它支持的最高版本号。作为回报,在其 MP_CAPABLE 选项中,接收器将发出它希望使用的版本号的信号,该版本号必须 等于或低于初始 MP_CAPABLE 中指示的版本号。但是,对于与仅支持 v0.0 的旧监听器的版本协商,有一个警告。支持 v0 的侦听器期望 SYN 段中的 MP_CAPABLE 选项将包含启动器的密钥。但是,如果启动器已经升级到 v1,它将不会在 SYN 段中包含密钥。因此,侦听器将忽略此 SYN 段的 MP_CAPABLE 并以不包含 MP_CAPABLE 的 SYN/ACK 进行回复。发起者可以 选择立即回退到 TCP 或MAY选择尝试使用 MPTCP v0 的连接(如果发起者支持 v0),以便发现侦听器是否支持早期版本的 MPTCP。一般来说,MPTCP v0 连接可能比 TCP 连接更受欢迎。但是,在特定的部署场景中,可能知道侦听器不太可能支持 MPTCP v0,因此发起者可能更愿意不尝试 v0 连接。发起方可以为对等方缓存有关其支持的 MPTCP 版本的信息(如果有的话),并将此信息用于未来的连接尝试

MP_CAPABLE 选项具有可变长度,包括不同的字段,具体取决于使用该选项的数据包。完整的 MP_CAPABLE 选项如图 4所示。

MP_CAPABLE 选项在启动 MPTCP 连接的第一个子流的 SYN、SYN/ACK 和 ACK 数据包上携带,如果发起者希望先发送,则在第一个携带数据的数据包上携带。每个选项携带的数据如下,其中A=发起者,B=监听者。

  • SYN (A->B):仅前 4 个八位字节(长度 = 4)。
  • SYN/ACK (B->A):B 用于此连接的密钥(长度 = 12)。
  • ACK(无数据)(A->B):A 的密钥后跟 B 的密钥(长度 = 20)。
  • ACK(第一个数据)(A->B):A 的密钥,然后是 B 的密钥,然后是数据级长度,以及可选的校验和(长度 = 22 或 24)。

选项的内容由数据包的 SYN 和 ACK 标志以及选项的 Length 字段决定。在图 4中,“Sender”和“Receiver”是指 TCP 数据包的发送方或接收方(可以是主机)。

仅包含 MP_CAPABLE 标头的初始 SYN 用于定义所请求的 MPTCP 的版本,也用于交换标志以协商连接功能,如下所述。

此选项用于声明终端主机为此 MPTCP 连接生成的 64 位密钥。这些密钥用于验证将未来子流添加到此连接。这是唯一一次通过网络以明文方式发送密钥(除非使用“快速关闭”(第 3.5 节));所有未来的子流都将使用 32 位“令牌”识别连接。此令牌是此密钥的加密哈希。此过程的算法取决于所选的身份验证算法;选择方法在本节后面定义。

收到初始 SYN 段后,有状态服务器生成随机密钥并回复 SYN/ACK。密钥的生成方法是特定于实现的。密钥必须难以猜测,并且对于发送主机在其所有当前 MPTCP 连接中必须是唯一的。[ RFC4086 ]中给出了生成用于密钥的随机数的建议。连接将在每个主机上通过令牌(密钥的单向哈希)进行索引。因此,实现将需要从每个令牌映射到相应的连接,然后映射到连接的键。

存在两个不同的密钥将散列到同一个令牌的风险。哈希冲突的风险通常很小,除非主机正在处理数以万计的连接。因此,一个实现应该检查它的连接令牌列表,以确保在发送它的密钥之前没有冲突,如果有,那么它应该生成一个新的密钥。但是,对于具有数千个连接的服务器来说,这将是昂贵的。子流握手机制(第 3.2 节) 将确保新的子流只加入正确的连接,但是,通过加密握手,以及检查两个方向的连接令牌,并确保序列号在窗口内。因此,在最坏的情况下,如果发生令牌冲突,新的子流不会成功,但 MPTCP 连接将继续提供常规 TCP 服务。

由于密钥生成是特定于实现的,因此不需要它们只是随机数。实现可以自由地在带外交换加密材料并从该材料生成这些密钥,以便提供额外的机制来验证通信实体的身份。例如,实现可以选择将其 MPTCP 密钥链接到高层 TLS 或 SSH 连接中使用的密钥。

如果服务器以无状态方式运行,它必须以可验证的方式生成自己的密钥。这种生成密钥的可验证方式可以通过使用 4 元组、序列号和本地机密的哈希来完成(类似于对 TCP 序列号[ RFC4987 ]所做的)。因此,它将能够验证它是否确实是在随后的 MP_CAPABLE 选项中回显的密钥的发起者。对于有状态的服务器,应该检查令牌的唯一性;但是,如果不满足唯一性并且无法生成替代的可验证密钥,则连接必须通过不在 SYN/ACK 中发送 MP_CAPABLE 来回退到使用常规 TCP。

ACK 携带 A 的密钥和 B 的密钥。这是第一次在线上看到 A 的密钥,尽管预计 A 将在初始 SYN 之前在本地生成密钥。如上所述,B 的密钥的回显允许 B 无状态地操作。因此,A 的密钥必须可靠地传递给 B,为了做到这一点,必须使该数据包的传输可靠。

如果 B 有数据要先发送,则 ACK + MP_CAPABLE 的可靠传递是通过使用 MPTCP 数据序列信号 (DSS) 选项(第 3.3 节)接收此数据来确保的,该选项包含 MP_CAPABLE 的 DATA_ACK(这是第一个数据序列空间的八位字节)。但是,如果 A 希望先发送数据,它有两个选项来确保 ACK + MP_CAPABLE 的可靠传递。如果它立即有数据要发送,那么第一个 ACK(带有数据)也将包含一个 MP_CAPABLE 选项和附加数据参数(数据级长度和可选校验和,如图 4所示)。如果 A 没有立即发送数据,它必须在第一个 ACK 上包含 MP_CAPABLE,但不包含其他数据参数。当 A 确实有数据要发送时,它必须从第一个 ACK 重复发送 MP_CAPABLE 选项,并带有额外的数据参数。这个 MP_CAPABLE 选项用于代替 DSS 并简单地指定 (1) 有效载荷的数据级长度和 (2) 校验和(如果协商使用校验和)。这是建立 MPTCP 连接所需的最少数据——它允许验证有效负载,并且鉴于它是第一个数据,初始数据序列号 (IDSN) 也是已知的(因为它是从密钥生成的,如如下面所描述的)。在第一个数据包上传送密钥允许 TCP 可靠性机制确保数据包成功传递。接收器将在连接级别使用数据 ACK 确认此数据,就好像已收到 DSS 选项一样。

可能存在 A 和 B 都尝试同时传输初始数据的情况。例如,如果 A 最初没有要发送的数据,但在从 B 接收到任何内容之前需要发送数据,它将使用带有数据参数的 MP_CAPABLE 选项(因为它不知道是否收到了 ACK 上的 MP_CAPABLE) . 在这种情况下,B 也可能已经发送了带有 DSS 选项的数据,但尚未在 A 处接收到。因此,B 在发送带有 DSS 选项的数据之后,已经收到了带有 MP_CAPABLE 映射的数据。为了确保可以处理这些情况,MP_CAPABLE 中的数据参数在语义上等同于 DSS 选项中的数据参数,并且可以互换使用。当带有数据的 MP_CAPABLE 丢失并重新传输时,可能会发生类似的情况。此外,在 TCP 分段卸载的情况下,带有数据参数的 MP_CAPABLE 可能在多个数据包中重复,并且实现还必须能够处理重复的 MP_CAPABLE 映射以及重复的 DSS 映射。

此外,MP_CAPABLE 交换允许确定 SYN 数据包上 MPTCP 选项的安全通过。如果这些选项中的任何一个被丢弃,MPTCP 将优雅地回退到常规的单路径 TCP,如第 3.7 节中所述。如果在握手的任何时候任何一方认为 MPTCP 协商受到损害——例如,通过中间盒破坏 TCP 选项或出现意外的 ACK 号——主机必须停止使用 MPTCP,并且以后不再包含 MPTCP 选项TCP 数据包。然后,另一台主机也将使用回退机制回退到常规 TCP。请注意,不得建立新的子流程(使用第 3.2 节中记录的过程) 直到通过路径成功接收到 DSS 选项(如第 3.3 节所述)。

与所有 MPTCP 选项一样,MP_CAPABLE 选项以 Kind 和 Length 开头,以指定 TCP 选项的种类和长度。此信息后跟 MP_CAPABLE 选项。MP_CAPABLE 选项(图 4 )中第一个八位字节的前 4 位定义了 MPTCP 选项子类型(参见第 7 节;对于 MP_CAPABLE,此值为 0x0),此八位字节的其余 4 位指定正在使用的 MPTCP 版本(对于本规范,该值为 1)。

第二个八位字节为标志保留,分配如下:

  • A:

    最左边的位,标记为“A”,应该设置为 1 以表示“需要校验和”,除非系统管理员决定不需要校验和(例如,如果环境受到控制并且不存在可能调整有效负载的中间盒)。

  • 乙:

    第二个位,标记为“B”,是一个可扩展性标志。对于当前的实现,它 必须设置为 0。该标志将用于未来规范中的可扩展机制,该标志的影响将在以后定义。预计但不是强制性的,该标志将用作替代安全机制的一部分,该机制不需要协议的完整版本升级,但确实需要重新定义握手的某些元素。如果接收到“B”标志设置为 1 的消息并且这不被理解,那么这个 SYN 中的 MP_CAPABLE必须被静默忽略,这会触发回退到常规 TCP;发件人应使用与此旧规范兼容的格式重试。请注意,MP_CAPABLE 选项的长度以及位“D”到“H”的含义可以通过设置 B=1 来改变。

  • C:

    第三个位,标记为“C”,设置为 1,表示此选项的发送方将不接受到源地址和端口的额外 MPTCP 子流,因此接收方不得尝试打开任何额外的子流向该地址和港口。这在发送者知道存在限制的情况下提高了效率——例如,如果发送者位于严格的 NAT 后面或在旧的第 4 层负载均衡器后面运行。

  • D 到 H:

    其余位,标记为“D”到“H”,用于加密算法协商。在本规范中,只分配了最右边的位,标记为“H”。位“H”表示使用 HMAC-SHA256(定义见第 3.2 节)。仅支持此方法的实现必须将位“H”设置为 1,将位“D”到“G”设置为 0。

必须指定加密算法。如果标志位“D”到“H”全为 0,MP_CAPABLE 选项必须被视为无效并被忽略(也就是说,它必须被视为常规 TCP 握手)。

认证算法的选择也会影响用于生成令牌和 IDSN 的算法。在本规范中,仅指定和选择了 SHA-256 算法(位“H”),令牌必须是密钥的截断(最高有效 32 位)SHA-256 哈希[ RFC6234 ]。必须使用密钥的 SHA-256 散列的不同 64 位截断(最低有效 64 位)作为 IDSN。请注意,密钥必须按网络字节顺序进行散列。另请注意,根据[ RFC6234 ] ,“最低有效”位必须是 SHA-256 摘要的最右边位. 未来使用加密比特的规范可能会选择为令牌和 IDSN 生成指定不同的算法。

加密位和校验和位都以类似的方式协商能力。对于“需要校验和”位(标记为“A”),如果任一主机需要使用校验和,则必须使用校验和。换句话说,不使用校验和的唯一方法是在它们的 SYN 中的两个主机都设置 A=0。该决定通过在握手的第三个数据包(ACK)中设置“A”位来确认。例如,如果发起者在 SYN 中设置 A=0,但响应者在 SYN/ACK 中设置 A=1,则校验和必须双向使用,发起者会在ACK中设置A=1。关于是否使用校验和的决定将由实现存储在每个连接的二进制状态变量中。如果不想使用校验和的主机接收到 A=1,它必须通过忽略 MP_CAPABLE 选项来回退到常规 TCP,就好像它是无效的一样。

对于加密协商,响应者可以选择。发起者为它支持的每个算法创建一个提案,将其设置为 1(在此版本的规范中,只有一个提案,因此位“H”将始终设置为 1)。响应者只设置了 1 个位来响应——这是选择的算法。这种行为的基本原理是响应者通常是具有潜在数千个连接的服务器,因此它可能希望根据负载选择计算复杂度最小的算法。如果响应者不支持(或不想支持)发起者的任何提议,它必须在没有 MP_CAPABLE 选项的情况下响应,从而强制回退到常规 TCP。

MP_CAPABLE 选项仅用于连接的第一个子流,以识别连接;所有后续子流将使用 MP_JOIN 选项(参见第 3.2 节)加入现有连接。

如果 SYN 包含 MP_CAPABLE 选项但 SYN/ACK 不包含,则假定 SYN/ACK 的发送者不支持多路径;因此,MPTCP 会话必须作为常规的单路径 TCP 会话运行。如果 SYN 不包含 MP_CAPABLE 选项,则 SYN/ACK 不得响应中包含一个。如果第三个数据包(ACK)不包含 MP_CAPABLE 选项,则会话必须退回到作为常规单路径 TCP 会话运行。这样做是为了保持与路径上丢弃部分或全部 TCP 选项的中间盒的兼容性。请注意,实现可能选择尝试多次发送 MPTCP 选项,然后再决定作为常规 TCP 运行(参见 第 3.9 节)。

如果 SYN 数据包未被确认,则由本地策略决定如何响应。预计发送方最终将回退到单路径 TCP(即,没有 MP_CAPABLE 选项),以便绕过可能丢弃具有未知选项的数据包的中间盒;但是,首先进行的支持多路径的尝试次数将取决于本地策略。MPTCP 和非 MPTCP SYN 可能会在网络中重新排序。因此,最终状态是根据 TCP 握手的第三个数据包中是否存在 MP_CAPABLE 选项来推断的。如果此选项不存在,则连接应该回退到常规 TCP,如 第 3.7 节中所述.

MPTCP 连接上的 IDSN 由密钥生成。IDSN 生成算法也由协商的认证算法确定。在本规范中,仅指定和选择了 SHA-256 算法,主机的 IDSN必须是其密钥的 SHA-256 哈希的最低有效 64 位,即 IDSN-A = Hash(Key-A) 和IDSN-B = 哈希(密钥-B)。IDSN 的这种确定性生成允许接收器确保在连接开始时序列空间中没有间隙。带有 MP_CAPABLE 的 SYN 占用数据序列空间的第一个八位字节,尽管在发送第一个数据之前不需要在连接级别进行确认(参见第 3.3 节)。

3.2. 启动新的子流

通过 MP_CAPABLE 交换开始 MPTCP 连接后,可以将更多子流添加到连接中。主机知道自己的地址,并且可以通过 第 3.4 节中描述的信令交换了解其他主机的地址。使用该知识,主机可以在当前未使用的地址对上启动新的子流。允许连接中的任一主机发起新子流的创建,但预计这通常是原始连接发起者(试探法见第 3.9 节)。

一个新的子流作为正常的 TCP SYN/ACK 交换启动。加入连接 (MP_JOIN) MPTCP 选项用于标识新子流要加入的连接。它使用在初始 MP_CAPABLE 握手(第 3.1 节)中交换的密钥材料,并且该握手还协商用于 MP_JOIN 握手的加密算法。

本节使用 HMAC-SHA256 算法指定 MP_JOIN 的行为。MP_JOIN 选项出现在三次握手的 SYN、SYN/ACK 和 ACK 中,尽管在每种情况下都有不同的格式。

在 SYN 数据包的第一个 MP_JOIN 中, 如图 5 所示,发起方发送一个令牌、随机数和地址 ID。

1
2
3
4
5
6
7
8
9
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+-----+-+- --------------+
| 种类 | 长度 = 12 |子类型|(rsv)|B| 地址 ID |
+---------------+---------------+-------+-----+-+- --------------+
| 接收方令牌(32 位)|
+-------------------------------------------------- --------------+
| 发件人的随机数(32 位)|
+-------------------------------------------------- --------------+

图 5加入连接 (MP_JOIN) 选项(用于初始 SYN)

令牌用于识别 MPTCP 连接,是接收方密钥的加密哈希,在初始 MP_CAPABLE 握手(第 3.1 节)中交换。在本规范中,此选项中提供的令牌由 SHA-256 算法[ RFC6234 ]生成,截断为最高有效 32 位。MP_JOIN 选项中包含的令牌是数据包的接收者用来识别此连接的令牌;即,Host A 将发送 Token-B(由 Key-B 生成)。请注意,哈希生成算法可以通过选择加密握手算法来覆盖,如第 3.1 节中所定义。

MP_JOIN SYN 不仅发送令牌(对于连接而言是静态的),还发送随机数(随机数),用于防止对身份验证方法的重放攻击。为此目的生成随机数的建议在[ RFC4086 ]中给出。

MP_JOIN 选项包括一个“地址 ID”。这是选项发送者生成的标识符,用于标识此数据包的源地址,即使 IP 标头在传输过程中已被中间盒更改。此字段的数值由发送方生成,并且必须唯一映射到发送主机的源 IP 地址。地址 ID 允许地址删除(第 3.4.2 节),而无需知道接收方的源地址是什么,因此允许通过 NAT 删除地址。地址 ID 还允许在新的子流设置尝试和地址信令之间建立关联(第 3.4.1 节)),如果同时发送 MP_JOIN 和 ADD_ADDR,以防止在同一路径上设置重复的子流。

在连接中的第一个子流的初始 SYN 交换中使用的子流的地址 ID 是隐含的,其值为零。主机必须为自己和远程主机存储地址 ID 和地址之间的映射。当地址从本地或远程主机中删除时,实现还需要知道哪些本地和远程地址 ID 与哪些已建立的子流相关联。

设置了 SYN 标志的数据包上的 MP_JOIN 选项还包括 4 位标志,其中 3 位当前保留, 发送方必须将其设置为 0。最后一位,标记为“B”,表示此选项的发送者 (1) 是否希望在其他路径发生故障时将此子流用作备用路径 (B=1) 或 (2) 希望子流立即用作连接的一部分。通过设置 B=1,选项的发送者请求其他主机仅在没有 B=0 的可用子流的情况下在该子流上发送数据。第 3.3.8 节更详细地讨论了子流策略。

当接收到一个带有 MP_JOIN 选项的 SYN 时,该选项包含一个现有 MPTCP 连接的有效令牌,接收者 应该以一个 SYN/ACK 响应,该 SYN/ACK 还包含一个 MP_JOIN 选项,其中包含一个随机数和一个截断的(最左边的 64 位)HMAC。此版本的选项如图 6所示。如果令牌未知或主机想要拒绝子流建立(例如,由于它允许的子流数量的限制),接收器将发送回重置(RST)信号,类似于 TCP 中的未知端口,包含一个 MP_TCPRST 选项(第 3.6 节) 带有“MPTCP 特定错误”原因代码。虽然计算 HMAC 需要加密操作,但相信 MP_JOIN SYN 中的 32 位令牌可以充分保护免受盲态耗尽攻击;因此,不需要提供机制来允许响应者在 MP_JOIN 阶段进行无状态操作。

1
2
3
4
5
6
7
8
9
10
11
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+-----+-+- --------------+
| 种类 | 长度 = 16 |子类型|(rsv)|B| 地址 ID |
+---------------+---------------+-------+-----+-+- --------------+
| |
| 发件人的截断 HMAC(64 位)|
| |
+-------------------------------------------------- --------------+
| 发件人的随机数(32 位)|
+-------------------------------------------------- --------------+

图 6加入连接 (MP_JOIN) 选项(用于响应 SYN/ACK)

HMAC 由两台主机发送——在第三个数据包(ACK)中由发起方(主机 A)发送,在第二个数据包(SYN/ACK)中由响应方(主机 B)发送。在这个阶段进行 HMAC 交换允许两个主机首先交换用作“消息”的随机数据(在前两个 SYN 数据包中)。本规范定义使用[ RFC2104 ]中定义的 HMAC 以及 SHA-256 哈希算法[ RFC6234 ],并且输出被截断到最左边的 160 位(20 个八位字节)。由于选项空间的限制,包含在 SYN/ACK 中的 HMAC 被截断到最左边的 64 位,但这是可以接受的,因为使用了随机数;因此,攻击者只有一次机会正确猜出与对端先前发送的随机数匹配的 HMAC(如果 HMAC 不正确,则 TCP 连接关闭,因此需要与新的随机数进行新的 MP_JOIN 协商)。

发起方的认证信息在其第一个 ACK(握手的第三个包)中发送, 如图 7所示。该数据需要可靠地发送,因为这是唯一一次发送此 HMAC;因此,收到这个数据包必须触发一个常规的 TCP ACK 作为响应,如果没有收到这个 ACK,则必须重新传输数据包。换句话说,发送 ACK/MP_JOIN 数据包会将子流置于 PRE_ESTABLISHED 状态,并且仅在收到来自接收器的 ACK 时才移动到 ESTABLISHED 状态。在 PRE_ESTABLISHED 状态下不允许发送数据。此选项中的保留位必须由发送方设置为 0。

1
2
3
4
5
6
7
8
9
10
11
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------- --------------+
| 种类 | 长度 = 24 |子类型| (保留)|
+---------------+---------------+-------+--------- --------------+
| |
| |
| 发件人的截断 HMAC(160 位)|
| |
| |
+-------------------------------------------------- --------------+

图 7加入连接 (MP_JOIN) 选项(用于发起者的第一个 ACK)

HMAC 算法的密钥,在主机 A 传输的消息的情况下,将是 Key-A,然后是 Key-B;在主机 B 的情况下,Key-B 后跟 Key-A。这些是在原始 MP_CAPABLE 握手中交换的密钥。在每种情况下,HMAC 算法的“消息”是每个主机的随机数串联(用 R 表示):对于主机 A,RA 后跟 RB;对于主机 B,RB 后跟 RA。

这些不同的 MPTCP 选项组合在一起以启用经过身份验证的子流设置,如图 8 所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
         主机 A 主机 B
---------- ----------
地址 A1 地址 A2 地址 B1
---------- ---------- ----------
| | |
| | SYN + MP_CAPABLE |
|---------------------------------------------------------->|
|<----------------------------------------------|
| SYN/ACK + MP_CAPABLE(Key-B) |
| | |
| ACK + MP_CAPABLE(Key-A, Key-B) |
|---------------------------------------------------------->|
| | |
| | SYN + MP_JOIN(Token-B, RA) |
| |------------------------------------------->|
| |<-------------------------------|
| | SYN/ACK + MP_JOIN(HMAC-B, RB) |
| | |
| | ACK + MP_JOIN(HMAC-A) |
| |------------------------------------------->|
| |<-------------------------------|
| | 确认 |

HMAC-A = HMAC(Key=(Key-A + Key-B), Msg=(RA + RB))
HMAC-B = HMAC(Key=(Key-B + Key-A), Msg=(RB + RA))

图 8MPTCP 身份验证的示例使用

如果主机 B 收到的令牌未知或本地策略禁止接受新的子流,则接收者必须 以子流的 TCP RST 响应。如果合适,应该包括一个带有“管理禁止”原因代码(第 3.6 节)的 MP_TCPRST 选项。

如果主机 B 接受了令牌,但返回给主机 A 的 HMAC 与预期的不匹配,主机 A必须使用 TCP RST 关闭子流。在本节中描述的发送 RST 的这种情况和所有后续情况下,发送者应该在这个 RST 数据包上发送一个 MP_TCPRST 选项(第 3.6 节),并带有“MPTCP-specific error”的原因代码。

如果主机 B 没有收到预期的 HMAC 或 ACK 中缺少 MP_JOIN 选项,它必须使用 TCP RST 关闭子流。

如果 HMAC 被验证为正确,则两台主机已相互验证为与连接开始时存在的那些相同的对等体,并且它们已同意该子流将成为哪个连接的一部分。

如果主机 A 收到的 SYN/ACK 没有 MP_JOIN 选项,主机 A必须使用 TCP RST 关闭子流。

这涵盖了 MP_JOIN 丢失的所有情况。更详细地说,如果从 A 到 B 的路径上的 SYN 中剥离了 MP_JOIN,并且主机 B 在相关端口上没有侦听器,它将以正常方式以 RST 响应。如果响应带有 MP_JOIN 选项的 SYN,则接收到没有 MP_JOIN 选项的 SYN/ACK(因为它要么在返回路径上被剥离,要么在导致主机 B 响应的传出路径上被剥离,就好像它是一个新的常规 TCP session),则子流不可用,主机 A必须使用 RST 关闭它。

请注意,可以在任何一对端口之间创建额外的子流(但请参阅第 3.9 节的启发式方法);打开其他子流不需要显式的应用程序级接受调用或绑定调用。要将新子流与现有连接相关联,子流的 SYN 交换中提供的令牌用于解复用。然后,这会将 TCP 子流的 5 元组绑定到连接的本地令牌。一个结果是可以允许任何端口对用于连接。

必须使用令牌来解复用子流 SYN ;这与传统 TCP 不同,在传统 TCP 中,目标端口用于解复用 SYN 数据包。一旦设置了子流,就使用 5 元组完成数据包的解复用,就像在传统 TCP 中一样。5 元组将映射到本地连接标识符(令牌)。请注意,主机 A 将知道其子流的本地令牌,即使它不是通过网络发送的——仅发送响应者的令牌。

3.3. MPTCP 操作和数据传输

本节讨论 MPTCP 用于数据传输的操作。在高层次上,MPTCP 实现将从应用程序获取一个输入数据流并将其拆分为一个或多个子流,并具有足够的控制信息以允许将其重新组合并可靠地传递给接收应用程序。以下小节详细定义了此行为。

数据序列映射和数据 ACK 在 DSS 选项中发出信号(图 9)。根据设置的标志,可以在一个 DSS 中用信号发送其中一个或两个。数据序列映射定义了子流上的序列空间如何映射到连接级别,数据 ACK 确认连接级别的数据接收。这些功能在以下两个小节中进行了更详细的描述。

1
2
3
4
5
6
7
8
9
10
11
12
13
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------- -------------+
| 种类 | 长度 |子类型| (保留)|F|m|M|a|A|
+---------------+---------------+-------+--------- -------------+
| 数据 ACK(4 或 8 个八位字节,取决于标志)|
+-------------------------------------------------- -------------+
| 数据序列号(4 或 8 个八位字节,取决于标志)|
+-------------------------------------------------- -------------+
| 子流序列号(4 个八位字节)|
+-------------------------------+------------------ -------------+
| 数据级长度(2 个八位字节)| 校验和(2 个八位字节) |
+-------------------------------+------------------ -------------+

图 9数据序列信号 (DSS) 选项

设置标志时,定义此选项的内容,如下所示:

  • A = 存在数据 ACK
  • a = 数据 ACK 为 8 个八位字节(如果未设置,数据 ACK 为 4 个八位字节)
  • M = 存在数据序列号 (DSN)、子流序列号 (SSN)、数据级长度和校验和(如果协商)
  • m = 数据序列号为 8 个八位字节(如果未设置,DSN 为 4 个八位字节)

只有设置了相应的“A”或“M”标志,标志“a”和“m”才有意义;否则,它们将被忽略。此选项的最大长度(设置了所有标志)为 28 个八位字节。

“F”标志表示“数据FIN”。如果存在,这意味着此映射涵盖来自发送方的最终数据。这是单路径 TCP 中 FIN 标志的连接级别等效项。除非存在数据 FIN 交换、MP_FASTCLOSE(第 3.5 节)消息或特定于实现的连接级别发送超时,否则连接不会关闭。数据 FIN 的用途以及该标志、子流级 FIN 标志和数据序列映射之间的交互在第 3.3.3 节中描述。剩余的保留位必须由本规范的实现设置为 0。

请注意,仅当在 MP_CAPABLE 握手时协商了 MPTCP 校验和的使用时,校验和才会出现在此选项中(参见第 3.1 节)。可以从选项的长度推断校验和的存在。如果存在校验和但尚未在 MP_CAPABLE 握手中协商其使用,则接收方必须使用 RST 关闭子流,因为它的行为与协商的不同。如果在协商使用校验和时不存在校验和,则接收方必须使用 RST 关闭子流,因为它被认为是损坏的。在这两种情况下,这个 RST应该伴随一个 MP_TCPRST 选项(第 3.6 节) 带有“MPTCP 特定错误”的原因代码。

3.3.1。数据序列映射

数据流作为一个整体可以通过使用 DSS 选项的数据序列映射组件(图 9)进行重组,这些组件定义了从子流序列号到数据序列号的映射。接收方使用它来确保按顺序传送到应用层。同时,子流级序号(即TCP头中的常规序号)只与子流相关。预计(但不是强制)SACK [ RFC2018 ]将在子流级别使用以提高效率。

数据序列映射指定从子流序列空间到数据序列空间的映射。这表示为子流和数据级别的起始序列号,以及此映射对其有效的字节长度。选择这种针对一系列数据的显式映射,而不是每个数据包的信令,以帮助与 TCP/IP 分段或合并与生成数据流的堆栈分开进行的情况兼容(例如,通过使用网络接口卡上的 TCP 分段卸载,或通过性能增强代理 (PEP) 等中间盒[ RFC3135 ])。它还允许单个映射覆盖多个数据包;这在批量传输情况下可能很有用。

映射是固定的,因为子流序号在映射处理后绑定到数据序号。发送者在声明后不得更改此映射;然而,相同的数据序列号可以被不同的子流映射到用于重传的目的(参见 第 3.3.6 节)。这也将允许在多个子流上同时发送相同的数据,以实现弹性或效率目的,尤其是在有损链路的情况下。尽管此类操作的详细规范超出了本文档的范围,但实现 应该将在数据序列空间的子流中接收到的第一个数据视为应该传递给应用程序的数据,并且应该忽略该序列空间的任何后续数据。

数据序号指定为绝对值,而子流序号是相对的(子流开始处的 SYN 的相对子流序号为 0)。这样做是为了允许中间盒更改子流的初始序列号 (ISN),例如承担 ISN 随机化的防火墙。

如果已在 MP_CAPABLE 交换中协商了校验和的使用,则数据序列映射还包含此映射覆盖的数据的校验和。校验和用于检测负载是否已被非 MPTCP 感知的中间盒以任何方式调整。如果此校验和失败,它将触发子流失败,或回退到常规 TCP,如第 3.7 节所述,因为 MPTCP 不再可靠地知道接收端的子流序列空间来构建数据序列映射。如果未启用校验和,则如果中间盒更改段边界、更改内容或未交付数据序列映射覆盖的所有段,则可能会将损坏的数据交付给应用程序。因此 建议使用校验和,除非已知网络路径不包含此类设备。

使用的校验和算法是标准的 TCP 校验和[ RFC0793 ],在此映射所涵盖的数据上进行操作,并带有一个伪标头,如图 10所示。

1
2
3
4
5
6
7
8
9
10
11
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-------------------------------------------------- -------------+
| |
| 数据序列号(8 个八位字节) |
| |
+-------------------------------------------------- -------------+
| 子流序列号(4 个八位字节)|
+-------------------------------+------------------ -------------+
| 数据级长度(2 个八位字节)| 零(2 个八位字节) |
+-------------------------------+------------------ -------------+

图 10DSS 校验和的伪标头

请注意,伪标头中使用的数据序列号始终是 64 位值,与 DSS 选项本身使用的长度无关。选择了标准的 TCP 校验和算法,因为它无论如何都会为 TCP 子流计算,如果在添加伪标头之前先对数据进行计算,则只需要计算一次。此外,由于 TCP 校验和是相加的,DSN_MAP 的校验和可以通过简单地将每个组成 TCP 段的数据的校验和相加并添加 DSS 伪报头的校验和来构造。

请注意,校验和依赖于包含连续数据的 TCP 子流;因此,TCP 子流不得使用紧急指针来中断现有映射。然而,进一步注意,如果在子流上接收到紧急数据,它应该被映射到数据序列空间并传递给应用程序,类似于常规 TCP 中的紧急数据。

为了避免可能的死锁情况,子流级处理应与连接级处理分开进行。因此,即使从子流空间到数据级空间的映射不存在,数据 仍然应该在子流中被确认(如果它在窗口内)。但是,该数据不能在数据级别(第 3.3.2 节)得到确认,因为它的数据序列号是未知的。实施可能暂时保留这些未映射的数据,期望映射很快就会到达。这种未映射的数据不能算在连接级接收窗口内,因为这与数据序列号有关,因此如果接收器用完内存来保存这些数据,则必须将其丢弃。如果该子流级序列空间的映射未在数据接收窗口内到达,则该子流被视为已损坏,并用 RST 关闭,并且任何未映射的数据都被静默丢弃。

数据序列号始终是 64 位的数量,并且 必须在实现中保持这种状态。如果连接以较慢的速度进行,因此不需要针对包装的序列号进行保护,那么实现可以在数据序列映射和/或数据ACK中仅包含数据序列号的低32位作为优化,并且一个实现可以为每个数据包独立地做出这个选择。一个实现必须能够接收和处理 64 位和 32 位序列号值,但并不要求一个实现能够同时发送这两者。

一个实现必须发送完整的 64 位数据序列号,如果它以足够高的速率传输,32 位值可以包含在最大段生命周期 (MSL) [ RFC7323 ]内。这些值中使用的 DSN 的长度(可能不同)在 DSS 选项中用标志声明。实现必须接受 32 位 DSN 并通过在每次低 32 位回绕时递增序列号的高 32 位来隐式地将其提升为 64 位数量。必须进行健全性检查实施以确保在预期时间发生回绕(例如,序列号从非常高的数字跳到非常低的数字)并且不会由乱序数据包触发。

与标准 TCP 序列号一样,数据序列号不应从零开始,而是从随机值开始,以使盲会话劫持更加困难。该规范要求将每个主机的 IDSN 设置为主机密钥的 SHA-256 散列的最低有效 64 位,如第 3.1 节所述。这也是为了让接收者知道预期的 IDSN 是什么,从而确定是否丢失了任何初始连接级数据包;如果两个子流同时开始传输,这一点尤其重要。

数据序列映射提供的映射必须应用于承载选项的 TCP 段中的部分或全部子流序列空间。它不需要包含在每个 MPTCP 数据包中,只要该数据包中的子流序列空间被接收方已知的映射覆盖即可。在事先知道映射的情况下,这可用于减少开销。一种情况是主机之间存在单个子流,另一种情况是数据段被安排在大于数据包大小的块中。

通过将子流级数据映射到连接其余部分的连接级数据,可以使用“无限”映射回退到常规 TCP(参见 第 3.7 节)。这是通过将 DSS 选项的 Data-Level Length 字段设置为保留值 0 来实现的。在这种情况下,校验和也将设置为 0。

3.3.2. 数据确认

为了提供完整的端到端弹性,MPTCP 提供了连接级别的确认,作为整个连接的累积 ACK。这是通过 DSS 选项的“数据确认”字段完成的(图 9)。数据 ACK 类似于标准 TCP 累积 ACK 的行为——指示已成功接收到多少数据(没有漏洞)。这可以与子流级别的 ACK 进行比较,它以类似于 TCP SACK 的方式起作用,因为在连接级别的数据流中可能仍然存在漏洞。数据 ACK 指定它期望接收的下一个数据序列号。

与 DSN 一样,数据 ACK 可以作为完整的 64 位值或低 32 位发送。如果使用 64 位 DSN 接收数据,则必须使用 64 位数据 ACK 对其进行确认。如果接收到的 DSN 是 32 位,则实现可以选择是发送 32 位还是 64 位数据 ACK,并且在这种情况下,实现必须接受其中任何一个。

数据 ACK 证明数据和所有需要的 MPTCP 信令都已被远程端接收和接受。数据 ACK 信号的一个关键用途是它用于指示广告接收窗口的左边缘。如 第 3.3.4 节所述,接收窗口由所有子流共享,并且与数据 ACK 相关。正因为如此,一个实现绝不能如果 TCP 段不携带带有数据 ACK 字段的 DSS 选项,则在连接级别使用 TCP 段的 RCV.WND 字段。此外,将连接级别的确认与子流级别分开允许单独完成处理,并且接收者可以在子流级别的确认后自由删除段 - 例如,由于内存限制,当许多段无序到达时.

MPTCP 发送方不得发送缓冲区释放数据,直到在任何子流上收到数据 ACK 和在子流级别被发送数据的所有子流确认。前一个条件保证了连接的活跃性,后一个条件保证了需要重传数据时子流的活跃性和自洽性。但是请注意,如果某些数据需要通过子流多次重新传输,则存在阻塞发送窗口的风险。在这种情况下,MPTCP 发送者可以决定通过发送一个 RST,使用适当的 MP_TCPRST(第 3.6 节)错误代码来终止表现不佳的子流。

数据 ACK可能包含在所有段中;然而, 在更高级的实现中应该考虑优化,其中数据 ACK 仅在数据 ACK 值增加时才出现在段中,并且这种行为必须 被视为有效。此行为可确保释放发送缓冲区,同时减少单向数据传输时的开销。

3.3.3. 关闭连接

在常规 TCP 中,FIN 向接收方宣布发送方没有更多数据要发送。为了允许子流独立运行并保持 TCP 在线路上的外观,MPTCP 中的 FIN 仅影响发送它的子流。这允许节点在任何时候对哪些路径正在使用中行使相当大的自由。FIN 的语义与常规 TCP 保持一致;即,直到双方都确认了对方的 FIN,子流才完全关闭。

当应用程序在套接字上调用 close() 时,这表明它没有更多数据要发送;对于常规 TCP,这将导致连接出现 FIN。对于 MPTCP,需要一个等效的机制;这称为 DATA_FIN。

DATA_FIN 表示发送方没有更多数据要发送,因此它可用于验证是否已成功接收所有数据。与常规 TCP 连接上的 FIN 一样,DATA_FIN 是单向信号。

DATA_FIN 通过将 DSS 选项(图 9)中的“F”标志设置为 1 来发出信号。DATA_FIN 占用连接级序列空间的 1 个八位字节(最后一个八位字节)。请注意,DATA_FIN 包含在数据级别长度中,但不在子流级别:例如,DSN 值为 80 且数据级别长度为 11 的段,设置了 DATA_FIN,将映射来自子流的 10 个八位字节进入数据序列空间 80-89,DATA_FIN 将是 DSN 90;因此,这个段,包括 DATA_FIN,将通过 91 的 DATA_ACK 得到确认。

请注意,当 DATA_FIN 未附加到包含数据的 TCP 段时,DSS必须具有 0 的子流序列号,1 的数据级长度,以及与 DATA_FIN 本身对应的数据序列号。在这种情况下,校验和将仅覆盖伪标头。

DATA_FIN 与常规 TCP FIN 具有相同的语义和行为,但在连接级别。值得注意的是,只有在连接级别成功接收到所有数据后才进行 DATA_ACKed。因此,请注意,DATA_FIN 与子流 FIN 分离。只有在其他子流上没有未处理的数据时,才允许在一个子流上组合这些信号。否则,可能需要在不同的子流上重新传输数据。本质上,主机不得关闭所有正常工作的子流,除非这样做是安全的,即,直到所有未完成的数据都已被 DATA_ACKed 或直到设置了 DATA_FIN 标志的段是唯一未完成的段。

一旦 DATA_FIN 被确认,所有剩余的子流 必须用标准的 FIN 交换关闭。出于礼貌,两个主机都应该在所有子流上发送 FIN,以允许中间盒清理状态,即使单个子流失败。还鼓励在收到 DATA_FIN 后减少终端主机上子流的超时 (MSL)。特别是,任何仍有未完成数据排队的子流(已在其他子流上重新传输以确认 DATA_FIN) 可能会以带有 MP_TCPRST(第 3.6 节)错误代码的“太多未完成数据”的 RST 关闭.

一旦两个主机的 DATA_FIN 都已被 DATA_ACK 确认,则认为连接已关闭。

如上所述,单个子流上的标准 TCP FIN 只会关闭发送它的子流。如果所有子流都已通过 FIN 交换关闭,但没有收到并确认任何 DATA_FIN,则 MPTCP 连接仅在超时后才被视为关闭。这意味着实现将在子流级别和连接级别都具有 TIME_WAIT 状态(请参阅附录 D)。这允许在重新建立新的子流之前所有子流上的连接都丢失的“先断后合”场景。

3.3.4。接收器注意事项

常规 TCP 在每个数据包中通告一个接收窗口,告诉发送方接收方愿意在累积 ACK 之后接受多少数据。接收窗口用于实现流量控制,当接收者跟不上时,限制快速发送者。

MPTCP 还使用一个唯一的接收窗口,在子流之间共享。这个想法是允许任何子流发送数据,只要接收者愿意接受它。另一种选择——维护每个子流的接收窗口——最终可能会停止一些子流,而其他子流不会用完它们的窗口。

接收窗口与 DATA_ACK 相关。与 TCP 一样,接收方不得缩小接收窗口的右边缘(即 DATA_ACK + 接收窗口)接收者将使用数据序列号来判断一个数据包是否应该在连接级别被接受。

当决定在子流级别接受数据包时,常规 TCP 会根据允许的接收窗口检查数据包中的序列号。对于 MPTCP,这种检查只使用连接级窗口完成。应该在子流级别执行完整性检查以确保子流和映射的序列号满足以下测试:SSN - SUBFLOW_ACK <= DSN - DATA_ACK,其中 SSN 是接收数据包的子流序列号,SUBFLOW_ACK 是 RCV。子流的 NXT(下一个预期序列号)(具有 DSN 和 DATA_ACK 的等效连接级别定义)。

在常规 TCP 中,一旦一个段被视为在窗口内,它就会被放入按序接收队列或无序队列中。在多路径 TCP 中,同样的事情会发生,但在连接级别:如果段在连接级别和子流级别都在窗口内,则将其放置在连接级别的有序或无序队列中。对于每个子流,堆栈仍然必须记住成功接收了哪些段,以便它可以在子流级别适当地确认它们。通常,这将通过保持每个子流的乱序队列(仅包含消息头 - 不包含有效负载)并记住累积 ACK 的值来实现。

对于实现者来说,了解接收缓冲区的大小是合适的很重要。完全网络利用率的下限是任何一条路径的最大带宽延迟乘积。但是,当数据包在较慢的子流上丢失并需要重新传输时,这可能是不够的(参见第 3.3.6 节)。严格的上限将是任何路径的最大往返时间 (RTT) 乘以所有路径上可用的总带宽。这允许所有子流以全速继续,同时在最大 RTT 路径上快速重传数据包。即使在最大 RTT 路径上发生重传超时的情况下,这也可能不足以维持完整的性能。确定重传策略和接收缓冲区大小之间的关系留待未来研究。

3.3.5。发件人注意事项

发送者记得接收来自接收者的窗口广告。只有在接收到 DATA_ACK 时允许的最大序列号(即 DATA_ACK + 接收窗口)增加时,它才应该更新其本地接收窗口值。这对于允许使用具有不同 RTT 并因此具有不同反馈回路的路径非常重要。

MPTCP 在所有子流中使用单个接收窗口,如果保证接收窗口端到端不变,主机总是可以读取最近的接收窗口值。但是,某些类型的中间盒可能会改变 TCP 级别的接收窗口。通常,这些会缩小提供的窗口,尽管在短时间内窗口可能会更大(但是请注意,这不会持续很长时间,因为最终中间盒必须跟上向接收者)。因此,如果接收窗口大小在多个子流上不同,则在发送数据时 MPTCP应该将最近的窗口大小中的最大值作为计算中使用的窗口大小。该规则隐含在不减少窗口右边缘的要求中。

发送方还必须记住每个子流通告的接收窗口。子流 i 的允许窗口为 (ack_i, ack_i + rcv_wnd_i),其中 ack_i 是子流 i 的子流级累积 ACK。这确保了数据不会被发送到中间盒,除非有足够的数据缓冲。

将这两个规则放在一起,我们得到以下结果:允许发送方发送数据级序列号介于 (DATA_ACK, DATA_ACK + receive_window) 之间的数据段。只要子流序列号在这些子流的允许窗口中,这些段中的每一个都将映射到子流上。请注意,如果在所有子流中通告相同的接收窗口,则子流序列号通常不会影响流控制。他们将对那些具有较小广告接收窗口的子流执行流控制。

发送缓冲区必须至少与接收缓冲区一样大,以使发送者能够达到最大吞吐量。

3.3.6。可靠性和重传

数据序列映射允许发送者在不同的子流上重新发送具有相同数据序列号的数据。这样做时,主机必须仍然在原始子流上重新传输原始数据,以保持子流的完整性(中间盒可以重放旧数据和/或可以拒绝子流中的漏洞),并且接收器将忽略这些重新传输。虽然这显然不是最理想的,但出于兼容性原因,这是明智的行为。可以在该协议的未来版本中协商优化。还要注意,如果出于可靠性原因需要,此属性还允许发送方始终在多个子流上发送具有相同数据序列号的相同数据。

该协议规范不强制要求任何机制来处理重传,并且很大程度上取决于本地策略(如第 3.3.8 节所述)。可以想象激进的连接级别重传策略,其中在子流级别丢失的每个数据包都在不同的子流上重传(因此浪费带宽但可能减少应用程序到应用程序的延迟)或保守的重传策略,其中仅在之后使用连接级别重传发生一些子流级别的重传超时。

设想一个标准的连接级重传机制将围绕一个连接级数据队列实现:所有没有被 DATA_ACKed 的段都被存储。当连接级别的头部在子流级别被确认但在数据级别没有被 DATA_ACK 时,将设置一个计时器。此计时器将防止主动 ACK 数据的中间盒重传失败。

只要数据在 (1) 连接级别和 (2) 已发送数据的所有子流上均未得到确认,发送方必须将数据保存在其发送缓冲区中。这样,发送方总是可以在需要时在同一子流或不同子流上重新传输数据。一种特殊情况是子流失败时:发送方通常会在超时后重新发送其他工作子流上的数据,并且也会继续尝试重新传输失败子流上的数据。在达到预定义的重传上限(可能低于 MSL 的通常 TCP 限制)或收到 ICMP 错误后,发送方将声明子流失败,然后才删除未完成的数据段。

如果触发了指示子流执行不良的多次重传,这可能会导致主机使用 RST 重置子流。但是,需要进一步的研究来了解如何以及何时重置表现不佳的子流的启发式方法。例如,高度不对称的路径可能被误诊为表现不佳。为此目的的 RST应该伴随一个“不可接受的性能”MP_TCPRST 选项(第 3.6 节)。

3.3.7。拥塞控制注意事项

MPTCP 连接中的不同子流具有不同的拥塞窗口。为了实现瓶颈和资源池的公平性,有必要耦合每个子流上使用的拥塞窗口,以便将大部分流量推送到不拥塞的链路。[ RFC6356 ]中介绍了一种实现此目的的算法。该算法没有实现完美的资源池化,但它是“安全的”,因为它很容易部署在当前的 Internet 中。我们的意思是,与仅使用该路由的单路径流相比,它不会在任何一条路径上占用更多容量,因此这确保了在共享瓶颈处与单路径 TCP 公平共存。

可以预见,MPTCP 将实现不同的拥塞控制器,每个拥塞控制器旨在实现资源池/公平/稳定性设计空间中的不同属性,以及实现服务质量、可靠性和弹性方面的不同属性。

无论使用何种算法,MPTCP 的设计旨在为拥塞控制实现提供足够的信息以做出正确的决策;对于每个子流,此信息包括哪些数据包丢失以及何时丢失。

3.3.8. 子流策略

在本地 MPTCP 实现中,主机可以使用它希望决定如何共享要通过可用路径发送的流量的任何本地策略。

在目标是最大化吞吐量的典型用例中,所有可用路径将同时用于数据传输,使用[ RFC6356 ]中描述的耦合拥塞控制。但是,预计还会出现其他用例。

例如,一种可能性是“全有或全无”的方法,即准备好第二条路径以在第一条路径发生故障时使用,但替代方案可能包括在使用附加路径之前使一条路径完全饱和( “溢出”的情况)。这种选择很可能基于链路的货币成本,但也可能基于链路的延迟或抖动等属性,其中稳定性(延迟或带宽)比吞吐量更重要。[ RFC6897 ]中详细讨论了诸如此类的应用需求。

在发送方做出有效选择的能力需要完全了解路径“成本”,但这种情况不太可能发生。希望接收器能够用信号通知他们自己对路径的偏好,因为他们通常是多宿主方并且可能必须为计量输入带宽付费。

为了启用这种行为,MP_JOIN 选项(参见第 3.2 节)包含“B”位,它允许主机向其对等方指示该路径应该被视为备用路径,仅在其他工作失败的情况下使用子流(即,接收方已指示 B=1 的子流应用于发送数据,除非 B=0 没有可用的子流)。

在可用路径集改变的情况下,主机可能希望向对等方发送子流优先级变化的信号(例如,先前设置为备份的子流现在应该优先于所有剩余子流)。因此,图 11中所示的 MP_PRIO 选项可用于更改发送它的子流的“B”标志。

1
2
3
4
5
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+-----+-+
| 种类 | 长度 |子类型|(rsv)|B|
+---------------+---------------+-------+-----+-+

图 11更改子流优先级 (MP_PRIO) 选项

MP_PRIO 选项的另一个用途是在子流上设置“B”标志,以便在关闭它并使用 REMOVE_ADDR (第 3.4.2 节)删除它之前干净地“退出”它的使用——例如,支持 make-before-break会话连续性,在关闭之前使用的子流之前添加新的子流。

需要注意的是,备份标志只是数据接收方对数据发送方的请求,数据发送方应该遵守这些请求。然而,主机不能假设数据发送者会这样做,因为本地策略——或技术困难——可能会覆盖 MP_PRIO 请求。另请注意,此信号适用于单个方向,因此此选项的发送方可以选择继续使用子流发送数据,即使它已向其他主机发出 B=1 信号。

3.4. 地址知识交换(路径管理)

我们使用术语“路径管理”来指代有关主机之间附加路径的信息交换,在此设计中由主机上的多个地址管理。有关此设计背后的架构思想的更多详细信息,请参阅 MPTCP 架构文档[ RFC6182 ]。

这种设计利用了两种共享此类信息的方法,并且都可以在连接上使用。第一个是直接设置新的子流(在 第 3.2 节中描述),其中发起者有一个额外的地址。第二种方法(在下面的小节中描述)显式地向其他主机发送地址信号,以允许它启动新的子流。这两种机制是互补的:第一种是隐式且简单的,而第二种(显式)更复杂但更健壮。总之,这些机制允许地址在飞行中改变(因此支持通过 NAT 的操作,因为不需要知道源地址);它们还允许以前未知地址和属于其他地址族(例如,IPv4 和 IPv6)的地址的信令。

这是协议的典型操作示例:

  • MPTCP 连接最初在主机 A 的地址/端口 A1 和主机 B 的地址/端口 B1 之间建立。如果主机 A 是多宿主和多地址的,它可以通过发送一个从其地址 A2 到 B1 的附加子流来启动从 A2 到 B1 的带有 MP_JOIN 选项的 SYN,使用 B 之前为该连接声明的令牌。或者,如果 B 是多宿主的,它可以尝试使用 A 先前声明的令牌设置从 B2 到 A1 的新子流。在任何一种情况下,SYN 都将被发送到接收主机上已用于原始子流的端口。
  • 同时(或超时后),在现有子流上发送ADD_ADDR 选项(第 3.4.1 节),通知接收者发送者的替代地址。收件人可以使用此信息打开一个新的子流到发件人的附加地址。在我们的示例中,A 将发送 ADD_ADDR 选项通知 B 地址⁠/端口 A2。使用基于 SYN 的选项和 ADD_ADDR 选项(包括超时)的组合是特定于实现的,并且可以根据本地策略进行调整。
  • 如果子流 A2-B1 设置成功,主机 B 可以使用 MP_JOIN 选项中的地址 ID 将此源地址与也将到达现有子流的 ADD_ADDR 选项相关联;现在 B 知道不打开 A2-B1,忽略 ADD_ADDR。否则,如果 B 没有收到 A2-B1 MP_JOIN SYN 但收到了 ADD_ADDR,它可以尝试从它的一个或多个地址启动一个新的子流到地址 A2。如果一台主机位于 NAT 之后,这将允许打开新会话。

使用这两种信令机制的其他方式是可能的;例如,其他地址族中的信令地址只能使用添加地址 (ADD_ADDR) 选项显式完成。

3.4.1。地址广告

ADD_ADDR MPTCP 选项宣布可以访问主机的其他地址(以及可选的端口)(图 12)。此选项可在连接期间的任何时间使用,具体取决于发送方何时希望启用多条路径和/或路径何时可用。与所有 MPTCP 信号一样,接收方必须在对其采取行动之前进行标准 TCP 有效性检查,例如,根据[ RFC5961 ]。

1
2
3
4
5
6
7
8
9
10
11
12
13
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------+- --------------+
| 种类 | 长度 |子类型|(rsv)|E| 地址 ID |
+---------------+---------------+-------+--------+- --------------+
| 地址(IPv4:4 个八位字节/IPv6:16 个八位字节)|
+-------------------------------+------------------ --------------+
| 端口(2 个八位字节,可选)| |
+-------------------------------+ |
| 截断 HMAC(8 个八位字节,如果 E=0)|
| +-------------------------------+
| |
+-------------------------------+

图 12添加地址 (ADD_ADDR) 选项

每个地址都有一个地址 ID,可用于唯一标识连接中的地址以进行地址删除。地址 ID 还用于识别与同一地址相关的 MP_JOIN 选项(参见第 3.2 节),即使在使用地址转换器时也是如此。地址 ID必须唯一标识选项发送者的地址(在连接范围内);分配此类 ID 的机制是特定于实现的。

通过 MP_JOIN 或 ADD_ADDR 学习的所有地址 ID 应该由接收器存储在一个数据结构中,该数据结构收集连接的所有地址 ID 到地址映射(由令牌对标识)。这样,在地址 ID、观察到的源地址和令牌对之间存储了一个映射,用于将来处理连接的控制信息。请注意,实现 可以随意丢弃传入的地址通告——例如,为了避免更新映射状态或因为通告的地址对其没有用处(例如,只有 IPv4 时的 IPv6 地址)。因此,主机必须将地址通告视为软状态,并且它可以选择定期刷新广告。还要注意,实现可以选择缓存这些地址通告,即使它们当前不相关但将来可能相关,例如当 IPv6 连接可用但 IPv4 正在等待 DHCP 时的 IPv4 地址。

该选项如图 12所示。该插图的大小适用于 IPv4 地址。对于 IPv6,地址的长度将是 16 个八位字节(而不是 4 个)。

指定要使用的 TCP 端口号的 2 个八位字节是可选的,可以从选项的长度推断出它们的存在。尽管预计大多数用例将使用与用于初始子流的端口对相同的端口对(例如,端口 80 在所有子流上仍然是端口 80,客户端的临时端口也是如此),但可能存在一些情况(例如基于端口的负载平衡),其中需要明确指定不同的端口。如果未指定端口,MPTCP应该尝试连接到与发送 ADD_ADDR 信号的子流已在使用的端口相同的端口上的指定地址;这将在第 3.9 节中更详细地讨论。

此选项中的截断 HMAC 参数是 HMAC 的最右边 64 位,协商和计算方式与第 3.2 节中描述的 MP_JOIN 相同。对于这个 MPTCP 规范,由于只指定了一个哈希算法选项,这将是[ RFC2104 ]中定义的 HMAC ,使用 SHA-256 哈希算法[ RFC6234 ]. 与 MP_JOIN 相同,HMAC 算法的密钥,对于 Host A 发送的消息,将是 Key-A 后跟 Key-B,而对于 Host B,Key-B 后跟键-A。这些是在原始 MP_CAPABLE 握手中交换的密钥。HMAC 的消息是 ADD_ADDR 选项中 HMAC 之前的地址 ID、IP 地址和端口。如果端口不存在于 ADD_ADDR 选项中,HMAC 消息将仍然包含 2 个零值八位字节。HMAC 的基本原理是防止未经授权的实体注入 ADD_ADDR 信号以试图劫持连接。请注意,另外,除非中间人知道密钥,否则此 HMAC 的存在可防止地址在飞行中被更改。如果主机收到无法验证 HMAC 的 ADD_ADDR 选项,它应该默默地忽略该选项。

在子类型之后和地址 ID 之前存在一组四个标志。在本规范中只分配了最右边的位——标记为“E”。其他位当前未分配;它们必须 由发送者设置为 0,并且必须被接收者忽略。

存在“E”标志以提供此选项的可靠性。由于此选项通常会在纯 ACK 上发送,因此无法保证可靠性。因此,接收一个新的 ADD_ADDR 选项(其中 E=0)的接收者会将相同的选项发送回发送者,但不包括 HMAC 并且 E=1,以指示接收。根据本地策略,缺少这种类型的“回声”可以向初始 ADD_ADDR 发送者表明需要重传 ADD_ADDR。

由于 NAT 的扩散,一台主机很可能会尝试发布私有地址[ RFC1918 ]。禁止这种行为是不可取的,因为可能存在两个主机在同一个专用网络上具有附加接口的情况,并且主机 可以通告这些地址。用于创建新子流的 MP_JOIN 握手(第 3.2 节) 提供将安全风险降至最低的机制。MP_JOIN 消息包含一个 32 位令牌,用于唯一标识与接收主机的连接。如果令牌未知,主机将以 RST 响应。万一令牌在接收主机有效,子流设置将继续,但必须进行 HMAC 交换以进行身份验证。HMAC 交换将失败,并将提供足够的保护,防止两个未连接的主机根据私有地址的信号意外设置新的子流。第 5 节讨论了有关意外误导或恶意引导新 MP_JOIN 尝试的 ADD_ADDR 消息问题的进一步安全考虑。

接收到 ADD_ADDR 但发现与该 IP 地址和端口号建立的连接不成功的主机不应该为该连接对该地址/端口组合执行进一步的连接尝试。因此,想要在先前公布的地址⁠/端口组合上触发新的传入连接尝试的发送者可以通过再次发送选项来刷新 ADD_ADDR 信息。

因此,主机可以发送带有已分配地址 ID 的 ADD_ADDR 消息,但地址必须与先前分配给此地址 ID 的地址相同。新的 ADD_ADDR 可能具有相同的端口号或不同的端口号。如果端口号不同,接收主机应该尝试为这个新地址/端口组合设置一个新的子流。

希望替换现有地址 ID 的主机必须首先删除现有地址 ID(第 3.4.2 节)。

在正常的 MPTCP 操作期间,不太可能有足够的 TCP 选项空间用于 ADD_ADDR 以及用于数据序列编号的选项空间(第 3.3.1 节)。因此,预计 MPTCP 实现将在单独的 ACK 上发送 ADD_ADDR 选项。然而,如前所述,MPTCP 实现不得将具有任何MPTCP选项的重复 ACK(DSS 选项除外)视为拥塞指示[ RFC5681 ],并且 MPTCP 实现不应连续发送两个以上的重复 ACK用于信号目的。

3.4.2. 删除地址

如果在 MPTCP 连接的生命周期内,先前宣布的地址变得无效(例如,如果接口消失或不再首选 IPv6 地址),受影响的主机应该宣布这种情况,以便对等方可以删除与此相关的子流地址。即使一个地址没有被 MPTCP 连接使用,如果它之前已经被宣布过,一个实现应该宣布它被移除。主机 也可以选择宣布不再使用有效的 IP 地址——例如,为了使会话连续性之前先生成。

这是通过删除地址 (REMOVE_ADDR) 选项(图 13)实现的,该选项将从连接中删除先前添加的地址(或地址列表)并终止当前使用该地址的任何子流。

1
2
3
4
5
6
                     1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+-------+---------------+
| Kind |Length = 3 + n |Subtype|(resvd)| Address ID | ...
+---------------+---------------+-------+-------+---------------+
(followed by n-1 Address IDs, if required)

图 13删除地址 (REMOVE_ADDR) 选项

出于安全目的,如果主机接收到 REMOVE_ADDR 选项,它必须确保受影响的路径或多个路径不再使用,然后才能启动关闭。收到 REMOVE_ADDR 应该首先触发在路径上发送 TCP keepalive [ RFC1122 ],如果收到响应,则不应删除路径。如果发现路径还活着,接收主机 应该不再使用指定的地址来进行未来的连接,但是发送 REMOVE_ADDR 的主机负责关闭子流。在地址被删除之前,请求主机 也可以使用 MP_PRIO(第 3.3.8 节)请求不再使用路径。还必须对子流进行典型的 TCP 有效性测试(例如,确保序列号和 ACK 号正确)。实现可以使用这些测试失败的指示作为入侵检测或错误记录的一部分。

出于礼貌,此消息的发送和接收(如果没有收到 keepalive 响应)应该触发受影响子流上的两个主机发送 RST(如果可能),以允许在清理之前清理中间盒状态任何地方州。

根据地址 ID 进行地址删除,以便允许使用 NAT 和其他重写源地址的中间盒。如果地址 ID 未知,接收方将默默地忽略该请求。

仍在运行的子流必须像在常规 TCP 中那样使用 FIN 交换关闭,而不是使用此选项。有关详细信息,请参阅第 3.3.3 节

3.5. 快速关闭

常规 TCP 具有发送 RST 信号以突然关闭连接的方法。使用 MPTCP,常规 RST 仅具有子流的范围;它只会关闭适用的子流,不会影响剩余的子流。MPTCP 的连接将在数据级别保持活动状态,以便允许子流之间的先断后续切换。因此有必要提供 MPTCP 级别的“重置”以允许突然关闭整个 MPTCP 连接;这是通过 MP_FASTCLOSE 选项完成的。

MP_FASTCLOSE 用于向对端指示连接将被突然关闭,不再接受任何数据。触发 MP_FASTCLOSE 的原因是特定于实现的。当连接处于同步状态时,常规 TCP 不允许发送 RST [ RFC0793 ]。然而,如果操作系统资源不足,则实现允许在此状态下发送 RST。在这些情况下,MPTCP 应该发送 MP_FASTCLOSE。该选项如图 14 所示

1
2
3
4
5
6
7
8
9
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------- --------------+
| 种类 | 长度 |子类型| (保留)|
+---------------+---------------+-------+--------- --------------+
| 期权接收方密钥 |
| (64 位)|
| |
+-------------------------------------------------- --------------+

图 14快速关闭 (MP_FASTCLOSE) 选项

如果主机 A 想要强制关闭 MPTCP 连接,它可以通过两个选项来实现:

  • 选项 A (ACK):主机 A 在一个子流上发送一个包含 MP_FASTCLOSE 选项的 ACK,其中包含在初始连接握手中声明的主机 B 的密钥。在所有其他子流上,主机 A 发送一个常规 TCP RST 来关闭这些子流并将它们拆除。主机 A 现在进入 FASTCLOSE_WAIT 状态。
  • 选项 R (RST):主机 A 在所有子流上发送一个包含 MP_FASTCLOSE 选项的 RST,其中包含在初始连接握手中声明的主机 B 的密钥。主机 A 可以立即断开子流和连接。

如果主机 A 决定通过使用选项 A 并发送带有 MP_FASTCLOSE 选项的 ACK 来强制关闭,则连接应按如下方式进行:

  • 主机 B 收到带有 MP_FASTCLOSE 的 ACK 后,包含有效密钥,主机 B 在同一子流上使用 TCP RST 进行应答,并通过发送 TCP RST 信号来拆除所有子流。主机 B 现在可以关闭整个 MPTCP 连接(它直接转换到 CLOSED 状态)。
  • 一旦主机 A 收到剩余子流上的 TCP RST,它就可以关闭该子流并断开整个连接(从 FASTCLOSE_WAIT 状态转换为 CLOSED 状态)。如果主机 A 收到 MP_FASTCLOSE 而不是 TCP RST,则两台主机同时尝试快速关闭。主机 A 应回复 TCP RST 并断开连接。
  • 如果主机 A 在一次重传超时 (RTO)(已发送 MP_FASTCLOSE 的子流的 RTO)后没有收到 TCP RST 来回复其 MP_FASTCLOSE,它应该 重传 MP_FASTCLOSE。为了不让这个连接被长时间保留,重传的次数应该被限制;此限制是特定于实现的。推荐的数字是 3。如果没有收到 TCP RST 作为响应,主机 A应该在释放状态时发送带有 MP_FASTCLOSE 选项的 TCP RST,以便清除中间盒的任何剩余状态。

但是,如果主机 A 决定通过使用选项 R 并发送带有 MP_FASTCLOSE 选项的 RST 来强制关闭,主机 B 将执行以下操作:在收到包含有效密钥的带有 MP_FASTCLOSE 的 RST 时,主机 B 拆除所有子流通过发送 TCP RST。主机 B 现在可以关闭整个 MPTCP 连接(它直接转换到 CLOSED 状态)。

3.6. 子流重置

MPTCP 的实现可能还需要发送常规 TCP RST 以强制关闭子流。主机发送 TCP RST 以关闭子流或拒绝打开子流的尝试 (MP_JOIN)。为了让接收主机知道子流被关闭或拒绝的原因,TCP RST 数据包 可以包含 MP_TCPRST 选项(图 15)。主机可以使用此信息来决定,例如,它是否尝试立即、稍后或从不尝试重新建立子流。

1
2
3
4
5
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------- --------------+
| 种类 | 长度 |子类型|U|V|W|T| 原因 |
+---------------+---------------+-------+--------- --------------+

图 15TCP RST 原因 (MP_TCPRST) 选项

MP_TCPRST 选项包含一个原因代码,允许选项的发送者提供有关子流终止原因的更多信息。使用 12 位选项空间,前 4 位保留用于标志(当前仅定义一个),其余八位字节用于表示此子流终止的原因代码,接收方可以从中推断有关这条路径的可用性。

发送方使用“T”标志来指示报告的错误情况是瞬态(“T”位设置为 1)还是永久(“T”位设置为 0)。如果 RST 段的发送者认为错误条件是瞬态的,则该段的接收者可以尝试在失败的路径上为此连接重新建立子流。接收方可能尝试重新建立此子流的时间是特定于实现的,但考虑由提供的原因代码定义的故障属性。如果错误条件被认为是永久的,则 RST 段的接收者不应该尝试通过此路径重新建立此连接的子流。本规范未定义“U”、“V”和“W”标志,保留供将来使用。本规范的实现必须将这些标志设置为 0,并且接收者必须忽略它们。

“原因”是一个 8 位字段,表示终止子流的原因代码。本文档中定义了以下代码:

  • 未指定的错误(代码 0x00)。这是默认错误;这意味着子流不再可用。此选项的存在表明 RST 是由 MPTCP 感知设备生成的。
  • MPTCP 特定错误(代码 0x01)。在处理 MPTCP 选项时检测到错误。这是由于无效响应而发送 RST 以关闭子流的情况下通常返回的原因代码。
  • 资源不足(代码 0x02)。此代码表明发送主机没有足够的资源来支持终止的子流。
  • 行政禁止(代码 0x03)。此代码表示请求的子流被发送主机的策略禁止。
  • 未完成的数据过多(代码 0x04)。此代码表示在已通过一个或多个其他子流确认的情况下,需要通过终止的子流传输过多的数据。如果路径在短时间内不可用,则可能会发生这种情况,并且重置和重新启动比重新传输排队的数据更有效。
  • 不可接受的性能(代码 0x05)。此代码表明与此多路径 TCP 连接的其他子流相比,此子流的性能太低。
  • 中间盒干扰(代码 0x06)。已在此子流上检测到中间盒干扰,使 MPTCP 信令无效。例如,如果校验和未验证,则可以发送此信息。

3.7. 倒退

有时,中间盒会存在于可能阻止 MPTCP 运行的路径上。MPTCP 已被设计为应对许多中间盒修改(参见第 6 节),但仍有一些情况下,子流可能无法在 MPTCP 要求内运行。值得注意的是,这些情况如下:路径上的 MPTCP 选项丢失和有效负载数据的修改。如果发生此类事件,则必须“退回”到之前的安全操作。这可能是退回到常规 TCP 或删除有问题的子流。

在 MPTCP 连接(即第一个子流)开始时,确保路径完全支持 MPTCP 并且必要的 MPTCP 选项可以到达每个主机是很重要的。如果任一 SYN 消息没有 MPTCP 选项,第 3.1 节 中描述的握手应该回退到常规 TCP:在主机不支持 MPTCP 或路径不支持的情况下,这是相同的,也是期望的行为支持 MPTCP 选项。当尝试加入现有的 MPTCP 连接(第 3.2 节)时,如果路径不支持 MPTCP 并且 MPTCP 选项没有通过 SYN,则子流将根据 MP_JOIN 逻辑关闭。

然而,还有另一个需要解决的极端情况:MPTCP 选项在 SYN 上通过但在常规数据包上不通过的情况。如果子流是第一个子流,因此传输中的所有数据都是连续的,则可以使用以下规则解决这种情况:

  • 发送方必须在每个段中包含一个带有数据序列映射的 DSS 选项,直到其中一个已发送段已使用包含数据 ACK 的 DSS 选项得到确认。收到确认后,发送方确认 DSS 选项在两个方向上通过,并且可以选择发送少于每个段一次的 DSS 选项。
  • 但是,如果接收到数据的 ACK(不仅仅是 SYN),但没有包含数据 ACK 的 DSS 选项,则发送方确定该路径不支持 MPTCP。如果这种情况发生在另一个子流上(即,以 MP_JOIN 开头的子流),主机必须使用 RST 关闭子流,该 RST应该包含带有“中间盒干扰”原因代码的 MP_TCPRST 选项(第 3.6 节)。
  • 如果在第一个子流(即以 MP_CAPABLE 开头)上接收到这样的 ACK,在添加任何其他子流之前,实现必须退出 MPTCP 模式并回退到常规 TCP。发送方将发送一个最终的数据序列映射,数据级别长度值为 0 表示无限映射(以通知另一端,以防路径仅在一个方向丢弃选项),然后恢复为单向发送数据没有任何 MPTCP 选项的子流。
  • 如果子流在操作期间中断,例如,如果它被重新路由并且不再允许 MPTCP 选项,那么一旦检测到这种情况(由于子流级别的接收缓冲区已填满,因为没有可用的映射来 DATA_ACK 此数据) ,应将子流 视为中断并使用 RST 关闭,因为无法将数据传递到应用层,也无法可靠地发送回退信号。这个 RST应该 包括 MP_TCPRST 选项(第 3.6 节)和“中间盒干扰”原因代码。

这些规则应涵盖所有可能发生此类故障的情况——无论是在正向还是反向路径上,以及服务器或客户端是否首先发送数据。

到目前为止,本节已经讨论了 MPTCP 选项的丢失,无论是最初还是在连接过程中。如第 3.3 节所述,如果已协商校验和,则存在映射的数据的每个部分都受校验和的保护。此机制用于检测中间盒是否对有效负载进行了任何调整(添加、删除或更改数据)。如果数据以任何方式更改,校验和将失败。使用校验和还会检测子流上的数据长度是增加还是减少,这意味着数据序列映射不再有效。发送方不再知道接收方真正操作的子流级别的序列号(中间盒将伪造 ACK 作为回报),并且它无法发出任何进一步的映射信号。此外,除了在应用层有效的有效载荷修改的可能性之外,有可能跨 MPTCP 段边界触发此类修改,从而破坏数据。因此,从未通过校验和的段开始的所有数据都是不可信的。

请注意,如果尚未协商校验和的使用,则无法使用此回退机制,除非有一些更高层或更低层的信号通知 MPTCP 实现有效载荷已被篡改。

当使用多个子流时,一个子流上的传输数据可能会涉及不是连接级流的连续部分的数据,因为段将分布在多个子流中。由于上述问题,无法确定对数据进行了哪些调整(特别是对子流序列编号的任何更改)。因此,无法恢复子流,并且必须立即使用包含 MP_FAIL 选项的 RST 关闭受影响的子流(图 16),它定义了校验和失败的段(由数据序列映射定义)开始处的数据序列号。请注意,MP_FAIL 选项要求使用完整的 64 位序列号,即使在路径上的 DSS 信号中通常使用 32 位序列号也是如此。

1
2
3
4
5
6
7
8
9
                     1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------+--------- -------------+
| 种类 | 长度=12 |子类型| (保留)|
+---------------+---------------+-------+--------- -------------+
| |
| 数据序列号(8 个八位字节) |
| |
+-------------------------------------------------- -------------+

图 16后备 (MP_FAIL) 选项

此选项的接收者必须丢弃指定数据序列号之后的所有数据。失败的数据绝不能被 DATA_ACKed,因此将在其他子流上重新传输(第 3.3.6 节)。

一种特殊情况是当有一个子流并且它失败并出现校验和错误时。如果已知传输中的所有未确认数据都是连续的(通常是单个子流的情况),则可以将无限映射应用于子流而无需先关闭它,基本上关闭所有进一步的 MPTCP 信令。在这种情况下,如果接收方在只有一个路径时识别出校验和失败,它将在子流级 ACK 上发回 MP_FAIL 选项,指的是校验和所在段的开头的数据级序列号检测到错误。发送者将收到此信息,并且如果所有未确认的传输中的数据都是连续的,则会发出无限映射的信号。这种无限映射将是一个 DSS 选项(第 3.3 节) 在第一个新数据包上,包含追溯作用的数据序列映射,指的是已知完整传送(即,已成功 DATA_ACKed)的最近段的子流序列号的开始。从那时起,中间盒可以在不影响 MPTCP 的情况下更改数据,因为数据流相当于常规的传统 TCP 会话。虽然理论上路径可能只在一个方向上被损坏——并且 MP_FAIL 信号只影响一个方向的流量——为了实现简单,MP_FAIL 的接收器也必须以相反方向响应 MP_FAIL 并完全恢复为常规 TCP 会话。

在数据不连续的极少数情况下(当只有一个子流但它正在从最近不干净关闭的子流中重新传输数据时可能发生这种情况),接收者必须使用带有 MP_FAIL 的 RST 关闭子流。接收者必须丢弃所有遵循指定数据序列号的数据。发送方可以尝试创建属于同一连接的新子流,如果它选择这样做,应该立即通过设置无限数据序列映射将单个子流置于单路径模式。此映射将从 MP_FAIL 中声明的数据级序列号开始。

在发送者发出无限映射信号后,它必须只使用子流 ACK 来清除其发送缓冲区。这是因为当中间盒插入或删除数据时,数据 ACK 可能与子流 ACK 不一致。接收方在接收到无限映射后应该停止生成数据 ACK。

当一个连接因无限映射而回退时,只有一个子流可以发送数据;否则,接收者将不知道如何重新排序数据。实际上,这意味着除了一个之外,所有 MPTCP 子流都必须终止。一旦 MPTCP 回退到常规 TCP,它绝不能在稍后的连接中恢复到 MPTCP。

应该强调的是,MPTCP 并没有试图阻止使用想要调整有效负载的中间盒。一个支持 MPTCP 的中间盒可以通过重写校验和来提供这样的功能。

3.8. 错误处理

除了上述回退机制之外,标准的 TCP 错误类别可能需要以 MPTCP 特定的方式进行处理。请注意,第 4 节介绍了不断变化的语义(例如 RST 的相关性)。在可能的情况下,我们不想偏离常规的 TCP 行为。

以下列表涵盖了可能的错误和适当的 MPTCP 行为:

  • MP_JOIN 中的未知令牌(或 MP_JOIN ACK 中的 HMAC 失败,或 SYN/ACK 响应中缺少 MP_JOIN):发送 RST(类似于 TCP 在未知端口上的行为)
  • DSN out of window(正常运行时):丢弃数据;不要发送数据 ACK
  • 删除未知地址 ID 的请求:静默忽略

3.9. 启发式

性能或部署需要许多启发式方法,但协议正确性不需要这些启发式方法。在本节中,我们将详细介绍此类启发式方法。请注意, 3.3.43.3.5节介绍了缓冲和某些发送方和接收方窗口行为的讨论,3.3.6 节讨论了重传。

3.9.1。端口使用

在典型操作下,MPTCP 实现应该使用与已经在使用的端口相同的端口。换句话说,包含 MP_JOIN 选项的 SYN 的目标端口应该 与连接中第一个子流的远程端口相同。此类 SYN 的本地端口也应该与第一个子流的端口相同(因此,实现应该保留所有本地 IP 地址的临时端口),尽管在某些情况下这是不可行的。此策略旨在最大限度地提高接收方防火墙或 NAT 允许 SYN 的可能性,并避免混淆任何网络监控软件。

然而,也可能存在主机希望使用特定端口的信号。此功能在 第 3.4.1 节中记录的 ADD_ADDR 选项中提供。因此,在相同的两个地址之间允许多个子流使用不同的端口对是可行的,并且这种设施可用于允许基于 5 元组的网络内的负载平衡(例如,一些 ECMP 实现[ RFC2992 ])。

3.9.2. 延迟子流启动和子流对称

许多 TCP 连接是短暂的,并且仅由几个段组成,因此使用 MPTCP 的开销超过了任何好处。因此,需要启发式方法来决定何时开始在 MPTCP 连接中使用其他子流。实验部署表明,MPTCP 可以应用于多种场景,因此实施可能需要考虑发送的流量类型和会话持续时间等因素;此信息 可能由应用层发出信号。

然而,对于标准 TCP 流量,一个实现可以选择采用的建议通用启发式如下。

如果主机为其对等方缓冲了数据(这意味着应用程序已收到数据请求),则主机为每个初始窗口的缓冲数据打开一个子流。

还应考虑限制添加新子流的速率,以及限制为特定连接打开的子流总数。主机可以根据其负载或对流量和路径特征的了解来选择改变这些值。

请注意,仅此启发式可能是不够的。许多常见应用程序的流量(例如下载)是高度不对称的,多宿主主机很可能是永远不会填充其缓冲区的客户端,因此根据此启发式永远不会使用 MPTCP。允许应用程序发出其流量需求信号的高级 API 将有助于这些决策。

可以应用额外的基于时间的启发式方法,在给定时间段过去后打开额外的子流。这将缓解上述问题,并为低带宽但寿命长的应用程序提供弹性。

另一个问题是两个通信主机可能同时尝试在同一对地址之间建立子流。这导致资源的低效使用。

如果如上所述在所有子流上使用相同的端口,则标准 TCP 同时打开逻辑应该处理这种情况,并且在地址对之间将只建立一个子流。但是,这依赖于在两个终端主机上使用的相同端口。如果主机不支持 TCP 同时打开,建议在打开新子流之前的等待时间中应用一些随机元素,以便在给定地址对之间仅创建一个子流。但是,如果主机发出要使用的其他端口的信号(例如,为了利用 ECMP on-path),则此启发式方法不合适。

本节展示了实施者在开发 MPTCP 启发式算法时应考虑的一些因素,但它并非是规定性的。

3.9.3. 故障处理

MPTCP 处理意外信号的要求在第 3.8 节中给出。但是,还有其他失败情况,主机可以选择适当的行为。

例如,第 3.1 节建议主机应该 在一次或多次连接的 MPTCP SYN 失败后回退到尝试常规 TCP SYN。主机可以保留此类信息的系统范围缓存,以便它可以退出使用 MPTCP,首先是针对该特定目标主机,最后是在整个接口上,如果 MPTCP 连接继续失败。这种缓存的持续时间将是特定于实现的。

当 MP_JOIN 握手失败时,可能会发生另一个失败。 第 3.8 节指定不正确的握手必须 导致子流以 RST 关闭。如果看到多次失败的 MP_JOIN 尝试,运行主动入侵检测系统的主机可能会选择开始阻止来自源主机的 MP_JOIN 数据包。从连接发起者的角度来看,如果 MP_JOIN 失败,它 不应该 在连接的生命周期内尝试连接到相同的 IP 地址和端口,除非其他主机使用另一个 ADD_ADDR 选项刷新信息。请注意,ADD_ADDR 选项仅供参考,并不保证其他主机会尝试连接。

此外,实现可以通过多个连接获知某些接口或目标地址始终失败,并且可能默认不尝试将 MPTCP 用于此类接口或地址。还可以学习性能特别差的子流或在使用期间经常失败的子流的行为,以便实现可以临时选择不使用这些路径。

4.语义问题

为了支持多路径操作,一些 TCP 组件的语义发生了变化。为了帮助澄清,本节列出了这些语义变化作为参考。

  • 序列号:

    (in-header) TCP 序列号特定于子流。为了允许接收器重新排序应用程序数据,使用了额外的数据级序列空间。在这个数据级序列空间中,初始 SYN 和最终 DATA_FIN 占用 1 个八位字节的序列空间。这样做是为了确保这些信号在连接级别得到确认。数据序列空间到子流序列空间的显式映射,通过数据包中的 TCP 选项发出信号。

  • 确认:

    TCP 标头中的 ACK 字段仅确认子流序列号——而不是数据级序列空间。实现不应该 尝试从子流 ACK 中推断出数据级别的确认。这将终端主机上的子流级和连接级处理分开。

  • 重复确认:

    包含任何 MPTCP 信令(DSS 选项除外)的重复 ACK 不得视为拥塞信号。为了限制非 MPTCP 感知实体错误地将重复 ACK 解释为拥塞信号的机会,MPTCP 不应连续发送超过两个包含(非 DSS)MPTCP 信号的重复 ACK。

  • 接收窗口:

    TCP 标头中的接收窗口指示接收方可用的整个数据级连接的可用缓冲区空间量(与此子流的空间量相反)。语义与常规 TCP 相同,但为了维护这些语义,接收窗口必须在发送方解释为相对于 DATA_ACK 中给出的序列号,而不是 TCP 标头中的子流 ACK。这样就保留了流量控制的原有作用。请注意,某些中间盒可能会更改接收窗口,因此主机应该使用最近在组成子流上看到的最大值作为连接级接收窗口,并且还需要为子流级处理维护一个子流级窗口。

  • 鳍:

    TCP 标头中的 FIN 标志仅适用于发送它的子流,而不适用于整个连接。对于连接级 FIN 语义,使用 DATA_FIN 选项。

  • 第一:

    TCP 标头中的 RST 标志仅适用于发送它的子流,而不适用于整个连接。MP_FASTCLOSE 选项在 MPTCP 连接级别提供 RST 的快速关闭功能。

  • 地址列表:

    地址列表管理(即本地和远程主机的可用 IP 地址列表的知识)是在每个连接的基础上处理的(而不是每个子流、每个主机或每对通信主机)。这允许应用每个连接的本地策略。将地址添加到一个连接(通过 ADD_ADDR 消息显式或通过 MP_JOIN 隐式)对同一对主机之间的其他连接没有影响。

  • 5元组:

    在非多路径感知应用程序中,内核 API 向应用程序层提供的 5 元组(协议、本地地址、本地端口、远程地址、远程端口)是第一个子流的,即使该子流已经关闭并从连接中删除。这个决定和其他相关的 API 问题在 [ RFC6897 ]中有更详细的讨论。

5.安全考虑

正如[ RFC6181 ]中所确定的,向 TCP 添加多路径功能将带来许多新的威胁类别。为了防止这些威胁,[ RFC6182 ]提出了一组 MPTCP 安全解决方案的要求。基本目标是让 MPTCP 的安全性“不比现在的常规 TCP 差”。关键安全要求如下:

  • 提供一种机制来确认子流握手中的各方与原始连接设置中的各方相同。
  • 在将其用作连接的一部分之前,验证对等方是否可以在新地址接收流量。
  • 提供重放保护,即确保添加/删除子流的请求是“新鲜的”。

为了实现这些目标,MPTCP 包括一个基于散列的握手算法,如3.13.2节所述。

MPTCP 连接的安全性取决于密钥的使用,这些密钥在第一个子流开始时共享一次并且永远不会通过网络再次发送(除非在快速关闭机制中使用(第 3.5 节)))。为了在不泄露任何加密材料的情况下简化解复用,未来的子流使用此密钥的截断加密散列作为连接标识“令牌”。这些密钥被连接起来并用作创建子流设置中使用的基于哈希的消息认证代码 (HMAC) 的密钥,以验证握手中的各方与原始连接设置中的各方相同。它还提供对等方可以在此新地址接收流量的验证。当只使用密钥时,重放攻击仍然是可能的;因此,握手在两端使用一次性随机数(随机数)——这确保了 HMAC 在两次握手中永远不会相同。[ RFC4086 ]并在第 3.1 节中讨论。随机数在 TCP 连接尝试的生命周期内有效。由于[ RFC7430 ]中确定的威胁,HMAC 还用于保护 ADD_ADDR 选项。

在初始连接握手中使用加密能力位来协商特定算法的使用允许在未来部署额外的加密机制。然而,这种协商容易受到路径上主动攻击者的降价攻击,该攻击者可以修改来自接收器的响应中的加密能力位以使用不太安全的加密机制。因此,本文档中介绍的安全机制应防止[ RFC6181 ]中讨论的所有形式的洪泛和劫持攻击。

第 3.1 节中指定的版本协商,如果不同的 MPTCP 版本共享一个共同的协商格式,将允许路径上的攻击者应用理论上的降价攻击。由于 v1 和 v0 协议具有不同的握手,因此这种攻击需要客户端使用 v0 重新建立连接并且服务器支持 v0。请注意,路径上的攻击者可以访问原始数据,从而否定任何其他 TCP 级别的安全机制。如附录 E中所述,本文档指定删除 MP_PRIO 选项中的 AddrID 字段[ RFC6824 ](第 3.3.8 节))。此更改消除了理论攻击的可能性,其中子流可能被攻击者置于“备份”模式。

在正常操作期间,常规 TCP 保护机制(例如确保序列号在窗口内)将提供与当前常规 TCP 的保护级别相同的保护级别,以防止对单个 TCP 子流的攻击。与常规 TCP 相比,实现将引入额外的缓冲区,以在连接级别重新组装数据。窗口大小的应用将减少拒绝服务攻击消耗资源的风险。

第 3.4.1 节所述,主机可能会公布其私有地址,但这些地址可能指向接收方网络中的不同主机。MP_JOIN 握手(第 3.2 节)将确保这不会成功地为不正确的主机设置子流。但是,它仍然可能创建不需要的 TCP 握手流量。MPTCP 的这一特性可能成为拒绝服务攻击的目标,MPTCP 连接中的恶意参与者会鼓励接收者以网络中的其他主机为目标。因此,实现应该在发送方和接收方都考虑启发式(第 3.9 节)以减少这种影响。

为了进一步防止偏离路径攻击者发送的恶意 ADD_ADDR 消息,ADD_ADDR 包含一个使用握手期间协商的密钥的 HMAC。这有效地防止了攻击者通过将路径外的 ADD_ADDR 注入转移到流中来转移 MPTCP 连接。

理论上,密钥重用可能存在小的安全风险,但为了完成重放攻击,MP_JOIN 握手(第 3.2 节)中的发送方和接收方密钥以及发送方和接收方随机数都必须匹配。

虽然本规范定义了一个“中等”安全解决方案,满足本节开头和威胁分析文档[ RFC6181 ]中指定的标准,但由于攻击只会变得更糟,因此未来版本的 MPTCP 可能需要能够支持更强的安全性。有几种方法可以潜在地提高 MPTCP 的安全性;其中一些将与本文档中定义的 MPTCP 兼容,而其他可能不兼容。目前,最好的方法是获取当前方法的经验,确定可行的方法,并检查威胁分析是否仍然准确。

提高 MPTCP 安全性的可能方法包括:

  • 定义一个新的 MPTCP 加密算法,在 MP_CAPABLE 中协商。如果一个实现被部署在一个可以做出额外假设的受控环境中,例如服务器在 TCP 握手期间存储状态的能力,那么就有可能使用比其他方式更强大的加密算法。
  • 定义如何使用 MPTCP 保护数据传输,同时不更改协议的信令部分。
  • 定义需要更多选项空间的安全性,可能与扩展 TCP 选项空间的“长选项”提案(例如[ TCPLO ]中调查的那些)相结合,或者可能在当前方法的基础上构建基于第二阶段的安全性MPTCP 选项。
  • 重新审视工作组对 MPTCP 信令仅使用 TCP 选项的决定,并转而研究使用 TCP 有效负载的可能性。

MPTCP 设计有多种方法可用于指示新的安全机制,包括:

  • MP_CAPABLE 中的可用标志(图 4)。
  • MPTCP 选项中的可用子类型(图 3)。
  • MP_CAPABLE 中的 Version 字段(图 4)。

6.与中间盒的交互

多路径 TCP 被设计为可在当今世界部署。它的设计考虑了“合理”的现有中间盒行为。在本节中,我们概述了一些具有代表性的与中间盒相关的故障场景,并展示了多路径 TCP 如何处理它们。接下来,我们列出了 Multipath TCP 为适应不同的中间盒而做出的设计决策。

一个主要问题是我们使用了一个新的 TCP 选项。中间盒应该转发未知选项不变的数据包,但有些不是。我们希望这些中间盒剥离选项并传递数据,丢弃带有新选项的数据包,将相同的选项复制到多个段中(例如,在进行分段时),或者在段合并期间丢弃选项。

MPTCP 使用一个名为“Kind”的新 TCP 选项,所有消息类型都由“子类型”值定义(参见第 7 节)。这应该会减少仅通过某些类型的 MPTCP 选项的机会;相反,关键的不同特征是不同的路径和 SYN 标志的存在。

连接的第一个子流上的 MPTCP SYN 数据包包含 MP_CAPABLE 选项(第 3.1 节)。如果这被丢弃,MPTCP应该回退到常规 TCP。如果带有 MP_JOIN 选项(第 3.2 节)的数据包被丢弃,则根本不会使用路径。

如果中间盒去掉了选项,但不改变地传递数据包,MPTCP 将安全运行。如果在传出路径或返回路径上删除了 MP_CAPABLE 选项,则发起主机可以回退到常规 TCP,如图 17 所示并在第 3.1 节中讨论。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  主机 A 主机 B
| 中间箱 M |
| | |
| SYN (MP_CAPABLE) | 同步 |
|--------------------------------|---------------->|
| 同步/确认 |
|<------------------------------------------------|
a) MP_CAPABLE 选项在传出路径上被剥离

主机 A 主机 B
| SYN (MP_CAPABLE) |
|-------------------------------------->|
| 中间箱 M |
| | |
| SYN/ACK |SYN/ACK (MP_CAPABLE)|
|<-----------------|--------------------|
b) 在返回路径上剥离 MP_CAPABLE 选项

图 17使用从数据包中剥离选项的中间盒的连接设置

子流 SYN 包含 MP_JOIN 选项。如果在传出路径上去掉此选项,则 SYN 将显示为主机 B 的常规 SYN。根据目标端口上是否存在侦听套接字,主机 B 将回复 SYN/ACK 或 RST (子流连接失败)。当主机 A 收到 SYN/ACK 时,它会发送一个 RST,因为 SYN/ACK 不包含 MP_JOIN 选项及其令牌。无论哪种方式,子流设置都会失败,但不会影响整个 MPTCP 连接。

我们现在检查 MPTCP 的数据流,假设流设置正确,这意味着 SYN 数据包中的选项被相关的中间盒允许通过。如果允许通过选项并且没有重新分段或合并到 TCP 段,则多路径 TCP 流可以继续进行而不会出现问题。

3.7 节讨论了数据包上的选项被剥离的情况。如果仅剥离了一些 MPTCP 选项,则行为是不确定的。如果丢失了一些数据序列映射,只要存在子流级数据的映射(例如,如果发送了多个相互加强的映射),连接就可以继续。但是,如果某些子流级别的空间未映射,则使用第 3.7 节中描述的过程将子流视为损坏并关闭。MPTCP 应该在丢失一些数据 ACK 的情况下继续存在,但性能会随着剥离选项的比例增加而下降。但是,我们不希望这种情况在实践中出现:大多数中间盒要么剥离所有选项,要么让它们全部通过。

我们以中间盒类列表、它们的行为以及 MPTCP 设计中允许通过此类中间盒进行操作的元素来结束本节。上面讨论了使用选项或剥离选项丢弃数据包的问题,此处不包括:

  • NAT(网络地址(和端口)转换器)[ RFC3022 ]更改数据包的源地址(通常是源端口)。这意味着主机将不知道其面向公众的 MPTCP 信令地址。因此,MPTCP 允许通过 MP_JOIN 选项添加隐式地址,并且握手机制确保到私有地址[ RFC1918 ]的连接尝试,因为它们经过身份验证,只会将子流设置到正确的主机。显式地址删除由地址 ID 承担,以允许不知道源地址。
  • 性能增强代理 (PEP) [ RFC3135 ]可能会主动确认数据以提高性能。然而,MPTCP 依赖于来自终端主机的准确拥塞控制信号,非 MPTCP 感知的 PEP 将无法提供此类信号。因此,MPTCP 将退回到单路径 TCP 或关闭有问题的子流(参见第 3.7 节)。
  • 流量规范器[ norm ]可能不允许序列号出现漏洞,它们可能会缓存数据包并重新传输相同的数据。MPTCP 看起来像网络上的标准 TCP,不会在相同的子流序列号上重新传输不同的数据。在重传的情况下,相同的数据将在原始 TCP 子流上重传,即使它在不同子流上的连接级别额外重传。
  • 防火墙[ RFC2979 ]可能会对 TCP 连接执行初始序列号 (ISN) 随机化。MPTCP 在数据序列映射中使用相对序列号来解决这个问题。与 NAT 一样,防火墙不允许许多传入连接,因此 MPTCP 支持地址信令 (ADD_ADDR),因此多地址主机可以邀请防火墙/NAT 后面的对等方连接到其附加接口。
  • 入侵检测系统/入侵防御系统 (IDS⁠/IPS) 观察数据包流中可能威胁网络的模式和内容。MPTCP 可能需要检测额外的路径,并且支持 MPTCP 的 IDS 或 IPS 需要读取 MPTCP 令牌以关联来自多个子流的数据,以保持对设备之间所有流量的可比可见性。如果没有此类更改,IDS 将无法完整地查看流量,从而增加丢失感兴趣流量的风险(误报),并增加由于仅看到部分数据(误报)而将子流错误识别为风险的机会。
  • 应用程序级中间盒(例如内容感知防火墙)可能会更改子流中的有效负载——例如,重写 HTTP 流量中的 URI。MPTCP 将使用校验和检测此类更改并关闭受影响的子流,如果有其他可以使用的子流。如果所有子流都受到影响,MPTCP 将回退到 TCP,从而允许此类中间盒更改有效负载。MPTCP 感知中间盒应该能够调整有效负载和 MPTCP 元数据,以免中断连接。

此外,所有类型的中间盒都可能通过以下方式影响 TCP 流量:

  • 许多类型的中间盒可能会删除 TCP 选项,或者丢弃具有未知选项的数据包。使用 TCP 选项的初始 SYN 交换旨在足以识别路径的能力。如果这样的数据包没有通过,MPTCP 将最终退回到常规 TCP。
  • 分段/合并(例如,TCP 分段卸载)可能会在数据包之间复制选项,并且可能会剥离一些选项。MPTCP 的数据序列映射包括相对子流序列号,而不是使用段中的序列号。这样,映射就独立于承载它的数据包。
  • 接收窗口可能会被子流级别的一些中间盒缩小。MPTCP 将在数据级别使用最大窗口,但也将遵循特定于子流的窗口。

7. IANA 考虑因素

本文档已过时[ RFC6824 ]。因此,IANA 更新了多个注册管理机构以指向该文档。此外,本文档创建了一个新的注册表。这些主题在以下小节中进行了描述。

7.1。TCP 选项种类编号

IANA 已更新“TCP Option Kind Numbers”注册表以指向多路径 TCP 的此文档,如表 1所示:

种类 长度 意义 参考
30 ñ 多路径 TCP (MPTCP) RFC 8684

7.2. MPTCP 选项子类型

“传输控制协议 (TCP) 参数”注册表下的“MPTCP 选项子类型”子注册表中的 4 位 MPTCP 子类型在[ RFC6824 ]中定义。由于[ RFC6824 ]是一个实验性 RFC 而不是标准跟踪 RFC,并且由于除了指向[ RFC6824 ]的条目之外没有出现其他条目,因此 IANA 已将现有注册表替换为 表 2的内容和以下解释性说明。

注意:此注册表指定 MPTCP v1 的 MPTCP 选项子类型,它淘汰了实验性 MPTCP v0。对于 MPTCP v0 子类型,请参考[ RFC6824 ]。

价值 象征 姓名 参考
0x0 MP_CAPABLE 多路径能力 RFC 8684,第 3.1 节
0x1 MP_JOIN 加入连接 RFC 8684,第 3.2 节
0x2 DSS 数据序列信号(数据 ACK 和数据序列映射) RFC 8684,第 3.3 节
0x3 ADD_ADDR 添加地址 RFC 8684,第 3.4.1 节
0x4 REMOVE_ADDR 删除地址 RFC 8684,第 3.4.2 节
0x5 MP_PRIO 更改子流优先级 RFC 8684,第 3.3.8 节
0x6 MP_FAIL 倒退 RFC 8684,第 3.7 节
0x7 MP_FASTCLOSE 快速关闭 RFC 8684,第 3.5 节
0x8 MP_TCPRST 子流重置 RFC 8684,第 3.6 节
0xf MP_EXPERIMENTAL 保留供私人使用

当前未分配值 0x9 到 0xe。选项 0xf 保留供私人实验使用。它的使用可能会在未来的规范中正式化。此注册表中的未来分配将由[ RFC8126 ]定义的标准行动定义。分配由 MPTCP 子类型的符号名称、其关联值和对其规范的引用组成。

7.3. MPTCP 握手算法

“传输控制协议 (TCP) 参数”注册表下的“MPTCP 握手算法”子注册表在[ RFC6824 ]中定义。由于[ RFC6824 ]是一个实验性 RFC,而不是标准跟踪 RFC,并且除了指向[ RFC6824 ]的条目之外没有出现其他条目,因此 IANA 已将现有注册表替换为 表 3的内容和以下解释性说明。

注意:此注册表指定 MPTCP v1 的 MPTCP 握手算法,它废弃了实验性 MPTCP v0。对于 MPTCP v0 子类型,请参考[ RFC6824 ]。

标志位 意义 参考
一个 需要校验和 RFC 8684,第 3.1 节
可扩展性 RFC 8684,第 3.1 节
C 不要尝试建立到源地址的新子流。 RFC 8684,第 3.1 节
危险品 未分配
H HMAC-SHA256 RFC 8684,第 3.2 节

请注意,位“D”到“H”的含义可能取决于位“B”,具体取决于未来规范中如何定义可扩展性参数;有关详细信息,请参阅 第 3.1 节。

此注册表中的未来分配也将由[ RFC8126 ]定义的标准行动定义。赋值由标志的值、算法的符号名称和对其规范的引用组成。

7.4. MP_TCPRST 原因代码

基于 MP_TCPRST(第 3.6 节)消息中的原因代码,IANA 在“传输控制协议 (TCP) 参数”注册表下创建了另一个子注册表“MPTCP MP_TCPRST 原因代码” 。该注册表的初始值在表 4中给出;未来的分配将由[ RFC8126 ]定义的规范要求来定义。赋值由代码的值、其含义的简短描述和对其规范的引用组成。最大值为 0xff。

代码 意义 参考
0x00 未指定的错误 RFC 8684,第 3.6 节
0x01 MPTCP 特定错误 RFC 8684,第 3.6 节
0x02 缺乏资源 RFC 8684,第 3.6 节
0x03 行政禁止 RFC 8684,第 3.6 节
0x04 未完成的数据太多 RFC 8684,第 3.6 节
0x05 不可接受的性能 RFC 8684,第 3.6 节
0x06 中间盒干扰 RFC 8684,第 3.6 节

作为对指定专家[ RFC8126 ]的指导,除非代码点空间变得稀缺,否则通常不应拒绝分配,前提是与其他已经存在的代码有明显的区别,并且为实施者提供足够的指导。接收这些代码。

8.参考文献

8.1。规范性参考

8.2. 参考资料

附录 A. TCP 选项使用注意事项

由于 TCP 标头中的数据偏移字段的长度(4 位),TCP 选项空间是有限的,它以 32 位字定义 TCP 标头长度。由于标准 TCP 标头为 20 字节,因此最多为选项留下 40 字节,其中许多可能已被时间戳和 SACK 等选项使用。

我们对 SYN、数据和纯 ACK 数据包中常用的 TCP 选项进行了简要研究,发现有足够的空间容纳本文档中讨论的所有选项。

SYN 数据包通常包括以下选项:最大段大小 (MSS)(4 字节)、窗口比例(3 字节)、允许的 SACK(2 字节)和时间戳(10 字节)。这些选项的总和为 19 个字节。一些操作系统似乎将每个选项填充到一个字边界,因此使用 24 个字节(一个简短的调查表明 Windows XP 和 Mac OS X 这样做,而 Linux 没有)。因此,乐观地说,我们有 21 个字节可用,如果选项必须按字对齐,则有 16 个字节。然而,在任何一种情况下,MP_CAPABLE(12 字节)和 MP_JOIN(12 或 16 字节)的 SYN 版本都将适合此剩余空间。

请注意,由于使用了 64 位数据级序列空间,MPTCP 可能不需要时间戳选项来防止包装序列号(根据保护包装序列 (PAWS) 机制,如[ RFC7323 ]),因为数据级序列空间的包装机会要小得多。这种优化的有效性的确认有待进一步研究。

TCP 数据包通常在每个包中携带时间戳选项,占用 10 个字节(或 12 个,带填充)。剩下 30 个字节(如果字对齐,则为 28 个字节)。DSS 选项的长度不同,取决于 (1) 是否包括数据序列映射、DATA_ACK 或两者,(2) 使用的序列号是 4 字节还是 8 字节,以及 (3) 是否存在校验和。DSS 选项的最大大小为 28 字节,因此即使这样也适合可用空间。但是,除非连接既是双向的又是高带宽的,否则每个 DSS 选项都不太可能需要所有选项空间。

在 DSS 选项中,不必在每个数据包中包含数据序列映射和 DATA_ACK,并且在许多情况下,可以交替它们的存在(只要映射覆盖在后续数据包中发送的数据)。也可以在每个选项中交替使用 4 字节和 8 字节序列号。

在子流和连接设置上,还为第三个数据包(ACK)设置了 MPTCP 选项。它们是 20 字节(对于 MP_CAPABLE)和 24 字节(对于 MP_JOIN),它们都将适合可用的选项空间。

TCP 中的纯 ACK 通常只包含时间戳(10 个字节)。在这里,多路径 TCP 通常只需要对 DATA_ACK(最多 12 个字节)进行编码。有时,ACK 会包含 SACK 信息。根据丢失数据包的数量,SACK 可能会利用整个选项空间。如果必须包含 DATA_ACK,则可能需要减少 SACK 块的数量以容纳 DATA_ACK。然而,在使用 SACK 的情况下,DATA_ACK 的存在不太可能是必要的,因为在至少一些 SACK 块被重传之前,累积的数据级 ACK 不会向前移动(或者如果它确实,由于在另一条路径上重传,则该路径也可用于传输新的 DATA_ACK)。

ADD_ADDR 选项可以在 16 到 30 个字节之间,这取决于 (1) 使用 IPv4 还是 IPv6 以及 (2) 端口号是否存在。这种信令不太可能适合数据包(尽管如果有空间,可以包含它)。建议不要将重复的 ACK 与任何其他有效载荷或选项一起使用,以便传输这些稀有信号。请注意,这是强制要求不要将带有 MPTCP 选项的重复 ACK 视为拥塞信号的原因。

附录 B. TCP 快速打开和 MPTCP

TCP Fast Open (TFO) 是一种实验性的 TCP 扩展,在 [ RFC7413 ]中进行了描述,它已被引入以允许比常规 TCP 早一个 RTT 发送数据。这被认为是一项宝贵的收益,因为非常短的连接非常常见,尤其是对于 HTTP 请求/响应方案。它通过将 SYN 段与应用程序的数据一起发送并允许侦听器在 SYN/ACK 之后立即回复数据来实现这一点。[ RFC7413 ]通过使用一个新的 TCP 选项来保护这种机制,该选项包括在前面的连接中协商的 cookie。

将 TFO 与 MPTCP 结合使用时,需要考虑两个关键点,如下所述。

当 TFO 发起者首次连接到侦听器时,出于安全原因,它不能立即在 SYN 中包含数据[ RFC7413 ]。相反,它请求将在后续连接中使用的 cookie。这是通过 TCP cookie 请求/响应选项完成的,分别为 2 个字节和 6-18 个字节(取决于所选的 cookie 长度)。

TFO 和 MPTCP 可以组合,前提是所有选项的总长度不超过 TCP 中可能的最大 40 字节:

  • 在 SYN: MPTCP 中使用 4 字节的 MP_CAPABLE 选项。MPTCP 和 TFO 选项的总和为 6 个字节。典型的 TCP 选项在 SYN 中最多使用 19 个字节(如果选项在字边界处填充,则为 24 个字节),有足够的空间将 MP_CAPABLE 与 TFO cookie 请求结合起来。
  • 在 SYN + ACK: MPTCP 中使用了 12 字节的 MP_CAPABLE 选项,但现在 TFO 选项可以长达 18 字节。由于可能会超过最大选项长度,因此由侦听器通过使用较短的 cookie 来避免此问题。例如,如果我们考虑将 19 个字节用于经典 TCP 选项,那么最大可能的 cookie 长度将是 7 个字节。请注意,对于 SYN 数据包,相同的限制适用于后续连接(因为发起者随后会将 cookie 回显给侦听器)。最后,如果认为减小 cookie 大小的安全影响不可接受,则侦听器可以通过省略 TCP 时间戳来减少其他 TCP 选项使用的空间量(如附录 A)。

B.2。TFO下的数据序列映射

在 TCP 建立阶段,MPTCP 使用密钥交换来生成初始数据序列号 (IDSN)。特别是,带有 MP_CAPABLE 的 SYN 占用了数据序列空间的第一个八位字节。使用 TFO,处理与 SYN 一起发送的数据的一种方法是考虑覆盖该 SYN 段的隐式 DSS 映射(因为 SYN 中没有足够的空间来包含 DSS 选项)。这种方法的问题在于,如果中间盒修改了 TFO 数据,MPTCP 将不会注意到这一点,因为没有 DSS 校验和。例如,支持 TCP(但不支持 MPTCP)的中间盒可以在流的开头插入字节,并相应地调整 TCP 校验和和序列号。使用隐式映射,此信息将为发起者和侦听器提供不同的 DSS 映射视图;没有办法检测到这种不一致,因为不存在 DSS 校验和。

为了解决这个问题,TFO 数据不能被认为是数据序列号空间的一部分:带有 MP_CAPABLE 的 SYN 仍然占用数据序列空间的第一个八位字节,但第一个非 TFO 数据字节占用第二个八位字节。这保证了,如果协商使用 DSS 校验和,则对数据序列号空间中的所有数据进行校验和。我们还注意到,这不会导致功能损失,因为 TFO 数据始终仅在初始子流上发送,然后再尝试创建其他子流。

B.3。连接建立示例

下面显示了一些可能的“TFO + MPTCP”建立方案示例。

在发起者可以与 SYN 一起发送数据之前,它必须向侦听器请求一个 cookie,如图 18所示。(注:序列号和长度在图 18中标注为 Seq(Length)(例如,“S. 0(0)”)并在随后的图中照此使用(例如,图 18 中的“S 0(20)” ) 19 ).) 这是通过简单地结合 TFO 和 MPTCP 选项来完成的。

1
2
3
4
5
6
7
8
9
10
11
发起者监听器
| |
| S Seq=0(Length=0) <MP_CAPABLE>, <TFO cookie request> |
| -------------------------------------------------- ------> |
| |
| S. 0(0) ack 1 <MP_CAPABLE>, <TFO cookie> |
| <---------------------------------------------------- -------- |
| |
| . 0(0) 确认 1 <MP_CAPABLE> |
| -------------------------------------------------- ------> |
| |

图 18Cookie 请求

完成此操作后,接收到的 cookie 可用于 TFO,如图 19所示。在本例中,发起方首先在 SYN 中发送 20 个字节。侦听器立即回复 SYN-ACK 后的 100 个字节,发起者回复 20 个字节。注意图中最后一段的 TCP 序号为 21,而 DSS 子流序号为 1(因为 TFO 数据不属于数据序号空间的一部分,如附录 B.2所述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
发起者监听器
| |
| S 0(20) <MP_CAPABLE>, <TFO cookie> |
| -------------------------------------------------- ------> |
| |
| S. 0(0) ack 21 <MP_CAPABLE> |
| <---------------------------------------------------- -------- |
| |
| . 1(100) ack 21 <DSS ack=1 seq=1 ssn=1 dlen=100> |
| <---------------------------------------------------- -------- |
| |
| . 21(0) 确认 1 <MP_CAPABLE> |
| -------------------------------------------------- ------> |
| |
| . 21(20) 确认 101 <DSS 确认=101 seq=1 ssn=1 dlen=20> |
| -------------------------------------------------- ------> |
| |

图 19监听器支持 TFO

图 20中,监听器不支持 TFO。发起者检测到侦听器中没有创建任何状态(因为没有数据被确认)并且现在在第三个数据包中发送 MP_CAPABLE,以便侦听器在建立结束时构建其 MPTCP 上下文。现在,TFO 数据在重新传输时成为数据序列映射的一部分,因为它是在建立之后有效发送(实际上是重新发送)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
发起者监听器
| |
| S 0(20) <MP_CAPABLE>, <TFO cookie> |
| -------------------------------------------------- ------> |
| |
| S. 0(0) ack 1 <MP_CAPABLE> |
| <---------------------------------------------------- -------- |
| |
| . 1(0) 确认 1 <MP_CAPABLE> |
| -------------------------------------------------- ------> |
| |
| . 1(20) ack 1 <DSS ack=1 seq=1 ssn=1 dlen=20> |
| -------------------------------------------------- ------> |
| |
| . 0(0) ack 21 <DSS ack=21 seq=1 ssn=1 dlen=0> |
| <---------------------------------------------------- -------- |
| |

图 20监听器不支持 TFO

如图 21所示,侦听器也可能只确认 TFO 数据的一部分。发起者将简单地与 DSS 映射一起重新传输丢失的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
发起者监听器
| |
| S 0(1000) <MP_CAPABLE>, <TFO cookie> |
| -------------------------------------------------- ------> |
| |
| S. 0(0) 确认 501 <MP_CAPABLE> |
| <---------------------------------------------------- -------- |
| |
| . 501(0) 确认 1 <MP_CAPABLE> |
| -------------------------------------------------- ------> |
| |
| . 501(500) 确认 1 <DSS 确认=1 seq=1 ssn=1 dlen=500> |
| -------------------------------------------------- ------> |
| |

图 21部分数据确认

附录 C.控制块

从概念上讲,一个 MPTCP 连接可以表示为一个 MPTCP 协议控制块 (PCB),其中包含几个跟踪 MPTCP 连接的进度和状态的变量,以及一组与已建立的子流相对应的链接 TCP 控制块。

RFC 793 [ RFC0793 ]指定了几个状态变量。只要有可能,我们就会重用与 RFC 793 相同的术语来描述 MPTCP 维护的状态变量。

C.1。MPTCP 控制块

MPTCP 控制块包含每个连接的以下变量。

C.1.1。身份验证和元数据

  • Local.Token(32 位):

    这是本地主机在此 MPTCP 连接上选择的令牌。令牌在所有已建立的 MPTCP 连接中必须是唯一的,并且由本地密钥生成。

  • 本地密钥(64 位):

    这是本地主机在此 MPTCP 连接上发送的密钥。

  • 远程令牌(32 位):

    这是远程主机在此 MPTCP 连接上选择的令牌,由远程密钥生成。

  • Remote.Key(64 位):

    这是远程主机在此 MPTCP 连接上选择的密钥。

  • MPTCP.Checksum(标志):

    如果至少有一个主机在连接建立期间交换的 MP_CAPABLE 选项中设置了“A”位,则此标志设置为 true;否则,它被设置为假。如果设置了此标志,则必须在所有 DSS 选项中计算校验和。

C.1.2。发送方

  • SND.UNA(64 位):

    这是在 MPTCP 连接级别要确认的下一个字节的数据序列号。此变量在接收到包含 DATA_ACK 的 DSS 选项时更新。

  • SND.NXT(64 位):

    这是要发送的下一个字节的数据序列号。SND.NXT 用于确定DSS 选项中DSN 的值。

  • SND.WND(32 位):

    这是发送窗口。如果使用 RFC 7323 中的特性,则为 32 位;否则为 16 位。MPTCP 在 MPTCP 连接级别维护发送窗口,所有子流共享同一个窗口。所有子流都使用 MPTCP 连接级别 SND.WND 来计算在每个传输段中发送的 SEQ.WND 值。

C.1.3。接收方

  • RCV.NXT(64 位):

    这是 MPTCP 连接上预期的下一个字节的数据序列号。该状态变量在接收到有序数据时被修改。RCV.NXT 的值用于指定在所有子流的 DSS 选项中发送的 DATA_ACK。

  • RCV.WND(32 位):

    这是连接级接收窗口,它是所有子流上 RCV.WND 的最大值。如果使用 RFC 7323 中的特性,则为 32 位;否则为 16 位。

C.2。TCP 控制块

MPTCP 控制块还包含与 MPTCP 连接关联的 TCP 控制块列表。

请注意,TCP 子流上的 TCP 控制块不包含 RCV.WND 和 SND.WND 状态变量,因为它们是在 MPTCP 连接级别而不是在子流级别维护的。

在每个 TCP 控制块中,定义了以下状态变量。

C.2.1。发送方

  • SND.UNA(32 位):

    这是要在子流上确认的下一个字节的序列号。此变量在接收到子流上的每个 TCP 确认时更新。

  • SND.NXT(32 位):

    这是要在子流上发送的下一个字节的序列号。SND.NXT 用于在传输下一个段时设置 SEG.SEQ 的值。

C.2.2。接收方

  • RCV.NXT(32 位):

    这是子流上预期的下一个字节的序列号。此状态变量在接收到有序段时被修改。RCV.NXT 的值被复制到在子流上传输的下一个段的 SEG.ACK 字段。

  • RCV.WND(32 位):

    这是子流级别的接收窗口,它使用来自在该子流上接收的段的窗口字段进行更新。如果使用 RFC 7323 中的特性,则为 32 位;否则为 16 位。

附录 D.有限状态机

图 22中的图表显示了用于连接级闭合的有限状态机。这说明了 DATA_FIN 连接级信号(在图中表示为 DATA_ACK 上的 DFIN 标志)(1)如何与子流级 FIN 交互,以及(2)允许子流之间的先断后通切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
                             +---------+
| M_ESTAB |
+---------+
M_CLOSE | | rcv DATA_FIN
------- | | -------
+---------+ snd DATA_FIN / \ snd DATA_ACK[DFIN] +-------+
| M_FIN |<----------------- ------------------->|M_CLOSE|
| WAIT-1 |--------------------------- | WAIT |
+---------+ rcv DATA_FIN \ +-------+
| rcv DATA_ACK[DFIN] ------- | M_CLOSE |
| -------------- snd DATA_ACK | ------- |
| CLOSE all subflows | snd DATA_FIN |
V V V
+-----------+ +-----------+ +----------+
|M_FINWAIT-2| | M_CLOSING | |M_LAST-ACK|
+-----------+ +-----------+ +----------+
| rcv DATA_ACK[DFIN] | rcv DATA_ACK[DFIN] |
| rcv DATA_FIN -------------- | -------------- |
| ------- CLOSE all subflows | CLOSE all subflows |
| snd DATA_ACK[DFIN] V delete MPTCP PCB V
\ +-----------+ +--------+
------------------------>|M_TIME WAIT|---------------->|M_CLOSED|
+-----------+ +--------+
All subflows in CLOSED
------------
delete MPTCP PCB

图 22连接关闭的有限状态机

附录 E.对 RFC 6824 的更改

本附录列出了[ RFC6824 ]之间的关键技术变化,其中指定了 MPTCP v0;和本文档,它废弃了[ RFC6824 ]并指定了 MPTCP v1。请注意,此规范不向后兼容[ RFC6824 ]。

  • 本文档结合了从文档“多路径 TCP 的用例和操作经验” [ RFC8041 ]和 IETF 期刊文章“多路径 TCP 部署” [部署]中收集的各种实现、部署和实验的经验教训。
  • 通过 MP_CAPABLE MPTCP 选项的交换启动连接与[ RFC6824 ]不同。SYN 不再包含发起者的密钥,以允许 SYN 上的 MP_CAPABLE 选项的长度更短,并避免重复发送密钥材料。
  • 这还通过允许其传输与数据结合并因此使用 TCP 的内置可靠性机制来确保 MP_CAPABLE 选项上的密钥的可靠传递。如果发起者没有立即有数据要发送,带有密钥的 MP_CAPABLE 选项将在第一个数据包上重复。如果另一端是第一个发送的,那么 DSS 选项的存在隐含地确认了 MP_CAPABLE 的接收。
  • 在 MP_CAPABLE 的 Flags 字段中,现在分配“C”表示该选项的发送方将不接受到源地址和端口的额外 MPTCP 子流。这提高了效率——例如,在发送方位于严格 NAT 之后的情况下。
  • 在 MP_CAPABLE 的标志字段中,“H”现在表示使用 HMAC-SHA256(而不是 HMAC-SHA1)。
  • 连接启动还定义了版本协商的过程,用于支持 v0 [ RFC6824 ]和 v1(本文档)的实现。
  • 使用 HMAC-SHA256(而不是 HMAC-SHA1)算法,因为它提供了更好的安全性。它用于在 MP_JOIN 和 ADD_ADDR 消息中生成令牌并设置 IDSN。
  • 存在一个新的子流级别选项来指示在子流上发送 RST 的原因(MP_TCPRST(第 3.6 节));这可以帮助实现决定是否尝试稍后重新连接。
  • MP_PRIO 选项(第 3.3.8 节)用于指示子流的优先级更改,不再包括 AddrID 字段。其目的是允许将更改的优先级应用于发送它的子流之外的子流。但是,已确定这可以被中间人用来将所有流量转移到自己的路径上,并且 MP_PRIO 不包括令牌或其他类型的安全机制。
  • ADD_ADDR 选项(第 3.4.1 节)用于通知其他主机另一个潜在地址,它在几个方面有所不同。它现在包括添加地址的 HMAC,以增强安全性。此外,添加了 ADD_ADDR 选项的可靠性:IPVer 字段替换为标志字段,并分配了一个标志(“E”)用作“回声”,以便主机可以指示它已收到选项。
  • 本文档描述了另一种执行快速关闭的方法——通过在所有子流的 RST 上发送 MP_FASTCLOSE 选项。这允许主机立即拆除子流和连接。
  • IANA 已保留值 0xf 的 MPTCP 选项子类型供私人使用(第 7.2 节)。本文档没有定义如何使用该值。
  • 本文档添加了一个新附录(附录 B),该附录讨论了 MPTCP 选项和 TFO 选项在同一数据包上的用法。

致谢

作者非常感谢Sebastien Barre和Andrew McDonald对本文档的重要贡献。

作者还要感谢 Iljitsch van Beijnum、Lars Eggert、Marcelo Bagnulo、Robert Hancock、Pasi Sarolahti、 Toby Moncaster、Philip Eardley、Sergio Lembo、Lawrence Conroy、Yoshifumi Nishida、 Bob Briscoe、Stein Gjessing、 Andrew McGregor的评论和贡献。格奥尔格·汉佩尔,阿努米塔·比斯瓦斯,韦斯·艾迪,阿列克谢·梅尔尼科夫,弗朗西斯·杜邦、阿德里安·法瑞尔、 巴里·莱巴、罗伯特·斯帕克斯、 肖恩·特纳、斯蒂芬·法瑞尔、马丁·斯蒂默林、格雷戈里·德塔尔、法比安·杜切内、 泽维尔·德福伊、拉胡尔·贾达夫、 克莱门斯·施拉格尔、米娅·库勒温德、姜升、艾丽莎·库珀、伊内斯·罗伯斯、罗曼丹尼利夫、亚当·罗奇、 埃里克·文克和本·卡杜克.

作者地址

艾伦福特

Pexip

电子邮件: alan.ford@gmail.com

科斯汀·赖丘

布加勒斯特理工大学

Splaiul Independentei 313

布加勒斯特

罗马尼亚

电子邮件: costin.raiciu@cs.pub.ro

马克汉德利

伦敦大学学院

高尔街

伦敦

WC1E 6BT

英国

电子邮件: m.handley@cs.ucl.ac.uk

奥利维尔·博纳旺德

鲁汶天主教大学

PL。圣巴贝,2

1348 新鲁汶

比利时

电子邮件: olivier.bonaventure@uclouvain.be

克里斯托夫·帕施

苹果公司。

库比蒂诺_ _

美国

电子邮件: cpaasch@apple.com


RFC 8684 具有多个地址的多路径操作的 TCP 扩展
http://blog.uanet.cn/NETWORK/RFC 8684 具有多个地址的多路径操作的 TCP 扩展.html
作者
dnsnat
发布于
2022年5月27日
许可协议