LinuxBalance

Материал из OpenWiki
Перейти к: навигация, поиск

Оригинал: 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