Equal Cost Multi-Path

Вы прекрасно помните, что двух одинаковых активных маршрутов, не может быть в одной таблице маршрутизации. Но если перед вами встала задача балансировать трафик через несколько шлюзов (именно шлюзов, а не интерфейсов) вам может прийти на помощь ECMP.

Схема сети

Для лучшего восприятия, наша схема сети.

20200830111959-5wfbx

Схема очень простая, в connected сети есть три маршрутизатора, которые имеют подключения к одной сети. Connected сеть 172.20.17.0/24, адрес сети к которой необходимо доставить пакет 10.255.255.0/24. Наш маршрутизатор имеет адрес 172.10.17.10, адреса маршрутизаторов которые подключены к сети 10.255.255.0/24, первого 172.20.17.1 и второго 172.20.17.8.

Соотвественно, нашему маршрутизатору необходимо указать, что сеть 10.255.255.0/24 находится за двумя маршрутизаторами 172.20.17.1 и 172.20.17.8.

Маршрутизация

Давайте поймём в чем суть.

Создадим на нашем маршрутизаторе два маршрут до необходимой сети.

/ip route
add dst-address=10.255.255.0/24 gateway=172.20.17.8
add dst-address=10.255.255.0/24 gateway=172.20.17.1

Результат

vasilevkirill mikrotik

Как видите у второго маршрута нет флага Active и до сети назначения, есть только один активный маршрут, все из-за того, что "в таблице маршрутизации не может быть двух одинаковых маршрутов в одной таблице маршрутизации". Даже если и представить, что можно было бы так сделать, то маршрутизатору необходимо было бы указать, по какому принципу в какой шлюз трафик.

Для того чтобы настроить ECMP необходимо, создать обычный маршрут, но немного по другому.

Удалим все созданные маршруты

 /ip route remove [find dst-address=10.255.255.0/24]

И настроим непосредственно маршрут ECMP. Перечислив шлюзы через запятую.

/ip route add dst-address=10.255.255.0/24 gateway=172.20.17.8,172.20.17.1

Результат

vasilevkirill mikrotik

Как видите, у нас теперь один маршрут, но который доступен через несколько шлюзов.

Принцип работы

Когда маршрутизатор, выбирает маршрут ECMP для отправки пакета, он рассчитывает хеш для таких полей как source address, destination address, source interface, routing mark и ToS (5-tuple) из пакета, далее для данного хеша по принципу Round-Robin (по кругу) RouterOS выбирает шлюз из маршрута ECMP. Выбранный шлюз и хеш маршрутизатор записывает в FIB (Forwarding Information Base).

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

Но в RouteOS принцип формирования хеша немного другой.

Если протокол поддерживает порты, т.е UDP или TCP, то к хешу добавляется ещё и данная информация из следующего заголовка. Поэтому одно соединение в протокол TCP или UDP будет использовать один и тот-же шлюз выбранные по RR и вполне возможно, что трафик будет примерно разделяться поровну, но именно по количеству соединений, а не по пакетам, но если протокол какой-нибудь другой, то его хеш всегда будет одинаковый и шлюз будет один и тот-же.

Кеш

Для того чтобы происходила перебалансировка трафика, раз в 10 минут происходит обнуления кеша, и выбор шлюза происходит заново для каждого уникального хеша. Это немного не верное утверждение, но очень удобное для восприятия.

Первоначально я не хотел этого писать и так глубоко погружаться.

Дело в том, что при формировании хеша используется алгоритм Jenkins и к данным из пакета добавляется соль именно эта соль обновляется каждые десять минут. Алгоритм хеширования не сильный и не очень стойкий. Если злоумышленник начнёт, для примера в одном и том же пакете менять TOS, а так как значение TOS учитывается при формировании хеша, может так совпасть что хеш будет одинаковые (коллизия) с каким-нибудь другим пакетом, маршрутизатор выберет неправильный интерфейс выхода, а значит пакет может уйти в неправильное направление с оригинальными заголовками, что позволит злоумышленнику отправить пакет в другую сеть, с неправильными заголовками.

