多路径 TCP (MPTCP)¶
简介¶
多路径 TCP 或 MPTCP 是标准 TCP 的扩展,在 RFC 8684 (MPTCPv1) 中进行了描述。它允许设备同时使用多个接口,通过单个 MPTCP 连接发送和接收 TCP 数据包。MPTCP 可以聚合多个接口的带宽,或者优先选择延迟最低的接口。它还允许在一条路径中断时进行故障转移,并将流量无缝地重新注入到其他路径上。
有关 Linux 内核中多路径 TCP 的更多详细信息,请参阅官方网站:mptcp.dev。
用例¶
与 TCP 相比,由于 MPTCP 能够并行或同时使用多个路径,因此带来了新的用例。
无缝切换:在保持已建立的连接的同时,从一条路径切换到另一条路径,例如,用于智能手机等移动用例。
最佳网络选择:根据一些条件(例如,延迟、丢包、成本、带宽等)使用“最佳”可用路径。
网络聚合:同时使用多个路径以获得更高的吞吐量,例如,结合固定网络和移动网络以更快地发送文件。
概念¶
从技术上讲,当使用 IPPROTO_MPTCP
协议(Linux 特有)创建新套接字时,会创建一个子流(或路径)。此子流由一个常规 TCP 连接组成,该连接用于通过一个接口传输数据。稍后可以在主机之间协商额外的子流。为了使远程主机能够检测到 MPTCP 的使用,在底层 TCP 子流的 TCP 选项字段中添加了一个新字段。此字段包含 MP_CAPABLE
选项,该选项告诉其他主机如果支持,则使用 MPTCP。如果远程主机或中间的任何中间设备不支持,则返回的 SYN+ACK
数据包的 TCP 选项字段将不包含 MPTCP 选项。在这种情况下,连接将“降级”为普通 TCP,并将在单个路径上继续。
这种行为是通过两个内部组件实现的:路径管理器和数据包调度器。
路径管理器¶
路径管理器负责子流,从创建到删除,以及地址宣告。通常,客户端发起子流,服务器端通过 ADD_ADDR
和 REMOVE_ADDR
选项宣告其他地址。
路径管理器由 net.mptcp.pm_type
sysctl 旋钮控制 - 请参阅 MPTCP Sysfs 变量。有两种类型:内核内置类型(类型 0
),其中相同的规则应用于所有连接(请参阅:ip mptcp
);以及用户空间类型(类型 1
),由用户空间守护进程(即 mptcpd)控制,其中可以为每个连接应用不同的规则。路径管理器可以通过 Netlink API 控制;请参阅 Family mptcp_pm netlink specification。
为了能够在主机上使用多个 IP 地址来创建多个子流(路径),默认的内核内置 MPTCP 路径管理器需要知道可以使用哪些 IP 地址。例如,可以使用 ip mptcp endpoint
配置此项。
数据包调度器¶
数据包调度器负责选择要使用哪个可用的子流来发送下一个数据包。它可以决定最大化可用带宽的使用,仅选择延迟较低的路径,或者根据配置选择任何其他策略。
数据包调度器由 net.mptcp.scheduler
sysctl 旋钮控制 - 请参阅 MPTCP Sysfs 变量。
套接字 API¶
创建 MPTCP 套接字¶
在 Linux 上,可以通过在创建 socket
时选择 MPTCP 而不是 TCP 来使用 MPTCP
int sd = socket(AF_INET(6), SOCK_STREAM, IPPROTO_MPTCP);
请注意,IPPROTO_MPTCP
定义为 262
。
如果不支持 MPTCP,则 errno
将设置为
EINVAL
:(无效参数):在内核版本 < 5.6 上,MPTCP 不可用。EPROTONOSUPPORT
(不支持协议):在内核版本 >= v5.6 上,MPTCP 未编译。ENOPROTOOPT
(协议不可用):已使用net.mptcp.enabled
sysctl 旋钮禁用了 MPTCP;请参阅 MPTCP Sysfs 变量。
MPTCP 是可选的:应用程序需要明确请求它。请注意,可以使用不同的技术强制应用程序使用 MPTCP,例如 LD_PRELOAD
(请参阅 mptcpize
)、eBPF(请参阅 mptcpify
)、SystemTAP、GODEBUG
(GODEBUG=multipathtcp=1
) 等。
对于用户空间应用程序,切换到 IPPROTO_MPTCP
而不是 IPPROTO_TCP
应该尽可能透明。
套接字选项¶
MPTCP 支持 TCP 处理的大多数套接字选项。可能不支持一些不太常见的选项,但欢迎贡献。
通常,相同的值会传播到所有子流,包括在调用 setsockopt()
之后创建的子流。可以使用 eBPF 为每个子流设置不同的值。
在 SOL_MPTCP
(284) 级别有一些 MPTCP 特有的套接字选项来检索信息。它们会填充 getsockopt()
系统调用的 optval
缓冲区。
MPTCP_INFO
:使用struct mptcp_info
。MPTCP_TCPINFO
:使用struct mptcp_subflow_data
,后跟一个struct tcp_info
数组。MPTCP_SUBFLOW_ADDRS
:使用struct mptcp_subflow_data
,后跟一个mptcp_subflow_addrs
数组。MPTCP_FULL_INFO
:使用struct mptcp_full_info
,其中一个指针指向struct mptcp_subflow_info
的数组(包括struct mptcp_subflow_addrs
),另一个指针指向struct tcp_info
的数组,后跟struct mptcp_info
的内容。
请注意,在 TCP 级别,可以使用 TCP_IS_MPTCP
套接字选项来了解当前是否正在使用 MPTCP:如果正在使用,该值将设置为 1。
设计选择¶
为面向用户空间的套接字添加了一种新的 MPTCP 套接字类型。内核负责创建子流套接字:它们是使用 TCP-ULP 修改其行为的 TCP 套接字。
如果客户端的连接请求没有请求 MPTCP,则 MPTCP 监听套接字将创建“普通”的接受 TCP 套接字,从而在默认启用 MPTCP 时使性能影响最小。