что такое hop в сети
А вы хорошо знаете статическую маршрутизацию?
Статический маршрут — первое, с чем сталкивается любой человек при изучении понятия маршрутизации IP пакетов. Считается, что это — наиболее простая тема из всех, в ней всё просто и очевидно. Я же постараюсь показать, что даже настолько примитивная технология может содержать в себе множество нюансов.
Оговорка. При написании топика я исхожу из того, что читатель знаком с концепцией маршрутизации, умеет делать статические маршруты и не считает слово «ARP» ругательным. Впрочем, даже бывалые связисты наверняка найдут тут что-то новое.
Все примеры были проверены на IOS линейки 15.2M. Поведение других ОС может различаться.
И никакого динамического роутинга тут не будет.
Мы работаем со следующей топологией:
Как появляется статический маршрут?
Для начала, выполним команду, которую знает каждый, и посмотрим дебагами, что произойдет:
IOS создал маршрут, и сразу послал arp запрос в поисках next hop, который у нас – 10.0.0.3. И сразу вопрос: откуда роутер узнал, что запрос надо слать в интерфейс Gi0/1? Наверняка кто-то скажет «из списка локальных интерфейсов», и жестоко ошибется. Маршрутизация так не работает. На самом деле, IOS сделал рекурсивный запрос к таблице маршрутизации, чтобы узнать, как добраться до next hop:
И вот он, наш Gi0/1. IOS узнает, что с рекурсивными запросами к RIB надо заканчивать, как только находит маршрут с флагом «directly connected». Но что если ему в ответ на изначальный запрос к 10.0.0.3 вернется вовсе не connected маршрут, а промежуточный, ссылающийся на другой next hop? Вернемся к этому чуть позже, а пока вспомним, что такое CEF.
Примерно во всей документации, ориентированной на начинающих, говорится, что каждый пакет перемещается в соответствии с таблицей маршрутизации. На самом деле на всех более-менее современных платформах это уже не так, ведь таблица маршрутизации (далее – RIB) вовсе не оптимизирована для быстрой передачи данных. Оценить масштаб бедствия позволяет эта таблица (хотя у process switching’а множество недостатков помимо неоптимальных запросов – например, постоянное переключение шедулера CPU между контекстами, что весьма затратно). CEF является серьезной оптимизацией. В современной реализации он строит две таблицы – FIB (Forwarding Information Base, таблица передачи пакетов, в основе нее – связный граф со страшным названием 256-way mtrie) и adjacency table (таблица соседств). Первая из них строится на основе таблицы маршрутизации и за один проход позволяет получить всю нужную информацию. Строится она заранее, еще до того, как появится первый соответствующий ей пакет.
Вернемся к нашему статическому маршруту. Вот запись в таблице маршрутизации:
Куда слать пакет? Где искать 10.0.0.3? Непонятно. Надо еще раз запросить таблицу маршрутизации, на этот раз по поводу 10.0.0.3, и, если надо, выполнить еще несколько итераций, пока не выясним connected интерфейс. И вот примерно таким образом мы фактически в несколько раз снижаем производительность маршрутизатора.
А вот что говорит CEF:
Просто и лаконично. Есть интерфейс, есть next hop, к которому надо слать пакет. Что там говорилось про adjacency table?
Обратим внимание на какую-то длинную последовательность в предпоследней строке. Что-то это напоминает… Смотрим mac 10.0.0.3:
Смотрим свой mac адрес на gi0/1:
Ага. Та страшная строка – всего лишь два мака, которые надо подставить в заголовок Ethernet на этапе инкапсуляции, и ethertype 0x0800, т.е. банальный IPv4. И в двух таблицах CEF есть абсолютно вся информация, какая нужна для успешной отправки пакета дальше по цепочке.
Если у кого-то возникнет вопрос, зачем железке держать сразу две таблицы вместо одной, то дам очевидный ответ: обычно у маршрутизатора мало интерфейсов (а заодно и соседей) и много маршрутов. Какой смысл тысячи раз дублировать одни и те же маки в FIB? Памяти много не бывает, особенно на аппаратных платформах, будь то новомодные ASR’ы или даже L3 свитчи линейки Catalyst. Все они задействуют CEF при передаче пакетов.
И кстати, вернемся на минутку к изначальному дебагу. Отключим CEF командой no ip cef (никогда так не делайте) и сравним результат:
Маршрут добавлен. Arp запроса не было. И правильно – зачем RIB сдался mac адрес? Если пустить пинг до, к примеру, 3.1.1.1, то скорее всего будет так:
Первый пакет отбрасывается, и роутер посылает arp запрос с целью узнать mac адрес 10.0.0.3, если он ранее не был известен. CEF же всегда заранее узнает mac адрес next hop’а.
С этим разобрались. Теперь вернемся к вопросу, что будет, если next hop статического маршрута вовсе не на directly connected интерфейсе. Поступим просто:
, где Gi0/2 имеет адрес 100.100.100.100/24.
Как все плохо-то… А что если у нас есть маршрут на целую суперсеть?
Сейчас наша таблица маршрутизации выглядит так:
Вроде хорошо. Новый маршрут на 100.100.100.101 не применяется для 10.0.0.3, так как его маска /8 намного короче, чем /24 у connected интерфейса. Но вдруг Gi0/1, содержавший next hop для 3.1.1.0/24, по какой-то непонятной причине ушел в down, и его connected маршрут пропал из RIB.
Ой. Теперь пакеты на сеть 3.1.1.0/24 идут куда-то не туда. Я не могу представить себе сценарий, когда ожидаемое поведение статического маршрута – переключение на другой интерфейс. Если за тем интерфейсом находится резервный путь, то все-таки надо создавать еще один статический маршрут…
Что делать? Указывать сразу в маршруте интерфейс. Пересоздадим маршрут:
Поднимаем Gi0/1. Смотрим, куда теперь ведет маршрут на 3.1.1.0/24:
Тут уже указан интерфейс. Поэтому не будет рекурсивных запросов к таблице маршрутизации. Проверяем FIB:
Да, никакого «recursive». А если снова погасить gi0/1? Маршрут исчез.
И это притом, что маршрут до 10.0.0.3 все еще был:
А что будет, если путь к next hop даст маршрут по умолчанию, а маршрут на 3.1.1.0/24 не ссылается на интерфейс?
Обратите внимание, что первой строкой после «show ip cef» идет «0.0.0.0/0», а не «3.1.1.0/24». Несмотря на то, что next hop формально есть, по факту все итерации опроса таблицы маршрутизации (кроме первой) игнорируют маршрут по умолчанию, что логично, иначе любой запрос к таблице маршрутизации почти всегда бы резолвился (под «резолвиться» понимается нахождение интерфейса, в который нужно отправить пакет). Поэтому наш статический маршрут отсутствует, но пакеты все равно улетают к Gi0/2. Вроде бы все то же самое, что и без явного указания интерфейса? Не совсем. Допустим, протоколу маршрутизации сказали «redistribute static». Если статический маршрут пропал, то анонс тоже отзывается. А если нет, то маршрутизатор продолжит говорить всем «туда идти через меня», и это почти наверняка обернется L3 кольцом для префикса 3.1.1.0/24, который мог бы быть доступен откуда-нибудь еще. Но стоп, мы договаривались не трогать динамический роутинг…
А что если в статическом маршруте указать интерфейс, но не указывать IP адрес следующего хопа? Ответ: в случае Ethernet, если на next hop не отключен proxy arp, связность не нарушится, но роутеру может ОЧЕНЬ поплохеть. Подробнее. Если сказать «ip route 3.1.1.0 255.255.255.0 gi0/1», то ничего особо страшного не случится, даже пару сотен записей в arp таблице любой роутер переварит (и существуют сценарии-workaround’ы, в которых оптимальным решением является именно такой костыль), но вот «ip route 0.0.0.0 0.0.0.0 gi0/1» на пограничном маршрутизаторе наверняка убьет его. Потому запомните общее правило: если создается статический маршрут с next hop’ом на Ethernet интерфейсе, то его IP адрес должен указываться всегда. Исключения – только когда вы очень хорошо представляете себе, что делаете, зачем делаете и почему нельзя сделать иначе.
И напоследок, сделаем одну очень нехорошую штуку.
Первый маршрут в порядке, сто раз протестирован. А вот второй странный – он ведет через первый. А первый теперь ссылается на второй, и у нас бесконечная рекурсия. Вот что произошло:
Добавилось успешно. Но затем в дебагах высветилось:
И появилась запись в лог с severity 3:
Однако, RIB никакого криминала не видит:
Вывод – никогда так не делайте.
Почему статический маршрут может не попасть в таблицу маршрутизации?
Любой сетевик должен сходу дать одно из объяснений, касающееся любого источника маршрутов в IOS: существует другой маршрут на тот же самый префикс, но с меньшим AD (все помнят Administrative Distance?). Маршрут, источник которого – “connected”, всегда имеет AD=0, и ни один другой источник маршрутов не может привнести ничего ниже, чем «1», даже статический маршрут с явным указанием интерфейса. Пример connected:
Т.е. пока интерфейс Gi0/1 находится в состоянии up и имеет адрес из подсети 10.0.0.0/24, ни один статический маршрут на этот префикс в таблице маршрутизации не появится.
Еще есть вариант «разные источники маршрутов добавляют маршруты на один и тот же префикс с одинаковым AD». Поведение IOS в данном случае не документировано, общая рекомендация – «никогда так делайте».
Но посмотрим другие, менее очевидные примеры. Например, статические маршруты можно создать со словом «permanent», которое переводится как «постоянный», и тогда они будут всегда висеть в таблице маршрутизации. Правильно? Нет.
Добавляем его и смотрим:
Кладем Gi0/1, и видим:
В RIB он есть, и другие протоколы маршрутизации могут его использовать:
А теперь, не поднимая Gi0/1:
Просто пересоздали его, ничего не меняя. И вот что произошло:
Постоянный, говорите? Нет. Есть один маленький нюанс: чтобы перманентный маршрут навеки вписался в таблицу маршрутизации, нужно, чтобы он хотя бы на долю секунды резолвился. Хотя какое еще «навеки»? Когда он остался висеть в воздухе без резолвящегося интерфейса, достаточно сказать «clear ip route *» или тем более «reload», чтобы он исчез из RIB.
Но продолжим. Сделаем вот так:
Вроде нормальные маршруты. Что произойдет? Со вторым – ровным счетом ничего.
Суть вот в чем. Допустим, есть маршрут на X.X.X.X через Y.Y.Y.Y. Мы добавляем маршрут на X1.X1.X1.X1 (этот префикс полностью покрывается X.X.X.X) через X2.X2.X2.X2 (а он тоже покрывается X.X.X.X). IOS делает закономерный вывод: второй маршрут не несет в себе никакой новой информации и совершенно бесполезен, поэтому его можно не устанавливать в RIB.
А теперь финт ушами.
И вот это подводит нас к еще одному важному моменту. Указание интерфейса в статическом маршруте позволяет обойти многие проверки, так как статическому маршруту больше не требуется выполнять рекурсивные запросы к RIB в поисках пути до next hop, и при своем добавлении он не заденет триггеры на других маршрутах. Но это не отменяет главного требования: next hop обязан резолвиться в конкретный интерфейс, а тот интерфейс обязан быть в up. Тот факт, что рекурсивных запросов к RIB больше не будет, означает, что указанный IP адрес next hop’а находится прямо за интерфейсом, и наверняка отзовется на arp запрос (с точки зрения роутера). Если у соседнего по Gi0/1 роутера включен proxy arp, то он в ответ на arp запрос наверняка вернет свой mac адрес, и всё будет хорошо. Разве что лишняя запись в arp таблице…
Но все равно так делать не стоит.
Необходимо упомянуть и о еще одном важном моменте. Статический маршрут должен по идее исчезнуть из таблицы маршрутизации, как только он перестанет резолвиться. Но на практике есть множество ситуаций, когда next hop пропадает, но при этом статический маршрут на какое-то время остается. К примеру, когда next hop резолвится через маршрут, полученный от протокола динамической маршрутизации. Все дело в том, что процесс, отслеживающий наличие next hop в RIB, не всегда может получить уведомление об исчезновении маршрута, и он вынужден периодически (раз в 60 секунд по умолчанию) перепроверять, все ли хорошо. Это вызовет заметную задержку сходимости сети.
Поменять интервал проверки, к примеру, на 10 секунд можно с помощью команды:
WIFI multi-hop mesh-сети с помощью технологии Mesh Connex
При построении беспроводных сетей часто нет возможности обеспечить проводное соединение для определенной точки доступа, и необходимо настраивать point-to-point беспроводной мост (WDS), эта технология хорошо изучена и реализована основной массой существующих предложений на рынке. Сложнее решить задачу построения multi-hop wifi mesh-сети. Для облегчения этой задачи вся линейка оборудования ExtremeWireless Wing поддерживает технологию Mesh Connex.
Основой Mesh Connex является стандарт IEEE802.11s, RFC 3561, а также собственные разработки Extreme Networks.
С помощью Mesh Connex можно успешно настроить multi-hop mesh, как в статической, так и в динамической конфигурации.
— Multi-hop static Mesh Connex – инфраструктурный режим, может использоваться при постороении таких объектов как морские или авиапорты, парки отдыха, карьеры;
— Multi-hop Mobile Mesh Connex – динамический mesh, когда точки доступа устанавливаются на движущихся объектах (автобусы, вагоны, самосвалы …)
Также оба режима могут использоваться одновременно в рамках одной mesh-сети.
Точки Доступа могут работать в качестве следующих элементов mesh-сети:
Основным же отличием Mesh Connex от других технологий, применяемых для построения multi-hop mesh-сетей, является протокол маршрутизации, рассчитывающий оптимальный маршрут между mesh нодами. Протоколы маршрутизации в беспроводных mesh сетях могут быть проактивные или реактивные.
В беспроводной multi-hop mesh сети часто бывает, что даже если сосед имеет более лучший SNR в целом маршрут к root точке через него будет обладать более худшими характеристиками, поэтому Mesh Connex расчитывает маршруты на основе следующих данных:
Настраиватся MeshConnex достаточно просто как в CLI, так и в GUI.
Другими важными преимуществами MeshConnex являются:
Tracert vs Traceroute
В чем отличие маршрута пакета от его пути?
Стандартный механизм маршрутизации пакетов в интернете — per hop behavior — то есть каждый узел в сети принимает решение куда ему отправить пакет на основе информации, полученной от протоколов динамической маршрутизации и статически указанных администраторами маршрутов.
Маршрут — это интерфейс, в который нам надо послать пакет для достижения какого то узла назначения и адрес следующего маршрутизатора (next-hop):
Что такое путь? Путь — это список узлов, через которые прошел (пройдет) пакет:
Путь пакета можно посмотреть с помощью утилит tracert в OC Windows и traceroute в GNU/Linux и Unix-подобных системах. (другие команды, типа tracepath мы не рассматриваем).
Многие считают что этих утилит один и тот же принцип работы, но это не так. Давайте разберемся.
Итак, утилита tracert.
В основе работы данной утилиты лежит протокол icmp. Рассмотрим вот такую схему:
Host отправляет по указанному в его таблице маршрутизации маршруту ICMP Echo-Request с ttl 1. Router1, получив такой пакет, проверит адрес назначения — может быть пакет ему. Так как данный пакет адресован другому хосту, то Router1 считает себя транзитным узлом, декрементирует ttl пакета и отбрасывает его, так как время жизни пакета становится равным 0. Так как пакет был дропнут, Router1 отправляет источнику пакета icmp сообщение с указанием причины дропа — Time Exceeded. Утилита tracert, получив данное icmp сообщение, указывает Router1 как первый хоп (информация об адресе указана в icmp сообщении). Далее процесс повторяется с инкрементированием ttl, пока ttl icmp запроса не будет равен количеству хопов между узлом-отправителем и узлом получателем. В данном примере Server1 является узлом назначения. Получив пакет, он проверит адрес назначения, увидит, что запрос адресован ему и отправит ICMP Echo-Reply, что и будет являться для утилиты tracert триггером к окончанию трассировки.
Traceroute — данная утилита работает по иному принципу, хоть и вывод команды похож на вывод предыдущей.
Traceroute основана не на ICMP Echo-Request, а на отправке udp фрагментов и получения сообщения о доступности/недостижимости порта. Вернемся к прошлой схеме. Host генерирует udp фрагмент, инкапсулирует его в IP пакет и выставляет ttl=1. Router1, являясь транзитным узлом, ответит на данный пакет icmp сообщением об окончании времени жизни пакета. Утилита traceroute, получив данное сообщение, указывает адрес источника icmp пакета (Router1) как адрес первого хопа. Далее процесс повторяется с инкрементированием ttl пакета. Всё практически так же, как и в tracert. Но ведь мы не отправляем ICMP Echo-Request, как утилита traceroute поймет, что трассировка закончена? Все просто — в udp заголовке есть поля source и destination порт. Логично, что source порт будет любым портом выше 1023. А каким указать destination порт? Как было сказано выше, работа утилиты traceroute основана на получении сообщения о недостижимости или доступности порта назначения. То есть мы отправляем udp фрагмент с порта 45000 ( к примеру) на порт 33434 (именно этот порт используется по умолчанию). Как и в предыдущем случае, Server1 является узлом назначения. Получив пакет, он распаковывает его и должен передать его протоколам высшего уровня. Но так как порт 33434 по умолочанию будет закрыт на сервере, то Server1 формирует icmp сообщение о недостижимости порта назначения (ICMP Type 3 «Destination Unreachable» Code 3 «Port Unreachable»). Получив данное сообщение, утилита traceroute считает трассировку законченной. В процессе трассировки номер порта назначения будет инкрементироваться при каждой попытке ( 33434, 33435 и т д). Может получится так, что порт назначения будет открыт. В данном случае сервер отправит на хост-инициатор например TCP ACK если для трассировки используются TCP SYN пакеты, что тоже будет являться триггером к окончанию трассировки.
Вывод:
Утилита traceroute позволяет сделать трассировку с указанием порта назначения.
Для этого разберем пример ниже:
Возьмем предыдущую схему и сделаем трассировку:
С использованием TCP SYN пакетов:
C использованием UDP пакетов:
Как видите трассировка прошла успешно. Мы видим путь до указанного хоста.
А теперь повесим на интерфейс Router4 фильтр на in (как указано на рисунке):
Снова сделаем трассировку:
Примечание: Возможен случай, когда пакеты будут дропаться без отправки ICMP сообщений ( отправка в Null-интерфейс в Cisco/Huawei или discard в Juniper). В данном случае трассировка будет идти пока не кончится максимальное TTL, указанное в утилите traceroute (по умолчанию максимум 30 хопов, но можно задать вручную до 255, правда обычно достаточно 15-18 хопов) или ее не прервет администратор, а в выводе будут звездочки.
Примечание: Появление звездочек вместо адресов хостов может быть обусловлено различными причинами и хорошо описано тут
Надеюсь мы разобрались в основных принципах работы данных утилит. Если надо сделать трассировку по какому то порту в Windows системах, можно использовать сторонние утилиты, к примеру tcptrace.
Policy-based Routing (PBR), как основное назначение (Часть 1)
Что такое Policy-based Routing (PBR)
Policy-based routing (PBR) перевод данного словосочетания несет смысл такого характера, как маршрутизация на основе определенных политик (правил, условий), которые являются относительно гибкими и устанавливаются Администратором. Другими словами это технология предоставляет условия гибкой маршрутизации (если смотреть на технологию с первоочередной ее задачи), по источнику или назначению пакета.
Где применяется
Применение данной технологии очень часто используется для организации избыточности в небольших офисах, при нескольких каналах связи с «вешним миром», «гуглится» примерно таким запросом (PBR 2 ISP). Ну, или другими аналогичными. Если вы «погуглите» то для избыточности нужно будет помимо PBR еще такие штуки как Tracking, SLA, на них я сильно внимание не буду заострять, как сейчас так и в дальнейшей части статьи.
Кратко про SLA и tracking — это две технологии, точнее связка двух технологий (в нашем случае), которые генерируют различного рода icmp трафик (при заданных условиях), это я про SLA, и выполняют мониторинг данного генератора, а это про tracking.
Так же PBR находит применение в настройках динамических протоколах маршрутизации (к примеру BGP; OSPF;EIGRP)для фильтрации и redistributions (перенаправления) роутов ну и мелочей типа изменение метрики маршрутов и т.п., и в статической маршрутизации (раскроется ниже), В построение механизмов улучшение качества сервисов (QoS). Возможно, что-то забыл, уж не обессудьте. В дальнейшем, в статье, я не буду раскрывать тему применения PBR в BGP, QoS, OSPF.
Основы конструкции
Собственно карта выглядит таким образом:
Route-map namemap permit 5
match int fa0/0
set ip default next-hop 10.10.10.1
Вторая строка (match interface fa0/0), содержит условие, для какого трафика применять нашу карту. В нашем случае, у нас будет применяться весь трафик проходящий через интерфейс маршрутизатора fastethernet0/0. Тут можно по различным критериям делать выборку, как правило, все рисуют карту по access-lists (листам доступа) т.е. рисуют access-list с параметрами для каких сетей применять карту. Примеры access-lists с легким комментарием представлены ниже.
access-list 101 permit ip 192.168.0.0 0.0.0.255 any
### этот access-list примененный к route-maps будет выбирать трафик сети 192.168.0.0/24
до любого назначения.
А при применении такого access-lists
access-list 101 deny ip 192.168.0.0 0.0.0.255 host 192.168.2.44
access-list 101 deny ip 192.168.0.0 0.0.0.255 192.168.1.0 0.0.0.31
access-list 101 permit ip 192.168.0.0 0.0.0.255 any
### в первой строчке не будет перенаправлять трафик до хоста 192.168.2.44
### по второй строке так же не будет перенаправлять на сеть 192.168.1.0/27
### ну и по третьей строке будет применять для всего остального трафика, сети 192.168.0.0/24.
Так же добавить хочется что параметр match повторяющийся, т.е. выборку можно делать по нескольким критериям. К примеру метим по access-lists, и параллельно по размеру пакета match length min max, где min max это диапазон размера пакета от и до). И еще маленькое дополнение к этому параметру он не является обязательным. Другими словами если не делать выборку по критериям, то карта будет применяться ко всем пакетам, проходящим через интерфейс на который мы применим нашу карту маршрутизации.
Мы взяли в пример set ip default next-hop 10.10.10.1
Тут мы опять же рассмотрим ключевое слово default, оно означает, что если не будет роутов в глобальной таблице маршрутизации информации о сети назначения пакета, то будет отрабатывать наша карта и пакет будет отправлен на следующий шаг в данном случае 10.10.10.1.
Можно написать явный set ip next-hop 10.10.10.1 и тогда пакет в не зависимости от глобальной таблицы будет перенаправлен на наш next-hop, т.е. пакет попавший в критерий что он пришел на интерфейс fa0/0, отправится на 10.10.10.1 и он уже будет решать что с этим пакетом делать.
interface FastEthernet0/0
encapsulation dot1Q 20
ip address 192.168.0.1 255.255.255.0
ip policy route-map namemap
Прошу заметить, что данная конфигурация не совсем правильная в нашем случае, хотя рабочая. Тут сами подумайте, чем она не корректна, и какие условия нужно изменить.
Послесловие:
В этой части я попытался раскрыть азы PBR и как он работает с пакетами. Если у меня это получилось не внятно, прошу указать на ошибки. Буду очень признателен. В части 2 я опишу еще несколько моментов касающихся PBR, и приведу примеры построения маршрутизации, для конкретных случаев.
Материал для статьи брался из головы, так что литературу указать не смогу, разве что www.
P.S статья эта была в песочнице, мне кто-то дал приглашение на хабр, но так как я был в офлайне долгое время приглашение утратило силу свою. хочу сказать спасибо товарищу который дал инвайт. сейчас я по приглашению smartov, мы с ним знакомы по другому ресурсу в сети. Ему так же благодарность за приглашение.