如何让关键业务流量不被抢占?如何限制某一台设备速度?如何保证低时延?如何防止内网乱访问、实现端口过滤、安全隔离?
这些问题,靠单纯的网卡配置、路由策略是解决不了的,必须依靠 Linux 内核两大核心子系统:TC (Traffic Control)流量控制与 Netfilter 防火墙。
TC 负责“调度流量快慢、优先级、带宽”,Netfilter 负责“允许谁通过、拒绝谁通过、如何修改地址”。两者结合,就是嵌入式网关里最核心的 QoS(服务质量)与安全框架。
一、先搞清楚:TC 与 Netfilter 到底在网络栈的什么位置?
在学习任何网络功能之前,最关键的是先认清它在协议栈里的位置。位置决定了它能干什么、不能干什么、什么时候生效、和谁有交互。
我们可以把 Linux 网络路径想象成一条城市道路:
那么: TC 就是高速口的“收费站、调度员、限速牌”。 它决定哪辆车先走、哪辆车限速、哪辆车排队、哪辆车可以优先通行。
Netfilter 就是道路上的“检查站、通行证、卡口”。 它决定谁能进、谁能出、谁不能过、谁需要被改造地址(NAT)。
两者都在内核网络栈中,但作用阶段完全不同:
- TC 主要作用在出方向(egress),靠近网卡驱动,专注于队列、延迟、吞吐量。
- Netfilter 作用在数据包流经的关键钩子点,无论是进来、出去、转发,都会经过它的检查。
如果用一条更直观的数据包流动路径描述,就是这样:
应用发包 → Socket → TCP/IP 协议栈 → 路由 → Netfilter 出口钩子 → TC 队列调度 → 网卡驱动发送
网卡收包 → 驱动 → Netfilter 入口钩子 → TC 入口控制 → 协议栈 → Socket → 应用
我们会发现,TC 更贴近硬件驱动,是“流量治理”; Netfilter 更贴近协议栈,是“安全策略”。
二、TC(Traffic Control)到底是什么?为什么嵌入式离不开它?
TC 并不是一个简单的“限速工具”,而是 Linux 内核完整的流量调度与队列管理体系。
它诞生的初衷很简单: 网卡发包速度是固定的,但数据包从协议栈涌进来的速度是不固定的。如果一瞬间大量数据包涌过来,网卡处理不过来,就必须排队。 怎么排?谁先谁后?超过多少要丢?拥堵了怎么办? 这就是 TC 要解决的问题。
在服务器上,TC 可能不那么显眼;但在嵌入式设备上,TC 几乎是系统级刚需:
- 多口设备(LAN/WAN/WiFi/4G)必须做出口限速
如果没有 TC,网关会出现典型现象: 一个设备全速下载 → 全网延迟飙升 → 控制指令卡顿 → 视频卡顿 → 网络“假死”。
TC 就是为了解决这类问题而存在。
它的核心思想是:给每一张网卡设置一个发送队列规则,让内核按照规则来发包,而不是无节制地发送。
三、TC 的核心逻辑:队列、分类、过滤三驾马车
有的教程一上来就讲 tc qdisc、tc class、tc filter,把人看晕。 实际上,我们只要理解 TC 的整体工作模型,就不会被命令绕晕。
TC 的工作流程非常贴近现实生活中的交通管理:
首先,网卡必须有一个队列规则(qdisc)。 这是最根本的“排队方式”。 比如:先来先服务、优先级排队、按带宽排队、智能丢包等。
有些队列支持分类(class),可以把流量再分成好几股。 例如:总带宽 100M,分成控制流量 20M、视频流量 30M、普通流量 50M。
然后需要过滤(filter),把不同的流“分拣”到对应的分类里。 例如:来自 192.168.1.10 的走普通类,目的端口 80 的走视频类,优先级 7 的走控制类。
最终的结构关系是: 一张网卡 → 一个根队列 qdisc → 多个 class 分类 → 多个 filter 匹配规则
内核按照这个结构,把数据包依次排序、限速、调度、发送。
最关键的是:TC 对协议栈完全透明。 应用、Socket、驱动都感知不到 TC 的存在,却被它有序管理。
四、嵌入式里最实用、最常用的 TC 队列
在真实项目里,我们并不会用太复杂的队列,绝大多数场景只需要掌握几类最稳定的 qdisc 就足够。
第一种,也是最简单的:TBF(Token Bucket Filter)令牌桶队列。 它的逻辑非常朴素:把流量想象成水流,桶里有“令牌”,每个包要消耗令牌才能发送。令牌以固定速率生成。 这样就能严格限制一个网卡或一个流的最大速度。 在嵌入式里最常用于:4G/5G 出口限速、子端口限速、WAN 口总带宽限制。
第二种:PRIO 优先级队列。 它把流量分成 3 个或更多优先级 band,高优先级的包永远先发,低优先级只有高优先级空闲时才能发。 这对工业、车载、实时性设备极其重要。 我们可以把远程调试、MQTT 控制指令、心跳帧设置为高优先级,确保即使在拥堵时也不延迟。
第三种:MQPRIO 多队列硬件优先级。 这是现代千兆网卡、车载 TSN 网络常用的队列。 它直接把流量映射到网卡硬件队列,由网卡硬件直接做优先级调度,CPU 几乎不占用。 在高性能、低时延嵌入式场景里是首选。
第四种:FQ_CODEL 智能队列。 它是目前解决“缓冲膨胀”(bufferbloat)最好的队列。 很多人遇到过“带宽很足,但延迟极高、丢包严重”,就是因为队列太长,数据包在里面排队太久。 FQ_CODEL 会自动监控队列延迟,主动提早丢包,让流自动降速,保证延迟极低。 在 WiFi 网关、弱网传输、远距离通信设备上效果非常明显。
我们只要记住: 要限速用 TBF,要优先用 PRIO,要硬件加速用 MQPRIO,要低延迟用 FQ_CODEL。 这四句话基本覆盖 99% 的嵌入式场景。
五、TC 在嵌入式网关里的典型用法
在真实的多网口 Linux 网关里,TC 的用法非常固定,也非常工程化。
最常见的场景是 WAN 出口限速。 因为外网带宽通常小于内网带宽,如果内网全速向外发包,会导致出口拥堵、延迟飙升、TCP 重传狂增。 我们只需要在 eth0 或 wan 口设置一个 TBF 队列,把速度限制在运营商给的带宽以内,整个网络立刻稳定。
第二个高频场景是 LAN 口分级限速。 比如内网有摄像头、屏幕、传感器、客人设备。 我们可以给每个设备分配独立带宽,防止某一台设备占满全网。
第三个场景是 车载/工业实时流量优先级。 把控制流、DoIP 诊断、TSN 流量映射到高优先级队列,确保在任何负载下都能最低延迟。
第四个场景是 4G/5G 模组流量保护。 蜂窝网络带宽小、延迟高、费用贵,TC 可以有效避免突发流量冲击模组,降低卡顿、断线概率。
六、Netfilter 防火墙:Linux 的网络安全心脏
如果说 TC 管“秩序”,那 Netfilter 就管“权限”。
Netfilter 是 Linux 内核里标准的数据包过滤框架。 我们平时说的 iptables、nftables、firewalld,其实都是 Netfilter 的用户态配置工具。 真正在内核里干活的,是 Netfilter。
它的工作方式非常直接: 在数据包流经网络栈的关键位置,设置钩子(hook)。 当数据包经过时,内核调用注册在钩子上的规则,判断是允许通过、丢弃、还是修改地址。
Netfilter 共有 5 个经典钩子,贯穿整个数据包生命周期:
- PREROUTING
- INPUT
- FORWARD
- OUTPUT
- POSTROUTING
这 5 个点覆盖了所有流量场景: 外来流量、本机流量、转发流量、外出流量。
在嵌入式里,Netfilter 的用途非常直接:
七、FORWARD 与 NAT:网关最核心的功能
嵌入式网关最离不开的两个 Netfilter 功能是转发(FORWARD)和网络地址转换(NAT)。
FORWARD 规则决定了“哪些包可以跨网口转发”。 比如 LAN 口可以访问 WAN 口,但 WAN 口不允许主动访问 LAN 口。
NAT 则让内网设备可以用同一个公网 IP 访问互联网。 当内网设备发包到外网时,网关修改源 IP 为自己的公网 IP; 当外网回复时,网关再转换回内网设备 IP。 这就是家庭路由、工业网关、无线路由器最核心的工作原理。
在 Linux 上开启网关功能只需要两步:
- 配置 POSTROUTING 链的 SNAT 或 MASQUERADE
八、总结
TC 与 Netfilter 是嵌入式 Linux 网络从“能用”走向“好用、稳定、商用”的关键。
TC 是流量调度的核心,靠近网卡驱动,解决拥堵、限速、优先级、时延问题; Netfilter 是安全过滤的核心,遍布协议栈,解决访问控制、转发、NAT、安全隔离问题。
一个负责“快与稳”,一个负责“安与通”。 两者共同构成了 Linux 网关的 QoS 与安全基石。