Не секрет, что OSPF – протокол маршрутизации типа link-state: он собирает информацию о топологии, строит соответствующий граф и вычисляет кратчайший путь с помощью алгоритма Дийкстры. Информация о топологии включает в себя то, что и так понадобилось бы даже для вычисления маршрута ручкой на бумаге: узлы, их интерфейсы и подсети, а также набор дополнительных технических примочек (например, флагов). Для организации этих данных OSPF использует структуру под названием LSA – link-state advertisement. Алгоритм SPF так же широко известен, задание по его реализации можно найти в программе любого современного технического вуза. Роли LSA довольно подробно разобраны в разных источниках: router LSA описывает узлы графа, network LSA предназначен для широковещательных сегментов сети, summary LSA обеспечивает взаимодействие разных зон между собой… Однако собрать эти структуры данных воедино в целостный граф кажется мне достаточно нетривиальной задачей. Безусловно, RFC является источником абсолютного знания в такого рода вопросах, но лично мне сравнительно долго не удавалось его полноценно осознать. В этой статье я хотел бы поделиться своим представлением о назначении типов LSA, а также процессом построения графа на основе LSDB. Тестовая топология представлена ниже: В этот раз я бы хотел последовательно настраивать OSPF с нуля, чтобы отслеживать влияние каждого изменения на LSDB и граф сети. Предварительный конфиг включает в себя только адресацию (R5 приведён в качестве примера): Чтобы построить граф, нужно определиться, с чём мы всё-таки имеем дело. Согласно RFC 2328 секции 2.1, OSPF оперирует направленным графом: узлы отражают подсети и маршрутизаторы, а ребра – соединения между ними. OSPF использует вес (cost) исходящего интерфейса в качестве веса ребра (секция  2.1.2), так что граф – направленный взвешенный. Создадим первый узел, соответствующий R1: В LSDB пока пусто, поскольку IOS требует хотя бы один активный с точки зрения OSPF интерфейс для инициализации процесса. Звучит разумно, однако такой подход не приближает нас к графу, который мог бы выглядеть так: Порадуем IOS, добавив 1.1.1.1/32 в топологию: Мы получили свой первый LSA1. Перед тем, как разбираться непосредственно с его содержанием, обратимся к формату: Заголовок LSA1 позволяет построить узел графа, соответствующий маршрутизатору, на основании поля Link State ID или же Advertising Router. Остальная часть LSA1 посвящена описанию подсетей (узлы графа) и соединений (ребра графа). OSPF различает 4 типа соединений: точка-точка (point-to-point); промежуточные (transit); конечные (stub); виртуальные (virtual). Посмотрим, к какому типу относится 1.1.1.1/32: 1.1.1.1/32 – это конечное соединение, которое обычно соответствует префиксам конечных устройств. На уровне графа такая подсеть представляет собой лист, т.к. в ней подразумевается отсутствие OSPF-соседей. Вершина графа соединена с одним узлом маршрутизатора двумя ребрами, соответствующими каждому направлению. Конечное соединение содержит в себе всю необходимую информацию для построения соответствующей части графа: подсеть, маску и исходящий вес (входящий вес ребра всегда равен нулю). Узел-маршрутизатор описан в заголовке LSA1 (LSID); однако соединение одной подсети с разными маршрутизаторами также допустимо, что позволяет реализовать ECMP. Следующий тип соединения – точка-точка: он описывает подключение к другому маршрутизатору OSPF. Включим OSPF на R2, чтобы установить соседство на соединении R1-R2, используя вышеупомянутый тип: Как и можно было ожидать, появился новый LSA1, описывающий R2. Обратите внимание на «странный» шаг изменения числа соединений: OSPF заработал на одном физическом интерфейсе, а число соединений увеличилось на 2 для каждого LSA1. Один интерфейс с назначенным IP-адресом порождает 2 сущности: конечное соединение (в конце концов там тоже могут находиться адресуемые извне устройства) и соединение типа точка-точка, которая соответствует ребру графа между вершинами-маршрутизаторами. Узел-сосед обозначен с помощью ссылки на его LSID, чтобы с помощью пары LSA1 корректно описать двустороннюю связность между вершинами. Такая связность критична для ребра между узлами, хотя вес каждого из направлений может быть разным. Адрес маршрутизатора-соседа так же включен в описание соединения, чтобы впоследствии его использовать для построения локальной таблицы маршрутизации. Веса соединений оставлены по умолчанию, так что граф теперь выглядит следующим образом: Виртуальное соединение выходит за рамки этой статьи, поскольку оно относится к ad-hoc инструментам для тушения пожаров, а не к проверенным решениям в рамках продуманного дизайна. Впрочем, эта любопытная сущность может представлять интерес и сама по себе, так что если вы хотите копнуть поглубже, обратите внимание на эту статью Петра Лапухова. Остался последний тип соединений – промежуточный (не путать с transit capability!). Соединения точка-точка описывают непосредственную связь между маршрутизаторами, без промежуточных устройств. Однако в общем виде это не обязательно верно: посередине может оказаться широковещательный (например, Ethernet) или NBMA (например, DMVPN) сегмент. Впрочем, последний случай обычно можно свести к набору соединений точка-точка, что соответствует логической топологии hub-and-spoke. Широковещательная среда, напротив, требует другого подхода, т.к. использование соединений точка-точка было бы неэффективно. Возьмём в качестве примера L2-сегмент между R2, R3 и R4. Очевидно, что не существует ребра, которое соединяло бы больше двух вершин. Количество соединений точка-точка в такой среде растёт как O(n2), что выражается в низкой масштабируемости решения за счёт увеличения нагрузки на CPU и RAM. Впрочем, оптимизация довольно проста: нужно всего лишь… (это не то, о чём вы подумали) использовать псевдоузел вместо L2-сегмента, который соединён с каждым маршрутизатором этого сегмента. Такой подход позволяет уменьшить число сессий OSPF с O(n2) до O(n), что в итоге повышает масштабируемость решения. Маршрутизатор, отвечающий за псевдоузел, называется designated router (DR); вершина графа, соответствующая псевдоузлу, описана с помощью LSA2; ребро графа между вершинами и псевдоузлом определено промежуточным соединением из LSA1 и содержанием LSA2.  Настроим OSPF на R2, R3 и R4, оставив настройки типа соединения без изменений (по умолчанию – промежуточное). Как мы видим, LSA2 действительно создан R4 (4.4.4.4), кто является DR на данный момент. Упрощённо процесс выбора DR можно описать так: составить список маршрутизаторов, участвующих в выборах (ненулевой приоритет); выбрать наибольший приоритет; выбрать наибольший RID.    Запасной DR (backup DR, BDR) проходит через тот же процесс согласования, что и DR, за одним важным исключением: избранный DR нельзя сместить до тех пор, пока не произойдёт отказ, тогда как роль BDR может переходить динамически к маршрутизатору с более приоритетными параметрами. DR отвечает за псевдоузел в графе, поэтому остальные участники сегмента синхронизуют с ним свои LSDB, что отражено в состоянии FULL между такими соседями. BDR ведёт себя точно так же, как и DR, кроме генерации LSA2, что позволяет снизить перебои маршрутизации при отказе DR. Посмотрим вначале на LSA1: Наконец, мы получили промежуточное соединение. Как вы могли уже догадаться, DR ID равен LSID соответствующего LSA2, т.е. IP-адресу DR. Так же, как и соединения точка-точка, промежуточное соединение описывает IP-адрес и вес интерфейса. Однако этих данных из LSA1 недостаточно для полноценного построения графа, т.к. они описывают только одно ребро из двух. Кроме того, информация о подсети самого L2-сегмента тоже недоступна. Обратимся к формату LSA2:  LSA2 содержит недостающие части картины: список соседних RID и маска подсети. Теперь у нас есть вся необходимая информация, чтобы расширить граф промежуточным сегментом: Тут стоит отметить ещё пару моментов. Во-первых, вес ребра, исходящего из псевдоузла, всегда равен нулю и не вносит изменений в стоимость маршрута. Во-вторых, информация о подсети вшита в LSA2: маска указана в явном виде, а адрес подсети можно получить из LSID и длины самого префикса. В качестве короткого отступления от основной темы хочу заметить, что принцип работы OSPF prefix suppression должен стать теперь очевидным: отсутствуют конечные соединения, создаваемые одновременно с соединениями точка-точка; промежуточные соединения включают маску /32 в LSA2 в качестве специального признака, по которому следует игнорировать такой маршрут; в худшем случае будет доступен только адрес DR, но не остальная подсеть. LSA1 и LSA2 позволяют целиком построить граф для одной зоны. Однако в OSPF существуют такие понятия, как внешние и межзональные маршруты – ими мы и займёмся. Этот LSA относительно однозначен: он анонсирует внешнюю подсеть, маску и дополнительную информацию, которая может облегчить жизнь (а может и существенно её усложнить). Формат этой структуры следующий: LSID равен подсети, маска и метрика явно указаны… Информации достаточно, чтобы построить вершину и соответствующие ребра, в целом ситуация похожа на конечные соединения из LSA1. Если есть желание узнать побольше о нюансах Forwarding address (FA), я бы посоветовал этот блог и ссылки в начале на другие статьи. Они посвящены LSA5 FA и соответствующим спецэффектам, которые в определённый момент могут оказаться полезными. Для остальных полей LSA5 описания из RFC 2338 секция A.4.5 более чем достаточно. В нашей схеме R3 генерирует LSA5, добавляя адреса подключенных сетей (в нашем случае – это loopback 0) в OSPF: Стоит помнить, что LSA5 распространяется по всей автономной системе OSPF, а не только в одной зоне. Чтобы продолжить граф, нужна информация о вершине (LSA5 LSID), ребре (Advertising Router) и весе ребра: Это всё про роль LSA5 в построении графа. Почти всё. Переключимся пока на межзональную связность. Первое впечатление обманчиво: этот LSA не имеет никакого отношения к суммаризации префиксов в обычном смысле. Он предназначен для суммаризации информации о топологии при передаче из одной зоны в другую: LSA1 и LSA2, используемые для построения графа, не переходят между зонами, а превращаются в LSA3 на основе LSDB или RIB (об этом чуть позже). Формат LSA3 выглядит так: Идея похожа на задумку с LSA5: передать подсеть (LSA3 LSID), маску и метрику в другую зону. Передача информации о топологии между зонами не происходит, чтобы сэкономить вычислительные ресурсы маршрутизаторов и сделать сеть более масштабируемой. Таким образом, OSPF с использованием нескольких зон ведёт себя, как distance-vector (DV) протокол маршрутизации. Такое поведение является причиной, по которой некоторые авторы относят OSPF к гибридным протоколам маршрутизации (EIGRP же является DV-протоколом в чистом виде, хотя и весьма технологичным). Логика DV обычно включает в себя какой-нибудь механизм защиты от петель маршрутизации, например, расщепление горизонта (split horizon), DUAL и так далее. OSPF же использует совершенно иной подход: LSA3 может пересечь границу зоны только в том случае, если одна из зон является зоной 0 (она же – опорная, backbone). Это позволяет построить дерево высотой, равной 2: зона 0 является корнем, тогда как остальные зоны находятся на следующем уровне после зоны 0. Очевидно, что в такой схеме петли маршрутизации невозможны, поскольку существует только один путь – через опорную зону. Настроим зону 1 на R4 и R5: Как и следовало ожидать, префиксы из зоны 1 видны в виде LSA3. R4, будучи ABR, является advertising router. С точки зрения зоны 0 все такие префиксы подключены напрямую к R4, что позволяет скрыть детали топологии зоны 1. Теперь у нас достаточно опыта, чтобы построить граф зоны 1 на основе LSDB, поэтому далее мы сконцентрируемся только на мнении зоны 0 о том, как выглядит OSPF AS. Осталось только проверить, что именно является причиной создания LSA3. Удалим 5.5.5.55/32 из таблицы маршрутизации R4 и пронаблюдаем, останется ли этот маршрут в зоне 0, отсутствуя при этом в RIB на ABR. Согласно RFC 2328 части 12.4.3, LSA3 маршруты нужно создавать на основе таблицы маршрутизации (“determined by examining the routing table structure”). Очевидно, что отсутствие 5.5.5.55/32 в RIB R4 не помешало IOS создать соответствующий LSA3 и отправить его в зону 0. В отличие от DV-протоколов, OSPF не предусматривает механизмов фильтрации маршрутов в произвольной точке сети, поэтому использование такой функции, как distribute-list in, не является в общем случае хорошей затеей. Как вы уже могли догадаться, LSA4 суммаризует информацию об ASBR. Не забыли, что LSA5 расходится по всей AS? LSA могут быть изменены только их создателем, это сделано для того, чтобы обеспечить целостность LSDB внутри зоны. Если ASBR расположен в другой зоне, информации для создания вершины, соответствующей LSA5, недостаточно, так как LSID маршрутизатора-создателя в текущей зоне неизвестен. Задача LSA4 – исправить это недоразумение. У него такой же формат, как и у LSA3: Разница заключается в значении, придаваемом полю LSID: LSA3 в этом поле несёт номер подсети, тогда как LSA4 помещает туда RID ASBR’а. Создадим LSA5 в зоне 1 и проверим, как это отразится на опорной зоне. LSA4 могут быть созданы только ABR’ами, когда они передают LSA5 из одной зоны в другую. В нашем случае передача 6.6.6.6/32 из зоны 1 в опорную зону заставляет R4 сгенерировать LSA4, соответствующий R5. Помимо ASBR ID, LSA4 также несёт в себе метрику до ASBR с точки зрения ABR. Теперь не составляет труда смоделировать узел из другой зоны, создавший LSA5, что позволяет достроить граф, описывающий AS целиком. За рамками основной статьи остались несколько LSA, которые я бы хотел кратко описать в этом разделе. Некоторые из них в определённой степени модифицируют алгоритм OSPF; однако эти метаморфозы, подчас существенные, не меняют кардинальным образом основных принципов построения графа, поэтому детальное обсуждение этих LSA – тема отдельных статей. LSA6 выделен для multicast OSPF, который устарел чуть больше, чем полностью. LSA7 – это костыль, позволяющий создавать внешние префиксы в тупиковых (stub) зонах, превращая их в NSSA (no-so-stubby – не-такая-уж-тупиковая, звучит!). Если от FA в LSA5 у вас мурашки по коже, то LSA7 заставляет встать дыбом волосы в самых неожиданных местах. LSA8 был предназначен для расширения функциональности LSA5 за счёт дополнительных атрибутов, однако так и не выбрался из состояния черновика. LSA9 (link-local), 10 (area-local) and 11 (AS-local) являются opaque LSAs. Они несут дополнительную информацию, которую активно использует SPF с условиями (constrained SPF) для расчётов туннелей MPLS TE. Спасибо за рецензию: Анастасии Куралёвой  Системный инженер