LINUX.ORG.RU
ФорумAdmin

Распределение нагрузки на несколько VPN соединений

 , , , ,


0

1

Привет

Есть машина, на которой поднята пара соединений с OVPN серверами.

При направлении трафика в одно из них всё работает хорошо.

default via vpn-gateway-1-ip \ default via vpn-gateway-2-ip

Если же я добавляю в схему маршрутизации второе, через nexthop, – возникают проблемы.

scope global default
    nexthop via vpn-gateway-1-ip weight 1
    nexthop via vpn-gateway-2-ip weight 1

Под проблемами подразумеваю то, что при пинге какого-либо ресурса возвращаются лишь чётные пакеты

$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=2 ttl=119 time=271 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=119 time=271 ms
64 bytes from 8.8.8.8: icmp_seq=6 ttl=119 time=271 ms
64 bytes from 8.8.8.8: icmp_seq=8 ttl=119 time=271 ms
64 bytes from 8.8.8.8: icmp_seq=10 ttl=119 time=271 ms
^C
--- 8.8.8.8 ping statistics ---
11 packets transmitted, 5 received, 54,5455% packet loss, time 10079ms
rtt min/avg/max/mdev = 270.648/270.672/270.691/0.016 ms

либо же они вообще могут не вернуться

$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=2 ttl=119 time=270 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=119 time=270 ms
64 bytes from 8.8.8.8: icmp_seq=6 ttl=119 time=271 ms
64 bytes from 8.8.8.8: icmp_seq=8 ttl=119 time=279 ms
^C
--- 8.8.8.8 ping statistics ---
8 packets transmitted, 4 received, 50% packet loss, time 7067ms
rtt min/avg/max/mdev = 270.264/272.631/279.198/3.793 ms
$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=2 ttl=119 time=271 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=119 time=270 ms
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 2 received, 50% packet loss, time 3026ms
rtt min/avg/max/mdev = 270.292/270.453/270.615/0.161 ms
$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=119 time=271 ms
^C
--- 8.8.8.8 ping statistics ---
29 packets transmitted, 1 received, 96,5517% packet loss, time 28627ms
rtt min/avg/max/mdev = 270.649/270.649/270.649/0.000 ms

Ресурсы по http(-s) открываются по своему усмотрению.

Например, морда гугла может открыться и запросы на его сервера будут проходить. Но не все используемые на странице гуглом ресурсы будут доступны, что приведёт к «бесконечной» загрузке.

Яндекс и абсолютное большинство из других проверенных мной ресурсов недоступны.

Нашёл информацию о том, что линь умеет то что мне нужно из коробки с версии ядра >= 4.4 линк

IPv4: Hash-based multipath routing. When the routing cache was removed in 3.6, the IPv4 multipath algorithm changed from more or less being destination-based into being quasi-random per-packet scheduling. This increased the risk of out-of-order packets and made it impossible to use multipath together with anycast services. In this release, the multipath routing implementation is replaced with a flow-based load balancing based on a hash over the source and destination addresses merge commit

Однако в одном из ответов к вопросу на https://unix.stackexchange.com/ человек написал, что этот способ балансировки подойдёт лишь в том случае, если выходной адрес балансируемых интерфейсов будет одинаков. Например, два канала под одним и тем же айпишником.

Ищу помощь. Подскажите куда посмотреть, где копнуть. Может кто-нибудь уже решал подобную проблему? Подходит ли для решения вопроса nexthop?

Список маршрутов:

default 
    nexthop via 10.16.0.1 dev tun0 weight 1 
    nexthop via 10.81.0.1 dev tun1 weight 1 
10.16.0.0/16 dev tun0 proto kernel scope link src 10.16.0.4 
10.81.0.0/16 dev tun1 proto kernel scope link src 10.81.0.2
x.x.x.x via 192.168.2.1 dev enswww
y.y.y.y via 192.168.2.1 dev enswww
192.168.2.0/24 dev enswww proto kernel scope link src 192.168.2.254 metric 101
192.168.3.0/24 dev enslll proto kernel scope link src 192.168.3.252 metric 100

