2026/08/31

tc (traffic control) in linux

tc(traffic control)是 Linux 裡用來做網路流量控制(QoS, Quality of Service)的工具。可針對網路卡,進行限速(rate limiting)、排程(traffic scheduling)、優先權控制(priority)、模擬網路狀況(延遲、丟包、抖動)、封包分類與整形(shaping)的網路封包控制。主要用途是用來模擬網際網路的封包狀況。

流量控制方式

  • shaping

    當流量被shaping限制後,它的傳輸速率就被控制在某個值以下。限制值可以遠小於有效頻寬,這樣可以平滑突發的資料流量,使網路更爲穩定。shaping(限制)只適用於向外的流量。shaping 只能用在 egress 對外的資料輸出。

  • scheduling

    通過調度封包的傳輸,可以在頻寬範圍內,按照優先等級分配頻寬。scheduling 只能用在 egress 對外的資料輸出。

  • policing

    shaping用於處理 egress 對外的流量,而 policing 用於處理 ingress 接收到的流量。

  • dropping

    如果流量超過某個設定的頻寬,就丟棄資料,可用在 egress 及 ingress。

主要元件

  1. qdisc (Queueing Discipline)

    佇列規則,決定封包排隊的送出規則。當kernel需要通過某個網絡port發送資料,它都需要按照爲這個port配置的qdisc排隊規則,把資料加入queue。然後kernel會儘可能地從qdisc裏面取出資料,交給網絡適配器驅動模塊。最簡單的qdisc是 pfifo,它不對進入的封包做任何的處理,採用先入先出的方式通過隊列。不過,它會暫存網絡接口短時間內無法處理的封包。

    常見的 qdisc:

    • pfifo_fast(預設)

    • htb(常用做限速)

    • fq_codel(改善 bufferbloat)

    • netem(模擬網路)

  2. class

    在 qdisc 底下建立不同流量分類,用來分配不同頻寬。不同的類別中可以包含更深入的QDisc(排隊規則),通過這些細分的QDisc還可以爲進入的隊列的封包排隊。通過設置各種類別封包的離隊次序,QDisc可以設定網路數據流量的優先等級。

  3. filter, policy 過濾器

    用來把封包分類到不同 class,決定它們按照何種QDisc進入隊列。分類的方法可以有多種,使用fileter(過濾器)就是其中之一。使用filter(過濾器)分類時,kernel會呼叫附屬於這個 class 的所有過濾器,直到回傳一個判決。如果沒有判決返回,就作進一步的處理,而處理方式和QDISC有關。filter(過濾器)是放在QDisc內部。

指令

tc [OPTIONS] OBJECT COMMAND

常見 OBJECT:

  • qdisc

  • class

  • filter

指令內可使用的資料單位

  • 頻寬或流量單位

    kbps
    mbps
    kbit
    mbit
    bps
  • 資料單位

    kb
    mb
    mbit
    kbit
    b
  • 時間

    s/sec/secs
    ms/msec/msecs
    us/usec/usecs

options

-s, -stats, -statistics: output more statistics about packet usage.
-d, -details: output more detailed information about rates and cell sizes.
-r, -raw: output raw hex values for handles.
-p, -pretty: decode filter offset and mask values to equivalent filter commands based on TCP/IP.
-iec: print rates in IEC units (ie. 1K = 1024).

Examples

tc 通常是控制 egress 的流量

查看設定

tc -s qdisc show dev eth0
tc class show dev eth0
tc filter show dev eth0
# tc -s qdisc show dev enp1s0
qdisc mq 0: root
 Sent 220264 bytes 431 pkt (dropped 0, overlimits 0 requeues 2)
 backlog 0b 0p requeues 2
