- PVSM.RU - https://www.pvsm.ru -
Недавно обзавёлся задачей по балансировке трафика между несколькими usb-модемами. В итоге родилось решение [1] коим и хочу поделиться с читателим.
На момент написания статьи это balancing_v0.5.2-alpha [2].
Изначально задача формулировалась примерно так:
Есть пучёк armhf девайсов c Ubuntu Trusty на борту.
У них есть несколько подключений к интернету. Обычно это основное проводное подключение (eth0) и несколько HiLink usb-модемов Huawei E303 (eth1-eth5). Через каждое из этих подключений нужно поднять openvpn-клиентов к единственному серверу и через них уже балансировать трафик.
Всё бы ничего, но у этих модемов нет возможности изменения подсети и шлюза (гвоздями прибиты 192.168.1.1/24), причём прошивок с реализацией этой возможности тоже не нашлось (в отличии, например от E3272 для которого есть прошивки с таким функционалом). Кроме того даже если бы и нашлись, то vpn-подключения всё равно были бы в одной подсети и с одинаковым шлюзом. Т.е. без продвинутой маршрутизации (policy routing) не обойтись.
Ах, да, ещё надо мониторить каждое подключение и отключать/включать, если порвалось/возобновилось. Т.е. маршрутизацией нужно управлять динамически.
Готовых решений под «обычный» Linux не нашёл. Киньте в меня ссылкой если они есть. Обычно публикуют свои собственные велосипеды на базе ip route, вот и я туда же.
Есть парочка OpenWrt-специфичных:
Основной трафик будет адресован сервису на openvpn-сервере, и для него достаточно будет балансировать соединения. Имейте ввиду, что такой способ балансировки не очень хорошо подходит для веб-сёрфинга, т.к. некоторые соединения внутри https-сессии могут быть направлены в разные интерфейсы. Тут нужно балансировать сессии (несколько соединений кряду, flow-based), поправьте меня, если не прав. В планах реализовать этот способ, вкупе с per-packet- и hash-based.
Живость подключения определяется минимальным объёмом трафика за период между проверками, и если он меньше порогового значения, то посредством пинга внешнего хоста.
Кроме этого, есть готовые инструкции [5] как получить доступ в веб интерфейсу каждого из модемов (у них же у всех одинаковые IP): можно привязать браузер к конкретному интерфейсу.
При поднятии или опускании интерфейса, который участвует в балансировке, автоматически должен рестартовать скрипт balancing (с помощью balancing_restart). Это обеспечивается соответствующей настройкой интерфейсов.
Скрипт инициализирует все упомянутые в настройках интерфейсы (и в то же время доступные) для балансировки: добавляет соответствующие правила маршрутизации (ip rule), маршруты (ip route), настраивает firewall (iptables).
В зависимости от настроек режима (solo или multi, которые, кстати, можно менять на лету записав соответствующее слово в balancing_mode), будет либо производиться балансировка между интерфейсами с указанным весом (multi), либо использоваться живой интерфейс с максимальным приоритетом (solo).
Через определённый период времени скрипт проверяет все интерфейсы на живость (а также сменился ли режим), и включает/отключает их соответственно посредством редактирования таблиц маршрутизации.
for conf in /proc/config.gz /boot/config-$(uname -r) /boot/config; do zgrep -e CONFIG_IP_ROUTE_MULTIPATH -e CONFIG_IP_MULTIPLE_TABLES -e CONFIG_IP_ADVANCED_ROUTER $conf 2>/dev/null; done
apt-get install iproute2 iptables coreutils iputils-ping grep sed
mkdir temp && cd temp
git clone https://github.com/vmspike/balancing
cd balancing
chmod +x balancing/balancing{_restart,} add_rt_table get_ovpn_by_base_ip bandwidth-measure
cp balancing/balancing* get_ovpn_by_base_ip add_rt_table bandwidth-measure /etc/network/
cd ../../ && rm -rf temp
apt-get install usb-modeswitch # Нужно для большинства usb-модемов
apt-get purge network-manager network-manager-gnome
apt-get autoremove # Аккуратно с этим, проверь точно ли всё это тебе не нужно.
# ARP kernel settings for multiple interfaces in the same subnet
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_filter = 1
net.ipv4.conf.all.arp_announce = 1
# Enable Loose Reverse Path
net.ipv4.conf.all.rp_filter = 2
# Remove routing cache if exists
net.ipv4.route.max_size = 0
sysctl -p
service networking stop
ну или
ifdown eth1 eth2 ... ethN
auto eth0
allow-hotplug eth0
iface eth0 inet static
address 192.168.1.10
network 255.255.255.0
dns-nameservers 8.8.8.8 208.67.222.222
pre-up /etc/network/add_rt_table eth0
# Gateway setup
up ip route add default via 192.168.1.1 dev eth0 src 192.168.1.10 proto static table eth0
up ip route add default via 192.168.1.1 dev eth0 src 192.168.1.10 proto static table default metric 2000
# IP rules setup for separate routing table
up ip rule add priority 10 from 192.168.1.10 lookup eth0
up ip rule add priority 110 from all oif eth0 lookup eth0
down while ip rule delete lookup eth0; do :; done || exit 0
# Start/stop OpenVPN
up service openvpn start $(/etc/network/get_ovpn_by_base_ip 192.168.1.10) || exit 0
down service openvpn stop $(/etc/network/get_ovpn_by_base_ip 192.168.1.10) || exit 0
# Restart balancing
up /etc/network/balancing_restart
down /etc/network/balancing_restart
# If it's WiFi interface
#wpa-driver nl80211
#wpa-key-mgmt WPA-PSK
#wpa-proto WPA2
#wpa-ssid SSID
#wpa-psk PASSWORD
## Repo for amd64 and i386 arch
# wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg|apt-key add -
# echo "deb http://swupdate.openvpn.net/apt trusty main" > /etc/apt/sources.list.d/swupdate.openvpn.net.list
apt-get update
apt-get install openvpn
adduser --system --no-create-home --home /nonexistent --disabled-login --group openvpn
mkdir /var/log/openvpn
chown openvpn:openvpn /var/log/openvpn
AUTOSTART="none"
client
remote openvpn.example.com 1194
local 192.168.1.10 # bind to eth0
;nobind
dev tun0
proto udp
resolv-retry infinite
remote-cert-tls server
comp-lzo
log-append /var/log/openvpn/ovpn-client-example.log
verb 3
;daemon
# Commented because balancing_restart require root permissions
;user openvpn
;group openvpn
;persist-key
;persist-tun
up "/etc/network/balancing_restart tun0 start"
down "/etc/network/balancing_restart tun0 stop"
;ca /etc/openvpn/ca.crt
CA CERT HERE
;cert /etc/openvpn/ovpn-client-example.crt
CERT HERE
;key /etc/openvpn/ovpn-client-example.key
PRIVATE KEY HERE
;tls-auth /etc/openvpn/ta.key 1
key-direction 1
<tls-auth>
STATIC TLS KEY HERE
</tls-auth>
tail -f -n30 /var/log/balancing.log
echo ======Current state======; echo ===Addresses===; ip a; echo; echo ===Rules===; ip rule; echo; echo ===Routing tables===; for TBL in $(ip rule | rev | cut -d' ' -f2 | rev | sort -u); do echo ==$TBL==; ip r l t $TBL; echo; done; echo; echo ===IPTABLES===; for table in raw mangle nat filter; do echo ==$table==; iptables -vnL -t $table; echo; done; echo; echo ===MODE===; cat /etc/network/balancing_mode;
======Current state======
===Addresses===
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 1a:2b:3c:4d:5e:6c brd ff:ff:ff:ff:ff:ff
inet 192.168.1.10/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::182b:3aff:fe4b:5e54/64 scope link
valid_lft forever preferred_lft forever
7: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
link/ether 12:34:56:78:90:12 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.11/24 brd 192.168.1.255 scope global eth1
valid_lft forever preferred_lft forever
inet 192.168.1.12/24 brd 192.168.1.255 scope global secondary eth1
valid_lft forever preferred_lft forever
inet6 fe80::5a2c:80fb:fe13:9263/64 scope link
valid_lft forever preferred_lft forever
8: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
link/none
inet 172.22.0.3/16 brd 172.22.255.255 scope global tun1
valid_lft forever preferred_lft forever
9: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
link/none
inet 172.22.0.2/16 brd 172.22.255.255 scope global tun0
valid_lft forever preferred_lft forever
===Rules===
0: from all lookup local
10: from 192.168.1.10 lookup eth0
11: from 192.168.1.11 lookup eth1
110: from all oif eth0 lookup eth0
111: from all oif eth1 lookup eth1
1000: from all fwmark 0x6a lookup tun0
1001: from 172.22.0.2 lookup tun0
1002: from all oif tun0 lookup tun0
1003: from all fwmark 0x6b lookup tun1
1004: from 172.22.0.3 lookup tun1
1005: from all oif tun1 lookup tun1
20000: from all lookup main
30000: from all lookup balancing
32767: from all lookup default
===Routing tables===
==balancing==
default proto static metric 1
nexthop via 172.22.0.1 dev tun0 weight 18
nexthop via 172.22.0.1 dev tun1 weight 1
default via 172.22.0.1 dev tun0 proto static src 172.22.0.2 metric 2
default via 172.22.0.1 dev tun1 proto static src 172.22.0.3 metric 4
default via 172.22.0.1 dev tun0 proto static src 172.22.0.2 metric 1002
default via 172.22.0.1 dev tun1 proto static src 172.22.0.3 metric 1004
==default==
default via 192.168.1.1 dev eth0 src 192.168.1.10 metric 2000
default via 192.168.1.1 dev eth1 src 192.168.1.11 metric 2001
==eth0==
default via 192.168.1.1 dev eth0 src 192.168.1.10
==eth1==
default via 192.168.1.1 dev eth1 src 192.168.1.11
==local==
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
broadcast 172.22.0.0 dev tun1 proto kernel scope link src 172.22.0.3
broadcast 172.22.0.0 dev tun0 proto kernel scope link src 172.22.0.2
local 172.22.0.2 dev tun0 proto kernel scope host src 172.22.0.2
local 172.22.0.3 dev tun1 proto kernel scope host src 172.22.0.3
broadcast 172.22.255.255 dev tun1 proto kernel scope link src 172.22.0.3
broadcast 172.22.255.255 dev tun0 proto kernel scope link src 172.22.0.2
broadcast 192.168.1.0 dev eth0 proto kernel scope link src 192.168.1.10
broadcast 192.168.1.0 dev eth1 proto kernel scope link src 192.168.1.11
local 192.168.1.10 dev eth0 proto kernel scope host src 192.168.1.10
local 192.168.1.11 dev eth1 proto kernel scope host src 192.168.1.11
broadcast 192.168.1.255 dev eth0 proto kernel scope link src 192.168.1.10
broadcast 192.168.1.255 dev eth1 proto kernel scope link src 192.168.1.11
==main==
169.254.0.0/16 dev eth0 scope link metric 1000
172.22.0.0/16 dev tun1 proto kernel scope link src 172.22.0.3
172.22.0.0/16 dev tun0 proto kernel scope link src 172.22.0.2
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.11
==tun0==
default via 172.22.0.1 dev tun0 proto static src 172.22.0.2 metric 2
==tun1==
default via 172.22.0.1 dev tun1 proto static src 172.22.0.3 metric 4
===IPTABLES===
==mangle==
Chain PREROUTING (policy ACCEPT 5473 packets, 631K bytes)
pkts bytes target prot opt in out source destination
5473 631K CONNMARK all -- * * 0.0.0.0/0 0.0.0.0/0 CONNMARK restore
19 1140 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 ctorigdst 172.22.0.2 mark match 0x0 MARK set 0x6a
19 1140 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 ctorigdst 172.22.0.3 mark match 0x0 MARK set 0x6b
Chain INPUT (policy ACCEPT 4621 packets, 587K bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 3344 packets, 541K bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 3344 packets, 541K bytes)
pkts bytes target prot opt in out source destination
590 92460 MARK all -- * tun0 0.0.0.0/0 0.0.0.0/0 mark match 0x0 MARK set 0x6a
590 92460 MARK all -- * tun1 0.0.0.0/0 0.0.0.0/0 mark match 0x0 MARK set 0x6b
3344 541K CONNMARK all -- * * 0.0.0.0/0 0.0.0.0/0 CONNMARK save
===MODE===
multi
(если проект будет развиваться)
Комментарии/предложения/критика горячо приветствуются!
Автор: vmspike
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/marshrutizatsiya/130993
Ссылки в тексте:
[1] решение: https://github.com/vmspike/balancing
[2] balancing_v0.5.2-alpha: https://github.com/vmspike/balancing/archive/v0.5.2-alpha.tar.gz
[3] multiwan: https://wiki.openwrt.org/ru/doc/howto/multiwan.failower
[4] mwan3: https://wiki.openwrt.org/ru/doc/howto/mwan3
[5] готовые инструкции: https://github.com/vmspike/balancing/tree/master/bind
[6] файлу: https://github.com/vmspike/balancing/blob/master/balancing/balancing_vars
[7] Источник: https://habrahabr.ru/post/303056/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.