Теоретические основы и архитектура

Базовые операции с метками в Data Plane MPLS — это Push, Swap и Pop. Операция Push выполняется на Ingress PE: к чистому IP-пакету добавляется сервисная метка (полученная по MP-BGP), а затем транспортная метка (полученная по LDP или SR). Операция Swap выполняется на транзитных P-маршрутизаторах: маршрутизатор считывает входящую верхнюю метку из заголовка кадра, находит её в таблице LFIB и заменяет (Swap) на исходящую метку для следующего перехода. Операция Pop заключается в удалении верхней метки. Ключевой оптимизацией ядра является Penultimate Hop Popping (PHP, RFC 3031): предпоследний маршрутизатор на пути к egress PE удаляет внешнюю транспортную метку заранее. Это происходит, когда egress PE анонсирует предпоследнему узлу специальную метку Implicit Null (значение 3). В результате egress PE получает пакет только с сервисной меткой (или чистый IP) и выполняет всего одно аппаратное обращение к памяти вместо двойного поиска (Double Lookup). Если же требуется сохранить значение QoS TC через всё ядро до самого выхода, egress PE анонсирует Explicit Null (значение 0 для IPv4, 2 для IPv6), и метка остаётся в пакете.

Три операции над стеком меток

MPLS пересылает пакет по верхней записи стека (архитектура - RFC 3031, формат 32-битной записи - RFC 3032: Label 20 бит, TC 3 бита, S 1 бит, TTL 8 бит). Любое решение LSR сводится к одной из трёх операций:

ОперацияГде выполняетсяЧто делает со стекомГде смотреть
PushIngress LER (PE1); также начало туннеля (TE, FRR)Добавляет одну или несколько записей поверх IP-пакета или существующего стекаFIB/CEF ingress: у префикса есть исходящая метка
SwapТранзитный LSR (P1)Заменяет верхнюю метку на ту, что объявил следующий сосед (downstream) для этого FECLFIB: входящая метка -> исходящая метка, интерфейс, next-hop
PopПредпоследний LSR (PHP) или egressСнимает верхнюю запись; если она была последней (S=1), пакет уходит как IPLFIB: исходящее значение Pop Label / Pop / 3

Push принимает решение по FIB (longest prefix match по IP-адресу), Swap и Pop - по LFIB (точное совпадение по метке). Поэтому транзитному P не нужна таблица BGP: ему достаточно LFIB.

Зарезервированные метки 0-15

Метки 0-15 не выделяются под FEC (RFC 3032, RFC 7274):

ЗначениеИмяСмысл
0IPv4 Explicit NullМетку нужно снять, затем выполнить IPv4-поиск; запись остаётся на проводе
1Router AlertОтдать пакет в control plane, затем при необходимости переслать дальше
2IPv6 Explicit NullТо же для IPv6
3Implicit NullНикогда не попадает в пакет; сигнал в LDP/RSVP: "upstream, сними метку сам"
7ELIEntropy Label Indicator (RFC 6790)
13GALGeneric Associated Channel Label (RFC 5586)
15ExtensionРасширение пространства меток (RFC 7274)

Метка 3 - "виртуальная": в LDP Label Mapping (тип сообщения 0x0400) она передаётся в Generic Label TLV (тип 0x0200) как обычное 20-битное значение, а в пакетах на проводе её не бывает. Динамические метки по умолчанию начинаются у Cisco IOS-XE с 16, у Junos (LDP) около 299776, у Huawei VRP с 1024; точные числа в вашей лабе отличаются, сверяйте цепочку входящая -> исходящая по своим bindings.

PHP: что происходит на предпоследнем узле

Egress LSR для FEC (здесь PE2 для 10.255.0.2/32) сам выбирает метку, которую объявит upstream-соседу в Label Mapping. Для собственных connected-префиксов, включая loopback, по умолчанию объявляется Implicit Null (3). Предпоследний узел P2, получив mapping с меткой 3, программирует в LFIB запись "входящая метка -> Pop, next-hop PE2". Когда пакет приходит на P2, он снимает метку и отправляет пакет к PE2 без неё (если под ней лежала ещё запись, например VPN-метка, - уже с ней наверху).

Зачем это нужно. Без PHP egress PE2 получил бы кадр с транспортной меткой, сделал бы lookup 1 в LFIB (метка -> "снять и смотреть IP") и затем lookup 2 в FIB (IP). С PHP остаётся один поиск. В L3VPN выигрыш нагляднее: PE2 получает кадр с единственной VPN-меткой и сразу попадает в нужную VRF, не тратя проход на транспортную метку.

Принцип "per FEC и per advertiser": тип метки определяет тот, кто является egress для данного FEC. Loopback PE2 объявлен с меткой 3, loopback PE1 тоже с 3, но PHP выполняют разные узлы: для 10.255.0.2/32 это P2, для 10.255.0.1/32 это P1. Поэтому включение explicit null только на PE2 меняет поведение в сторону PE2 и не затрагивает трафик в сторону PE1.

Explicit Null: что меняется на проводе

