在Linux中必须用iptables -t mangle修改DSCP位,因其是唯一支持操作IP头DS字段的表;需在PREROUTING、OUTPUT或POSTROUTING链标记,再配合tc调度才能实现端到端QoS。

在Linux中用iptables -t mangle修改DSCP位,是实现端到端QoS流量分级最常用且有效的方式。关键不在于“能不能”,而在于链的选择、标记时机和后续调度是否匹配——DSCP只是打个标签,真正起作用的是tc(traffic control)对这些标签的识别与处理。
为什么必须用mangle表打DSCP
mangle表是iptables中唯一支持操作IP包头DS字段(即DSCP)的表。filter表只能丢弃或放行,nat表只改地址和端口,它们都不具备修改DSCP的能力。DSCP模块(--set-dscp 或 --set-dscp-class)仅在mangle表中可用;若误写成iptables -A OUTPUT -j DSCP(缺-t mangle),命令会静默失败,规则根本不会加载。
选对链:PREROUTING、OUTPUT还是POSTROUTING
DSCP标记需在数据包进入调度队列前完成,否则tc无法识别:
- PREROUTING:适合网关/路由器场景,对所有入向流量(含转发)统一标记,例如将来自内网的SSH、VoIP流量标为EF
- OUTPUT:适合本机主动发出的业务流量,如Web服务器响应、数据库连接,标记后由本机出口队列识别
- POSTROUTING:常用于出口策略统一兜底,比如给所有发往外网的HTTP流量标AF21;但注意它发生在路由之后,不适用于需按源IP或应用层特征精细分类的场景
不建议在INPUT或FORWARD链打DSCP——前者已抵达本机协议栈,后者虽经转发但若未启用路由决策前标记,部分路径可能绕过tc调度。
常用DSCP类与标记命令示例
实际部署中推荐使用语义化类名(如EF、AF21),系统会自动映射为对应十六进制值:
- 实时语音/视频(低延迟):
iptables -t mangle -A PREROUTING -p udp --dport 5060 -j DSCP --set-dscp-class EF - SSH管理流量:
iptables -t mangle -A OUTPUT -p tcp --sport 22 -j DSCP --set-dscp-class EF - 网页浏览(中优先级):
iptables -t mangle -A POSTROUTING -p tcp --dport 80 -j DSCP --set-dscp-class AF21 - P2P或备份流量(尽力而为):
iptables -t mangle -A PREROUTING -p tcp --dport 6881:6999 -j DSCP --set-dscp-class BE
注意:DSCP值本身不保证带宽或延迟,它只是一个8位字段中的高6位(DS字段),需配合tc的u32或fw过滤器才能触发对应调度动作。
验证与联调要点
光看iptables规则是否添加成功没用,必须确认DSCP真正写入了IP头,并被tc正确分流:
- 抓包验证:
tcpdump -i eth0 -nn -c 2 'ip[1] & 0xfc != 0' -X查看IP头第2字节(DS字段)是否非零 - 检查tc过滤器是否命中:
tc -s filter show dev eth0 parent 1:0观察对应flowid的计数器是否增长 - 避免常见错配:若tc用u32匹配
ip dsfield,iptables却打了netfilter MARK(-j MARK),二者完全不互通;务必统一用DSCP - 持久化保存:
iptables-save -t mangle > /etc/iptables/mangle.rules,并确保开机加载
不复杂但容易忽略:DSCP只是QoS链条的第一环,没有tc的类定义、队列规则和过滤绑定,再准的标记也形同虚设。


