qdisc fq_codel 0: parent :4 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
 Sent 20103 bytes 107 pkt (dropped 0, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0
  maxpacket 0 drop_overlimit 0 new_flow_count 0 ecn_mark 0
  new_flows_len 0 old_flows_len 0
qdisc fq_codel 0: parent :3 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
 Sent 43974 bytes 148 pkt (dropped 0, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0
  maxpacket 0 drop_overlimit 0 new_flow_count 0 ecn_mark 0
  new_flows_len 0 old_flows_len 0
qdisc fq_codel 0: parent :2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
 Sent 146267 bytes 124 pkt (dropped 0, overlimits 0 requeues 2)
 backlog 0b 0p requeues 2
  maxpacket 8925 drop_overlimit 0 new_flow_count 1 ecn_mark 0
  new_flows_len 0 old_flows_len 0
qdisc fq_codel 0: parent :1 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
 Sent 9920 bytes 52 pkt (dropped 0, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0
  maxpacket 0 drop_overlimit 0 new_flow_count 0 ecn_mark 0
  new_flows_len 0 old_flows_len 0
# tc -d qdisc show dev enp1s0
qdisc mq 0: root
qdisc fq_codel 0: parent :4 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
qdisc fq_codel 0: parent :3 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
qdisc fq_codel 0: parent :2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
qdisc fq_codel 0: parent :1 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
  • qdisc mq 0: root

    根節點 mq : multi-queue

    代表你的硬體網路卡有多個傳輸佇列(在這個例子中是 4 個,分別對應 parent :1:4)。通常發生在多核心 CPU 的伺服器上,系統會將網路流量分散到不同的 CPU 核心處理,以提升效能

  • fq_codel (Fair Queuing Controlled Delay)

    這是目前 Linux 系統非常推薦的排隊規則,它由兩個部分組成

    • FQ (Fair Queuing):確保每個「連線」(Flow)都能公平分配頻寬。例如,即使有人在下載大檔案,你的網頁瀏覽或視訊通話依然能順暢通過。

    • CoDel (Controlled Delay):這是一個智慧演算法,當它發現緩衝區(Buffer)塞車太久時,會主動丟棄封包或標記 ECN,強制降低延遲,解決「緩衝區膨脹」問題。

  • 以其中一個 fq_codel 為例:

    • limit 10240p: 佇列中最多可以存放 10,240 個封包。

    • flows 1024: 它最多可以同時追蹤並隔離 1024 個不同的連線。

    • target 5ms / interval 100ms: 這是 CoDel 的核心參數。它會嘗試將延遲控制在 5ms 以內;如果延遲超過這個數值持續 100ms,它就會開始干預流量。

    • ecn: 支援顯式擁塞通知。當網路塞車時,它會通知發送端減速,而不是直接丟棄封包。

  • -s 統計

    Sent 146267 bytes 124 pkt (dropped 0, overlimits 0 requeues 2)

    • Sent: 該佇列目前傳送的資料量與封包數。

    • dropped 0: 這是一個好現象。 代表目前沒有封包因為塞車而被強制丟棄。

    • requeues 2: 封包重新排隊的次數。通常發生在硬體驅動程式暫時無法處理封包時(例如網路卡發送視窗滿了),這在正常運作下是偶爾會發生的。

    • new_flow_count 1: 代表自從統計開始以來,有一個「新連線」被偵測到。fq_codel 會優先處理新連線(互動式流量),以保證反應速度。

刪除設定

清除所有設定

tc qdisc del dev eth0 root

備份/還原完整設定

# 備份
tc -dump qdisc show dev eth0 > tc-backup.txt
tc -dump class show dev eth0 >> tc-backup.txt
tc -dump filter show dev eth0 >> tc-backup.txt

# 還原前先清空
tc qdisc del dev eth0 root
tc qdisc del dev eth0 ingress
tc -batch tc-backup.txt

完整備份所有網卡

tc -dump qdisc show > tc-all.txt
tc -dump class show >> tc-all.txt
tc -dump filter show >> tc-all.txt

# 還原
tc -batch tc-all.txt

限制整個網卡頻寬

限制 eth0 最大 1Mbps

tc qdisc add dev eth0 root tbf rate 1mbit burst 32kbit latency 400ms
  • tbf = Token Bucket Filter(簡單限速)

  • rate = 頻寬

  • burst = 突發流量

  • latency = 最大延遲

使用 HTB 做分流

# 建立 root qdisc
tc qdisc add dev eth0 root handle 1: htb default 30

# 建立 class 做頻寬分配
tc class add dev eth0 parent 1: classid 1:1 htb rate 10mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 2mbit
1: (root)
 └── 1:1 (10mbit)
      ├── 1:10 (5mbit)
      └── 1:20 (2mbit)

依 IP 分流

ex

192.168.1.100 → 5Mbps
其他 → 2Mbps
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
match ip dst 192.168.1.100 flowid 1:10

模擬網路延遲

增加 100ms 延遲

tc qdisc add dev eth0 root netem delay 100ms

模擬丟包

10% 封包丟失

tc qdisc add dev eth0 root netem loss 10%

延遲 + 抖動 + 丟包

tc qdisc add dev eth0 root netem delay 100ms 20ms loss 5%
  • 100ms = 基本延遲

  • 20ms = 抖動(jitter)

  • loss 5% = 丟包

控制 ingress

tc qdisc add dev eth0 handle ffff: ingress

ingress shaping ifb

tc 原生只能控制 egress(送出流量) ,要控制 ingress(進來的流量),就要「轉送」到 ifb 再做 shaping

eth0 (ingress)
   ↓ redirect
ifb0 (egress)
   ↓ tc 控制

限制下載速度(ingress 10Mbps)

# 載入 ifb 模組
modprobe ifb

# 指定數量
modprobe ifb numifbs=1

# 啟用 ifb0
ip link add ifb0 type ifb
ip link set dev ifb0 up

# 在 eth0 加 ingress qdisc
tc qdisc add dev eth0 handle ffff: ingress

# 把 ingress 流量導到 ifb0
# mirred = mirror/redirect
tc filter add dev eth0 parent ffff: protocol ip u32 \
match u32 0 0 action mirred egress redirect dev ifb0

# 在 ifb0 上做限速
tc qdisc add dev ifb0 root tbf rate 10mbit burst 32k latency 400ms

# show
tc -s qdisc show dev ifb0

clear

tc qdisc del dev eth0 ingress
tc qdisc del dev ifb0 root
ip link delete ifb0

不同 IP 不同下載速度

ex

192.168.1.100 → 5 Mbps
其他 → 2 Mbps

用 HTB

tc qdisc add dev ifb0 root handle 1: htb default 20

tc class add dev ifb0 parent 1: classid 1:1 htb rate 10mbit

tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 5mbit
tc class add dev ifb0 parent 1:1 classid 1:20 htb rate 2mbit

# filter 分流
# ingress → ifb 後.  source IP 才是外部來源 IP
tc filter add dev ifb0 protocol ip parent 1: prio 1 u32 \
match ip src 192.168.1.100 flowid 1:10

note: ingress 只能有一個 qdisc

References

程式扎記: [Linux 文章收集] TC 入門 (traffic control)

TC (Traffic Control) - HackMD

沒有留言:

張貼留言