Введение

Если вы работали с 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), довольно широко освещена в интернете; здесь можно освежить память при необходимости. Впрочем, большинство авторов опускают ряд существенных нюансов, чтобы упростить погружение в тему.

  1. LDP выделяет метки для всех префиксов кроме тех, которые получены по BGP. В последнем случае именно BGP ответственен за выделение необходимого числа меток, например, в случае VPNv4 AF, labelled unicast и других подходящих сценариев.

  2. В общем случае 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

Комментарии (1)


  1. arider77
    16.11.2023 08:05

    Спасибо за статью и интересные кейсы.