<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>junos &amp;mdash; Цифровой дворник</title>
    <link>https://articles.clr58.ru/tag:junos</link>
    <description>Практические заметки о сетях, self-hosting, виртуализации, мониторинге, автоматизации и локальном ИИ.</description>
    <pubDate>Wed, 30 Sep 2026 01:15:38 +0000</pubDate>
    <item>
      <title>Почему OSPF не пошёл по «дешёвому» линку: Junos, VRF и состояние 2Way</title>
      <link>https://articles.clr58.ru/ospf-2way</link>
      <description>&lt;![CDATA[Обложка&#xA;&#xA;Есть такие сетевые задачи, которые на первый взгляд выглядят абсолютно прямолинейно.&#xA;&#xA;Есть два линка между маршрутизаторами.  &#xA;На одном OSPF cost 50.  &#xA;На другом OSPF cost 10.&#xA;&#xA;Кажется очевидным: маршрут должен пойти через линк с cost 10.&#xA;&#xA;Но сеть, как обычно, решила напомнить, что «кажется» — это не метод диагностики.&#xA;&#xA;Исходная картина&#xA;&#xA;Есть Juniper с routing-instance, условно назовём его vrf-inet.&#xA;&#xA;В нём крутится OSPF. Один из маршрутов приходит как внешний OSPF-маршрут:&#xA;&#xA;192.0.2.0/24   *[OSPF/150], metric 60&#xA;                  to 198.51.100.195 via xe-0/0/0.100&#xA;&#xA;И вот это metric 60 сначала немного смущает.&#xA;&#xA;На экспортирующем роутере для этого маршрута уже поставили external metric 10.  &#xA;На альтернативном интерфейсе OSPF cost тоже 10.&#xA;&#xA;Но маршрут всё равно идёт через старый интерфейс, у которого cost 50.&#xA;&#xA;Возникает нормальный человеческий вопрос:&#xA;&#xA;  почему оно не идёт через интерфейс, где cost 10?&#xA;&#xA;Первая ловушка: export metric и interface cost — это разные вещи&#xA;&#xA;В OSPF важно не смешивать две разные сущности:&#xA;&#xA;OSPF cost интерфейса — стоимость пути внутри OSPF-топологии.&#xA;External metric — метрика внешнего маршрута, который мы редистрибутим в OSPF через export policy.&#xA;&#xA;Если маршрут экспортируется в OSPF как external type 1, итоговая метрика считается примерно так:&#xA;&#xA;external metric + internal cost до ASBR&#xA;&#xA;То есть если мы задали external metric 10, а до ASBR роутер видит путь cost 50, то в таблице маршрутизации вполне логично появится:&#xA;&#xA;metric 60&#xA;&#xA;И это как раз хорошая подсказка.&#xA;&#xA;Не «OSPF сошёл с ума», а наоборот: он честно сложил 10 + 50.&#xA;&#xA;Вторая ловушка: смотреть OSPF надо внутри routing-instance&#xA;&#xA;На Junos, если OSPF работает не в default instance, а внутри routing-instance, то команда:&#xA;&#xA;show ospf neighbor&#xA;&#xA;может ответить:&#xA;&#xA;OSPF instance is not running&#xA;&#xA;И это не значит, что OSPF умер. Это значит, что мы смотрим не туда.&#xA;&#xA;Правильно так:&#xA;&#xA;show ospf neighbor instance vrf-inet&#xA;show ospf interface instance vrf-inet&#xA;show ospf route instance vrf-inet&#xA;&#xA;Для конкретных интерфейсов:&#xA;&#xA;show ospf interface xe-0/0/0.100 detail instance vrf-inet&#xA;show ospf interface xe-0/0/1.200 detail instance vrf-inet&#xA;&#xA;И вот тут началось интересное.&#xA;&#xA;Что показала диагностика&#xA;&#xA;На старом интерфейсе картина была нормальная:&#xA;&#xA;Interface: xe-0/0/0.100&#xA;Type: LAN&#xA;Cost: 50&#xA;Adj count: 2&#xA;&#xA;Соседи есть, adjacency есть, OSPF живёт полноценной жизнью.&#xA;&#xA;А на новом «дешёвом» интерфейсе было так:&#xA;&#xA;Interface: xe-0/0/1.200&#xA;Type: LAN&#xA;Cost: 10&#xA;Priority: 0&#xA;Adj count: 0&#xA;&#xA;И в соседях:&#xA;&#xA;neighbor 198.51.100.121 via xe-0/0/1.200 state 2Way&#xA;&#xA;Вот тут и спряталась причина.&#xA;&#xA;Cost 10 на интерфейсе есть.  &#xA;Но полноценной OSPF-смежности нет.  &#xA;Сосед виден, hello принимаются, но состояние только 2Way, а не Full.&#xA;&#xA;А если нет Full, то этот линк не становится нормальным маршрутом через OSPF для нужного расчёта SPF.&#xA;&#xA;Почему оно зависло в 2Way&#xA;&#xA;Интерфейс был типа LAN, то есть OSPF воспринимал его как broadcast-сегмент.&#xA;&#xA;На broadcast-сети OSPF не обязан строить Full adjacency со всеми подряд. Там есть DR/BDR, и полноценные соседства строятся через них.&#xA;&#xA;Но на линке /30 между двумя роутерами это обычно не то поведение, которое мы хотим.&#xA;&#xA;В нашем случае ещё и priority был 0.&#xA;&#xA;Условно:&#xA;&#xA;Type: LAN&#xA;Priority: 0&#xA;DR: 0.0.0.0&#xA;BDR: 0.0.0.0&#xA;Adj count: 0&#xA;&#xA;Получается типичная ситуация:&#xA;&#xA;интерфейс маленький, фактически point-to-point;&#xA;OSPF считает его LAN/broadcast;&#xA;priority 0;&#xA;DR/BDR не выбирается;&#xA;соседство остаётся в 2Way;&#xA;cost 10 вроде есть, но маршрут через этот линк не строится.&#xA;&#xA;Очень жизненно. Вроде всё настроено, но нет.&#xA;&#xA;Решение&#xA;&#xA;Для /30-линка между двумя маршрутизаторами логичнее явно сказать OSPF, что это point-to-point.&#xA;&#xA;На первом конце:&#xA;&#xA;configure&#xA;set routing-instances vrf-inet protocols ospf area 0.0.0.0 interface xe-0/0/1.200 interface-type p2p&#xA;commit&#xA;&#xA;На втором конце — то же самое на соответствующем интерфейсе:&#xA;&#xA;configure&#xA;set routing-instances vrf-inet protocols ospf area 0.0.0.0 interface xe-0/0/1.200 interface-type p2p&#xA;commit&#xA;&#xA;После этого проверяем:&#xA;&#xA;show ospf neighbor instance vrf-inet | match &#34;xe-0/0/1.200|198.51.100.121&#34;&#xA;show ospf interface xe-0/0/1.200 detail instance vrf-inet&#xA;show ospf route instance vrf-inet | match &#34;192.0.2.0|router-id&#34;&#xA;show route 192.0.2.0&#xA;&#xA;Нормальная картина после исправления:&#xA;&#xA;neighbor 198.51.100.121 via xe-0/0/1.200 state Full&#xA;&#xA;И маршрут должен пересчитаться уже через новый интерфейс.&#xA;&#xA;Если external metric 10, а cost линка 10, то для external type 1 можно ожидать итоговую метрику около:&#xA;&#xA;10 + 10 = 20&#xA;&#xA;Разумеется, если нет других ASBR, forwarding-address и дополнительных особенностей топологии.&#xA;&#xA;Что ещё стоит проверить&#xA;&#xA;Если после перевода в p2p маршрут всё равно не пошёл куда надо, я бы проверял уже вот это:&#xA;&#xA;show ospf database external 192.0.2.0 extensive instance vrf-inet&#xA;show route 192.0.2.0 extensive&#xA;show ospf route instance vrf-inet&#xA;show route router-id или forwarding-address&#xA;&#xA;Особенно важно посмотреть:&#xA;&#xA;Advertising router&#xA;Forwarding address&#xA;External type&#xA;Metric&#xA;&#xA;Потому что для external route OSPF выбирает путь не «к префиксу в вакууме», а к ASBR или forwarding address. И если forwarding address резолвится через другой интерфейс, маршрут тоже может уйти не туда, куда мы глазами ожидали.&#xA;&#xA;Важный момент про export policy&#xA;&#xA;В этом кейсе export policy тоже фигурировала.&#xA;&#xA;Изначально маршрут экспортировался в OSPF без явного external metric, поэтому в таблице была метрика 0.&#xA;&#xA;Потом для exported route задали:&#xA;&#xA;then external type 1&#xA;then metric 10&#xA;&#xA;После этого метрика стала 60.&#xA;&#xA;И это было правильно: Junos начал считать E1 как external metric плюс internal cost до ASBR.&#xA;&#xA;Но попытка менять export policy на принимающем роутере не влияет на то, как он выбирает next-hop для уже полученного OSPF-маршрута.&#xA;&#xA;То есть:&#xA;&#xA;set policy-options policy-statement rp-ospf-export ...&#xA;&#xA;на принимающей стороне влияет только на то, что этот роутер сам экспортирует в OSPF.&#xA;&#xA;А выбор next-hop для полученного маршрута — это уже SPF, соседства, cost, ASBR и forwarding-address.&#xA;&#xA;Короткая памятка&#xA;&#xA;Если OSPF-маршрут не идёт через интерфейс с меньшим cost:&#xA;&#xA;1. Проверь, в каком instance живёт OSPF&#xA;&#xA;show ospf neighbor instance instance-name&#xA;&#xA;2. Проверь состояние соседа&#xA;&#xA;show ospf neighbor instance instance-name&#xA;&#xA;Нужно Full, а не просто 2Way.&#xA;&#xA;3. Проверь тип интерфейса&#xA;&#xA;show ospf interface interface detail instance instance-name&#xA;&#xA;Если это /30 или /31 между двумя роутерами, часто правильнее:&#xA;&#xA;interface-type p2p&#xA;&#xA;4. Проверь, до кого реально строится путь&#xA;&#xA;show ospf database external prefix extensive instance instance-name&#xA;show route forwarding-address или router-id&#xA;&#xA;5. Не путай external metric и interface cost&#xA;&#xA;Для E1:&#xA;&#xA;итоговая метрика = external metric + internal cost до ASBR&#xA;&#xA;Для E2 логика другая: внешняя метрика обычно доминирует, а internal cost используется иначе при сравнении. Но это не означает, что E2 «заставит» маршрут пойти через нужный интерфейс. Next-hop всё равно зависит от SPF и достижимости ASBR/forwarding-address.&#xA;&#xA;Вывод&#xA;&#xA;В этой истории проблема была не в том, что Junos неправильно считал метрику.&#xA;&#xA;Он как раз считал её очень честно:&#xA;&#xA;10 external + 50 до ASBR = 60&#xA;&#xA;Проблема была в том, что альтернативный линк с cost 10 не имел полноценной OSPF adjacency. Он висел в 2Way, потому что интерфейс был LAN/broadcast, priority был 0, DR/BDR не выбрался, а Full-соседство не построилось.&#xA;&#xA;После перевода интерфейса в point-to-point всё стало на свои места.&#xA;&#xA;Мораль простая: если OSPF «не хочет» идти по дешёвому пути, сначала убедитесь, что этот путь вообще существует для SPF, а не просто красиво выглядит в конфиге.&#xA;&#xA;---&#xA;&#xA;#networking #junos #ospf #juniper #routing #nsp&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://paste.clr58.ru/post-ospf-2way-digclean.jpg" alt="Обложка"></p>

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

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

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

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

<h2 id="исходная-картина">Исходная картина</h2>

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

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

<pre><code class="language-text">192.0.2.0/24   *[OSPF/150], metric 60
                &gt; to 198.51.100.195 via xe-0/0/0.100
</code></pre>

<p>И вот это <code>metric 60</code> сначала немного смущает.</p>

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

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

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

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

<h2 id="первая-ловушка-export-metric-и-interface-cost-это-разные-вещи">Первая ловушка: export metric и interface cost — это разные вещи</h2>

<p>В OSPF важно не смешивать две разные сущности:</p>
<ol><li><strong>OSPF cost интерфейса</strong> — стоимость пути внутри OSPF-топологии.</li>
<li><strong>External metric</strong> — метрика внешнего маршрута, который мы редистрибутим в OSPF через export policy.</li></ol>

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

<pre><code class="language-text">external metric + internal cost до ASBR
</code></pre>

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

<pre><code class="language-text">metric 60
</code></pre>

<p>И это как раз хорошая подсказка.</p>

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

<h2 id="вторая-ловушка-смотреть-ospf-надо-внутри-routing-instance">Вторая ловушка: смотреть OSPF надо внутри routing-instance</h2>

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

<pre><code class="language-bash">show ospf neighbor
</code></pre>

<p>может ответить:</p>

<pre><code class="language-text">OSPF instance is not running
</code></pre>

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

<p>Правильно так:</p>

<pre><code class="language-bash">show ospf neighbor instance vrf-inet
show ospf interface instance vrf-inet
show ospf route instance vrf-inet
</code></pre>

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

<pre><code class="language-bash">show ospf interface xe-0/0/0.100 detail instance vrf-inet
show ospf interface xe-0/0/1.200 detail instance vrf-inet
</code></pre>

<p>И вот тут началось интересное.</p>

<h2 id="что-показала-диагностика">Что показала диагностика</h2>

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

<pre><code class="language-text">Interface: xe-0/0/0.100
Type: LAN
Cost: 50
Adj count: 2
</code></pre>

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

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

<pre><code class="language-text">Interface: xe-0/0/1.200
Type: LAN
Cost: 10
Priority: 0
Adj count: 0
</code></pre>

<p>И в соседях:</p>

<pre><code class="language-text">neighbor 198.51.100.121 via xe-0/0/1.200 state 2Way
</code></pre>

<p>Вот тут и спряталась причина.</p>

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

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

<h2 id="почему-оно-зависло-в-2way">Почему оно зависло в 2Way</h2>

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

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

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

<p>В нашем случае ещё и priority был <code>0</code>.</p>

<p>Условно:</p>

<pre><code class="language-text">Type: LAN
Priority: 0
DR: 0.0.0.0
BDR: 0.0.0.0
Adj count: 0
</code></pre>

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

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

<h2 id="решение">Решение</h2>

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

<p>На первом конце:</p>

<pre><code class="language-bash">configure
set routing-instances vrf-inet protocols ospf area 0.0.0.0 interface xe-0/0/1.200 interface-type p2p
commit
</code></pre>

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

<pre><code class="language-bash">configure
set routing-instances vrf-inet protocols ospf area 0.0.0.0 interface xe-0/0/1.200 interface-type p2p
commit
</code></pre>

<p>После этого проверяем:</p>

<pre><code class="language-bash">show ospf neighbor instance vrf-inet | match &#34;xe-0/0/1.200|198.51.100.121&#34;
show ospf interface xe-0/0/1.200 detail instance vrf-inet
show ospf route instance vrf-inet | match &#34;192.0.2.0|router-id&#34;
show route 192.0.2.0
</code></pre>

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

<pre><code class="language-text">neighbor 198.51.100.121 via xe-0/0/1.200 state Full
</code></pre>

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

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

<pre><code class="language-text">10 + 10 = 20
</code></pre>

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

<h2 id="что-ещё-стоит-проверить">Что ещё стоит проверить</h2>

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

<pre><code class="language-bash">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 &lt;router-id или forwarding-address&gt;
</code></pre>

<p>Особенно важно посмотреть:</p>

<pre><code class="language-text">Advertising router
Forwarding address
External type
Metric
</code></pre>

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

<h2 id="важный-момент-про-export-policy">Важный момент про export policy</h2>

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

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

<p>Потом для exported route задали:</p>

<pre><code class="language-bash">then external type 1
then metric 10
</code></pre>

<p>После этого метрика стала <code>60</code>.</p>

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

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

<p>То есть:</p>

<pre><code class="language-bash">set policy-options policy-statement rp-ospf-export ...
</code></pre>

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

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

<h2 id="короткая-памятка">Короткая памятка</h2>

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

<h3 id="1-проверь-в-каком-instance-живёт-ospf">1. Проверь, в каком instance живёт OSPF</h3>

<pre><code class="language-bash">show ospf neighbor instance &lt;instance-name&gt;
</code></pre>

<h3 id="2-проверь-состояние-соседа">2. Проверь состояние соседа</h3>

<pre><code class="language-bash">show ospf neighbor instance &lt;instance-name&gt;
</code></pre>

<p>Нужно <code>Full</code>, а не просто <code>2Way</code>.</p>

<h3 id="3-проверь-тип-интерфейса">3. Проверь тип интерфейса</h3>

<pre><code class="language-bash">show ospf interface &lt;interface&gt; detail instance &lt;instance-name&gt;
</code></pre>

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

<pre><code class="language-bash">interface-type p2p
</code></pre>

<h3 id="4-проверь-до-кого-реально-строится-путь">4. Проверь, до кого реально строится путь</h3>

<pre><code class="language-bash">show ospf database external &lt;prefix&gt; extensive instance &lt;instance-name&gt;
show route &lt;forwarding-address или router-id&gt;
</code></pre>

<h3 id="5-не-путай-external-metric-и-interface-cost">5. Не путай external metric и interface cost</h3>

<p>Для E1:</p>

<pre><code class="language-text">итоговая метрика = external metric + internal cost до ASBR
</code></pre>

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

<h2 id="вывод">Вывод</h2>

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

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

<pre><code class="language-text">10 external + 50 до ASBR = 60
</code></pre>

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

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

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

<hr>

<p><a href="https://articles.clr58.ru/tag:networking" class="hashtag"><span>#</span><span class="p-category">networking</span></a> <a href="https://articles.clr58.ru/tag:junos" class="hashtag"><span>#</span><span class="p-category">junos</span></a> <a href="https://articles.clr58.ru/tag:ospf" class="hashtag"><span>#</span><span class="p-category">ospf</span></a> <a href="https://articles.clr58.ru/tag:juniper" class="hashtag"><span>#</span><span class="p-category">juniper</span></a> <a href="https://articles.clr58.ru/tag:routing" class="hashtag"><span>#</span><span class="p-category">routing</span></a> <a href="https://articles.clr58.ru/tag:nsp" class="hashtag"><span>#</span><span class="p-category">nsp</span></a></p>
]]></content:encoded>
      <guid>https://articles.clr58.ru/ospf-2way</guid>
      <pubDate>Fri, 28 Aug 2026 18:22:50 +0000</pubDate>
    </item>
  </channel>
</rss>