32.7. 使用 tc-ctinfo 工具配置数据包的速率限制

您可以使用速率限制来限制网络流量,并防止网络中资源耗尽。通过速率限制,您还可以通过限制特定时间段内重复的数据包请求来减少服务器上的负载。另外,您可以通过使用 tc-ctinfo 工具在内核中配置流量控制来管理带宽率。

连接跟踪条目存储 Netfilter 标记和连接信息。当路由器转发来自防火墙的数据包时,路由器会删除或修改数据包的连接跟踪条目。连接跟踪信息(ctinfo)模块将数据从连接跟踪标记检索到各个字段。此内核模块通过将 Netfilter 标记复制到套接字缓冲区(skb)标记元数据字段来保留 Netfilter 标记。

先决条件

  • iperf3 工具安装在服务器和客户端上。

步骤

  1. 在服务器上执行以下步骤:

    1. 在网络接口中添加一个虚拟链接:

      # ip link add name ifb4eth0 numtxqueues 48 numrxqueues 48 type ifb

      这个命令有以下参数:

      name ifb4eth0
      设置新的虚拟设备接口。
      numtxqueues 48
      设置传输队列的数量。
      numrxqueues 48
      设置接收队列的数量。
      type ifb
      设置新设备的类型。
    2. 更改接口的状态:

      # ip link set dev ifb4eth0 up
    3. 在物理网络接口上添加 qdisc 属性,并将其应用到传入流量:

      # tc qdisc add dev enp1s0 handle ffff: ingress

      handle ffff: 选项中,handle 参数将主号 ffff: 作为默认值分配给 enp1s0 物理网络接口上的类 qdisc,其中 qdisc 是一个分析流量控制的排队规则参数。

    4. ip 协议的物理接口上添加一个过滤器,以对数据包进行分类:

      # tc filter add dev enp1s0 parent ffff: protocol ip u32 match u32 0 0 action ctinfo cpmark 100 action mirred egress redirect dev ifb4eth0

      这个命令有以下属性:

      parent ffff:
      为父 qdisc 设置主号 ffff:
      u32 match u32 0 0
      设置 u32 过滤器,以 匹配 u32 模式的 IP 标头。第一个 0 表示 IP 标头的第二个字节,另一个 0 用于掩码匹配,告知过滤器要匹配哪个位。
      action ctinfo
      设置操作,以将连接跟踪标记的数据检索到各个字段。
      cpmark 100
      将连接跟踪标记(connmark) 100 复制到数据包 IP 标头字段中。
      action mirred egress redirect dev ifb4eth0
      设置 action mirred,来将接收的数据包重定向到 ifb4eth0 目的接口。
    5. 向接口中添加类 qdisc

      # tc qdisc add dev ifb4eth0 root handle 1: htb default 1000

      此命令将主号 1 设置为 root qdisc,并将 htb 层次结构令牌存储桶与 minor-id 1000 的类 qdisc 一起使用。

    6. 将接口上的流量限制为 1 Mbit/s,上限为 2 Mbit/s:

      # tc class add dev ifb4eth0 parent 1:1 classid 1:100 htb ceil 2mbit rate 1mbit prio 100

      这个命令有以下参数:

      parent 1:1
      parent 设为 classid1,将 root 设为 1
      classid 1:100
      classid 设置为 1:100,其中 1 是父 qdisc 的数量,100 是父 qdisc 的类的数量。
      htb ceil 2mbit
      htbqdisc 允许上限带宽 2 Mbit/s 作为 ceil 速率限制。
    7. 将无类别 qdisc 的 Stochastic Fairness Queuing (sfq)应用到 时间间隔为 60 秒的接口,以减少队列算法的影响:

      # tc qdisc add dev ifb4eth0 parent 1:100 sfq perturb 60
    8. 在接口中添加防火墙标记(fw)过滤器:

      # tc filter add dev ifb4eth0 parent 1:0 protocol ip prio 100 handle 100 fw classid 1:100
    9. 从连接标记(CONNMARK)恢复数据包元标记:

      # nft add rule ip mangle PREROUTING counter meta mark set ct mark

      在这个命令中,nft 工具有一个带有 PREROUTING 链规则规范的 mangle 表,该表在路由之前更改传入的数据包,来将数据包标记替换为 CONNMARK

    10. 如果没有 nft 表和链存在,请创建一个表并添加一个链规则:

      # nft add table ip mangle
      # nft add chain ip mangle PREROUTING {type filter hook prerouting priority mangle \;}
    11. 在指定目标地址 192.0.2.3 上接收的 tcp 数据包上设置 meta 标记:

      # nft add rule ip mangle PREROUTING ip daddr 192.0.2.3 counter meta mark set 0x64
    12. 将数据包标记保存到连接标记中:

      # nft add rule ip mangle PREROUTING counter ct mark set mark
    13. 使用 -s 参数在系统上运行 iperf3 工具来作为服务器,然后服务器等待客户端连接的响应:

      # iperf3 -s
  2. 在客户端上,将 iperf3 作为客户端运行,并连接到在 IP 地址 192.0.2.3 上侦听定期的 HTTP 请求响应时间戳的服务器:

    # iperf3 -c 192.0.2.3 -t TCP_STREAM | tee rate

    192.0.2.3 是服务器的 IP 地址,而 192.0.2.4 是客户端的 IP 地址。

  3. Ctrl+C 终止服务器上的 iperf3 工具:

    Accepted connection from 192.0.2.4, port 52128
    [5]  local 192.0.2.3 port 5201 connected to 192.0.2.4 port 52130
    [ID] Interval       	Transfer 	Bitrate
    [5]   0.00-1.00   sec   119 KBytes   973 Kbits/sec
    [5]   1.00-2.00   sec   116 KBytes   950 Kbits/sec
    ...
    [ID] Interval       	Transfer 	Bitrate
    [5]   0.00-14.81  sec  1.51 MBytes   853 Kbits/sec  receiver
    
    iperf3: interrupt - the server has terminated
  4. Ctrl+C 终止客户端上的 iperf3 工具:

    Connecting to host 192.0.2.3, port 5201
    [5] local 192.0.2.4 port 52130 connected to 192.0.2.3 port 5201
    [ID] Interval       	Transfer 	Bitrate     	Retr  Cwnd
    [5]   0.00-1.00   sec   481 KBytes  3.94 Mbits/sec	0   76.4 KBytes
    [5]   1.00-2.00   sec   223 KBytes  1.83 Mbits/sec	0   82.0 KBytes
    ...
    [ID] Interval       	Transfer 	Bitrate     	Retr
    [5]   0.00-14.00  sec  3.92 MBytes  2.35 Mbits/sec   32     sender
    [5]   0.00-14.00  sec  0.00 Bytes  0.00 bits/sec            receiver
    
    iperf3: error - the server has terminated

