Трассировка в MPLS L3VPN

Около года назад у меня была небольшая статейка с каверзными вопросами. Среди них был один очень для нас актуальный.

Пришло время разобрать его получше.

Если вдруг, вы не знали, как работает обычная трассировка, то стыд вам я вкратце расскажу.

Вы отправляете получателю пакеты с постепенно увеличивающимся значением TTL. Обычно это UDP, но может быть и ICMP и даже TCP.

Сначала это 1. Пакет доходит до непосредственно подключенного маршрутизатора, тот уменьшает TTL, видит, что теперь он равен нулю, формирует сообщение «time exceeded in transit» и посылает его вам обратно. Так по адресу отправителя вы знаете первый хоп.

Потом это 2. Пакет доходит до второго маршрутизатора. Происходит то же самое, так вы узнали следующий хоп.

Наконец TTL достигает N, узел назначения получает пакет, видит, что это к нему, формирует ответ (в соответствии с протоколом), по которому вы понимаете, что всё, кончено, и концы в консоль.

Кроме того, можно добавить, что на каждой итерации вы посылаете не один, а несколько пакетов (как правило, три).

В чём же особенность трассировки через L3VPN?

Пока пакет коммутируется по меткам значения каких-бы то ни было полей любых заголовков глубже MPLS не имеют никакого значения. В том числе и TTL. Маршрутизаторы ориентируются на TTL в заголовке MPLS.

И вот когда PE получает пакет от CE, есть два варианта:

  1. Скопировать значение TTL из заголовка IP в MPLS (Это режим Uniform).

  2. Записать в поле TTL заголовка MPLS 255 (Это режим Pipe или Short-Pipe).

В первом сценарии вы сможете увидеть каждый маршрутизатор на пути к получателю. Результат трассировки будет таким:

Механика же следующая:

  1. На первом шаге ничего не меняется. TARS_1 отправляет ICMP-запрос с TTL=1. R1 его получает, уменьшает TTL до нуля и отправляет на TARS_1 «time exceeded in transit». Первый хоп (R1) готов.

  2. TARS_1 отправляет ICMP-запрос с TTL=2.

  3. R1 его получает, уменьшает до 1, навешивает сервисную метку, навешивает транспортную метку, записывает в поле TTL значение 1, отправляет пакет с метками на R2.

  4. R2 его получает, уменьшает TTL до 0. Тут бы ему отправить обратно «time exceeded in transit». Но не по Сеньке шапка – нет у него ни сервисной метки для этого VPN, ни маршрута до отправителя – он же всего лишь ничем не примечательный P-маршрутизатор.

    Таким образом он формирует новый пакет, содержащий «time exceeded in transit». В этом пакете адрес отправителя принадлежит R2, а адрес получателя – TARS_1.

    Далее R2 навешивает на него ту же самую сервисную метку, что была и до этого, затем добавляет транспортную метку в сторону R3 и отправляет его на R3 (опять же можно сказать, что транспортную метку он не добавляет — PHP). То есть можно сказать, что он аккуратно вскрыл MPLS-мешок, выпотрошил IP-пакет, засунул на его место что-то новое и отправил дальше.

  5. Пакет доходит до R3. Тот его раздевает, обнаруживает, что получатель – TARS_1, чья сеть известна где-то там за VPN'ом, за R1. Он упаковывает его в MPLS с сервисной и транспортной метками и шлёт назад.

  6. TARS_1 отправляет ICMP-запрос с TTL=3. Он доходит до R3, который видит значение MPLS TTL, равное в данный момент 1, уменьшает его до 0 и возвращает «time exceeded in transit»

  7. TARS_1 отправляет ICMP-запрос с TTL=4. R3 уменьшает MPLS TTL до 1, снимает метку, копирует значение MPLS TTL в IP TTL. А дальше пакет благополучно доходит до TARS_2, тот отправляет ответ об успешном завершении. Трассировка закончена.

А что, если у меня есть закономерное желание, чтобы клиенты не видели топологию моей сети своими трассировками? Надо запретить, скажете вы. Как отец двухгодовалой дочки, я вам говорю: не нужно запрещать. Можно и нужно поступить хитрее – я просто не буду внутри своей сети уменьшать TTL MPLS до нуля.

Для этого используется второй сценарий — установить TTL MPLS в 255. В этом случае при трассировке с TARS_1 вы увидите следующий путь: R1↔R3↔TARS_2.

  1. TARS_1 отправляет ICMP-запрос с TTL=1. R1 его получает, уменьшает TTL до нуля и отправляет на TARS_1 «time exceeded in transit». Первый хоп (R1) готов.

  2. TARS_1 отправляет ICMP-запрос с TTL=2.

  3. R1 его получает, уменьшает до 1, навешивает сервисную метку, навешивает транспортную метку, записывает в поле TTL значение 255, отправляет пакет с метками на R2.

  4. R2 его получает, уменьшает TTL до 254, меняет транспортную метку (или в данном случае снимает – POP Label) и отправляет на R3.

  5. R3, сняв все метки, видит, что TTL истёк и отправляет «time exceeded in transit» обратно источнику (естественно, упаковывая в сервисную и транспортную метки)

  6. TARS_1 отправляет ICMP-запрос с TTL=3. Он благополучно доходит до TARS_2, тот отправляет успешный ответ. Трассировка закончена.

И сколько бы ни было транзитных P-маршрутизаторов, TTL=3 будет достаточно всегда при трассировке с TARS_1 на TARS_2.

Поведение по умолчанию различается у вендоров. Циска считает, что инженер знает, что делает и чем ему грозит каждое действие, поэтому выбирает первый путь, а, например, Хуавэй предпочитает перестраховаться — лучше сначала запретить, дабы чего не вышло, а потом инженер разрешит при необходимости. Как бы то ни было, режим всегда можно поменять — в нашем случае в режиме глобальной конфигурации нужно для этого дать команду «no mpls ip propagate-ttl».

Замечательный пятидесятитрёхстраничный документ по трассировке на nano.org.

Кстати, для MPLS есть особенные утилиы пинга и трассировки.