nftables的priority决定链在内核hook中的执行顺序而非规则排序,真正影响单条规则生效顺序的是其在链内的位置;应使用预定义语义化priority常量划分策略层级(如nf_nat=-100、filter=0、security=150),再通过insert/append控制链内规则顺序,并结合jump调用命名链实现模块化控制。

nftables 的优先级(priority)不是用来“排序规则”的数字,而是决定链挂载到内核 hook 的执行顺序——它控制的是不同链(比如自定义链、base chain)在数据包处理流程中谁先介入、谁后介入。真正影响单条规则生效顺序的,是规则在链内的位置,而非 priority 值本身。
要实现流量精细化控制,关键在于:用 priority 区分策略层级(如连接跟踪前置、状态放行、应用层标记、最终决策),再用规则插入位置(position)和链内顺序落实细节。
用 priority 划分策略层级,避免逻辑冲突
每个 base chain(如 input、forward)都绑定一个 hook 和 priority。priority 值越小,链越早被调用。Linux 内核预定义了常用 priority 常量,推荐直接使用语义化名称,而不是硬写数字:
-
nf_nat(-100):NAT 相关,最早介入,用于地址转换 -
filter(0):过滤主链,默认值,适合放行/拒绝逻辑 -
mangle(-50 或 150):修改包字段(如 TOS、TTL),常用于 QoS 标记 -
security(150):SELinux/MAC 策略,最晚执行
例如,若你希望先做连接跟踪修正(如 FTP helper),再做端口限速,最后才由白名单链决策,就应按 priority 从低到高组织链:
# 创建 NAT 链(最早执行,确保地址已转换)
nft add chain inet filter prerouting { type nat hook prerouting priority -100 \; }
# 创建连接跟踪增强链(如启用 conntrack helper)
nft add chain inet filter ct_helper { type filter hook input priority -50 \; }
# 主过滤链(默认 priority 0)
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
# 安全审计链(最后执行,记录所有未匹配包)
nft add chain inet filter audit { type filter hook input priority 150 \; }这样设计后,一个进来的 TCP 包会依次经过:prerouting(NAT)→ ct_helper(修正 conntrack 状态)→ input(核心放行/限速)→ audit(兜底日志),各层职责清晰,互不干扰。
在同一链内用 position 精确控制规则顺序
priority 管链之间顺序,而链内规则顺序靠插入位置(position)或追加顺序决定。nftables 规则严格按链内顺序匹配,第一条匹配即执行对应动作(accept/drop),后续不再检查。
所以必须保证:
-
ct state established,related accept放最前(保障回包畅通) -
iifname "lo" accept紧随其后(本地通信无需审查) - 新连接规则(带
ct state new)放在中间 - 默认
drop放最后(或设为链默认策略)
插入规则时可指定位置:
# 查看当前链规则及 handle(handle 是唯一位置标识) nft list chain inet filter input --numeric # 在 handle 5 的规则之前插入新规则(比如插在 established 后、lo 前) nft insert rule inet filter input position 5 ip saddr 127.0.0.1 accept # 或追加到末尾(等效于 append,但显式更安全) nft add rule inet filter input tcp dport 22 ct state new accept
常见错误是把 drop 规则写在中间,导致后续所有规则失效。正确做法是设链默认策略为 drop,或确保 drop 是链内最后一条规则。
结合命名链 + jump 实现模块化精细控制
把复杂逻辑拆成多个命名链(named chain),再用 jump 按需调用,既能复用、又便于调试。每个子链可设独立 priority(仅对 base chain 有效),但更常用的是在主链中用 jump 控制执行时机。
例如,对外 API 流量需同时做源限速、并发控制、SNI 过滤:
# 创建专用子链
nft add chain inet filter api_policy { type filter \; }
# 子链内规则(按需叠加)
nft add rule inet filter api_policy ip saddr @trusted_ips accept
nft add rule inet filter api_policy tcp dport 3000 ct count over 20 drop
nft add rule inet filter api_policy ct mark & 0x1 == 0x1 accept
nft add rule inet filter api_policy drop
# 主链中调用
nft add rule inet filter input tcp dport 3000 ct state new jump api_policy这样,只有目标端口是 3000 且为新连接的包才会跳入 api_policy,其他流量不受影响,逻辑隔离干净。
优先级与性能优化的实用配合
priority 影响的是链调度开销,而链内规则匹配效率取决于结构:
- 使用
set替代重复ip saddr条件(哈希查找 O(1)) - 把高频匹配条件(如
iifname、ct state)放在规则前面 - 避免在高 priority 链里放耗时操作(如
log或limit应尽量后置)
例如,把日志规则放在 priority 150 的 audit 链,而不是塞进主 input 链,既不影响主路径性能,又能集中审计。
本质上,priority 是策略分层的“楼层号”,而规则顺序才是每层楼里的“房间号”。搞清这个分工,精细化控制就不容易错位。

