验证

  1. 显示接口上 htbsfq 类的数据包计数的统计信息:

    # tc -s qdisc show dev ifb4eth0
    
    qdisc htb 1: root
    ...
     Sent 26611455 bytes 3054 pkt (dropped 76, overlimits 4887 requeues 0)
    ...
    qdisc sfq 8001: parent
    ...
     Sent 26535030 bytes 2296 pkt (dropped 76, overlimits 0 requeues 0)
    ...
  2. 显示 mirredctinfo 操作的数据包计数的统计信息:

    # tc -s filter show dev enp1s0 ingress
    filter parent ffff: protocol ip pref 49152 u32 chain 0
    filter parent ffff: protocol ip pref 49152 u32 chain 0 fh 800: ht divisor 1
    filter parent ffff: protocol ip pref 49152 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 terminal flowid not_in_hw (rule hit 8075 success 8075)
      match 00000000/00000000 at 0 (success 8075 )
        action order 1: ctinfo zone 0 pipe
          index 1 ref 1 bind 1 cpmark 0x00000064 installed 3105 sec firstused 3105 sec DSCP set 0 error 0
          CPMARK set 7712
        Action statistics:
        Sent 25891504 bytes 3137 pkt (dropped 0, overlimits 0 requeues 0)
        backlog 0b 0p requeues 0
    
        action order 2: mirred (Egress Redirect to device ifb4eth0) stolen
           index 1 ref 1 bind 1 installed 3105 sec firstused 3105 sec
        Action statistics:
        Sent 25891504 bytes 3137 pkt (dropped 0, overlimits 61 requeues 0)
        backlog 0b 0p requeues 0
  3. 显示 htb 速率限制器及其配置的统计信息:

    # tc -s class show dev ifb4eth0
    class htb 1:100 root leaf 8001: prio 7 rate 1Mbit ceil 2Mbit burst 1600b cburst 1600b
     Sent 26541716 bytes 2373 pkt (dropped 61, overlimits 4887 requeues 0)
     backlog 0b 0p requeues 0
     lended: 7248 borrowed: 0 giants: 0
     tokens: 187250 ctokens: 93625

其他资源

  • tc(8)tc-ctinfo(8) 手册页
  • nft(8) 手册页