Кросспостинг, оригинальная публикация

Про настройку и диагностику технологии DMVPN в интернете написано немало статей. Однако про использование мультикаста поверх DMVPN лучшее, что мне удалось найти – это маленькая заметка в Configuration Guide.

In DMVPN, it is recommended to configure a Rendezvous Point (RP) at or behind the hub. If there is an IP multicast source behind a spoke, the ip pim spt-threshold infinity command must be configured on spokes to avoid multicast traffic going through spoke-to-spoke tunnels.

Давайте выясним, в чем на самом деле заключается необходимость этой команды. Тестовая схема выглядит следующим образом.

Как можно заметить, это самый обыкновенный DMVPN Phase 2, собранный в GNS3. Интерфейсы Loopback на каждом маршрутизаторе позволяют смоделировать клиентские подсети; также логично разместить RP на Hub-маршрутизаторе как центральной точке логической топологии. Для удобства адресации примем Hub = R1, Spoke1 = R2, Spoke2 = R3, Internet = R4.

Настроим PIM и RP внутри DMVPN облака:

Hub(config)#interface Loopback0
Hub(config-if)#ip address 1.1.1.1 255.255.255.255
Hub(config-if)#ip pim sparse-mode
Hub(config)#interface Tunnel0
Hub(config-if)#ip address 192.168.0.1 255.255.255.0
Hub(config-if)#no ip redirects
Hub(config-if)#no ip split-horizon eigrp 1
Hub(config-if)#ip pim sparse-mode
Hub(config-if)#ip nhrp map multicast dynamic
Hub(config-if)#ip nhrp network-id 1
Hub(config-if)#tunnel source FastEthernet0/0
Hub(config-if)#tunnel mode gre multipoint
Hub(config-if)#tunnel vrf A
Hub(config)#ip pim rp-address 1.1.1.1
Spoke1(config)#interface Loopback0
Spoke1(config-if)#ip address 2.2.2.2 255.255.255.255
Spoke1(config-if)#ip pim sparse-mode
Spoke1(config)#interface Tunnel0
Spoke1(config-if)#ip address 192.168.0.2 255.255.255.0
Spoke1(config-if)#no ip redirects
Spoke1(config-if)#ip pim sparse-mode
Spoke1(config-if)#ip nhrp network-id 1
Spoke1(config-if)#ip nhrp nhs 192.168.0.1 nbma 192.168.14.1 multicast
Spoke1(config-if)#tunnel source FastEthernet0/1
Spoke1(config-if)#tunnel mode gre multipoint
Spoke1(config-if)#tunnel vrf A
Spoke1(config)#ip pim rp-address 1.1.1.1
Spoke2(config)#interface Loopback0
Spoke2(config-if)#ip address 3.3.3.3 255.255.255.255
Spoke2(config-if)#ip pim sparse-mode
Spoke2(config)#interface Tunnel0
Spoke2(config-if)#ip address 192.168.0.3 255.255.255.0
Spoke2(config-if)#no ip redirects
Spoke2(config-if)#ip pim sparse-mode
Spoke2(config-if)#ip nhrp network-id 1
Spoke2(config-if)#ip nhrp nhs 192.168.0.1 nbma 192.168.14.1 multicast
Spoke2(config-if)#tunnel source FastEthernet1/0
Spoke2(config-if)#tunnel mode gre multipoint
Spoke2(config-if)#tunnel vrf A
Spoke2(config)#ip pim rp-address 1.1.1.1

На данном этапе есть связность между Spoke, а также необходимые протоколы управления групповым вещанием. Самое время подписаться на мультикаст поток на Spoke1:

Spoke1(config)#int lo 0
Spoke1(config-if)#ip igmp join-group 224.1.1.1
Spoke1#sho ip mroute
(*, 224.1.1.1), 00:00:37/00:02:22, RP 1.1.1.1, flags: SJCL
  Incoming interface: Tunnel0, RPF nbr 192.168.0.1
  Outgoing interface list:
   Loopback0, Forward/Sparse, 00:00:37/00:02:22

Запустим сам поток в виде ICMP echo request сообщений, отправляемых на multicast адрес, на Spoke2:

Spoke2#ping 224.1.1.1 source lo0 rep 1000 Type escape sequence to abort.
Sending 1000, 100-byte ICMP Echos to 224.1.1.1, timeout is 2 seconds:
Packet sent with a source address of 3.3.3.3
Reply to request 0 from 2.2.2.2, 156 ms....

