[Перевод] MPLS: всего по чуть-чуть
Введение
Если вы работали с MPLS на стенде или в живой сети, то вы, пожалуй, согласитесь, что сама технология довольно проста. Однако даже в такой несложной штуке можно спрятать пачку граблей, которые усложнят жизнь. Большая часть этих сельскохозяйственных сюрпризов описана множеством статей в интернете, однако есть и пара слабо освещённых аспектов. Сегодня я бы хотел внести свой посильный вклад в общую базу знаний по MPLS, рассказав о нескольких малоизвестных особенностях технологии, которые сами по себе не тянут на отдельную статью, но могут представлять некоторый интерес.
Топология проста, как палка:
MPLS в сети ISP выполняет всего лишь функцию инкапсуляции транзитного трафика (L3VPN, TE и подобные отсуствуют). IGP — банальный OSPF, разделение же на зоны позволит впоследствии манипулировать префиксами на PE. Ниже представлены начальные настройки маршрутизаторов:
CE1#show run | section FastEthernet|router|Loopback
interface Loopback0
ip address 1.1.1.1 255.255.255.255
interface Loopback1
ip address 1.1.2.1 255.255.255.255
interface FastEthernet0/0
ip address 192.168.12.1 255.255.255.0
router ospf 1
router-id 1.1.1.1
network 0.0.0.0 255.255.255.255 area 1
PE1#show run | section FastEthernet|router|Loopback
interface Loopback0
ip address 2.2.2.2 255.255.255.255
interface FastEthernet0/0
ip address 192.168.12.2 255.255.255.0
ip ospf 1 area 1
interface FastEthernet0/1
ip address 192.168.23.2 255.255.255.0
router ospf 1
mpls ldp autoconfig area 0
router-id 2.2.2.2
area 1 range 1.1.1.0 255.255.255.0
network 0.0.0.0 255.255.255.255 area 0
P#show run | section FastEthernet|router|Loopback
interface Loopback0
ip address 3.3.3.3 255.255.255.255
interface FastEthernet0/1
ip address 192.168.23.3 255.255.255.0
interface FastEthernet1/0
ip address 192.168.34.3 255.255.255.0
router ospf 1
mpls ldp autoconfig
router-id 3.3.3.3
network 0.0.0.0 255.255.255.255 area 0
PE2#show run | section FastEthernet|router|Loopback
interface Loopback0
ip address 4.4.4.4 255.255.255.255
interface FastEthernet0/0
ip address 192.168.45.4 255.255.255.0
ip ospf 1 area 2
interface FastEthernet1/0
ip address 192.168.34.4 255.255.255.0
router ospf 1
mpls ldp autoconfig area 0
network 0.0.0.0 255.255.255.255 area 0
CE2#show run | section FastEthernet|router|Loopback
interface Loopback0
ip address 5.5.5.5 255.255.255.255
interface FastEthernet0/0
ip address 192.168.45.5 255.255.255.0
router ospf 1
router-id 5.5.5.5
network 0.0.0.0 255.255.255.255 area 2
Сказ 1: исповедь PHP
Теория, стоящая за penultimate hop popping (PHP), довольно широко освещена в интернете; здесь можно освежить память при необходимости. Впрочем, большинство авторов опускают ряд существенных нюансов, чтобы упростить погружение в тему.
LDP выделяет метки для всех префиксов кроме тех, которые получены по BGP. В последнем случае именно BGP ответственен за выделение необходимого числа меток, например, в случае VPNv4 AF, labelled unicast и других подходящих сценариев.
В общем случае PHP действительно избавляет от одной итерации поиска в таблице меток, однако это поведение справедливо только для connected и aggregated маршрутов; транзитные маршруты всё так же получают метку. Причина проста: connected и aggregated префиксы всё равно требуют поиска следующего узла в соответствующих таблицах, тогда как трафик по транзитным маршрутам можно передать далее на основе полученной метки.
Проверим последнее утверждение на практике:
CE2#show ip route ospf
Обратите внимание, что выделенные метки отличаются друг от друга из-за режима per-prefix label allocation, включенного по умолчанию. Connected маршруты требуют поиска в ARP таблице, поскольку по входящей метке невозможно определить нужную L2 информацию; аналогичное наблюдение справедливо и для aggregated маршрутов. Однако пакет до 1.1.1.1/32 может быть передан следующему узлу без задействования таблицы маршрутизации:
PE1#show mpls forwarding-table 1.1.1.0 24 detail
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
None No Label 1.1.1.0/24 0 punt
MAC/Encaps=0/0, MRU=0, Label Stack{}
No output feature configured
PE1#
PE1#show mpls forwarding-table 192.168.12.0 24 detail
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
None No Label 192.168.12.0/24 0 punt
MAC/Encaps=0/0, MRU=0, Label Stack{}
No output feature configured
PE1#
PE1#show mpls forwarding-table 1.1.2.1 32 detail
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
23 No Label 1.1.2.1/32 672 Fa0/0 192.168.12.1
MAC/Encaps=14/14, MRU=1504, Label Stack{}
CA010BDB0008CA020BDF00080800
No output feature configured
Сказ 2: необычный loopback
Ещё одно любопытное поведение связано с «неправильной» настройкой маски на loopback. Широко распространено использование /32 маски для адресации loopback. И правда, зачем платить больше? Однако, мои пальцы оказывались слишком толстыми для клавиатуры не один раз, настраивая на стенде привычную маску /24. Последствия могут быть неочевидны с первого взгляда, что в свою очередь усложняет поиск ошибки. Внесём изменение в нашу схему:
PE1(config)#interface loopback 0
PE1(config-if)#ip address 2.2.2.2 255.255.255.0
Ничего существенного, не так ли? Однако наш LSP уже развалился:
PE2#traceroute mpls ipv4 2.2.2.0/24 source 4.4.4.4 verbose
Tracing MPLS Label Switched Path to 2.2.2.0/24, timeout is 2 seconds
Codes: '!' - success, 'Q' - request not sent, '.' - timeout,
'L' - labeled output interface, 'B' - unlabeled output interface,
'D' - DS Map mismatch, 'F' - no FEC mapping, 'f' - FEC mismatch,
'M' - malformed request, 'm' - unsupported tlvs, 'N' - no label entry,
'P' - no rx intf label prot, 'p' - premature termination of LSP,
'R' - transit router, 'I' - unknown upstream index,
'X' - unknown return code, 'x' - return code 0
Type escape sequence to abort.
0 4.4.4.4 0.0.0.0 MRU 0 [No Label]
Q 1 *
Причина отказа — отсутствие соответствующей метки на P. Может быть, маршрут был передан некорректно?
P#show ip route 2.2.2.0 255.255.255.0 longer-prefixes
Нет, всё именно так, как мы и задумывали, за исключением отсуствия метки в CEF. За метки ответственен LDP, поэтому проверим, что именно P получает от PE1:
P#show mpls ldp bindings neighbor 2.2.2.2
lib entry: 1.1.1.0/24, rev 22
remote binding: lsr: 2.2.2.2:0, label: imp-null
lib entry: 1.1.1.1/32, rev 27
remote binding: lsr: 2.2.2.2:0, label: 16
lib entry: 1.1.2.1/32, rev 24
remote binding: lsr: 2.2.2.2:0, label: 23
lib entry: 2.2.2.0/24, rev 28
remote binding: lsr: 2.2.2.2:0, label: imp-null
lib entry: 3.3.3.3/32, rev 2
remote binding: lsr: 2.2.2.2:0, label: 18
lib entry: 4.4.4.4/32, rev 16
remote binding: lsr: 2.2.2.2:0, label: 20
lib entry: 5.5.5.5/32, rev 20
remote binding: lsr: 2.2.2.2:0, label: 22
lib entry: 192.168.12.0/24, rev 14
remote binding: lsr: 2.2.2.2:0, label: imp-null
lib entry: 192.168.23.0/24, rev 4
remote binding: lsr: 2.2.2.2:0, label: imp-null
lib entry: 192.168.34.0/24, rev 6
remote binding: lsr: 2.2.2.2:0, label: 19
lib entry: 192.168.45.0/24, rev 18
remote binding: lsr: 2.2.2.2:0, label: 21
Метка для 2.2.2.0/24 верна — это implicit-null. Заметили уже что-либо необычное?
P#show ip route 2.2.2.0 255.255.255.0 longer-prefixes
Маски сетей не совпадают! OSPF по умолчанию игнорирует маски loopback, отличающиеся от хостовой, и продолжает анонсировать /32. LDP же играет по разумным правилам, распространяя именно то, что настроено. P не может сопоставить маршрут из RIB метке в LIB, поэтому исходящая метка и отсутствует. Лекарство весьма простое, особенно если вы провели достаточно времени с OSPF в лабе:
PE1(config)#interface loopback 0
PE1(config-if)#ip ospf network point-to-point
PE2#traceroute mpls ipv4 2.2.2.0/24 source 4.4.4.4 verbose
Tracing MPLS Label Switched Path to 2.2.2.0/24, timeout is 2 seconds
Codes: '!' - success, 'Q' - request not sent, '.' - timeout,
'L' - labeled output interface, 'B' - unlabeled output interface,
'D' - DS Map mismatch, 'F' - no FEC mapping, 'f' - FEC mismatch,
'M' - malformed request, 'm' - unsupported tlvs, 'N' - no label entry,
'P' - no rx intf label prot, 'p' - premature termination of LSP,
'R' - transit router, 'I' - unknown upstream index,
'X' - unknown return code, 'x' - return code 0
Type escape sequence to abort.
0 192.168.34.4 192.168.34.3 MRU 1500 [Labels: 18 Exp: 0]
L 1 192.168.34.3 192.168.23.2 MRU 1504 [Labels: implicit-null Exp: 0] 16 ms, ret code 8
! 2 192.168.23.2 40 ms, ret code 3
PE2#
PE2#show ip cef 2.2.2.2 detail
2.2.2.0/24, epoch 0
local label info: global/19
nexthop 192.168.34.3 FastEthernet1/0 label 18
Сказ 3: отменённый loopback
Схемы с overlay VPN обычно используют loopback в качестве BGP next-hop. Помимо очевидных причин (балансировка, отказоусточивость транспорта и т.д.) есть и более серьёзное основание не использовать физический интерфейс для L3VPN узла — PHP. PE2, расположенный на расстоянии одного узла от PE1, не будет менять метки для пакетов в сторону 192.168.23.2; вместо этого он снимет верхнюю метку, поскольку P анонсирует implicit-null для своего connected маршрута.
PE2#traceroute 192.168.23.2 source 4.4.4.4
Type escape sequence to abort.
Tracing the route to 192.168.23.2
VRF info: (vrf in name/id, vrf out name/id)
1 192.168.34.3 20 msec 24 msec 12 msec
2 192.168.23.2 8 msec 28 msec 24 msec
Как следствие, в случае L3VPN маршрутизатор P получил бы пакет с VPN меткой на вершине стека, поэтому пакет был бы отброшен или мы бы смогли наблюдать настоящие чудеса, достойные Хогвартса.
А что если нельзя использовать loopback для установления BGP соседства? Честно говоря, единственный сценарий, который мне приходит в голову, — это очень странная задача для CCIE уровня, поэтому это обсуждение весьма абстрактное. Так или иначе, в этом случае необходимо сделать так, чтобы маршрутизатор P не считал адрес PE1 как directly connected. Новые IOS используют в RIB /32 маршруты до адресов своих интерфейсов (она называются Local route), однако эти префиксы не попадают в OSPF. Впрочем, OSPF анонсирует /32 адреса интерфейсов в случае P2M:
PE1(config)#interface f0/1
PE1(config-if)#ip ospf network point-to-multipoint
P(config)#interface f0/1
P(config-if)#ip ospf network point-to-multipoint
Вуаля! Записи в OSPF RIB и в таблице LDP созданы, так что LSP снова работает:
P#show mpls forwarding-table 192.168.23.2 32 detail
Local Outgoing Prefix Bytes Label Outgoing Next Hop
Label Label or Tunnel Id Switched interface
17 Pop Label 192.168.23.2/32 252 Fa0/1 192.168.23.2
MAC/Encaps=14/14, MRU=1504, Label Stack{}
CA020BDF0006CA030BFB00068847
No output feature configured
PE2#traceroute 192.168.23.2 source lo 0
Type escape sequence to abort.
Tracing the route to 192.168.23.2
VRF info: (vrf in name/id, vrf out name/id)
1 192.168.34.3 [MPLS: Label 17 Exp 0] 4 msec 16 msec 8 msec
2 192.168.23.2 12 msec 32 msec 28 msec
Заключение
В этой статье мы обсудили несколько характеристик MPLS сети в общем виде: функционирование PHP, «неверную» настройку loopback с OSPF, последствия такой шалости, а также сценарий для тех, кто одержим CCIE+. Надеюсь, вам зашло неглубоко, не переключайтесь!
Спасибо за рецензию: Анастасии Куралёвой
Канал в Телеграме: https://t.me/networking_it_ru