Где,

x.x.x.x и y.y.y.y IP адреса VPN гейтов.

enswww (w от wan), enslll (l от lan) – физические интерфейсы.

Система:

Linux pc 5.4.0-45-generic #49-Ubuntu SMP Wed Aug 26 13:38:52 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

No LSB modules are available.
Distributor ID: Linuxmint
Description:    Linux Mint 20
Release:    20
Codename:   ulyana

P.S.

Для чистоты эксперимента проверил тот же конфиг на чистом дебиане – то же самое.

Linux debian 4.19.0-10-amd64 #1 SMP Debian 4.19.132-1 (2020-07-24) x86_64 GNU/Linux


Последнее исправление: borisb (всего исправлений: 3)
Ответ на: комментарий от Kuzz

Этой ночью уже курил этот мануальчик.

Решил попробовать ещё раз после вашего сообщения и о чудо! Всё получилось и работает. Помониторю, но как минимум ранее недоступные ресурсы грузятся хорошо =)

Но не могли бы вы рассказать, как так получилось, что до добавления правил из мана сеть не работала? Получался примерно следующий сценарий?

  1. Отправка пакета из первого интерфейса на ресурс.
  2. Ресурс отвечает. Первый интерфейс (tun0) обрабатывает пакет и вливает его в систему.
  3. Пакет каким-то образом обрабаывается.
  4. Система формирует пакет и отправляет его ресурсу.
  5. Ядро линя выбирает второй интерфейс (tun1), а не tun0.

Итоговый набор правил:

root@debian:~# ip route list
default
	nexthop via 10.16.0.1 dev tun0 weight 1
	nexthop via 10.81.0.1 dev tun1 weight 1
10.16.0.0/16 dev tun0 proto kernel scope link src 10.16.0.2
10.81.0.0/16 dev tun1 proto kernel scope link src 10.81.0.2
x.x.x.x via 192.168.2.1 dev enswww
y.y.y.y via 192.168.2.1 dev enswww
192.168.2.0/24 dev enswww proto kernel scope link src 192.168.2.253 metric 101
192.168.3.0/24 dev enslll proto kernel scope link src 192.168.3.253 metric 100

root@debian:~# ip route show table table1
default via 10.16.0.1 dev tun0
10.16.0.0/16 dev tun0 scope link src 10.16.0.2

root@debian:~# ip route show table table2
default via 10.81.0.1 dev tun1
10.81.0.0/16 dev tun1 scope link src 10.81.0.2

root@debian:~# ip rule list
0:	from all lookup local
32764:	from 10.81.0.0/16 lookup table2
32765:	from 10.16.0.0/16 lookup table1
32766:	from all lookup main
32767:	from all lookup default

P.S.

Пробовал на linux-mint, а не как сейчас (на debian). Вряд ли в этом разница, видимо ночью сам ошибся.

borisb
() автор топика
Ответ на: комментарий от borisb

А что в таблице nat iptables? В туннель не должны попадать пакеты с адресом отправителя от другого туннеля.

Еще нужно отключить rp_filter.

vel ★★★★★
()
Ответ на: комментарий от vel

Проверяю работу варианта с двумя подключениями на чистом debian. Правила не трогал.

root@debian:~# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Не могли бы вы рассказать о необходимости отключения rp_filter? Погуглил, узнал для чего это нужно. Разве в моём варианте может прийти ответ через другой интерфейс?

borisb
() автор топика
Ответ на: комментарий от borisb

У тебя почти каждый второй ответ должен приходить через другой туннель, т.ч. rp_filter точно должен быть отключен.

Если туннели ведут к одному «провайдеру», то можно обойтись без NAT.

IMHO твоя система будет работать при условии использования белых адресов в туннелях и при отсутствии фильтрации трафика «провайдером».

Если туннели от абсолютно разных провайдеров и с серыми адресами, то без NAT оно работать будет именно так, как у тебя сейчас.

