2. TC核心对象与命令体系
Linux TC(Traffic Control)并不是一个单一命令,而是一套围绕“对象”组织起来的流量控制框架。理解 TC 的关键,是先分清四个核心对象:qdisc(排队规则)、class(类)、filter(过滤器)和action(动作)。它们之间存在明确的挂载与引用关系,而不是彼此独立的配置项。只有先建立对象模型,才能正确写出 tc 命令,并在排障时知道该查哪一层。
一、四个核心对象的概念模型
qdisc 是 TC 的基本调度单元,挂载在网络设备的某个方向上。每个网卡默认存在一个根 qdisc(root qdisc),例如 pfifo_fast 或 noqueue。qdisc 分为两类:无类 qdisc(如 pfifo、fq_codel、tbf)和可分类 qdisc(如 htb、hfsc、prio)。无类 qdisc 只做整体排队与调度;可分类 qdisc 内部可以再挂载 class,形成层级结构。
class 只存在于可分类 qdisc 内部,用于把流量划分成不同类别,并分别施加带宽、速率、优先级等参数。class 可以继续嵌套 class,形成树状层级。例如 HTB 中,根 class 下可以再分多个子 class,每个子 class 拥有独立的 rate 和 ceil。
filter 负责“把报文分到哪个 class”。它挂载在 qdisc 或 class 上,通过匹配条件(如 IP、端口、TOS、fwmark)决定报文进入哪个 class。filter 是分类决策点,没有 filter,可分类 qdisc 就无法把流量导向不同 class。
action 是 filter 匹配后可以执行的附加操作,例如 drop、mirred、police、gact 等。action 让 TC 不仅能“分类”,还能“处置”,例如限速丢弃、镜像到另一网卡、修改标记等。
二、tc 命令语法与对象管理方法
tc 命令的基本语法为:tc [ OPTIONS ] OBJECT { COMMAND | help }。其中 OBJECT 可以是 qdisc、class、filter、action 等;COMMAND 通常是 add、del、change、replace、show 等。所有对象都通过 dev 指定网络设备,通过 parent 指定父对象,通过 handle 指定自身标识。
下面以 HTB 为例,给出一组可直接参考的示例命令。假设在 eth0 出方向建立根 qdisc,handle 为 1:,并创建两个子 class:
# 1. 挂载根 qdisc(可分类 HTB)
tc qdisc add dev eth0 root handle 1: htb default 20
# 2. 创建根 class 1:1,限定总带宽
tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit
# 3. 创建子 class 1:10 和 1:20
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30mbit ceil 60mbit
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 50mbit ceil 100mbit
# 4. 为子 class 挂载叶子 qdisc(可选,用于精细排队)
tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
# 5. 添加 filter,把 80 端口流量分到 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 1 \
u32 match ip dport 80 0xffff flowid 1:10
# 6. 查看对象
tc qdisc show dev eth0
tc class show dev eth0
tc filter show dev eth0
这组命令体现了 TC 对象管理的核心逻辑:先建 qdisc,再建 class,然后挂 filter,最后按需加 action。每一步都依赖上一步的 handle 或 classid。如果顺序颠倒,例如先加 filter 再建 class,filter 会因找不到目标 class 而失败。
三、对象标识与定位规则
TC 中每个对象都有唯一标识。qdisc 和 class 使用 handle 或 classid,格式为 主号:次号,例如 1:、1:1、1:10。filter 使用 prio 表示优先级,数值越小越先匹配。action 则通过 filter 的 action 子句挂载。
parent 的写法需要特别注意:根 qdisc 的 parent 是 root;class 的 parent 是所属 qdisc 或父 class 的 handle;filter 的 parent 通常是 qdisc 的 handle 加 :0,例如 parent 1:0。如果 parent 写错,命令会报 “Cannot find device” 或 “Parent Qdisc doesn't exist” 之类的错误。
tc qdisc show dev eth0 和 tc class show dev eth0 可以快速确认当前对象树。
四、对象生命周期与常用管理命令
TC 对象支持增、删、改、查四类操作。新增用 add,删除用 del,修改用 change,替换用 replace,查看用 show。删除 qdisc 时,其下挂的 class、filter 会一并删除;删除 class 时,其子 class 和挂载的 qdisc 也会被清理。因此删除操作通常从叶子向根进行,或者直接删除根 qdisc 以清空整棵树。
| 操作 | 命令示例 | 说明 |
|---|---|---|
| 新增 qdisc | tc qdisc add dev eth0 root handle 1: htb |
在 eth0 出方向挂载根 HTB |
| 新增 class | tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit |
在 1: 下创建 1:1 |
| 新增 filter | tc filter add dev eth0 parent 1:0 u32 match ip dport 80 0xffff flowid 1:10 |
把 80 端口流量指向 1:10 |
| 修改 class | tc class change dev eth0 classid 1:10 htb rate 40mbit |
调整 1:10 的速率 |
| 删除 qdisc | tc qdisc del dev eth0 root |
清空整棵对象树 |
| 查看统计 | tc -s qdisc show dev eth0 |
显示队列统计与丢包计数 |