Не работает, причём довольно хитрым образом: первый пакет проходит (мы получаем на него ответ), однако последующие почему-то пропадают. Взглянем на то, что происходит в данный момент, на уровне пакетов.

Spoke1:

Hub:

Итак, это Hub не шлёт пакеты потока после обработки самого первого пакета. С чего бы вдруг?

Hub#sho ip mroute
<output omitted>
(*, 224.1.1.1), 00:03:31/00:02:55, RP 1.1.1.1, flags: SP
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list: Null
(3.3.3.3, 224.1.1.1), 00:03:08/00:02:46, flags: PJT
  Incoming interface: Tunnel0, RPF nbr 192.168.0.3
  Outgoing interface list: Null

Список OIL (outgoing interface list) пуст, что и является причиной потери потока. Или не является? Почему же тогда прошёл самый первый пакет? Давайте взглянем на Hub за пару секунд до того:

Hub#sho ip mroute
<output omitted>
(*, 224.1.1.1), 00:00:13/00:03:16, RP 1.1.1.1, flags: S
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
   Tunnel0, Forward/Sparse, 00:00:13/00:03:16

(*,G) содержит Tunnel0, что ожидаемо; RPF сосед также пока неизвестен, поскольку ни один пакет из потока ещё не прошёл через Hub. А дальше следите за руками:

  1. Spoke2 шлёт самый первый мультикаст пакет внутри unicast сообщения RP-Register;

  2. Hub, он же RP, получает RP-Register и выполняет следующие два действия: отправляет пакет согласно OIL (Tunnel0); кроме того, отправляет PIM Join в сторону источника потока (Tunnel0);

  3. В режиме PIM-SM входящий интерфейс (IIF, incoming interface) не может присутствовать в OIL (RPF check), поскольку это может породить петлю; следовательно, Tunnel0 необходимо исключить из OIL – в этот момент Spoke2 теряет поток.

Суть проблемы кроется в NBMA (non-broadcast multiple access) поведении DMVPN: Spoke2 логически находится в одном широковещательном сегменте со Spoke1, хотя физически это совсем не так (а Вы думали, Frame-Relay жил, Frame-Relay жив, Frame-Relay будет жить; надеюсь, это шутка). Впрочем, решение задачи довольно простое – надо явно указать Hub, что Tunnel0 следует рассматривать не как один интерфейс, а как набор нескольких:

Hub(config)#interface Tunnel0
Hub(config-if)#ip pim nbma-mode

Теперь таблица маршрутизации мультикаста правильная:

Hub#sho ip mroute
(*, 224.1.1.1), 00:03:51/00:03:27, RP 1.1.1.1, flags: S
 Incoming interface: Null, RPF nbr 0.0.0.0
 Outgoing interface list:
  Tunnel0, 192.168.0.2, Forward/Sparse, 00:00:02/00:03:27
(3.3.3.3, 224.1.1.1), 00:03:29/00:02:25, flags: JT
  Incoming interface: Tunnel0, RPF nbr 192.168.0.3
 Outgoing interface list:
   Tunnel0, 192.168.0.2, Forward/Sparse, 00:00:02/00:03:27

Поскольку Tunnel0 теперь работает как несколько интерфейсов, таблица маршрутизации мультикаста содержит не только сам интерфейс, но и адреса как получателя (192.168.0.2), так и отправителя (192.168.0.3) потока. Стоит отметить ещё одну любопытную особенность поведения DMVPN, когда поток мультикаста идёт со стороны Hub в сторону Spoke. По умолчанию, DMVPN отправляет мультикаст каждому Spoke (ip nhrp map multicast dynamic), что успешно используют протоколы маршрутизации, отправляя служебную информацию или обновления мультикастом. Однако если сеть является географически распределённой (например, несколько регионов), такое поведение может быть нежелательным: мультикаст, отправленный во все регионы, в том числе туда, где нет PIM подписки, занимает полосу, после чего его отбрасывают все Spoke, кроме того, кому поток был действительно нужен. Такое поведение можно исправить использованием PIM NBMA режима для DMVPN, что позволяет различать Spoke по адресам на уровне мультикаста и отправлять поток только тем регионам, где на него есть подписка.

Настало время ещё раз проверить связность между Spoke для мультикаста:

Spoke2#ping 224.1.1.1 so lo 0 rep 1000 Type escape sequence to abort.
Sending 1000, 100-byte ICMP Echos to 224.1.1.1, timeout is 2 seconds:
Packet sent with a source address of 3.3.3.3 
Reply to request 0 from 2.2.2.2, 176 ms....

