3.6后内核中的多path路由

正如大家所知,在Linux内核系列中,ipv4路由caching已经被删除,这对多path路由有严重影响。 IPv4路由代码(与IPv6不同)以循环方式select下一跳,因此从给定源IP到给定目的IP的数据包并不总是经过相同的下一跳。 在3.6之前,路由caching正在纠正这种情况,下一跳一旦被选中,就停留在caching中,并且从同一个源到同一个目的地的所有其他数据包都要经过该下一跳。 现在为每个数据包重新select下一跳,这会导致一些奇怪的事情:在路由表中有两个等价的默认路由,每个指向一个Internet提供者,我甚至不能build立TCP连接,因为初始的SYN和最终的ACK经由不同的路由,并且由于每条path上的NAT,它们以不同来源的分组到达目的地。

是否有任何相对简单的方法来恢复多path路由的正常行为,以便下一跳select每个stream而不是每个数据包? 有没有补丁可以使IPv4下一跳select基于散列,就像IPv6一样? 或者你们怎么处理呢?

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

  1. 为每个链接设置路由表 – 每个链接一个表,只有一个默认网关
  2. 使用netfilter在单个stream的所有数据包上标记相同的标记
  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 

2.防火墙规则(使用ipset强制“stream量”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 

你可能想关注netfilter邮件列表的讨论,了解上面的一些变化。

如果可能,升级到Linux Kernel> = 4.4 ….

已经引入了基于哈希的多path路由 ,在许多方面都比3.6版本的行为更好。 它是基于stream的,对源IP和目标IP(忽略端口)进行哈希以保持单个连接的path稳定。 一个缺点是,我相信3.6之前有各种algorithm/configuration模式,但现在你得到你给的东西! 你可以用weight来影响path的select。

如果你是我的情况,那么你实际上需要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 

或者通过设备:

 ip route add default proto static scope global \ nexthop dev <if_1> weight 1 \ nexthop dev <if_2> weight 1