Цифровой дворник

juniper

Обложка

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

Есть два линка между маршрутизаторами.
На одном OSPF cost 50.
На другом OSPF cost 10.

Кажется очевидным: маршрут должен пойти через линк с cost 10.

Но сеть, как обычно, решила напомнить, что «кажется» — это не метод диагностики.

Исходная картина

Есть Juniper с routing-instance, условно назовём его vrf-inet.

В нём крутится OSPF. Один из маршрутов приходит как внешний OSPF-маршрут:

192.0.2.0/24   *[OSPF/150], metric 60
                > to 198.51.100.195 via xe-0/0/0.100

И вот это metric 60 сначала немного смущает.

На экспортирующем роутере для этого маршрута уже поставили external metric 10.
На альтернативном интерфейсе OSPF cost тоже 10.

Но маршрут всё равно идёт через старый интерфейс, у которого cost 50.

Возникает нормальный человеческий вопрос:

почему оно не идёт через интерфейс, где cost 10?

Первая ловушка: export metric и interface cost — это разные вещи

В OSPF важно не смешивать две разные сущности:

  1. OSPF cost интерфейса — стоимость пути внутри OSPF-топологии.
  2. External metric — метрика внешнего маршрута, который мы редистрибутим в OSPF через export policy.

Если маршрут экспортируется в OSPF как external type 1, итоговая метрика считается примерно так:

external metric + internal cost до ASBR

То есть если мы задали external metric 10, а до ASBR роутер видит путь cost 50, то в таблице маршрутизации вполне логично появится:

metric 60

И это как раз хорошая подсказка.

Не «OSPF сошёл с ума», а наоборот: он честно сложил 10 + 50.

Вторая ловушка: смотреть OSPF надо внутри routing-instance

На Junos, если OSPF работает не в default instance, а внутри routing-instance, то команда:

show ospf neighbor

может ответить:

OSPF instance is not running

И это не значит, что OSPF умер. Это значит, что мы смотрим не туда.

Правильно так:

show ospf neighbor instance vrf-inet
show ospf interface instance vrf-inet
show ospf route instance vrf-inet

Для конкретных интерфейсов:

show ospf interface xe-0/0/0.100 detail instance vrf-inet
show ospf interface xe-0/0/1.200 detail instance vrf-inet

И вот тут началось интересное.

Что показала диагностика

На старом интерфейсе картина была нормальная:

Interface: xe-0/0/0.100
Type: LAN
Cost: 50
Adj count: 2

Соседи есть, adjacency есть, OSPF живёт полноценной жизнью.

А на новом «дешёвом» интерфейсе было так:

Interface: xe-0/0/1.200
Type: LAN
Cost: 10
Priority: 0
Adj count: 0

И в соседях:

neighbor 198.51.100.121 via xe-0/0/1.200 state 2Way

Вот тут и спряталась причина.

Cost 10 на интерфейсе есть.
Но полноценной OSPF-смежности нет.
Сосед виден, hello принимаются, но состояние только 2Way, а не Full.

А если нет Full, то этот линк не становится нормальным маршрутом через OSPF для нужного расчёта SPF.

Почему оно зависло в 2Way

Интерфейс был типа LAN, то есть OSPF воспринимал его как broadcast-сегмент.

На broadcast-сети OSPF не обязан строить Full adjacency со всеми подряд. Там есть DR/BDR, и полноценные соседства строятся через них.

Но на линке /30 между двумя роутерами это обычно не то поведение, которое мы хотим.

В нашем случае ещё и priority был 0.

Условно:

Type: LAN
Priority: 0
DR: 0.0.0.0
BDR: 0.0.0.0
Adj count: 0

Получается типичная ситуация:

  • интерфейс маленький, фактически point-to-point;
  • OSPF считает его LAN/broadcast;
  • priority 0;
  • DR/BDR не выбирается;
  • соседство остаётся в 2Way;
  • cost 10 вроде есть, но маршрут через этот линк не строится.

Очень жизненно. Вроде всё настроено, но нет.

Решение

Для /30-линка между двумя маршрутизаторами логичнее явно сказать OSPF, что это point-to-point.