Ничего не поменялось, но мы упорные. Начнём проверять по порядку, начиная с Hub:

Hub#sho ip mroute
(*, 224.1.1.1), 00:52:32/00:02:58, RP 1.1.1.1, flags: S
 Incoming interface: Null, RPF nbr 0.0.0.0
 Outgoing interface list:
  Tunnel0, 192.168.0.2, Forward/Sparse, 00:02:12/00:02:58
(3.3.3.3, 224.1.1.1), 00:01:30/00:01:31, flags: PT
 Incoming interface: Tunnel0, RPF nbr 192.168.0.3
  Outgoing interface list: Null

(S,G) запись неактивна (флаг P) на Hub, соответственно, OIL пуст. Очевидно, что это дело рук Spoke1, больше некому:

Spoke1#sho ip mroute
<output omitted>
(*, 224.1.1.1), 00:52:44/stopped, RP 1.1.1.1, flags: SJCL
 Incoming interface: Tunnel0, RPF nbr 192.168.0.1
 Outgoing interface list:
  Loopback0, Forward/Sparse, 00:09:18/00:02:26
(3.3.3.3, 224.1.1.1), 00:01:39/00:01:20, flags: LJT
 Incoming interface: Tunnel0, RPF nbr 192.168.0.3
 Outgoing interface list:
   Loopback0, Forward/Sparse, 00:01:39/00:02:26

Вроде бы таблица правильная… Но нет: RPF сосед – Spoke 2, а должен быть Hub. Посмотрим внимательно на весь процесс ещё раз.

  1. Spoke2 отправляет первый пакет потока внутри RP-Register;

  2. Hub пересылает пакет Spoke1 и начинает построение SPT дерева в сторону Spoke2;

  3. Spoke1 получает первый пакет, создаёт новое состояние для потока в таблице маршрутизации, высылает ответ.

  4. Spoke1 осознаёт, что RPF сосед для источника мультикаста – это Spoke2, поэтому он отправляет SPT-Join в сторону Spoke2. Однако в силу NBMA поведения DMVPN, физически SPT-Join идёт в сторону Hub. Последний его с радостью отбрасывает, поскольку внутри пакета в качестве RPF соседа указан Spoke2.

  5. IIF для RPT и SPT один и тот же, Tunnel0, поэтому Spoke1 отправляет сообщение (*,G) Prune в сторону Hub, где он и обрабатывается.

В результате, Hub отключает у себя (*,G) запись, а Spoke1 не может завершить создание (S,G) записи в таблице маршрутизации, что приводит к нарушению связности между Spoke.Корень зла в этом случае – SPT-switchover: между Spoke нет прямой связности для мультикаста, единственный доступный путь – через Hub. В конце концов, мы пришли к команде, которая упоминается в Configuration Guide – ip pim spt-threshold infinity. Неужели теперь связность появится?

Spoke2#ping 224.1.1.1 so lo 0 rep 1000 Type escape sequence to abort.
Sending 1000, 100-byte ICMP Echos to 224.1.1.1, timeout is 2 seconds:
Packet sent with a source address of 3.3.3.3 
Reply to request 0 from 2.2.2.2, 112 ms
Reply to request 1 from 2.2.2.2, 84 ms
Reply to request 2 from 2.2.2.2, 76 ms
Reply to request 3 from 2.2.2.2, 80 ms
Reply to request 4 from 2.2.2.2, 52 ms
Reply to request 5 from 2.2.2.2, 48 ms

На данном этапе мультикаст работает, как и ожидалось вначале. Поток может быть передан в любом направлении (hub-spoke, spoke-spoke, spoke-hub), причём только в сторону тех Spoke, которые на него подписались. Стоит отметить, однако, что передача мультикаста напрямую между Spoke чревата повышением нагрузки на канал вследствие рассылки мультикаста внутри направленных пакетов; канал до Spoke на такую нагрузку, как правило, не рассчитан, что может привести как к проблемам с масштабированием решения, так и к ухудшению связности для существующих приложений.

В статье мы рассмотрели, что необходимо добавить к обычному DMVPN Phase 2, чтобы успешно запустить поверх него мультикаст. К тонким моментам можно отнести, пожалуй, только режим PIM NBMA и SPT-switchover – это единственное отличие от общеизвестных настроек DMVPN Phase 2.