Теоретические основы и архитектура
Базовые операции с метками в 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 сводится к одной из трёх операций:
| Операция | Где выполняется | Что делает со стеком | Где смотреть |
|---|---|---|---|
| Push | Ingress LER (PE1); также начало туннеля (TE, FRR) | Добавляет одну или несколько записей поверх IP-пакета или существующего стека | FIB/CEF ingress: у префикса есть исходящая метка |
| Swap | Транзитный LSR (P1) | Заменяет верхнюю метку на ту, что объявил следующий сосед (downstream) для этого FEC | LFIB: входящая метка -> исходящая метка, интерфейс, next-hop |
| Pop | Предпоследний LSR (PHP) или egress | Снимает верхнюю запись; если она была последней (S=1), пакет уходит как IP | LFIB: исходящее значение 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):
| Значение | Имя | Смысл |
|---|---|---|
| 0 | IPv4 Explicit Null | Метку нужно снять, затем выполнить IPv4-поиск; запись остаётся на проводе |
| 1 | Router Alert | Отдать пакет в control plane, затем при необходимости переслать дальше |
| 2 | IPv6 Explicit Null | То же для IPv6 |
| 3 | Implicit Null | Никогда не попадает в пакет; сигнал в LDP/RSVP: "upstream, сними метку сам" |
| 7 | ELI | Entropy Label Indicator (RFC 6790) |
| 13 | GAL | Generic Associated Channel Label (RFC 5586) |
| 15 | Extension | Расширение пространства меток (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.
Как наблюдать операции
- FIB ingress PE1: у 10.255.0.2/32 есть исходящая метка (CEF показывает метку в nexthop; Junos -
Pushв inet.3) - это Push. - LFIB P1: входящая метка -> исходящая метка, интерфейс и next-hop - это Swap.
- LFIB P2: исходящее значение
Pop Label(Cisco),Pop(Junos),3(Huawei) - это PHP; при explicit null вместо Pop:explicit-n(Cisco),Swap 0(Junos),0(Huawei). - LDP bindings: на PE2 локальная привязка
imp-null(после сменыexp-null), на P2 удалённая привязка от PE2 равна 3 (после смены 0). - 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 начинают теряться.
- Сравнение с иллюстрациями: номера меток на разных платформах разные; проверяйте логику цепочки, а не числа.
Схема архитектуры и топология
+---------+ +----------------------+ +--------------------+ +--------------------+ +--------------------+ +---------+
| 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 | | |
+---------+ +----------------------+ +--------------------+ +--------------------+ +--------------------+ +---------+