Bha*_*vya 5 routing iptables load-balancing linux-networking
我正在尝试在具有两个网关的 linux 路由器上对来自内部 LAN 的流量进行负载平衡。最初我选择了 iproute 实现,它没有按预期平衡负载,原因是路由被缓存。
现在我使用 iptables 使用 CONNMARK 标记每个新连接,然后添加规则以通过不同的网关路由这些标记的连接。
Eth0 - 局域网,Eth1 - ISP1,Eth2 - ISP2
以下是我正在使用的脚本,
#!/bin/bash
echo 1 >| /proc/sys/net/ipv4/ip_forward
echo 0 >| /proc/sys/net/ipv4/conf/all/rp_filter
# flush all iptables entries
iptables -t filter -F
iptables -t filter -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -t filter -P INPUT ACCEPT
iptables -t filter -P OUTPUT ACCEPT
iptables -t filter -P FORWARD ACCEPT
# initialise chains that will do the work and log the packets
iptables -t mangle -N CONNMARK1
iptables -t mangle -A CONNMARK1 -j MARK --set-mark 1
iptables -t mangle -A CONNMARK1 -j CONNMARK --save-mark
iptables -t mangle -A CONNMARK1 -j LOG --log-prefix 'iptables-mark1: ' --log-level info
iptables -t mangle -N CONNMARK2
iptables -t mangle -A CONNMARK2 -j MARK --set-mark 2
iptables -t mangle -A CONNMARK2 -j CONNMARK --save-mark
iptables -t mangle -A CONNMARK2 -j LOG --log-prefix 'iptables-mark2: ' --log-level info
iptables -t mangle -N RESTOREMARK
iptables -t mangle -A RESTOREMARK -j CONNMARK --restore-mark
iptables -t mangle -A RESTOREMARK -j LOG --log-prefix 'restore-mark: ' --log-level info
iptables -t nat -N SNAT1
iptables -t nat -A SNAT1 -j LOG --log-prefix 'snat-to-192.168.254.74: ' --log-level info
iptables -t nat -A SNAT1 -j SNAT --to-source 192.168.254.74
iptables -t nat -N SNAT2
iptables -t nat -A SNAT2 -j LOG --log-prefix 'snat-to-192.168.253.132: ' --log-level info
iptables -t nat -A SNAT2 -j SNAT --to-source 192.168.253.132
# restore the fwmark on packets that belong to an existing connection
iptables -t mangle -A PREROUTING -i eth0 \
-m state --state ESTABLISHED,RELATED -j RESTOREMARK
# if the mark is zero it means the packet does not belong to an existing connection
iptables -t mangle -A PREROUTING -m state --state NEW \
-m statistic --mode nth --every 2 --packet 0 -j CONNMARK1
iptables -t mangle -A PREROUTING -m state --state NEW \
-m statistic --mode nth --every 2 --packet 1 -j CONNMARK2
iptables -t nat -A POSTROUTING -o eth1 -j SNAT1
iptables -t nat -A POSTROUTING -o eth2 -j SNAT2
if ! cat /etc/iproute2/rt_tables | grep -q '^51'
then
echo '51 rt_link1' >> /etc/iproute2/rt_tables
fi
if ! cat /etc/iproute2/rt_tables | grep -q '^52'
then
echo '52 rt_link2' >> /etc/iproute2/rt_tables
fi
ip route flush table rt_link1 2>/dev/null
ip route add 192.168.254.0/24 dev eth1 src 192.168.254.74 table rt_link1
ip route add default via 192.168.254.5 table rt_link1
ip route flush table rt_link2 2>/dev/null
ip route add 192.168.253.0/24 dev eth2 src 192.168.253.132 table rt_link2
ip route add default via 192.168.253.5 table rt_link2
ip rule del from all fwmark 0x1 lookup rt_link1 2>/dev/null
ip rule del from all fwmark 0x2 lookup rt_link2 2>/dev/null
ip rule del from all fwmark 0x2 2>/dev/null
ip rule del from all fwmark 0x1 2>/dev/null
ip rule add fwmark 1 table rt_link1
ip rule add fwmark 2 table rt_link2
ip route flush cache
Run Code Online (Sandbox Code Playgroud)
使用此连接确实会通过两条路线进行路由。但是,其中一些被丢弃,即连接无法通过。在某些情况下,已建立的连接会在中途中断。
我错过了什么吗?
这是另一种方法。无需根据数据包计数标记连接并希望它们不会被重新初始化、重复或以其他方式更改,只需按源或目标 IP 划分数据包即可。对于任何足够大的连接集,您应该有大约 50-50 的分布。
我将发布以下内容作为直接替换,但您可能可以通过更多的修补来完全消除 CONNMARK 逻辑。
iptables -t mangle -A PREROUTING -m state --state NEW \
-d 0.0.0.0/0.0.0.1 -j CONNMARK1
iptables -t mangle -A PREROUTING -m state --state NEW \
-d 0.0.0.1/0.0.0.1 -j CONNMARK2
Run Code Online (Sandbox Code Playgroud)
如果源 IP 存在更多差异,您还可以将目标更改为源,甚至将它们组合到括号中。(奇/奇或偶/偶是 CONNMARK1,奇/偶或偶/奇是 CONNMARK2)。