nftables 的 chain priority 用于精确划分数据包处理阶段,而非兼容 iptables;其核心是通过数值越小越先执行的机制(如 raw=-300、mangle=-150、filter=0、nat=100),在同 hook 下构建无冲突的流水线式处理顺序。

nftables 的 chain priority 特性不是用来“兼容”旧 iptables 规则的,而是帮你彻底绕开冲突——关键在于不共存、不混用。一旦系统启用 nftables 后端(Ubuntu 22.04+、RHEL9、OpenWrt 23.05 等默认如此),iptables 命令实际走的是 iptables-nft 兼容层;此时若还手动运行传统 iptables-legacy 或残留旧规则,就会触发链表覆盖、策略错乱、FORWARD 被静默设为 DROP 等问题。真正有效的解法,是利用 priority 明确划分处理阶段,把不同功能的流量隔离到互不干扰的执行序位中。
先清空旧规则,避免底层状态污染
混合使用的最大风险不是语法报错,而是内核 netfilter 子系统里存在两套并行但未协同的状态。必须从源头清理:
- 运行
nft flush ruleset彻底清空当前所有 nftables 规则(包括兼容层加载的) - 检查是否残留 legacy 模块:
lsmod | grep -E 'ipt_|xt_',如有且非必要,用modprobe -r卸载(如iptable_filter、ipt_MASQUERADE) - 确认无活跃的 iptables-legacy 进程:
ps aux | grep -i "iptables.*-t nat" - 禁用 systemd 中可能自动拉起的 iptables 服务:
sudo systemctl stop iptables && sudo systemctl disable iptables
用 priority 划分功能层级,替代“表隔离”思维
iptables 依赖 filter/nat/mangle 表硬分离,而 nftables 用 priority 实现更精细的时序控制。同一 hook(如 input)下,priority 值越小越早执行,天然形成处理流水线:
- raw 链(priority -300):跳过连接跟踪,适合封禁恶意 IP 或 bypass conntrack 开销
- mangle 链(priority -150):修改数据包字段(如 TOS、TCP MSS),不影响后续过滤决策
- filter 链(priority 0):标准放行/拦截逻辑,如 SSH、HTTP 白名单
- nat 链(priority 100):SNAT/Masquerade 必须放在这里,否则会被 filter 链提前丢弃
例如,Docker 容器出向流量若需 SNAT,不能写在 priority 0 的 filter forward 中,而应建独立链:nft add chain inet nat postrouting { type nat hook postrouting priority 100 \; },再加 masquerade 规则。
让 Docker 等工具与 priority 协同,而非对抗
Docker 默认操作 iptables,会强行改写 FORWARD 链策略并插入 DOCKER 链——这正是冲突高发点。正确做法是放弃让它“插手”,转为显式纳管:
- 停用 Docker 自动管理:
{"iptables": false, "ip6tables": false}写入/etc/docker/daemon.json,重启 dockerd - 在 nftables 中为容器网桥显式放行:
nft add rule inet filter forward iifname "docker0" oifname "eth0" ct state new accept - 若需端口映射,用 nftables 的 DNAT 替代 iptables 的 PREROUTING:
nft add rule inet nat prerouting tcp dport 8080 dnat to 172.17.0.2:80(注意 prerouting priority 是 -100)
验证 priority 是否生效,避免静默失败
nftables 不报错不等于规则已加载。常见陷阱是 chain 创建时漏写 hook 或 type,导致后续规则挂载失败:
- 查所有链及其 priority:
nft list chains,确认你的 raw/mangle/filter/nat 链都列在对应 hook 下且 priority 不重复 - 看完整规则带 handle:
nft list ruleset -a -n,handle 是内核中唯一标识,删除或替换必须依赖它 - 检查内核日志:
dmesg | tail -15,出现Could not process rule: File exists就是 priority 冲突 - 测试时用
tcpdump -i docker0或conntrack -E观察实际匹配路径,比看规则列表更可靠

















