суббота, 23 января 2010 г.

Настройка балансировки трафика в Linux на примере двух провайдеров

1. Имеется компьютер, подключенный одновременно к двум провайдерам, предоставляющим выделенные каналы
связи с интернетом (Interzet и Твое ТВ). Один из провайдеров (Interzet) также предоставляет доступ к
внутренним ресурсам его локальной сети

Скорость доступа в интернет отличается: в Интерзете оплачен тариф с безлимитным доступом на скорости
1.5 мб/сек, в Твоем ТВ - безлимитный на скорости 1.0 мб/сек.

Необходимо обеспечить примерно равномерную загрузку одновременно обоих каналов в интернет (получить
суммарную скорость примерно 2.5мбит/сек), сохранить при этом возможность использования локальной сети
Interzet.

2. Идея решения была найдена тут: http://litec.ru/wiki/index.php/%D0%A8%D0%B...B0_%D0%B2_Linux и
адаптирована под описанную выше задачу.

В общих чертах решение сводится к следующему:
1) все исходящие соединения с интернетом, устанавливаемые софтом, отмечаются (маркируются) двумя разными метками - 1 и 2.
Для маркировки пакетов используется модуль CONNMARK пакета iptables. Модуль CONNMARK не входит в стандарное
(vanilla) ядро с kernel.org и в штатный состав пакета iptabels. Если в используемом дистрибутиве не наложены
необходимые патчи, придется их наложить самостоятельно из репозитория patch-o-matic и с ними скомпилировать
ядро и пакет iptables.

2) при маркировке метка 1 ставится в 60% случаев, а метка 2 - в 40%, чтобы через более быстрый канал (1.5 мбит/сек)
устанавливалось в 1.5 раза больше соединений, чем через более медленный канал (1.0 мбит/сек). Это достигается
за счет модуля statistic пакета iptables.

2) в зависимости от метки (1 или 2) пакет направляется соответственно либо на роутер 1, либо на роутер 2. Для
этого используются таблицы маршрутизации, настраиваемые через утилиту ip пакета iproute2;

3.Детальное описание необходимых настроек.

3.1. Проверяем, есть ли в дистрибутиве модуль CONNMARK пакета iptables.
В gentoo linux этого модуля нет в gentoo-sources и iptables, поэтому необходимо наложить патчи и пересобрать
ядро и пакет iptables. Если модуль CONNMARK уже есть на компьютере, можно пропустить пункт 3.2.

3.2. Накладываем на gentoo linux патчи из patch-o-matic, собираем ядро и пакет iptables с поддержкой CONNMARK.

3.2.1. Заходим пользователем root и создаем временный каталог.
Код
su -
cd
mkdir patch-o-matic
cd patch-o-matic/


3.2.2. Скачиваем набор патчей из репозитория patch-o-matic, проверяем их целостность и распаковываем их.
Код
wget http://ftp.netfilter.org/pub/patch-o-matic-ng/snapshot/patch-o-matic-ng-20071211.tar.bz2
wget http://ftp.netfilter.org/pub/patch-o-matic-ng/snapshot/patch-o-matic-ng-20071211.tar.bz2.md5sum
md5sum -c patch-o-matic-ng-20071211.tar.bz2.md5sum
# если все ок, то видим: patch-o-matic-ng-20071211.tar.bz2: Успех
tar xfjv patch-o-matic-ng-20071211.tar.bz2


3.2.3. Настраиваем компиляцию iptables с расширенным набором модулей (потребуется дальше) и распаковываем
исходные тексты iptables (потребуется для накладывания патчей patch-o-matic).
Код
echo net-firewall/iptables ipv6 extensions -imq -l7filter -static>>/etc/portage/package.use
ebuild  /usr/portage/net-firewall/iptables/iptables-1.3.8-r2.ebuild fetch
ebuild  /usr/portage/net-firewall/iptables/iptables-1.3.8-r2.ebuild unpack


3.2.4. Накладываем патчи patch-o-matic и удаляем распакованные исходники iptables (они в дальнейшем
не нужны).
Код
cd patch-o-matic-ng-20071211
KERNEL_DIR=/usr/src/linux IPTABLES_DIR=/var/tmp/portage/net-firewall/iptables-1.3.8-r2/work/iptables-1.3.8/ ./runme
rm -Rv /var/tmp/portage/net-firewall/iptables-1.3.8-r2/work/iptables-1.3.8/


3.2.5. Конфигурируем ядро для компиляции модуля CONNMARK.
Код
cd /usr/src/linux
make clean
make mrproper
cp /proc/config.gz .
gunzip config.gz
make menuconfig
    Networking  --->
        Networking options  --->
             [*] Network packet filtering framework (Netfilter)  --->
                Core Netfilter Configuration  --->
                       "CONNMARK" target support
                IP: Netfilter Configuration  --->
                     IPv4 connection tracking support (required for NAT)


