四项检查把一条可用的标记规则和一条可用的路由区分开来:规则读的是哪个标记,包在查找时是否还带着它,连接标记是否被恢复到后续包上,以及匹配规则的掩码与优先级是否允许它触发。计数器增加只能证明某条规则匹配了某个东西。它完全不能说明内核选路时包上带着什么。

两个标记住在不同的地方,按不同的时间表过期。

两个标记,两种寿命

包标记属于一个 skb,随它穿过各个钩子,并由策略路由的 fwmark 选择器消费。连接标记属于 conntrack 表项,在该流的所有包上持续存在,在有人把它复制回来之前,路由规则看不到它。把包标记保存进连接是一次存储;恢复它是另一个动作。两者都不会自动发生。

这就是为什么一套规则看起来自洽,路由决策却看到零:值被保存了,但没有任何东西把它恢复过来。

两者之间的复制是你自己写的一步

两条关键语句方向相反:一条把包的标记存进连接,另一条把连接的标记装载到包上。你需要哪一条,取决于分类相对于流发生的时机。设计可能只需要包标记,而因为某个绕行做法两者都用过就顺手加上 conntrack 标记,正是一条简单策略获得第二种失效模式的方式。

ct mark set meta mark
meta mark set ct mark

把方向写在规则旁边,因为只看语法并不明显。第一行是存储,第二行是恢复,两者互不包含。

在消费它的那次查找之前完成分类

本地生成的流量和从 LAN 转发来的流量经过不同的钩子,并在不同时刻到达路由决策。对路由器自身连接有效的输出规则,并不能证明被转发客户端的包在查找之前已经被标记。把分类放在消费它的查找尚未发生的位置,并检查同一链中后面的规则是否会覆盖该值。链内顺序是配置的一部分,不是实现细节。

连接状态的持久化同样需要明确计划。如果只对流的第一个包做了分类,后续包就需要恢复保存的标记,否则它们会走未标记的路径。这就是描述连接的标记与描述包的标记之间的差别。

向路由提出一个带标记的问题

ip route get 10.77.0.10 mark 0x2

先检查规则和表,再带着标记查询路由,如果源地址或入接口会影响策略,也一并加上。普通的无标记查找回答的是另一个问题,并且会欣然报告你并不想要的那条路径。除了规则的值,还要检查它的掩码和优先级,并确认所选表里有一条可用的路由。

计数器增加是某条规则匹配了某个包的证据。它不是最终包在正确的决策点上带着预期标记的证据。

读标记、方向、时机和掩码。四项检查,路由就不再是谜。

相关文章