Введение
Если вы работали с 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
<output omitted>
1.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
O IA 1.1.1.0/24 [110/5] via 192.168.45.4, 00:07:20, FastEthernet0/0
O IA 1.1.2.1/32 [110/5] via 192.168.45.4, 00:05:26, FastEthernet0/0
2.0.0.0/32 is subnetted, 1 subnets
O IA 2.2.2.2 [110/4] via 192.168.45.4, 00:52:54, FastEthernet0/0
3.0.0.0/32 is subnetted, 1 subnets
O IA 3.3.3.3 [110/3] via 192.168.45.4, 00:52:54, FastEthernet0/0
4.0.0.0/32 is subnetted, 1 subnets
O IA 4.4.4.4 [110/2] via 192.168.45.4, 00:52:54, FastEthernet0/0
O IA 192.168.12.0/24 [110/4] via 192.168.45.4, 00:52:54, FastEthernet0/0
O IA 192.168.23.0/24 [110/3] via 192.168.45.4, 00:52:54, FastEthernet0/0
O IA 192.168.34.0/24 [110/2] via 192.168.45.4, 00:52:54, FastEthernet0/0
CE2#
CE2#traceroute 1.1.1.1 source 5.5.5.5
Type escape sequence to abort.
Tracing the route to 1.1.1.1
VRF info: (vrf in name/id, vrf out name/id)
1 192.168.45.4 12 msec 12 msec 8 msec
2 192.168.34.3 [MPLS: Label 23 Exp 0] 48 msec 12 msec 32 msec
3 192.168.23.2 68 msec 36 msec 40 msec
4 192.168.12.1 76 msec 96 msec 44 msec
CE2#
CE2#traceroute 192.168.12.1 source 5.5.5.5
Type escape sequence to abort.
Tracing the route to 192.168.12.1
VRF info: (vrf in name/id, vrf out name/id)
1 192.168.45.4 8 msec 16 msec 12 msec
2 192.168.34.3 [MPLS: Label 19 Exp 0] 12 msec 32 msec 28 msec
3 192.168.23.2 64 msec 44 msec 44 msec
4 192.168.12.1 56 msec 48 msec 60 msec
CE2#
CE2#traceroute 1.1.2.1 source 5.5.5.5
Type escape sequence to abort.
Tracing the route to 1.1.2.1
VRF info: (vrf in name/id, vrf out name/id)
1 192.168.45.4 16 msec 20 msec 20 msec
2 192.168.34.3 [MPLS: Label 24 Exp 0] 52 msec 64 msec 56 msec
3 192.168.23.2 [MPLS: Label 23 Exp 0] 64 msec 48 msec 64 msec
4 192.168.12.1 100 msec 80 msec 84 msec
Обратите внимание, что выделенные метки отличаются друг от друга из-за режима 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
<output omitted>
2.0.0.0/32 is subnetted, 1 subnets
O 2.2.2.2 [110/2] via 192.168.23.2, 01:24:24, FastEthernet0/1
P#
P#show ip cef 2.2.2.2/32 detail
2.2.2.2/32, epoch 0
local label info: global/16
nexthop 192.168.23.2 FastEthernet0/1
Нет, всё именно так, как мы и задумывали, за исключением отсуствия метки в 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
<output omitted>
2.0.0.0/32 is subnetted, 1 subnets
O 2.2.2.2 [110/2] via 192.168.23.2, 01:30:17, FastEthernet0/1
P#
P#show mpls ldp bindings 2.2.2.0 24
lib entry: 2.2.2.0/24, rev 28
remote binding: lsr: 2.2.2.2:0, label: imp-null
Маски сетей не совпадают! 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
arider77
Спасибо за статью и интересные кейсы.