3.2.6. Компилируем и устанавливаем пропатченное ядро, перезагружаемся.
Код
make
mount /boot
make install
make modules_install
reboot


3.2.7. Компилируем iptables с расширениями (используя в качестве заголовков файлы из пропатченного
ядра).
Код
emerge iptables


3.3. Настройка балансировки.

3.3.1. Настраиваем правила для маркировки
- создаем новую цепочку NEW_OUT_CONN, в которую дальше будем направлять первый пакет каждого
нового исходящего соединения с интернетом:
Код
iptables -t mangle -N NEW_OUT_CONN

- маркируем пакеты меткой 1. Далее для 60% пакетов выходим из цепочки с сохранением метки 1, а
для оставшихся 40% перезаписываем метку значением 2:
Код
iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 1
iptables -t mangle -A NEW_OUT_CONN -m statistic --mode random --probability 0.60 -j RETURN
iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 2


3.3.2. Разбиваем исходящие пакеты на группы (локалка или интернет), маркируем соединения с интернетом и
индивидуальные пакеты из таких соединений:
- пакеты, идущие в локальную сеть (с адресами из диапазонов 172.16.0.0/24, 192.168.0.0/16 и
10.0.0.0/8) никак не маркируются:
Код
iptables -t mangle -A OUTPUT -d 172.16.0.0/24 -j RETURN
iptables -t mangle -A OUTPUT -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A OUTPUT -d 10.0.0.0/8 -j RETURN

- пакеты, начинающие новые соединения с интернетом, напраляются для маркировки в цепочку_NEW_OUT_CONN:
Код
iptables -t mangle -A OUTPUT -s 172.16.0.0/24 -m state --state new,related -j NEW_OUT_CONN

- пакеты, входящие в состав установленных с интернетом соединений, маркируются той же меткой,
которая при была назначена для соединения в целом:
Код
iptables -t mangle -A OUTPUT -s 172.16.0.0/24 -j CONNMARK --restore-mark

Примечание. В кажлом пакете имеются две метки: поле "метка соединения" и поле "метка пакета"
В цепочке NEW_OUT_CONN заносится 1 или 2 в "метку соединения", затем эта метка копируется в
поле "метка пакета". Это необходимо, поскольку решение о маршрутизации принимается на основе
поля "метка пакета"

3.3.3. Настраиваем дополнительные таблицы маршрутизиции 101 и 102 и направляем в них пакеты
с метками 1 и 2 соответственно.
3.3.3.1. Настраиваем таблицу 101 (для Interzet):
- выполняем команду ip route и переносим из нее правила (кроме строки с default) в новую таблицу:
Код
ip route add 172.16.0.0/24 dev eth0 proto kernel scope link src 172.16.0.4 table 101
ip route add 127.0.0.0/8 dev lo scope link table 101

- добавляем строку, в которой в качестве шлюза по умолчанию задан роутер 1 (подключенный к Interzet):
Код
ip route add default via 172.16.0.97 table 101

- направляем пакеты с меткой 1 в таблицу 101 (Interzet):
Код
ip rule add prio 51 fwmark 1 table 101


3.3.3.2. Аналогично настраиваем таблицу 102 (пакеты с меткой 2, для Твоего ТВ):
Код
ip route add 172.16.0.0/24 dev eth0 proto kernel scope link src 172.16.0.4 table 102
ip route add 127.0.0.0/8 dev lo scope link table 102
ip route add default via 172.16.0.96 table 102
ip rule add prio 52 fwmark 2 table 102


3.3.3.3. Очищаем кэш маршрутов.
Код
ip route flush cache


4. Пробуем запустить софт, умеющий качать файлы в несколько потоков, для проверки что все работает.
Например, axel, aria2 - для закачки с ftp, http; ctorrent - для закачки из торрент-сетей.
Скорость соединения должна превышать скорость любого отдельного канала (Interzet, Твое ТВ), если
выбран достаточно быстрый ресурс.

Результат проверки закачкой в 60 потоков ядра с kernel.org:
Код
axel -n 60 ftp://204.152.191.37/pub/linux/kernel/v2.6/linux-2.6.23.9.tar.gz
...
[ 20%]  .......... .......... .......... .......... ..........  [ 279,6KB/s]
[ 20%]  .......... .......... .......... .......... ..........  [ 279,9KB/s]
[ 20%]  .......... .......... .......... .......... ..........  [ 279,8KB/s]
...
Connection 38 finished
        ,,,,,,,,,, ,,,,,..... .......... .......... ..........  [ 215,7KB/s]
[100%]  .......... ..
Connection 54 finished

Downloaded 22,4 megabytes in 1:46 seconds. (214,85 KB/s)

