tc 是 traffic control(流量控制)的缩写,它是 Linux 内核中 Netfilter 和 网络队列 discipline (qdisc) 框架下的一个命令行工具,它的功能远不止限速,而是一个复杂的网络流量整形和管理的“瑞士军刀”。

tc 是什么?为什么需要它?
想象一下,你家里的网络带宽是一条高速公路,你的所有网络应用(网页、下载、视频、游戏)都在这条路上行驶。
- 没有
tc的情况:所有应用都“自由竞争”车道,如果你的电脑正在用迅雷下载一个大文件(一个“重型卡车”),它可能会占满整条路,导致你看视频(一辆“小轿车”)卡顿,或者玩游戏(一辆“救护车”)延迟极高。 - 使用
tc的情况:你可以扮演“交通警察”,用tc来制定交通规则。- 限速:规定迅雷下载不能超过 10MB/s。
- 保证带宽:保证视频通话始终有 1MB/s 的专用带宽,不受其他应用影响。
- 优先级:让游戏数据包(如 UDP)拥有最高优先级,即使网络拥堵,它也能优先通过。
- 延迟控制:降低关键应用的网络延迟。
- 丢包控制:在拥塞时,优先丢弃不重要的数据包(如旧网页数据),而不是重要的实时数据。
tc 就是实现这些“交通规则”的核心工具。
核心概念:理解 tc 的工作原理
要掌握 tc,必须先理解它的几个核心组件,它们之间是层层嵌套的关系。
qdisc (Queueing Discipline) - 队列规则
这是 tc 的最核心概念。qdisc 是附加在网络接口(如 eth0, wlan0)上的一个排队规则,所有从接口发出的数据包,都必须先经过这个 qdisc 的“队列”进行处理,然后再发送出去。

