将传出的数据包从虚拟机路由到 GRE 隧道,收入数据包来自哪里?(TCP 流)

将传出的数据包从虚拟机路由到 GRE 隧道,收入数据包来自哪里?(TCP 流)

我们在多个国家的边缘服务器上拥有带 Anycast IP 的网络基础设施,这些服务器将流量封装在 GRE 隧道中,通过虚拟机传输到端点节点

目前,我们使用其中一个 EDGE 将所有 TX 路由到默认路由,但不对称和较差的 RTT 有时对我们来说是不利的。

(例如:传出的 TCP SYN 数据包到达默认路由(EDGE ams-1),传入的 TCP SYN/ACK 来自其他国家的 EDGE de-1)

问题在于将虚拟机的传出流量路由到传入流量(tcp 流)来自的边缘服务器。

解决方案是进行如上所述的某种对称路由,我们尝试了 fwmarks/connmarks 但没有成功(或者我们使用错了?)

sysctl -w net.netfilter.nf_conntrack_tcp_loose=1

ip rule add fwmark 10001 table 10001 priority 45
ip route add default dev e-kiev1 table 10001

iptables -t mangle -A PREROUTING -p tcp -i vm+ -m set --match-set networks src -j CONNMARK --restore-mark

iptables -t mangle -A PREROUTING -i e-kiev1 -p tcp --tcp-flags SYN SYN -m set --match-set networks dst -j CONNMARK --set-mark 10001

(对所有边缘服务器重复命令)

我们可以付费寻求解决方案。

答案1

有两个问题:正确处理标记和缺失路线。

标记和连接标记

路由栈知道防火墙标记(又名福马克又名标记)。它对 Netfilter 的康马克。这对第一个 SYN 数据包有影响。

规则集必须在需要时采取措施将值从流移动到数据包。在这里,它从流的康马克到数据包的标记但在初始阶段,当遇到 SYN 数据包时,第二条规则直接创建流康马克无需标记数据包本身标记:SYN 数据包不会立即被路由堆栈以不同的方式评估,因为它没有标记,而此流的所有其他数据包都将继承康马克作为标记

iptables规则应该像这样改变(进一步的优化和适当的简化和分解当然是可能的,应该这样做,但留作练习):

iptables -t mangle -A PREROUTING -p tcp -i vm+ -m set --match-set networks src -j CONNMARK --restore-mark
# no need to continue evaluation if we already have the mark.
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j RETURN

# various per-POP rules
iptables -t mangle -A PREROUTING -i e-kiev1 -p tcp --tcp-flags SYN SYN -m set --match-set networks dst -j MARK --set-mark 10001

# after all per-POP rules are done, store the mark to connmark. Required only once: at the end.
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j CONNMARK --save-mark

注意:with net.netfilter.nf_conntrack_tcp_loose=1(默认设置)-p tcp --tcp-flags SYN SYN可能应该替换为-p tcp -m conntrack --ctstate NEW(或者甚至不替换,-p tcp以便正确处理 UDP、ICMP 等...):如果此路由器重新启动(从而丢失流的内存),它可以将即时建立的连接作为新连接,并且当第一次再次看到从“外部”到“内部”的数据包时,将恢复对流的正确标记(如果此流的第一个数据包是从“内部”到“外部”的,它们仍将暂时被错误路由)。目前它永远无法正确地重新标记此类流:其流量中不再有 SYN。

正确的策略路由需要的不仅仅是默认路由

路由部分存在缺陷:备用路由表只分配了一条默认路由。这将使路由的数据包后退在到达预定目标之前,它们不知道自己来自哪里,从而造成了流量循环和下降。

按照 OP 的例子:

  • 来自新流的带有 SYN 的新 TCP 数据包到达接口e-基辅1
  • mangle/PREROUTING 首先看到该数据包,并为其分配防火墙标记 10001
  • 路由堆栈看到数据包
  • 其 fwmark 10001 与低优先级(45)路由规则匹配
  • 数据包穿过路由表 10001
  • 数据包与到接口的默认路由匹配e-基辅1
  • 数据包被送回原处,而没有到达预定目标
  • 下一跳路由器(实际上是“上一跳”路由器)再次看到此数据包并将其(再次)路由到当前路由器
  • 循环:来自新流的带有 SYN 的新 TCP 数据包到达接口e-基辅1
  • 继承标记(或再次被标记,无所谓)
  • (重复)
  • IPv4 的 TTL 最终达到 0:数据包被丢弃

所有内部路线主要的表应复制到所有附加路由表:不涉及特定任播接入点 (POP) 路由器的路由表,以便数据包能够到达其内部目标。如果在主要的表它们当然也应该复制到特定的附加表(而不是所有附加表)。

另一种更简单的方法,可能有效也可能无效,具体取决于完整的设置,是首先调用主要的路由表,但绕过其默认路由,然后调用附加的 POP 路由表:这样可以避免每个附加路由表中的重复,从而避免整个设置中使用单个附加路由规则带来的维护负担。

对于此示例,只需添加:

ip rule add prio 40 table main suppress_prefixlength 0

一定不能有其他路由规则(当然,当地的您可以使用其他任何规则(例如,任何优先级低于该规则的路由表)来更改此规则的优先级。

table main suppress_prefixlength 0意思是:“如果主要的与其相匹配的表默认路线(即:0.0.0.0/0)而不是更具体的路线,忽略结果,就好像还没有匹配的路线一样,继续进一步的路由规则评估。”

相关内容