LinuxBalance
Оригинал: Balancing Connections Over Multiple Links
В статье рассказывается о распределении трафика между тремя каналами в Linux, используя iptables. Балансировка производится через модули "random" или "nth", сопоставление пакетов открытых сессий с интерфейсов производится через модуль "connmark".
Имеем Linux ядро 2.6.14.2 с наложенными patch-o-matic-ng патчами и три сетевых интерфейса в системе:
- eth0: Wired connection, 192.168.1.0/24, gateway 192.168.1.1, default route.
- eth1: Wireless connetion 1, 172.16.0.0/16, gateway 172.16.0.1
- rausb0: Wireless connetion 2, 192.168.0.0/24, gateway 192.168.0.1
Привязываем TCP сессии к интерфейсам (чтобы пакеты в пределах одной сессии шли через один и тотже интерфейс):
# prevent incoming packets on masqueraded connections from being dropped # as "martians" due to the destination address being translated before the # rp_filter check is performed echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter echo 0 > /proc/sys/net/ipv4/conf/rausb0/rp_filter # Load protocol-specific connection tracking modules so that new connections # associated with existing connections have state "RELATED" and inherit the # same connmark. modprobe ip_conntrack_ftp # masquerade outgoing connections on secondary interfaces iptables -t nat -A POSTROUTING -o eth1 -s ! 172.16.0.0/16 -m state --state NEW,RELATED -j MASQUERADE iptables -t nat -A POSTROUTING -o rausb0 -s ! 192.168.0.0/24 -m state --state NEW,RELATED -j MASQUERADE # create a chain for processing new outgoing connetions iptables -t mangle -N NEW_OUT_CONN # Skip connections we want to always go out wired interface iptables -t mangle -A NEW_OUT_CONN -d 192.168.1.0/24 -j RETURN iptables -t mangle -A NEW_OUT_CONN -p tcp -m multiport --destination-ports 21,22,80,443,6667 -j RETURN iptables -t mangle -A NEW_OUT_CONN -p udp --dport 53 -j RETURN # have new outgoing connections pass through the above chain iptables -t mangle -A OUTPUT -o eth0 -m state --state NEW -j NEW_OUT_CONN # send packets out chosen interface iptables -t mangle -A OUTPUT -m connmark --mark 2 -j ROUTE --gw 172.16.0.1 --continue iptables -t mangle -A OUTPUT -m connmark --mark 3 -j ROUTE --gw 192.168.0.1 --continue
Определяем процент трафика уходящий через каждый интерфейс. Первый вариант балансировки:
# 34% of the time go out the default interface iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 0 iptables -t mangle -A NEW_OUT_CONN -m random --average 34 -j RETURN # 33% of the time go out eth1 (50% of the remaining probability) iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 2 iptables -t mangle -A NEW_OUT_CONN -m random --average 50 -j RETURN # else (hopefully 33% of the time) go out rausb0 iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 3
Второй вариант:
# Первое соединение из каждых трех отправляем в интерфейс по умолчанию. iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 0 iptables -t mangle -A NEW_OUT_CONN -m nth --counter 1 --every 3 --packet 0 -j RETURN # Второе соединение из каждых трех отправляем в интерфейс eth1 iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 2 iptables -t mangle -A NEW_OUT_CONN -m nth --counter 1 --every 3 --packet 1 -j RETURN # Третье соединение из каждых трех отправляем в интерфейс rausb0 iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 3 iptables -t mangle -A NEW_OUT_CONN -m nth --counter 1 --every 3 --packet 2 -j RETURN
Обрабатываем ситуацию отключения одного из линков (в /etc/network/if-down.d/ для Debian):
#!/bin/sh if [ "$IFACE" = "eth1" ]; then iptables -t mangle -D OUTPUT -m connmark --mark 2 -j ROUTE --gw 172.16.0.1 --continue 2>/dev/null fi if [ "$IFACE" = "rausb0" ]; then iptables -t mangle -D OUTPUT -m connmark --mark 3 -j ROUTE --gw 192.168.0.1 --continue 2>/dev/null fi exit 0
Скрипт вызываемый когда упавший интерфейс поднялся (в /etc/network/if-up.d/ для Debian):
#!/bin/sh if [ "$IFACE" = "eth1" ]; then iptables -t mangle -A OUTPUT -m connmark --mark 2 -j ROUTE --gw 172.16.0.1 --continue 2>/dev/null fi if [ "$IFACE" = "rausb0" ]; then iptables -t mangle -A OUTPUT -m connmark --mark 3 -j ROUTE --gw 192.168.0.1 --continue 2>/dev/null fi exit 0