Red Hat Training

A Red Hat training course is available for RHEL 8

第 27 章 多路径 TCP 入门

重要

多路径 TCP 仅作为技术预览提供。红帽产品服务级别协议(SLA)不支持技术预览功能,且其功能可能并不完善,因此红帽不建议在生产环境中使用它们。这些预览可让用户早期访问将来的产品功能,让用户在开发过程中测试并提供反馈意见。

如需有关 技术预览功能支持范围 的信息,请参阅红帽客户门户网站中的技术预览功能支持范围。

多路径 TCP(MPTCP)是传输控制协议(TCP)的扩展。通过使用互联网协议(IP),主机可以将数据包发送到目的地。TCP 可确保通过互联网可靠地提供数据,并自动调整其带宽以响应网络负载。

以下是 MPTCP 的优点:

  • 它为带有两个或者多个网络接口的设备启用 TCP。
  • 它允许用户同时使用不同的网络接口或从一个连接间无缝切换。
  • 它提高了网络中的资源使用量以及网络故障的恢复能力。

本节描述了如何:

  • 创建新的 MPTCP 连接,
  • 使用 iproute2 为 MPTCP 连接添加新的子流和 IP 地址,以及
  • 在内核中禁用 MPTCP 以避免使用 MPTCP 连接的应用程序。

27.1. 准备 RHEL 启用 MPTCP 支持

一些应用程序原生支持 MPTCP。大多数在套接字()调用中,连接和流的套接字请求 TCP 协议。您可以在 RHEL 中为原生 MPTCP 支持使用 sysctl 工具启用 MPTCP 支持。MPTCP 的实现也被设计为允许在请求 IPPROTO_TCP 调用内核的应用程序中使用 MPTCP 协议。

此流程描述了如何启用 MPTCP 支持并准备 RHEL,以便使用 SystemTap 脚本启用 MPTCP 系统范围。

先决条件

安装以下软件包:

  • kernel-debuginfo
  • kernel-debuginfo-common
  • systemtap
  • systemtap-devel
  • kernel-devel
  • nmap-ncat

流程

  1. 在内核中启用 MPTCP 套接字:

    # echo "net.mptcp.enabled=1" > /etc/sysctl.d/90-enable-MPTCP.conf
    # sysctl -p /etc/sysctl.d/90-enable-MPTCP.conf
  2. 使用以下内容创建 mptcp.stap 文件:

    #!/usr/bin/env stap
    
    %{
    #include <linux/in.h>
    #include <linux/ip.h>
    %}
    
    /* according to [1], RSI contains 'type' and RDX
     * contains 'protocol'.
     * [1] https://github.com/torvalds/linux/blob/master/arch/x86/entry/entry_64.S#L79
     */
    
    function mptcpify () %{
        if (CONTEXT->kregs->si == SOCK_STREAM &&
            (CONTEXT->kregs->dx == IPPROTO_TCP ||
             CONTEXT->kregs->dx == 0)) {
                    CONTEXT->kregs->dx = IPPROTO_MPTCP;
                    STAP_RETVALUE = 1;
        } else {
               STAP_RETVALUE = 0;
        }
    %}
    
    probe kernel.function("__sys_socket") {
            if (mptcpify() == 1) {
                    printf("command %16s mptcpified\n", execname());
            }
    }
  3. 将 TCP 套接字替换为 MPTCP:

    # stap -vg mptcp.stap

    注: 使用 Ctrl+C 将连接从 MPTCP 转换回 TCP。

  4. 启动侦听 TCP 端口 4321 的服务器:

    # ncat -4 -l 4321

  5. 连接到服务器并交换流量。例如,这里的客户端将 "Hello world" 写入服务器 5 次,然后它终止连接。

    # ncat -4 192.0.2.1 4321
    Hello world 1
    Hello world 2
    Hello world 3
    Hello world 4
    Hello world 5

    Ctrl+D 退出。

