3. TC 限速常用命令详解

TC(Traffic Control)是 Linux 内核提供的流量控制工具,通过三种核心对象——qdisc(队列规则)、class(类)和filter(过滤器)——实现精细化的带宽管理。每个对象都支持 add、del、change、show 四种操作。本章逐一拆解这些命令的语法、参数含义和实战用法。

3.1 命令体系总览

三条命令的通用结构如下:

tc [qdisc | class | filter] [ add | del | change | show ] [dev 网卡名] [参数...]

下表对比了三种对象的核心差异:

对象 作用层级 核心参数 典型场景
qdisc 网卡根节点或类子节点 root、handle、parent 设置根队列规则(如 htb、pfifo_fast)
class qdisc 下的子分支 classid、parent、rate、ceil 划分带宽层级,分配保障速率和最大速率
filter 挂载在 qdisc 或 class 上 parent、protocol、prio、u32 match 按 IP、端口、协议等条件匹配流量到指定 class
操作记忆口诀:“qdisc 管队列,class 分带宽,filter 做匹配;add 创建,del 删除,change 修改,show 查看。”

3.2 tc qdisc 命令详解

qdisc 是流量进入网卡后的第一个处理节点。根 qdisc 必须绑定在 root 上,子 qdisc 挂载在 class 下。

3.2.1 添加根 qdisc

# 添加 HTB 根队列,默认 handle 1:0
tc qdisc add dev eth0 root handle 1: htb default 30

# 参数说明:
#   dev eth0       —— 目标网卡
#   root           —— 根节点
#   handle 1:      —— 队列句柄(1:0 可简写为 1:)
#   htb            —— 队列算法(Hierarchical  Bucket)
#   default 30     —— 未匹配 filter 的流量默认进入 class 1:30

3.2.2 删除 qdisc

# 删除 eth0 上的根 qdisc(会级联删除所有子 class 和 filter)
tc qdisc del dev eth0 root

# 删除指定 handle 的 qdisc
tc qdisc del dev eth0 parent 1:1 handle 10: htb
⚠ 删除风险:删除根 qdisc 会清空该网卡上所有 TC 规则,生产环境操作前务必执行 tc qdisc show dev eth0 确认现有规则。

3.2.3 修改 qdisc 参数

# 修改根 qdisc 的 default 值
tc qdisc change dev eth0 root handle 1: htb default 50

# 注意:change 只能修改部分运行时参数,不能改变队列算法类型

3.2.4 查看 qdisc

# 查看所有网卡的 qdisc
tc qdisc show

# 查看指定网卡
tc qdisc show dev eth0

# 查看详细统计(包含丢包、超限等)
tc -s qdisc show dev eth0
qdisc 操作流程与层级关系 网卡 eth0 根 qdisc (handle 1:) class 1:10 (rate 10M) class 1:20 (rate 20M) class 1:30 (default) 常用操作命令 添加:tc qdisc add dev eth0 root handle 1: htb default 30 删除:tc qdisc del dev eth0 root

3.3 tc class 命令详解

class 必须在已有 qdisc 下创建,用于划分带宽子通道。每个 class 通过 classid 唯一标识,格式为 主编号:子编号。

3.3.1 添加 class

# 在根 qdisc 1: 下创建三个子类
tc class add dev eth0 parent 1: classid 1:10 htb rate 10mbit ceil 20mbit
tc class add dev eth0 parent 1: classid 1:20 htb rate 20mbit ceil 30mbit
tc class add dev eth0 parent 1: classid 1:30 htb rate 5mbit  ceil 10mbit

# 参数说明:
#   parent 1:       —— 父节点为根 qdisc
#   classid 1:10    —— 本类 ID
#   rate            —— 保障带宽
#   ceil            —— 最大带宽(允许突发借用)

3.3.2 删除 class

# 删除指定 class(必须先删除其下的子 qdisc 和 filter)
tc class del dev eth0 classid 1:20

# 注意:如果 class 下有子 qdisc 或子类,必须先清理下级对象

3.3.3 修改 class

# 修改 class 的带宽参数
tc class change dev eth0 classid 1:10 htb rate 15mbit ceil 25mbit

# 限制:不能修改 parent 和 classid,只能调整 rate/ceil/burst 等参数

3.3.4 查看 class

# 查看所有 class
tc class show dev eth0

