Почему маршруты с равной стоимостью делают сбои VPN трудно заметными
Когда несколько туннелей делят одну стоимость, каждый поток может выбрать другой. Успешный ping ничего не говорит о пути, который ваше приложение действительно использует.
Пользователь сообщает, что внутреннее приложение работает с одной машины и не работает с другой, а ping, запущенный со шлюза, успешен в обоих случаях. При нескольких туннелях равной стоимости это не противоречие. Каждый поток помещается на свой следующий хоп, поэтому ваша проверка и сеанс пользователя могут просто использовать разные пути. Разбор ниже воспроизводит этот выбор до каких-либо изменений.
Один ping, несколько возможных путей
Когда у маршрута больше одного следующего хопа с одинаковой стоимостью, маршрутизатор должен выбрать один на каждый пакет. Большинство реализаций хешируют поля пакета, обычно адреса источника и назначения вместе с протоколом и портами, чтобы ответы оставались на том же пути. Разные приложения и даже разные соединения одного приложения дают разные хеши.
Именно поэтому диагностика со шлюза доказывает так мало. Собственная проверка шлюза имеет свои адреса и порты, а значит и свой хеш. Она может попасть на исправный туннель, тогда как пользователь продолжает попадать на сломанный.
Как платформа выбирает следующий хоп
Воспроизведите выбор вместо того, чтобы угадывать его. Спросите ядро, какой маршрут оно использовало бы для тех же источника и назначения, что и сбойный сеанс. Этот поиск включает поля, которые обычный поиск по назначению игнорирует. Запустите его и с работающего клиента и сравните два ответа:
ip route get 10.20.5.7 from 10.20.0.14
Более новые выпуски iproute2 принимают также протокол и порт назначения, что важно, когда хеш включает их. Сравните этот вывод с тем же поиском с работающего клиента, и разница станет недостающим доказательством.
| Observation | Likely cause | First check |
|---|---|---|
| Ping works, application fails | A different flow hash selects another tunnel | Per-flow lookup from the client's address |
| Some users fail, others do not | One tunnel lacks a prefix or selector | Compare both tunnels' installed routes |
| Fails only at larger sizes | Tunnels have different effective MTU | Probe the same size over each path |
| Fails after a reconnect | Stateful asymmetry between paths | Session state on both gateways |
Идите по сбойному потоку, а не по таблице маршрутов
Таблица маршрутов перечисляет оба туннеля и по определению выглядит правильной. Вопрос в том, что каждый туннель делает с пакетом после выбора. Проверьте, что оба несут одинаковые защищённые префиксы, одинаковое разрешение на пересылку и обратный путь, достигающий того же клиента.
Обратите внимание на устройства с состоянием посередине. Если запрос уходит через один туннель, а ответ возвращается через другой, межсетевой экран или NAT, который никогда не видел исходный поток, отбросит его. Оба туннеля пересылают трафик правильно, и соединение всё равно сбоит.
Проверьте также MTU на каждом пути. Путь с дополнительной инкапсуляцией уменьшает полезный размер, и передача, которая проходит через один туннель, застревает на другом ровно на том размере, где ломается меньший.
Сравнивайте по одному пути за раз
Там, где архитектура допускает обслуживание, выведите один туннель из эксплуатации и повторите задачу пользователя. Если сбой исчез, проблема относится к удалённому пути, и следующий шаг — сравнить его конфигурацию с соседней, а не заново изучать таблицу маршрутизации.
Сравнивайте реальное приложение, а не повторные ping. Запишите, следует ли сбой за определённым следующим хопом, размером пакета или переходом после переподключения, потому что эти три закономерности указывают на разные исправления.
Наконец, запишите, почему пути считаются эквивалентными и как сбой должен выводить один из них из эксплуатации. Многопутевость безопасна только тогда, когда пути действительно взаимозаменяемы, и это проектное утверждение, которое стоит проверить, а не предполагать.