Если egress объявил метку 0 (IPv4 Explicit Null), P2 не снимает метку, а выполняет Swap на 0. На линк P2-PE2 пакет уходит как [0 | IP]: EtherType 0x8847, одна MPLS-запись с Label=0, S=1, TTL уменьшен на единицу относительно входящей записи. PE2 видит метку 0, снимает её и делает IP-поиск; TC и TTL этой записи ему доступны. Если под нулевой меткой лежит ещё запись (S=0 у метки 0), то после её снятия PE2 работает со следующей.

Стоимость: egress выполняет дополнительный проход по пайплайну, а в линк P2-PE2 добавляется 4 байта на пакет (учитывайте MTU). Выгода: egress получает TC (и TTL) внешней записи.

TC/QoS: зачем нужен explicit null

При PHP внешняя запись снимается на P2 вместе с полем TC (3 бита), и egress не может классифицировать пакет по провайдерскому TC транспортной метки. Модели туннелирования DiffServ (RFC 3270):

  • Uniform: TC копируется из DSCP при Push и обратно в DSCP при Pop. Работает с PHP, но маркировка клиента может быть изменена провайдером.
  • Short Pipe: на egress классификация идёт по DSCP клиента (IP или внутреннему слою), провайдерский TC не нужен. Совместим с PHP; самый частый вариант для L3VPN.
  • Pipe: egress должен видеть провайдерский TC, чтобы применить политику выходного интерфейса по классу оператора, не меняя DSCP клиента. Для этого PHP не подходит: нужен explicit null, метка 0 доносит TC до egress.

TTL при push, swap и pop

Ingress копирует IP TTL в MPLS-запись (propagate), уменьшив на 1; каждый swap уменьшает TTL на 1; при pop (PHP) значение возвращается в IP TTL. Следствие для traceroute: в Uniform-режиме ядро (P1, P2) видно как hop-ы. Если отключить propagation (Cisco no mpls ip propagate-ttl, Junos no-propagate-ttl), traceroute не показывает P-маршрутизаторы. При TTL=0 на транзитном LSR пакет не отбрасывается молча: P генерирует ICMP Time Exceeded.

Как наблюдать операции

  1. FIB ingress PE1: у 10.255.0.2/32 есть исходящая метка (CEF показывает метку в nexthop; Junos - Push в inet.3) - это Push.
  2. LFIB P1: входящая метка -> исходящая метка, интерфейс и next-hop - это Swap.
  3. LFIB P2: исходящее значение Pop Label (Cisco), Pop (Junos), 3 (Huawei) - это PHP; при explicit null вместо Pop: explicit-n (Cisco), Swap 0 (Junos), 0 (Huawei).
  4. LDP bindings: на PE2 локальная привязка imp-null (после смены exp-null), на P2 удалённая привязка от PE2 равна 3 (после смены 0).
  5. Capture (Wireshark, фильтр mpls): на PE1-P1 запись [17], на P1-P2 запись [18], на P2-PE2 без explicit null кадр без MPLS (EtherType 0x0800), с explicit null - запись с Label=0. TTL уменьшается на единицу на каждом участке.

Платформы и ограничения

  • Cisco IOS-XE: mpls ldp explicit-null в глобальном режиме; применяется к меткам, которые маршрутизатор объявляет как egress. Команда допускает фильтр по префиксам (for <prefix-acl>); синтаксис проверьте в вашей версии.
  • Juniper Junos: set protocols ldp explicit-null. Команда set protocols mpls explicit-null относится к RSVP-сигнализации; не путайте.
  • Huawei VRP: поведение egress задаётся командой label advertise { explicit-null | implicit-null | non-null }; non-null означает реальную метку и отсутствие PHP.
  • MikroTik RouterOS v7: параметр use-explicit-null в /mpls/ldp (по умолчанию no).

Режимы отказа

  • Capture на последнем линке показывает "голый" IP, и инженер решает, что MPLS сломан: это норма при PHP; нужно смотреть на предыдущий линк.
  • Explicit null включён только на одном PE: TC доходит до egress лишь в одном направлении, QoS становится асимметричным.
  • PE2 объявляет не Implicit Null, а обычную метку (non-null на Huawei): P2 делает Swap вместо Pop, на линке лишние 4 байта и дополнительный lookup.
  • Линк P2-PE2 с MTU 1500 без запаса: после перехода на explicit null каждый пакет получает +4 байта, и крупные кадры с DF=1 начинают теряться.
  • Сравнение с иллюстрациями: номера меток на разных платформах разные; проверяйте логику цепочки, а не числа.

Схема архитектуры и топология

text
+---------+   +----------------------+   +--------------------+   +--------------------+   +--------------------+   +---------+
|  CE-1   |-->|   PE-1 (Ingress)     |-->|   P-1 (Transit)    |-->| P-2 (Penultimate)  |-->|    PE-2 (Egress)   |-->|  CE-2   |
| Cust IP |   | PUSH Service: 24001  |   | SWAP: 16002->16012 |   | POP transport(PHP) |   | POP Service: 24001 |   | Cust IP |
|         |   | PUSH Transport:16002 |   | Core LSR switching |   | sends [24001 | IP] |   | Lookup in VRF      |   |         |
+---------+   +----------------------+   +--------------------+   +--------------------+   +--------------------+   +---------+

Схема прохождения трафика и стек меток