Именно поэтому каждые 10 минут, обновляется соль, для того чтобы уменьшить шанс коллизии, и постфактум очищается и Кеш, так как старые хеши со старой солью уже не актуальны и могу привести как к забиванию памяти так и к проблемам безопастности.

Также таблица кеша очищается каждый раз, когда происходит изменение таблицы маршрутизации. Т.е. Если вы изменили маршрут ECMP или по какой-то причине он сам изменился, то Кеш чистится и снова происходит расчет для каждого хеша свой уникальный шлюз.

Check-gataway

Эта известная проблема, если в маршруте ECMP вы поставите check-gatеway, то по факту это не работает, хотя и должны быть. Обратите внимание, не правильно поведение только при маршруте ECMP.

Я покажу вам скриншот

vasilevkirill mikrotik

Как видите, не оного пакета icmp не было отправлено до шлюзов, это известный баг, который обходится просто, необходимо создать любой, даже самый дурацкий маршрут до шлюза.

Например так

add check-gateway=ping dst-address=172.31.255.254/32 gateway=172.20.17.14
add check-gateway=ping dst-address=172.31.255.255/32 gateway=172.20.17.1

И пинги сразу пойдут, как вы помните, что шлюз это общая сущность для всей таблицы маршрутизации и если шлюз признан как недоступный ВСЕ МАРШРУТЫ даже в тех где не установлено check-gatеway выпадут и таблицы маршрутизации.

И соответственно КЕШ очистится и заново будет пересчитываться без учёта "мёртвого" шлюза.

Балансировка

Если по ширине каналы разные, то можно указать в пропорциях количество шлюзов одноствольно друг друга, так как процесс выбора для каждого хеша происходит по технологии Round Robin, то увеличения количества записей одного и того же шлюза приведёт к большему попаданию по выбор.

1/1 = 50%/50%

/ip route 
add dst-address=10.255.255.0/24 gateway=172.20.17.8,172.20.17.1

1/5 = или 20%/80%

/ip route 
add dst-address=10.255.255.0/24 gateway=172.20.17.8,172.20.17.1,172.20.17.1,172.20.17.1,172.20.17.1

Главное помните, что всё ровно используется хеш, и если соединение уже пошло через медленный канал, больше чем пропускная способность до шлюза, данное соединение уже не получит суммарную скорость. Чаще всего я в своей практике если и использую ECMP то использую чтобы снизить нагрузку на оборудование, допустим если разные маршрутизаторы по загрузки CPU, то вполне можно таким образом увести львиную долю трафика на другой маршрутизатор.

КЕШ

А можно ли добиться того чтобы трафик по пакетно маршрутизировался? Мой ответ ДА, но только очень аккуратно, честно я не проводил нагрузочного тестирования не на стенде не на реальном проде, но у нас есть возможность отключить Кеш, и тогда вы увидите такую картину.

vasilevkirill mikrotik

Для того чтобы отключить КЕШ необходимо выполнить вселишь одну команду.

/ip settings set route-cache=no

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

Я возможно в будущем проведу эксперименты на стенде, в которых проверим, разные размеры таблиц маршрутизации и при разной нагрузки pps и возможности моделей микротик.

RouterOS v7

А теперь я бы хотел рассмотреть, что нас ждём в новой версии RouterOS относительно ECMP.

В отличии от шестой версии, теперь необходимо создавать два маршрута

/ip/route
add dst-address=10.255.255.0/24 gateway=172.20.17.1 
add dst-address=10.255.255.0/24 gateway=172.20.17.14

Теперь маршрутизатор сам соберёт ECMP маршрут, если dst-address И distance одинаковые.

vasilevkirill mikrotik

Обратите внимание на флаг +.

Теперь для того, что бы принудительно перечитать хеши, можно заставить маршрутизатор перезапустить процессы формирования FIB

/routing/reinstall-fib

Надо сказать уверенно что седьмая версия RouterOS ещё не готова для прода.

Рассказать друзьям

Чатик телеграм

@mikrotikme