验证步骤

  1. 验证内核中是否启用了 MPTCP:

    # sysctl -a | grep mptcp.enabled
    net.mptcp.enabled = 1
  2. mptcp.stap 脚本安装内核探测后,会在内核 dmesg 输出中出现以下警告:

    # dmesg
    ...
    [ 1752.694072] Kprobes globally unoptimized
    [ 1752.730147] stap_1ade3b3356f3e68765322e26dec00c3d_1476: module_layout: kernel tainted.
    [ 1752.732162] Disabling lock debugging due to kernel taint
    [ 1752.733468] stap_1ade3b3356f3e68765322e26dec00c3d_1476: loading out-of-tree module taints kernel.
    [ 1752.737219] stap_1ade3b3356f3e68765322e26dec00c3d_1476: module verification failed: signature and/or required key missing - tainting kernel
  3. 建立连接后,验证 ss 输出以查看特定于子流的状态:

    # ss -nti '( dport :4321 )' dst 192.0.2.1
    State Recv-Q Send-Q Local Address:Port    Peer Address:Port Process
    
    ESTAB 0      0          192.0.2.2:60874      192.0.2.1:4321
    cubic wscale:7,7 rto:201 rtt:0.042/0.017 mss:1448 pmtu:1500 rcvmss:536 advmss:1448 cwnd:10 bytes_sent:64 bytes_$cked:65 segs_out:6 segs_in:5 data_segs_out:4 send 2758095238bps lastsnd:57 lastrcv:3054 lastack:57 pacing_rate 540361516$bps delivery_rate 413714280bps delivered:5 rcv_space:29200 rcv_ssthresh:29200 minrtt:0.009 tcp-ulp-mptcp flags:Mmec token:0000(id:0)/4bffe73d(id:0) seq:c11f40d6c5337463 sfseq:1 ssnoff:f7455705 maplen:0
  4. 使用 tcpdump 捕获流量并检查 MPTCP 子选项的使用:

    # tcpdump -tnni interface tcp port 4321
    client Out IP 192.0.2.2.60802 > 192.0.2.1.4321: Flags [S], seq 3420255622, win 29200, options [mss 1460,sackOK,TS val 411 4539945 ecr 0,nop,wscale 7,mptcp capable v1], length 0
    client In  IP 192.0.2.1.4321 > 192.0.2.2.60802: Flags [S.], seq 2619315374, ack 3420255623, win 28960, options [mss 1460 sackOK,TS val 3241564233 ecr 4114539945,nop,wscale 7,mptcp capable v1 {0xb6f8dc721aee7f64}], length 0
    client Out IP 192.0.2.2.60802 > 192.0.2.1.4321: Flags [.], ack 1, win 229, options [nop,nop,TS val 4114539945 ecr 3241564 233,mptcp capable v1 {0xcc58d5d632a32d13,0xb6f8dc721aee7f64}], length 0
    client Out IP 192.0.2.2.60802 > 192.0.2.1.4321: Flags [P.], seq 1:17, ack 1, win 229, options [nop,nop,TS val 4114539945 ecr 3241564233,mptcp capable v1 {0xcc58d5d632a32d13,0xb6f8dc721aee7f64},nop,nop], length 16
    client In  IP 192.0.2.1.4321 > 192.0.2.2.60802: Flags [.], ack 17, win 227, options [nop,nop,TS val 3241564233 ecr 411459945,mptcp dss ack 1105509586894558345], length 0
    client Out IP 192.0.2.2.60802 > 192.0.2.1.4321: Flags [P.], seq 17:33, ack 1, win 229, options [nop,nop,TS val 4114540939 ecr 3241564233,mptcp dss ack 13265586846326199424 seq 105509586894558345 subseq 17 len 16,nop,nop], length 16

    运行这个命令时需要 tcpdump 软件包。

其它资源

27.2. 使用 iproute2 通知应用程序有关多个可用路径

默认情况下,MPTCP 套接字以一个子流开始,但您可以在第一次创建它后向连接添加新的子流和 IP 地址。此流程描述了如何为子流和 IP 地址更新每个连接限制,并在 MPTCP 连接中添加新的 IP 地址(端点)。

请注意,MPTCP 尚不支持为同一套接字混合 IPv6 和 IPv4 端点。使用属于同一地址系列的端点。

