tcコマンドでqdiscを設定しネットワーク遅延や帯域制限を行う

linuxnetworkkubernetes

tc はカーネルがパケットをネットワークインタフェースに送る前にキューイングしてトラフィックを制御する qdisc (queueing discipline) を設定するコマンドあるいはサブシステム。Kubernetes CNI の bandwidth plugin も tc によって実現されており次の annotatiton によって Pod の帯域を制限できる。

annotations:
  kubernetes.io/ingress-bandwidth: 1M
  kubernetes.io/egress-bandwidth: 1M

Amazon Linux 2023 の t2.micro EC2 インスタンスで実行してみる。

$ ip link
...
2: enX0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP mode DEFAULT group default qlen 1000

$ sudo yum -y install iproute-tc
$ tc -json qdisc show dev enX0 | jq
[
  {
    "kind": "fq_codel",
    "handle": "0:",
    "root": true,
    "refcnt": 2,
    "options": {
      "limit": 10240,
      "flows": 1024,
      "quantum": 9015,
      "target": 4999,
      "interval": 99999,
      "memory_limit": 33554432,
      "ecn": true,
      "drop_batch": 64
    }
  }
]

fq_codel は systemd を使う OS やルーターのファームウェアなどで広く使われているアルゴリズムで、トラフィックがバーストしたとしてもキューの最小遅延時間が options の target になるように制御する。limit はパケットの上限、memory_limit はバイト数の上限となっており、これらを超過すると以後のパケットは捨てられる。handle は parent を指定するときに使われる qdisc の識別子。

netem (Network Emulator) で遅延を発生させ、tbf (Token Bucket Filter) で帯域を制限してみる。

$ sudo tc qdisc add dev enX0 root handle 1: netem delay 100ms
$ sudo tc qdisc add dev enX0 parent 1: tbf rate 50mbit burst 512kbit latency 400ms
$ tc -json qdisc show dev enX0 | jq
[
  {
    "kind": "netem",
    "handle": "1:",
    "root": true,
    "refcnt": 2,
    "options": {
      "limit": 1000,
      "delay": {
        "delay": 0.1,
        "jitter": 0,
        "correlation": 0
      },
      "ecn": false,
      "gap": 0
    }
  },
  {
    "kind": "tbf",
    "handle": "800b:",
    "parent": "1:",
    "options": {
      "rate": 6250000,
      "burst": 65531,
      "lat": 400000
    }
  }
]

他のインスタンスと iperf や ping で通信することで帯域制限と遅延がはたらいていることが確認できる。tbf の burst が少ないと途中で Transfer が 0 になってしまったので増やした。

# iperf3 -s # another instance

$ sudo yum install -y iperf3
$ iperf3 -c 172.31.25.78
Connecting to host 172.31.25.78, port 5201
[  5] local 172.31.16.172 port 51834 connected to 172.31.25.78 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  5.50 MBytes  46.1 Mbits/sec    0   1.11 MBytes
[  5]   1.00-2.00   sec  5.38 MBytes  45.1 Mbits/sec    0   1.41 MBytes
[  5]   2.00-3.00   sec  6.75 MBytes  56.6 Mbits/sec    0   1.70 MBytes
[  5]   3.00-4.00   sec  5.38 MBytes  45.1 Mbits/sec    0   2.00 MBytes
[  5]   4.00-5.00   sec  6.62 MBytes  55.6 Mbits/sec    0   2.30 MBytes
[  5]   5.00-6.00   sec  5.50 MBytes  46.2 Mbits/sec    0   2.59 MBytes
[  5]   6.00-7.00   sec  5.25 MBytes  44.0 Mbits/sec    0   2.88 MBytes
[  5]   7.00-8.00   sec  6.62 MBytes  55.6 Mbits/sec    0   3.16 MBytes
[  5]   8.00-9.00   sec  5.25 MBytes  44.0 Mbits/sec    0   3.16 MBytes
[  5]   9.00-10.00  sec  6.50 MBytes  54.5 Mbits/sec    0   3.16 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  58.8 MBytes  49.3 Mbits/sec    0             sender
[  5]   0.00-10.50  sec  58.5 MBytes  46.7 Mbits/sec                  receiver

$ ping 172.31.25.78
PING 172.31.25.78 (172.31.25.78) 56(84) bytes of data.
64 bytes from 172.31.25.78: icmp_seq=1 ttl=127 time=101 ms
64 bytes from 172.31.25.78: icmp_seq=2 ttl=127 time=100 ms
64 bytes from 172.31.25.78: icmp_seq=3 ttl=127 time=100 ms

qdisc を削除すると元に戻る。

$ sudo tc qdisc del dev enX0 root
$ ping 172.31.25.78
PING 172.31.25.78 (172.31.25.78) 56(84) bytes of data.
64 bytes from 172.31.25.78: icmp_seq=1 ttl=127 time=0.461 ms
64 bytes from 172.31.25.78: icmp_seq=2 ttl=127 time=0.476 ms
64 bytes from 172.31.25.78: icmp_seq=3 ttl=127 time=0.626 ms

参考

tcコマンドでNetworkの帯域と遅延を制御してみてみた - Qiita

How to Use the Linux Traffic Control

Chapter 32. Linux traffic control Red Hat Enterprise Linux 9 | Red Hat Customer Portal