Если включить NAT, то все будет так же плохо. С NAT можно делать только балансировку соединений.

vel ★★★★★
()
Последнее исправление: vel (всего исправлений: 2)
Ответ на: комментарий от borisb

Вообще, сначала нужно было убедиться в работоспособности конструкции без балансировки при обоих поднятых интерфейсах ping-ом с явным выбором адреса источника пакетов.

vel ★★★★★
()
Ответ на: комментарий от vel

Не понимаю почему каждый второй пакет будет приходить через другой туннель =(

На каком шаге я ошибаюсь?

  1. Генерация пакета на стороне машины.
  2. Ядро выбирает интерфейс для отправки запроса (хэш от адреса источника и адреса назначения).
  3. Определённым образом выбран tun0.
  4. Происходит отправка пакета.
  5. OVPN клиент обрабатывает пакет и оборачивает его.
  6. OVPN клиент отправляет пакет на адрес VPN сервера (отдельный маршрут).
  7. Происходит некая работа и пакет приходит обратно на машину.
  8. tun0 получает пакет и обрабатывает его, удаляя VPN обёртку, затем отправляя пакет на физический интерфейс.
  9. Ядро получает пакет и далее идёт его обработка.
  10. Затем по добавленным правилам ip rule from … ответный пакет будет отправлен через тот же интерфейс, через который он и пришёл.

Насколько я понимаю, тонкости про NAT и rp_filter будут важны лишь тогда, когда я переведу машину в режим роутера для перенаправления трафика. Но я в любом случае проверил текущее значение rp_filter на debian – равняется нулю. Установил в единицу для всех интерфейсов, перезагрузился и настроил всё заново – так же работает хорошо.

Если я вас правильно понял по пингу, то всё хорошо.

root@debian:~# ping -I tun0 8.8.8.8
PING 8.8.8.8 (8.8.8.8) from 10.18.0.2 tun0: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=120 time=124 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=120 time=62.9 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=120 time=62.7 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=120 time=62.8 ms
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 7ms
rtt min/avg/max/mdev = 62.693/78.179/124.326/26.644 ms
root@debian:~# ping -I tun1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) from 10.81.0.2 tun1: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=712 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=118 time=270 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=118 time=271 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=118 time=271 ms
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 5ms
rtt min/avg/max/mdev = 270.448/381.096/712.204/191.166 ms

Кстати, проверил ещё раз эту же схему на linux mint. Не работает ни в какую. На данный момент единственная найденная мной разница это значение rp_filter, которое по-умолчанию выставлено в единицу для всех интерфейсов. Перевод его в ноль с последующей перезагрузкой не помог. Загадка…

borisb
() автор топика
Ответ на: комментарий от borisb

«ping -I» по имени интерфейса использует ядерную магию, которая может искажать результат. Во многих случаях «ping -I name dst» и «ping -I src dst» дают разные результаты.

Вся проблема в том, что без явного указания адреса источника, ядро должно подставить туда что-то и делается это не при выборе машрута, а значительно раньше - при передаче данных в сокет.

IMHO это делается 1 раз при первой посылке пакета. Так что при отправке через другой шлюз адрес источника не изменится.

Для транзитных пакетов такой проблемы нет. Но чтобы такая схема работала нужно чтобы оба vpn провайдера знали про эту сеть, иначе оно не будет работать без NAT.

п.10 вообще бред. «ip ru» будет действовать после передачи данных из сокета в ipv4, т.е. значительно раньше. «ip ru» будет вызван еще раз для пакета который идет в сторону vpn сервера.

ответный пакет будет отправлен через тот же интерфейс, через который он и пришёл.

@#$%^&* с какого перепуга? У нас коммутация пакетов, а не соединений! Посмотри, что такое ассиметричная маршутизация.

vel ★★★★★
()

Полагаю, конкретно ваша реализация будет работать только с рабочей L2-связностью (OpenVPN в режиме tap, а не tun).

ValdikSS ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.