Hi, I have two ISPs and a LAN. I need to load balance outgoing connections from the LAN between the ISPs.
My router is running OpenBSD 4.6-stable, up-to-date. ----------------- | | ISP 1 ---(isp1 box)---+-ext1_if | | | | int_if-+--- LAN | | ISP 2 ---(isp2 box)---+-ext2_if | | | ----------------- OpenBSD int_if -> interface to LAN int_net -> 192.168.0.0/24 ext1_if -> interface to ISP 1 (192.168.1.2) ext1_gw -> ISP 1 gateway (192.168.1.1) ext2_if -> interface to ISP 2 (192.168.2.2) ext2_gw -> ISP 2 gateway (192.168.2.1) There is no default route (empty /etc/mygate). Following http://www.openbsd.org/faq/pf/pools.html#outgoing I ended up with the following : ---sysctl.conf--- net.inet.ip.forwarding=1 ---sysctl.conf--- ---pf.conf--- set debug loud set block-policy return #set optimization aggressive #set timeout src.track 300 set skip on lo nat log on $ext1_if from $int_net -> ($ext1_if) nat log on $ext2_if from $int_net -> ($ext2_if) block log pass in log on $int_if route-to \ { ($ext1_if $ext1_gw), ($ext2_if $ext2_gw) } \ from $int_net pass in log on $int_if from $int_net to $int_if pass out log pass out log on $ext1_if route-to ($ext2_if $ext2_gw) from $ext2_if pass out log on $ext2_if route-to ($ext1_if $ext1_gw) from $ext1_if ---pf.conf--- Everything works fine with this setup but https and some ftp servers are very sensitive to IP changes, so I did add sticky-address to bind a connection to an ISP and fix this issue : pass in log on $int_if route-to \ { ($ext1_if $ext1_gw), ($ext2_if $ext2_gw) } sticky-address \ from $int_net This works when only one PC open a connection. When another PC open a connection the first one has no longer access to the internet. After some time in tcpdump and /var/log/messages, it seems because packets are routed to the wrong interface. /var/log/messages analysis : 192.168.0.78 tries a connection : /bsd: pf_map_addr: selected address 192.168.2.1 /bsd: pf_map_addr: selected address 192.168.2.2 /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.1 /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.2 /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.1 /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.2 Looks ok, now 192.168.0.29 tries a connection too : /bsd: pf_map_addr: selected address 192.168.1.1 /bsd: pf_map_addr: selected address 192.168.1.2 /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.1 /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.2 /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.1 /bsd: pf_map_addr: src tracking maps 192.168.0.29 to 192.168.1.2 Looks good, now 192.168.0.78 retries a connection : /bsd: pf_map_addr: src tracking maps 192.168.0.78 to 192.168.2.1 /bsd: pf_map_addr: selected address 192.168.1.2 [and that's all] This is confirmed by tcpdump (on pflog0, bge0, em0 and em1) : the packets are routed to the wrong interface. Three SYN are sent, then client bail out. Tests were quickly done, so there is no state/track timeout here. Is there something I am doing wrong ?