流程

  1. 将每个连接和 IP 地址限值设置为服务器上的 1:

    # ip mptcp limits set subflow 1

  2. 为客户端将每个连接和 IP 地址限值设置为 1

    # ip mptcp limits set subflow 1 add_addr_accepted 1

  3. 在服务器中添加 IP 地址 198.51.100.1 作为新的 MPTCP 端点:

    # ip mptcp endpoint add 198.51.100.1 dev enp1s0 signal

    重要

    您可以为 subflowbackupsignal 设置以下值。将标签设置为:

    • signal,在三方握手完成后发送 ADD_ADDR 数据包
    • subflow,由客户端发送 MP_JOIN SYN
    • backup,将端点设置为备份地址
  4. 使用 -k 参数启动服务器绑定到 0.0.0.0,以防止 ncat 在接受第一个连接后关闭监听套接字,并使服务器拒绝客户端完成的 MP_JOIN SYN

    # ncat -4 0.0.0.0 -k -l 4321

  5. 启动客户端并连接到服务器以交换流量。例如,这里的客户端将 "Hello world" 写入服务器 5 次,然后它终止连接。

    # ncat -4 192.0.2.1 4321
    Hello world 1
    Hello world 2
    Hello world 3
    Hello world 4
    Hello world 5

    Ctrl+D 退出。

验证步骤

  1. 验证连接和 IP 地址限制:

    # ip mptcp limit show

  2. 验证新添加的端点:

    # ip mptcp endpoint show

  3. 使用 tcpdump 捕获流量并检查 MPTCP 子选项的使用:

    # tcpdump -tnni interface tcp port 4321
    client Out IP 192.0.2.2.56868 > 192.0.2.1.4321: Flags [S], seq 3107783947, win 29200, options [mss 1460,sackOK,TS val 2568752336 ecr 0,nop,wscale 7,mptcp capable v1], length 0
    client In  IP 192.0.2.1.4321 > 192.0.2.2.56868: Flags [S.], seq 4222339923, ack 3107783948, win 28960, options [mss 1460,sackOK,TS val 1713130246 ecr 2568752336,nop,wscale 7,mptcp capable v1 {0xf51c07a47cc2ba75}], length 0
    client Out IP 192.0.2.2.56868 > 192.0.2.1.4321: Flags [.], ack 1, win 229, options [nop,nop,TS val 2568752336 ecr 1713130246,mptcp capable v1 {0xb243376cc5af60bd,0xf51c07a47cc2ba75}], length 0
    client Out IP 192.0.2.2.56868 > 192.0.2.1.4321: Flags [P.], seq 1:17, ack 1, win 229, options [nop,nop,TS val 2568752336 ecr 1713130246,mptcp capable v1 {0xb243376cc5af60bd,0xf51c07a47cc2ba75},nop,nop], length 16
    client In  IP 192.0.2.1.4321 > 192.0.2.2.56868: Flags [.], ack 17, win 227, options [nop,nop,TS val 1713130246 ecr 2568752336,mptcp add-addr id 1 198.51.100.1 hmac 0xe445335073818837,mptcp dss ack 5562689076006296132], length 0
    client Out IP 198.51.100.2.42403 > 198.51.100.1.4321: Flags [S], seq 3356992178, win 29200, options [mss 1460,sackOK,TS val 4038525523 ecr 0,nop,wscale 7,mptcp join backup id 0 token 0xad58df1 nonce 0x74a8137f], length 0
    client In  IP 198.51.100.1.4321 > 198.51.100.2.42403: Flags [S.], seq 1680863152, ack 3356992179, win 28960, options [mss 1460,sackOK,TS val 4213669942 ecr 4038525523,nop,wscale 7,mptcp join backup id 0 hmac 0x9eff7a1bf4e65937 nonce 0x77303fd8], length 0
    client Out IP 198.51.100.2.42403 > 198.51.100.1.4321: Flags [.], ack 1, win 229, options [nop,nop,TS val 4038525523 ecr 4213669942,mptcp join hmac 0xdfdc0129424f627ea774c094461328ce49d195bc], length 0
    client In  IP 198.51.100.1.4321 > 198.51.100.2.42403: Flags [.], ack 1, win 227, options [nop,nop,TS val 4213669942 ecr 4038525523,mptcp dss ack 5562689076006296132], length 0

    运行这个命令时需要 tcpdump 软件包。

其它资源

  • 有关可用端点标记的更多信息,请参阅 ip-mptcp(8) man page。

27.3. 在内核中禁用多路径 TCP

这个步骤描述了如何在内核中禁用 MPTCP 选项。

流程

  • 禁用 mptcp.enabled 选项。

    # echo "net.mptcp.enabled=0" > /etc/sysctl.d/90-enable-MPTCP.conf
    # sysctl -p /etc/sysctl.d/90-enable-MPTCP.conf

验证步骤

  • 验证 mptcp.enabled 是否在内核中被禁用。

    # sysctl -a | grep mptcp.enabled
    net.mptcp.enabled = 0