Видно, что все ОК, так как достигнутая скорость (279 кбайт/сек) выше любой из скоростей
отдельных каналов (180кбайт/сек=1.5мбит/сек у Interzet; 120кбайт/сек=1.0мбит/сек у Твоего ТВ).

5. Оформляем настройку балансировки в виде скрипта (например, как в приложении 2). И наслаждаемся
возросшей скоростью инета :smile:

Приложение 1. Шпаргалка по выполненным командам для включения поддержки CONNMARK в gentoo linux
Код
su -
cd
mkdir patch-o-matic
cd patch-o-matic/
wget http://ftp.netfilter.org/pub/patch-o-matic-ng/snapshot/patch-o-matic-ng-20071211.tar.bz2
wget http://ftp.netfilter.org/pub/patch-o-matic-ng/snapshot/patch-o-matic-ng-20071211.tar.bz2.md5sum
md5sum -c patch-o-matic-ng-20071211.tar.bz2.md5sum
# если все ок, то видим: patch-o-matic-ng-20071211.tar.bz2: Успех
tar xfjv patch-o-matic-ng-20071211.tar.bz2
echo net-firewall/iptables ipv6 extensions -imq -l7filter -static>>/etc/portage/package.use
ebuild  /usr/portage/net-firewall/iptables/iptables-1.3.8-r2.ebuild fetch
ebuild  /usr/portage/net-firewall/iptables/iptables-1.3.8-r2.ebuild unpack
cd patch-o-matic-ng-20071211
KERNEL_DIR=/usr/src/linux IPTABLES_DIR=/var/tmp/portage/net-firewall/iptables-1.3.8-r2/work/iptables-1.3.8/ ./runme
rm -Rv /var/tmp/portage/net-firewall/iptables-1.3.8-r2/work/iptables-1.3.8/
cd /usr/src/linux
make clean
make mrproper
cp /proc/config.gz .
gunzip config.gz
make menuconfig
    Networking  --->
        Networking options  --->
             [*] Network packet filtering framework (Netfilter)  --->
                Core Netfilter Configuration  --->
                       "CONNMARK" target support
                IP: Netfilter Configuration  --->
                     IPv4 connection tracking support (required for NAT)
make
mount /boot
make install
make modules_install
reboot
emerge iptables


Приложение 2. Полный текст скрипта для включения балансировки.
gav4 ~ # cat loadbalance
Код
#! /bin/sh

( . ./delbal ) > /dev/null

iptables -t mangle -N NEW_OUT_CONN
iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 1
iptables -t mangle -A NEW_OUT_CONN -m statistic --mode random --probability 0.60 -j RETURN
iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 2

iptables -t mangle -A PREROUTING -d 172.16.0.0/24 -j RETURN
iptables -t mangle -A PREROUTING -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A PREROUTING -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A PREROUTING -s 172.16.0.0/24 -m state --state new,related -j NEW_OUT_CONN
iptables -t mangle -A PREROUTING -s 172.16.0.0/24 -j CONNMARK --restore-mark

iptables -t mangle -A OUTPUT -d 172.16.0.0/24 -j RETURN
iptables -t mangle -A OUTPUT -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A OUTPUT -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A OUTPUT -s 172.16.0.0/24 -m state --state new,related -j NEW_OUT_CONN
iptables -t mangle -A OUTPUT -s 172.16.0.0/24 -j CONNMARK --restore-mark

iptables -t mangle -L -n

ip route add 172.16.0.0/24 dev eth0 proto kernel scope link src 172.16.0.4 table 101
ip route add 127.0.0.0/8 dev lo scope link table 101
ip route add default via 172.16.0.97 table 101
ip rule add prio 51 fwmark 1 table 101
ip route add 172.16.0.0/24 dev eth0 proto kernel scope link src 172.16.0.4 table 102
ip route add 127.0.0.0/8 dev lo scope link table 102
ip route add default via 172.16.0.96 table 102
ip rule add prio 52 fwmark 2 table 102
ip route flush cache

ip rule ls
echo "interzet (table 101)"
ip route ls table 101
echo "tvoetv (table 102)"
ip route ls table 102


Текст вспомогательного скрипта, удаляющего настройки (например, если балансировку надо на время
выключить). Он же выполняется автоматически перед настройкой балансировки.
gav4 ~ # cat delbal
Код
#! /bin/sh

iptables -t mangle -F NEW_OUT_CONN
iptables -t mangle -F PREROUTING
iptables -t mangle -F OUTPUT
iptables -t mangle -X NEW_OUT_CONN
iptables -t mangle -L -n
ip route flush table 102
ip rule del table 102
ip route flush table 101
ip rule del table 101
ip route flush cache

Комментариев нет:

Отправить комментарий