Linux 内核默认的 qdisc 是 pfifo_fast(一个先进先出的快速队列),我们通常用 tc 来替换或修改它。
常见的 qdisc 类型:
pfifo/bfifo(First-In, First-Out / Byte-In, First-Out):最简单的队列,先进先出。bfifo按字节计算队列大小。pfifo_fast:默认 qdisc,基于三个优先级队列的先进先出,内核网络包会根据 TOS (Type of Service) 字段被分类到不同队列。htb(Hierarchical Token Bucket):非常重要且常用,分层令牌桶模型,可以实现复杂的分层带宽保证和限速,就像一个公司的组织架构,可以为不同部门(类)分配不同的预算(带宽)。cbq(Class Based Queueing):比 HTB 更老但功能强大的分类队列,同样可以实现分层带宽管理。sfq(Stochastic Fairness Queueing):随机公平队列,旨在让数据流之间公平地共享带宽,防止某个“大象流”(大文件传输)霸占所有带宽。tbf(Token Bucket Filter):令牌桶过滤器,非常简单,只做一件事:以恒定的速率发送数据包,可以用来做简单的限速。netem(Network Emulator):网络模拟器,主要用于测试,可以模拟网络延迟、丢包、乱序、重复等真实网络环境中的问题。
class (Class) - 类
当使用像 htb 或 cbq 这样的分层 qdisc 时,我们可以在 qdisc 内部创建多个 class,每个 class 可以有自己的带宽限制、优先级和子 qdisc,这构成了一个“类树”,是实现精细化管理的基础。
在 htb qdisc 下:
- 根类 (
root class)- 类1: 保证带宽 10Mbps,优先级高
- 子 qdisc:
sfq
- 子 qdisc:
- 类2: 保证带宽 5Mbps,优先级低
- 子 qdisc:
pfifo
- 子 qdisc:
- 类1: 保证带宽 10Mbps,优先级高
filter (过滤器)
数据包到达接口后,需要被分类到某个 class 中。filter 就是做这件事的规则。tc 提供了多种匹配条件来判断一个数据包应该去哪个 class。
常见的 filter 类型:
u32:最强大、最灵活的过滤器,可以根据数据包头(IP地址、端口、协议等)的任意比特位进行匹配。fw:基于iptables的mark,先通过iptables给数据包打上标记(mark),tc filter根据mark进行分类,这是非常实用的方法。route:基于路由表进行分类,可以根据数据包的目的 IP 地址所在的网络路由进行分类。cgroup:基于 cgroup 分类,可以根据进程所属的 cgroup 来分类数据包,非常适合为特定应用(如 Docker 容器)设置流量策略。
tc 命令基本语法
tc 的命令结构非常清晰,遵循一个固定的模式:
tc [ OPTIONS ] OBJECT { COMMAND | help }
OBJECT: 操作对象,可以是qdisc,class,filter。COMMAND: 具体操作,如add,del,change,show。- 常用
OPTIONS:-s(--stats): 显示详细的统计信息,如包数、字节、延迟等。-d(--details): 显示更详细的信息。-g(--gov): 显示类树结构。
实战案例:从简单到复杂
我们假设目标网络接口是 eth0。
案例 1:简单的全局限速 (使用 tbf)
目标:限制 eth0 的总出站带宽不超过 1Mbps (即 1024 kbit/s)。
# 1. 添加一个 tbf qdisc 到 eth0 的根 # root: 添加到根 # handle 1: 给这个 qdisc 一个句柄 1 # dev eth0: 作用于 eth0 设备 # rate 1mbit: 平均速率 1Mbps # burst 32kbit: 突发流量大小,通常设置为速率的几十分之一 tc qdisc add dev eth0 root handle 1: tbf rate 1mbit burst 32kbit latency 400ms # 2. 查看规则 tc -s qdisc show dev eth0
解释:
tbf会以rate设定的速率匀速地发送数据包。burst允许在短时间内以高于rate的速度发送数据,用于处理突发流量。latency是一个延迟参数,tbf会尽力保证数据包的延迟不超过这个值。
案例 2:为特定 IP 保证带宽 (使用 htb + u32)
目标:局域网内 IP 为 168.1.100 的电脑保证有 2Mbps 的带宽,其余设备共享剩下的带宽。
# 1. 首先删除 eth0 上可能存在的旧规则 tc qdisc del dev eth0 root # 2. 添加一个 HTB qdisc 作为根 tc qdisc add dev eth0 root handle 1: htb default 30 # 3. 创建一个根类 (class 1:1),总带宽上限为 10Mbps tc class add dev eth0 parent 1: classid 1:1 htb rate 10mbit # 4. 创建一个子类 (class 1:10),专门给 192.168.1.100 保证 2Mbps tc class add dev eth0 parent 1:1 classid 1:10 htb rate 2mbit ceil 2mbit # 5. 创建过滤器,将来自 192.168.1.100 的数据包分类到 1:10 类 # protocol ip: 只匹配 IP 包 # u32: 使用 u32 过滤器 # match ip dst 192.168.1.100: 匹配目的 IP # flowid 1:10: 匹配成功后,流入类 1:10 tc filter add dev eth0 protocol ip parent 1:0 prio 0 u32 match ip dst 192.168.1.100 flowid 1:10 # 6. 创建一个默认类 (class 1:30),其余流量共享剩下的带宽 tc class add dev eth0 parent 1:1 classid 1:30 htb rate 8mbit ceil 10mbit # 7. 查看类树结构 tc -s class show dev eth0 tc -s filter show dev eth0
解释:
htb需要先创建一个root class(1:1),它定义了总带宽池。- 然后在这个池下创建子类 (1:10 和 1:30)。
rate是保证带宽,ceil(ceiling) 是最大带宽,在 1:10 中,我们保证 2Mbps,也限制它最多用 2Mbps,在 1:30 中,保证 8Mbps,但最多可以抢占到 10Mbps。filter负责将数据包“路由”到正确的类中。
案例 3:为应用限速 (使用 iptables + tc)
目标:限制 Transmission 下载工具的带宽不超过 500KB/s (即 4mbit/s)。
这种方法更优雅,因为它不关心 IP,只关心进程。
# 1. 给 Transmission 的流量打上防火墙标记 (mark) # --set-mark 1: 将匹配的数据包标记为 1 # -m owner --pid-owner $(pgrep transmission): 匹配 transmission 进程的 PID # -j MARK: 执行 MARK 动作 # 注意:需要先安装 iptables iptables -t mangle -A OUTPUT -m owner --pid-owner $(pgrep transmission) -j MARK --set-mark 1 # 2. 添加一个 HTB qdisc tc qdisc add dev eth0 root handle 1: htb default 20 # 3. 创建根类 tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit # 4. 创建一个用于标记流量的类 tc class add dev eth0 parent 1:1 classid 1:10 htb rate 4mbit ceil 4mbit # 5. 创建过滤器,根据防火墙标记来分类 # protocol ip: 匹配 IP 包 # handle 1: 匹配标记为 1 的数据包 tc filter add dev eth0 protocol ip parent 1:0 prio 0 handle 1 fw flowid 1:10 # 6. 创建一个默认类,让其他流量正常通过 tc class add dev eth0 parent 1:1 classid 1:20 htb rate 100mbit # 7. 查看 tc -s qdisc show dev eth0 tc -s filter show dev eth0
解释:
iptables的mangle表和MARK目标用于给数据包“盖章”。tc filter的fw类型会读取这个mark,并根据它进行分类。- 这种方法的优点是即使 Transmission 连接了不同的 IP 地址,限速规则依然有效。
tc 的常见问题与注意事项
-
作用范围:
tc默认只控制出站流量 (egress),如果要控制入站流量 (ingress),需要先启用ingressqdisc。tc qdisc add dev eth0 handle ffff: ingress
入站控制通常用于限制下载流量,但配置更复杂,且需要配合
tc filter的u32匹配数据包的源 IP 等。 -
单位:
tc中的速率单位通常是kbit(千比特) 或mbit(兆比特),注意与KB/s(千字节/秒) 的区别。1MB/s = 8mbit/s。 -
规则的持久性:
tc的规则在重启后会丢失,如果需要永久生效,可以编写一个systemd服务或在网络启动脚本(如/etc/network/interfaces或 NetworkManager 的 dispatcher)中执行tc命令。 -
复杂性:
tc功能强大,但配置复杂,一个错误的规则可能导致网络中断。强烈建议在测试环境或非生产时间进行操作。 -
监控:使用
tc -s [qdisc|class|filter] show dev <interface>来监控规则的效果和统计信息,这对于调试至关重要。
tc 是 Linux 网络管理中一个极其强大且底层的工具,它通过 qdisc、class 和 filter 三个核心组件,提供了对网络流量的精细控制能力。
- 入门:从简单的
tbf全局限速开始。 - 进阶:学习使用
htb和u32为特定 IP 或端口进行分类和限速。 - 高级:结合
iptables的mark功能,为特定应用设置策略。
掌握 tc 意味着你从一个普通用户变成了网络管理员,能够深度定制和优化你的网络环境,解决各种复杂的网络性能问题,虽然学习曲线陡峭,但其带来的回报也是巨大的。