На первом конце:

configure
set routing-instances vrf-inet protocols ospf area 0.0.0.0 interface xe-0/0/1.200 interface-type p2p
commit

На втором конце — то же самое на соответствующем интерфейсе:

configure
set routing-instances vrf-inet protocols ospf area 0.0.0.0 interface xe-0/0/1.200 interface-type p2p
commit

После этого проверяем:

show ospf neighbor instance vrf-inet | match "xe-0/0/1.200|198.51.100.121"
show ospf interface xe-0/0/1.200 detail instance vrf-inet
show ospf route instance vrf-inet | match "192.0.2.0|router-id"
show route 192.0.2.0

Нормальная картина после исправления:

neighbor 198.51.100.121 via xe-0/0/1.200 state Full

И маршрут должен пересчитаться уже через новый интерфейс.

Если external metric 10, а cost линка 10, то для external type 1 можно ожидать итоговую метрику около:

10 + 10 = 20

Разумеется, если нет других ASBR, forwarding-address и дополнительных особенностей топологии.

Что ещё стоит проверить

Если после перевода в p2p маршрут всё равно не пошёл куда надо, я бы проверял уже вот это:

show ospf database external 192.0.2.0 extensive instance vrf-inet
show route 192.0.2.0 extensive
show ospf route instance vrf-inet
show route <router-id или forwarding-address>

Особенно важно посмотреть:

Advertising router
Forwarding address
External type
Metric

Потому что для external route OSPF выбирает путь не «к префиксу в вакууме», а к ASBR или forwarding address. И если forwarding address резолвится через другой интерфейс, маршрут тоже может уйти не туда, куда мы глазами ожидали.

Важный момент про export policy

В этом кейсе export policy тоже фигурировала.

Изначально маршрут экспортировался в OSPF без явного external metric, поэтому в таблице была метрика 0.

Потом для exported route задали:

then external type 1
then metric 10

После этого метрика стала 60.

И это было правильно: Junos начал считать E1 как external metric плюс internal cost до ASBR.

Но попытка менять export policy на принимающем роутере не влияет на то, как он выбирает next-hop для уже полученного OSPF-маршрута.

То есть:

set policy-options policy-statement rp-ospf-export ...

на принимающей стороне влияет только на то, что этот роутер сам экспортирует в OSPF.

А выбор next-hop для полученного маршрута — это уже SPF, соседства, cost, ASBR и forwarding-address.

Короткая памятка

Если OSPF-маршрут не идёт через интерфейс с меньшим cost:

1. Проверь, в каком instance живёт OSPF

show ospf neighbor instance <instance-name>

2. Проверь состояние соседа

show ospf neighbor instance <instance-name>

Нужно Full, а не просто 2Way.

3. Проверь тип интерфейса

show ospf interface <interface> detail instance <instance-name>

Если это /30 или /31 между двумя роутерами, часто правильнее:

interface-type p2p

4. Проверь, до кого реально строится путь

show ospf database external <prefix> extensive instance <instance-name>
show route <forwarding-address или router-id>

5. Не путай external metric и interface cost

Для E1:

итоговая метрика = external metric + internal cost до ASBR

Для E2 логика другая: внешняя метрика обычно доминирует, а internal cost используется иначе при сравнении. Но это не означает, что E2 «заставит» маршрут пойти через нужный интерфейс. Next-hop всё равно зависит от SPF и достижимости ASBR/forwarding-address.

Вывод

В этой истории проблема была не в том, что Junos неправильно считал метрику.

Он как раз считал её очень честно:

10 external + 50 до ASBR = 60

Проблема была в том, что альтернативный линк с cost 10 не имел полноценной OSPF adjacency. Он висел в 2Way, потому что интерфейс был LAN/broadcast, priority был 0, DR/BDR не выбрался, а Full-соседство не построилось.

После перевода интерфейса в point-to-point всё стало на свои места.

Мораль простая: если OSPF «не хочет» идти по дешёвому пути, сначала убедитесь, что этот путь вообще существует для SPF, а не просто красиво выглядит в конфиге.


#networking #junos #ospf #juniper #routing #nsp