多路径 TCP (MPTCP)¶
简介¶
多路径 TCP 或 MPTCP 是标准 TCP 的扩展,在 RFC 8684 (MPTCPv1) 中有所描述。它允许设备同时使用多个接口,通过单个 MPTCP 连接发送和接收 TCP 数据包。MPTCP 可以聚合多个接口的带宽,或优先选择延迟最低的接口。如果其中一条路径出现故障,它还允许故障转移,流量将无缝地重新注入到其他路径上。
有关 Linux 内核中多路径 TCP 的更多详细信息,请参阅官方网站:mptcp.dev。
用例¶
得益于 MPTCP,能够并行或同时使用多条路径带来了与 TCP 相比的新用例
无缝切换:在保留已建立连接的同时从一条路径切换到另一条路径,例如用于移动性用例,如智能手机。
最佳网络选择:根据某些条件(例如延迟、丢包、成本、带宽等)使用“最佳”可用路径。
网络聚合:同时使用多条路径以获得更高的吞吐量,例如结合固定网络和移动网络以更快地发送文件。
概念¶
从技术上讲,当使用 IPPROTO_MPTCP
协议(Linux 特有)创建新的套接字时,会创建一个子流(或路径)。这个子流由一个常规的 TCP 连接组成,用于通过一个接口传输数据。主机之间稍后可以协商额外的子流。为了使远程主机能够检测到 MPTCP 的使用,在底层 TCP 子流的 TCP 选项字段中添加了一个新字段。该字段包含(除其他外)一个 MP_CAPABLE
选项,如果支持 MPTCP,则它会告诉另一个主机使用 MPTCP。如果远程主机或其间的任何中间设备不支持 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
:(无效参数):MPTCP 在内核版本 < 5.6 时不可用。EPROTONOSUPPORT
(协议不支持):MPTCP 在内核版本 >= v5.6 时未编译。ENOPROTOOPT
(协议不可用):MPTCP 已通过net.mptcp.enabled
sysctl 旋钮禁用;参见 MPTCP Sysfs 变量。
MPTCP 随后是可选的(opt-in):应用程序需要明确请求它。请注意,应用程序可以通过不同的技术强制使用 MPTCP,例如 LD_PRELOAD
(参见 mptcpize
)、eBPF(参见 mptcpify
)、SystemTAP、GODEBUG
(GODEBUG=multipathtcp=1
)等。
对于用户空间应用程序来说,从 IPPROTO_TCP
切换到 IPPROTO_MPTCP
应该尽可能透明。
套接字选项¶
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 时将性能影响降至最低。