tc只能限制本机发出的流量,无法直接限速入向带宽;限速下载需伪造路径或依赖上游设备,且必须作用于真实物理网卡并以root权限执行。

Linux 中的 tc 只能限制本机**发出**的流量(egress),无法直接限速“进来”的带宽;所谓“限速下载”,本质是伪造入向路径或依赖上游设备,本地配置必须作用于真实物理网卡(如 eth0、ens33),且 root 权限不可省略。
确认网卡状态与清理旧规则
很多限速失败,不是命令写错,而是环境没理清:
- 用
ip link show确认目标网卡名(比如ens33)处于UP状态,且不是lo或 Docker 的vethxxx - 运行
tc qdisc show dev ens33—— 若有输出,说明已有规则,不清理就加新规则会冲突或被忽略 - 清空旧规则:
sudo tc qdisc del dev ens33 root 2>/dev/null(静默失败也无妨)
用 tbf 快速限全局限速(适合压测或简单封顶)
tbf 是最简稳的单一流量限速方式,原理是令牌桶,不分类、不匹配,只控总出口:
- 限
ens33出向为 5Mbps:sudo tc qdisc add dev ens33 root tbf rate 5mbit burst 64kb latency 70ms - 单位严格区分大小写:
mbit(兆比特)≠mbps(内核可能拒识) -
burst太小(如1kb)会导致 SSH/DNS 小包频繁丢弃;太大(如10mb)会让限速失效;经验上设为rate / 10左右较平衡 -
latency不是网络延迟,而是包在队列里最长等待时间;设太小(10ms)易丢包,太大(2s)会让突发“憋太久”,影响交互
按目标 IP 或端口限速必须用 htb + u32 filter
tbf 无法定向限速,得用分层结构 htb 配合过滤器;关键陷阱在 match 方向——出向规则中,ip dst 才是你想限的“对方 IP”:
- 先挂根:
sudo tc qdisc add dev ens33 root handle 1: htb default 30 - 建总带宽类:
sudo tc class add dev ens33 parent 1: classid 1:1 htb rate 100mbit - 建子类限速目标 IP(如响应发给
192.168.1.100的流量):sudo tc class add dev ens33 parent 1:1 classid 1:10 htb rate 2mbit ceil 2mbit - 绑定流量:
sudo tc filter add dev ens33 protocol ip parent 1:0 prio 1 u32 match ip dst 192.168.1.100 flowid 1:10 - 若限 HTTP 响应(目的端口 80):
match ip dport 80 0xffff;若限本机主动发起的源端口(如客户端用 7003):match ip sport 7003 0xffff
入向流量(下载)限速不能直接用 tc egress
内核 tc 没有真正入向排队能力;现代内核(5.0+)已弃用 imq,推荐用 ingress + mirred 曲线实现:
- 添加 ingress qdisc:
sudo tc qdisc add dev ens33 handle ffff: ingress - 重定向进来的包到虚拟接口(需提前启用
ifb0):sudo tc filter add dev ens33 parent ffff: protocol ip u32 match ip src 0.0.0.0/0 action mirred egress redirect dev ifb0 - 再对
ifb0做出向限速(即模拟入向限速):sudo tc qdisc add dev ifb0 root tbf rate 5mbit burst 64kb latency 70ms - 注意:
ifb0需手动加载模块:sudo modprobe ifb numifbs=1,并sudo ip link set dev ifb0 up
真正容易被忽略的点:所有限速都只生效于**本机发出去**的数据包;哪怕你写了 match ip src,在 egress 规则里它匹配的是本机 IP,不是远端;而 ingress 方案本质是“骗”内核把入包转成出包再控,中间多一跳,实际带宽和延迟会有微小损耗。











