tc不能直接在网卡上限制下行带宽,因ingress qdisc不支持速率整形,仅支持过滤和丢包;可靠方案是启用ifb虚拟设备,将入向流量重定向至ifb0,在其egress方向用htb限速。

tc命令限制下行带宽为什么不能直接在网卡上配?
因为 tc 的 ingress qdisc 不支持速率整形,只支持过滤和丢包;真正能限速下行(即进入本机的流量)的常规做法,是把限速逻辑“挪到上游”,也就是在出口方向(egress)模拟下行限速——这需要借助中间节点或反向策略。但如果你的 Linux 主机本身是网关(比如做 NAT 转发),就可以在内网口的 egress 方向对回程流量做限速,效果等同于限制客户端的下行。
常见错误现象:tc filter add ... direction ingress 配了没反应,或者 tc qdisc add dev eth0 root handle 1: htb default 30 对进来的流量完全不生效——本质是方向理解错了。
- 下行 = 数据从外部发往本机 → 实际由上游设备控制,本机只能“事后”丢包(用
ifb设备间接实现) - 最可靠的方式:启用
ifb(Intermediate Functional Block)虚拟设备,把入向流量重定向到 ifb 接口,再在其 egress 上限速 - 必须先加载内核模块:
modprobe ifb,然后启用接口:ip link set dev ifb0 up
如何用 ifb + tc 对 192.168.10.0/24 段限速 5Mbps?
核心思路是:用 tc ingress 在物理网卡捕获入向流量,通过 mirred 动作重定向到 ifb0,再在 ifb0 的 egress 上用 htb 限速。
实操步骤(假设物理网卡是 eth0,目标 IP 段为 192.168.10.0/24):
- 加载模块并启用 ifb:
modprobe ifb;ip link set dev ifb0 up - 在
eth0上挂 ingress qdisc:tc qdisc add dev eth0 handle ffff: ingress - 添加过滤器,匹配目标 IP 段并重定向:
tc filter add dev eth0 parent ffff: protocol ip u32 match ip src 192.168.10.0/24 action mirred egress redirect dev ifb0 - 在
ifb0上配置 HTB 限速:tc qdisc add dev ifb0 root handle 1: htb default 30 - 建一个 5Mbps 的 class:
tc class add dev ifb0 parent 1: classid 1:1 htb rate 5mbit ceil 5mbit - 加过滤器把重定向过来的包归入该 class:
tc filter add dev ifb0 protocol ip parent 1: u32 match ip src 192.168.10.0/24 flowid 1:1
注意:match ip src 这里写的是源 IP,是因为你限制的是“从该网段发来的下行数据”,即它们作为服务器时的响应流量(如 HTTP 返回、视频流),所以匹配的是响应包的源地址——也就是客户端 IP 段。
为什么限速后实际速率不稳定或远低于设定值?
常见原因不是配置写错,而是 TCP 窗口、ACK 延迟、缓冲区与 qdisc 队列交互导致的瞬时抖动。尤其当使用 htb + sfq 或 fq_codel 时,底层排队算法会影响吞吐感知。
-
htb的ceil和rate设为相同值才能硬限速;若ceil > rate,短时突发仍可能超限 - 物理网卡驱动或网卡本身开启 TSO/GSO 可能绕过
tc限速,建议临时关闭:ethtool -K eth0 tso off gso off - 若用
ifb,确保没有其他规则干扰ifb0的出向队列;可用tc -s qdisc show dev ifb0查看 drops 和 backlog - 测试时避免用单线程工具(如老版
wget),改用iperf3 -c $server -R(-R 表示反向测下行)或浏览器多标签下载,更贴近真实负载
删除规则和恢复网络的最小安全操作
误配 tc 规则可能导致 SSH 断连(尤其在网关场景),删规则前务必确认有本地终端或带外访问通道。
- 清空物理网卡 ingress:
tc qdisc del dev eth0 ingress - 清空 ifb0 所有 qdisc:
tc qdisc del dev ifb0 root - 停用 ifb 接口(可选):
ip link set dev ifb0 down - 卸载模块(谨慎):
rmmod ifb—— 若有其他服务依赖该模块会失败,跳过即可 - 验证是否清空:
tc qdisc show应仅剩默认noqueue;tc filter show dev eth0和tc filter show dev ifb0应无输出
ifb 是个“透明中转层”,但它依赖精确的重定向路径;一旦漏掉某条 filter 或 class,流量就直通不被限速——这种静默失效比报错更难排查。


















