nftables链优先级是控制同一hook下多链执行顺序的机制,非systemd网络策略开关;它通过priority数值(越小越先执行)决定规则处理时序,需配合hook、表类型及内核模块(如br_netfilter)协同工作。

nftables 的链优先级不是用来“完美融合” systemd 内部虚拟网络策略的魔法开关,而是提供一种可控的执行时序机制——关键在于理解 systemd 管理的网络对象(如 veth、bridge、networkd 分配的地址)本身不生成 nftables 规则,真正需要协调的是 nftables 如何在数据包流转路径中,与 systemd 启动的容器、podman、或 networkd 创建的虚拟接口共存且互不干扰。
明确 systemd 虚拟网络不直接干预 nftables
systemd-networkd、systemd-resolved 或 podman(通过 systemd socket 激活)本身不会自动写入或修改 nftables 规则。它们只配置内核网络栈:创建 veth 对、设置桥接、分配 IP、启用 forwarding 等。nftables 是否生效、在哪一环节拦截或放行,完全取决于你定义的表、链、hook 和 priority。
- 例如,podman 默认使用 slirp4netns 或 cni 插件,其流量可能绕过 host 的 forward 链;而使用 --network=host 或桥接模式时,才真正进入 host 的 input/forward 链
- systemd-networkd 配置的 bridge 接口(如 br0)是物理/虚拟设备,nftables 通过 iifname/oifname 匹配它,但不会因为该接口由 systemd 创建就自动获得特殊规则
- 真正需要关注的,是 systemd 启动的服务(如 docker、podman、k3s)是否启用了 netfilter 相关参数(如 br_netfilter 模块、net.bridge.bridge-nf-call-iptables=1),否则桥接流量根本不会触达 nftables
用 priority 控制 hook 阶段中的执行顺序
同一 hook(如 prerouting)上可存在多个链,priority 决定谁先处理。systemd 不参与这个排序,但你可以主动把自定义链插入到合适位置,避免被其他组件(如 firewalld、docker 自动规则)覆盖或跳过。
- firewalld 默认在 inet filter 表中使用 priority 0 的 input/output 链;若你希望自定义策略更早生效(比如做连接标记或早期丢弃),可设 priority -100(如 nft add chain inet myfw input { type filter hook input priority -100 \; })
- 若需在 NAT 前做源地址预处理(例如为来自 systemd-networkd 某个 bridge 的流量打 mark),应放在 nat 表的 prerouting 链,priority 设为 -10(早于 firewalld 的 nat prerouting,默认 priority -100 是 mangle,-50 是 nat)
- 对于容器间通信,若使用 cni 或 podman 默认桥,常需在 forward 链中显式允许 br0 ↔ eth0 或 veth* ↔ container 网段,此时 priority 可设为 0,与标准过滤链对齐
适配典型 systemd 场景的链组织建议
不要试图让 nftables “识别” systemd,而是按流量路径和意图组织链,再用 priority 锚定位置。
- 宿主机服务暴露:input 链设 priority 0,仅开放 ssh、http 等端口;systemd 启动的 nginx 或 sshd 就自然受控
- 容器/VM 流量隔离:新建 regular chain(如 container-filter),在 forward 链中用 jump 调用,并用 iifname "cni0" oifname "eth0" 等精确匹配;priority 设为 10,确保在默认 forward 策略之后、但仍在 conntrack 处理完成前
- 防止桥接绕过防火墙:加载 br_netfilter 模块后,bridge 流量会进入 ebtables → iptables/nftables 的 bridge/forward 链;此时应在 inet filter 表的 forward 链中,用 priority 0 显式限制 br0 入口,而非依赖 output/input
验证与调试要点
systemd 网络本身不可见,但你能看到它的效果。重点检查三点:
- 运行 nft list ruleset,确认你的链确实挂载在对应 hook 和 priority 上;注意 inet 表同时覆盖 IPv4/IPv6,避免只配了 ip 却漏掉 ip6
- 用 tcpdump -i br0 和 nft monitor trace 联合抓包,看数据包是否进入你期望的链(trace 输出里会显示 chain 名和 priority)
- 检查 sysctl net.bridge.bridge-nf-call-nftables 是否为 1(Linux 5.15+ 默认开启),这是 bridge 流量进 nftables 的开关;旧内核需用 bridge-nf-call-iptables 并配合 iptables-nft 层兼容











