3.6 后内核中的多路径路由

Eug*_*ene 18 linux routing

大家可能都知道,3.6 Linux内核系列已经去掉了ipv4路由缓存,这对多路径路由产生了严重的影响。IPv4 路由代码(与 IPv6 不同)以循环方式选择下一跳,因此从给定源 IP 到给定目标 IP 的数据包并不总是经过相同的下一跳。在 3.6 之前,路由缓存正在纠正这种情况,因为下一跳一旦被选中,就会留在缓存中,并且所有从同一源到同一目的地的其他数据包都经过该下一跳。现在为每个数据包重新选择下一跳,这导致了奇怪的事情:路由表中有 2 个等价默认路由,每个都指向一个互联网提供商,我什至无法建立 TCP 连接,因为初始 SYN 和最终 ACK走不同的路线,

是否有任何相对简单的方法来恢复多路径路由的正常行为,以便按流而不是按数据包选择下一跳?是否有补丁可以使 IPv4 下一跳选择基于哈希,就像 IPv6 一样?或者大家都是怎么处理的?

bao*_*7uo 9

如果可能,升级到 Linux 内核 >= 4.4 ....

引入了基于散列的多路径路由,它在许多方面都比 3.6 之前的行为更好。它是基于流的,采用源 IP 和目标 IP(忽略端口)的哈希值来保持各个连接的路径稳定。一个缺点是我相信在 3.6 之前有各种算法/配置模式可用,但现在你得到了你所得到的!。您可以使用影响路径的选择weight

如果您处于我的情况,那么您实际上想要 ,3.6 >= behaviour < 4.4但它不再受支持。

如果您确实升级到> = 4.4,那么这应该可以解决问题,而无需所有其他命令:

ip route add default  proto static scope global \
nexthop  via <gw_1> weight 1 \
nexthop  via <gw_2> weight 1
Run Code Online (Sandbox Code Playgroud)

或者通过设备:

ip route add default  proto static scope global \
 nexthop  dev <if_1> weight 1 \
 nexthop  dev <if_2> weight 1
Run Code Online (Sandbox Code Playgroud)


the*_*bit 7

“相对容易”是一个困难的词,但你可能

  1. 为每个链接设置路由表 - 每个链接一个表,带有一个默认网关
  2. 使用 netfilter 在单个流的所有数据包上标记相同的标记
  3. 使用 ip 规则表根据标记通过不同的路由表路由数据包
  4. 使用多下一跳加权路由来平衡网关/链接上的第一个会话数据包。

在 netfilter 邮件列表上有一个关于这个主题的讨论,我从那里窃取了列表:

1. 路由规则(RPDB 和 FIB)

ip route add default via <gw_1> lable link1
ip route add <net_gw1> dev <dev_gw1> table link1
ip route add default via <gw_2> table link2
ip route add <net_gw2> dev <dev_gw2> table link2

/sbin/ip route add default  proto static scope global table lb \
 nexthop  via <gw_1> weight 1 \
 nexthop  via <gw_2> weight 1

ip rule add prio 10 table main
ip rule add prio 20 from <net_gw1> table link1
ip rule add prio 21 from <net_gw2> table link2
ip rule add prio 50 fwmark 0x301 table link1
ip rule add prio 51 fwmark 0x302 table link2
ip rule add prio 100 table lb

ip route del default
Run Code Online (Sandbox Code Playgroud)

2.防火墙规则(使用ipset强制采用“流”LB模式)

ipset create lb_link1 hash:ip,port,ip timeout 1200
ipset create lb_link2 hash:ip,port,ip timeout 1200

# Set firewall marks and ipset hash
iptables -t mangle -N SETMARK
iptables -t mangle -A SETMARK -o <if_gw1> -j MARK --set-mark 0x301
iptables -t mangle -A SETMARK -m mark --mark 0x301 -m set !
--match-set lb_link1 src,dstport,dst -j SET \
          --add-set lb_link1 src,dstport,dst
iptables -t mangle -A SETMARK -o <if_gw2> -j MARK --set-mark 0x302
iptables -t mangle -A SETMARK -m mark --mark 0x302 -m set !
--match-set lb_link2 src,dstport,dst -j SET \
          --add-set lb_link2 src,dstport,dst

# Reload marks by ipset hash
iptables -t mangle -N GETMARK
iptables -t mangle -A GETMARK -m mark --mark 0x0 -m set --match-set
lb_link1 src,dstport,dst -j MARK --set-mark 0x301
iptables -t mangle -A GETMARK -m mark --mark 0x0 -m set --match-set
lb_link2 src,dstport,dst -j MARK --set-mark 0x302

# Defining and save firewall marks
iptables -t mangle -N CNTRACK
iptables -t mangle -A CNTRACK -o <if_gw1> -m mark --mark 0x0 -j SETMARK
iptables -t mangle -A CNTRACK -o <if_gw2> -m mark --mark 0x0 -j SETMARK
iptables -t mangle -A CNTRACK -m mark ! --mark 0x0 -j CONNMARK --save-mark
iptables -t mangle -A POSTROUTING -j CNTRACK

# Reload all firewall marks
# Use OUTPUT chain for local access (Squid proxy, for example)
iptables -t mangle -A OUTPUT -m mark --mark 0x0 -j CONNMARK --restore-mark
iptables -t mangle -A OUTPUT -m mark --mark 0x0 -j GETMARK
iptables -t mangle -A PREROUTING -m mark --mark 0x0 -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark --mark 0x0 -j GETMARK
Run Code Online (Sandbox Code Playgroud)

您可能希望关注 netfilter 邮件列表讨论,了解上述内容的一些变体。