# 查看带统计信息的 class
tc -s class show dev eth0
📊 统计字段解读:
Sent —— 已发送字节数/包数
rate —— 当前瞬时速率
dropped —— 因超限丢弃的包数(回滚验证的关键指标)

3.4 tc filter 命令详解

filter 决定流量进入哪个 class。最常用的是 u32 匹配器,支持按 IP、端口、协议等字段过滤。

3.4.1 添加 filter

# 将源 IP 192.168.1.100 的流量匹配到 class 1:10
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
  match ip src 192.168.1.100/32 flowid 1:10

# 将目标端口 80 的流量匹配到 class 1:20
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 \
  match ip dport 80 0xffff flowid 1:20

# 参数说明:
#   parent 1:       —— 挂载到根 qdisc
#   protocol ip     —— 只匹配 IP 包
#   prio            —— 优先级(数字越小越优先)
#   u32             —— 匹配器类型
#   match ip src    —— 匹配源 IP
#   flowid          —— 目标 class ID

3.4.2 删除 filter

# 删除指定 parent 和 prio 的 filter
tc filter del dev eth0 parent 1: prio 1

# 删除所有 filter(谨慎使用)
tc filter del dev eth0 parent 1:

3.4.3 修改 filter

# filter 不支持直接 change,需要先删除再添加
# 错误示例(会报错):
# tc filter change dev eth0 parent 1: prio 1 u32 match ip src 10.0.0.1/32 flowid 1:30

# 正确做法:
tc filter del dev eth0 parent 1: prio 1
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
  match ip src 10.0.0.1/32 flowid 1:30

3.4.4 查看 filter

# 查看所有 filter
tc filter show dev eth0

# 查看指定 parent 的 filter
tc filter show dev eth0 parent 1:
filter 匹配流程与 class 映射 入口流量 根 qdisc 1: filter 链 prio 1: src IP 匹配 prio 2: dport 80 匹配 class 1:10 class 1:20 未匹配任何 filter 的流量 → 进入 default class(如 1:30) default 值在添加根 qdisc 时指定:tc qdisc add ... htb default 30 filter 操作要点 添加:tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ... 删除:tc filter del dev eth0 parent 1: prio 1

3.5 命令组合实战示例

以下是一个完整的“创建 → 查看 → 修改 → 删除”闭环示例:

# 1. 创建根 qdisc
tc qdisc add dev eth0 root handle 1: htb default 30

# 2. 创建三个 class
tc class add dev eth0 parent 1: classid 1:10 htb rate 10mbit ceil 20mbit
tc class add dev eth0 parent 1: classid 1:20 htb rate 20mbit ceil 30mbit
tc class add dev eth0 parent 1: classid 1:30 htb rate 5mbit  ceil 10mbit

# 3. 添加 filter
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
  match ip src 192.168.1.100/32 flowid 1:10
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 \
  match ip dport 80 0xffff flowid 1:20

# 4. 查看当前配置
tc -s qdisc show dev eth0
tc -s class show dev eth0
tc filter show dev eth0

# 5. 修改 class 带宽(回滚场景常用)
tc class change dev eth0 classid 1:10 htb rate 5mbit ceil 10mbit

# 6. 删除 filter 并重新添加
tc filter del dev eth0 parent 1: prio 1
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
  match ip src 10.0.0.1/32 flowid 1:30

# 7. 清理全部规则
tc qdisc del dev eth0 root
💡 回滚验证要点:在修改 class 或 filter 前后,使用 tc -s class show dev eth0 对比 dropped 和 rate 字段,确认限速策略是否按预期生效。这是后续章节“回滚验证”的核心操作基础。

3.6 常见错误与排查

错误信息 原因 解决方法
RTNETLINK answers: No such file or directory 指定的 parent 或 classid 不存在 先执行 tc qdisc show 确认现有节点
RTNETLINK answers: Invalid argument 参数值超出范围或语法错误 检查 rate/ceil 单位(mbit/kbit),确认 handle 格式
RTNETLINK answers: File exists 重复添加相同的 handle 或 classid 使用 change 修改或先 del 再 add
filter 不生效 prio 冲突或 protocol 不匹配 检查 prio 唯一性,确认 protocol ip 与流量类型一致
⚠ 生产环境建议:在执行 del 操作前,务必使用 tc qdisc show dev eth0 和 tc filter show dev eth0 备份当前规则。批量删除时,建议逐级删除(先 filter → 再 class → 最后 qdisc),避免因依赖关系导致删除失败。