Сети для самых маленьких. Часть 9.3. Мультикаст. Протокол PIM
Продолжим изучение мультикаста, рассмотрев протокол PIM (Protocol Independent Multicast), его режимы (Dense Mode, Sparse Mode), типы деревьев и SPT Switchover, механизмы предотвращения дублирования трафика (Designated Router (Source DR и Receiver DR), Assert, Forwarder), автоматический выбор Rendezvous Point, SSM, BIDIR PIM.
Содержание серии статей про мультикаст
Протокол PIM
Итак, мы разобрались, как клиенты сообщают ближайшему маршрутизатору о своих намерениях. Теперь неплохо было бы передать трафик от источника получателю через большую сеть.
Если вдуматься, то мы стоим перед довольной сложной проблемой — источник только вещает на группу, он ничего не знает о том, где находятся получатели и сколько их. Получатели и ближайшие к ним маршрутизаторы знают только, что им нужен трафик конкретной группы, но понятия не имеют, где находится источник и какой у него адрес. Как в такой ситуации доставить трафик?
Существует несколько протоколов маршрутизации мультикастового трафика: DVMRP, MOSPF, CBT — все они по-разному решают такую задачу. Но стандартом де факто стал PIM — Protocol Independent Multicast.
Другие подходы настолько нежизнеспособны, что порой даже их разработчики практически признают это. Вот, например, выдержка из RFC по протоколу CBT:
CBT version 2 is not, and was not, intended to be backwards compatible with version 1; we do not expect this to cause extensive compatibility problems because we do not believe CBT is at all widely deployed at this stage.
PIM имеет две версии, которые можно даже назвать двумя различными протоколами в принципе, уж сильно они разные:
- PIM Dense Mode (DM)
- PIM Sparse Mode (SM)
Independent он потому, что не привязан к какому-то конкретному протоколу маршрутизации юникастового трафика, и позже вы увидите почему.
PIM Dense Mode
PIM DM пытается решить проблему доставки мультиакста в лоб. Он заведомо предполагает, что получатели есть везде, во всех уголках сети. Поэтому изначально он наводняет всю сеть мультикастовым трафиком, то есть рассылает его во все порты, кроме того, откуда он пришёл. Если потом оказывается, что где-то он не нужен, то эта ветка «отрезается» с помощью специального сообщения PIM Prune — трафик туда больше не отправляется.
Но через некоторое время в эту же ветку маршрутизатор снова пытается отправить мультикаст — вдруг там появились получатели. Если не появились, ветка снова отрезается на определённый период. Если клиент на маршрутизаторе появился в промежутке между этими двумя событиями, отправляется сообщение Graft — маршрутизатор запрашивает отрезанную ветку обратно, чтобы не ждать, пока ему что-то перепадёт.
Как видите, здесь не стоит вопрос определения пути к получателям — трафик достигнет их просто потому, что он везде.
После «обрезания» ненужных ветвей остаётся дерево, вдоль которого передаётся мультикастовый трафик. Это дерево называется SPT — Shortest Path Tree.
Оно лишено петель и использует кратчайший путь от получателя до источника. По сути оно очень похоже на Spanning Tree в STP, где корнем является источник.
SPT — это конкретный вид дерева — дерево кратчайшего пути. А вообще любое мультикастовое дерево называется MDT — Multicast Distribution Tree.
Предполагается, что PIM DM должен использоваться в сетях с высокой плотностью мультикастовых клиентов, что и объясняет его название (Dense). Но реальность такова, что эта ситуация — скорее, исключение, и зачастую PIM DM нецелесообразен.
Что нам действительно важно сейчас — это механизм избежания петель.
Представим такую сеть:
Один источник, один получатель и простейшая IP-сеть между ними. На всех маршрутизаторах запущен PIM DM.
Что произошло бы, если бы не было специального механизма избежания петель?
Источник отправляет мультикастовый трафик. R1 его получает и в соответствии с принципами PIM DM отправляет во все интерфейсы, кроме того, откуда он пришёл — то есть на R2 и R3.
R2 поступает точно так же, то есть отправляет трафик в сторону R3. R3 не может определить, что это тот же самый трафик, который он уже получил от R1, поэтому пересылает его во все свои интерфейсы. R1 получит копию трафика от R3 и так далее. Вот она — петля.
Что же предлагает PIM в такой ситуации? RPF — Reverse Path Forwarding. Это главный принцип передачи мультикастового трафика в PIM (любого вида: и DM и SM) — трафик от источника должен приходить по кратчайшему пути.
То есть для каждого полученного мультикастового пакета производится проверка на основе таблицы маршрутизации, оттуда ли он пришёл.
- Маршрутизатор смотрит на адрес источника мультикастового пакета.
- Проверяет таблицу маршрутизации, через какой интерфейс доступен адрес источника.
- Проверяет интерфейс, через который пришёл мультикастовый пакет.
- Если интерфейсы совпадают — всё отлично, мультикастовый пакет пропускается, если же данные приходят с другого интерфейса — они будут отброшены.
В нашем примере R3 знает, что кратчайший путь до источника лежит через R1 (статический или динамический маршрут). Поэтому мультикастовые пакеты, пришедшие от R1, проходят проверку и принимаются R3, а те, что пришли от R2, отбрасываются.
Такая проверка называется RPF-Check и благодаря ей даже в более сложных сетях петли в MDT не возникнут. Этот механизм важен нам, потому что он актуален и в PIM-SM и работает там точно также.
Как видите, PIM опирается на таблицу юникастовой маршрутизации, но, во-первых, сам не маршрутизирует трафик, во-вторых, ему не важно, кто и как наполнял таблицу.
Останавливаться здесь и подробно рассматривать работу PIM DM мы не будем — это устаревший протокол с массой недостатков (ну, как RIP).
Однако PIM DM может применяться в некоторых случаях. Например, в совсем небольших сетях, где поток мультикаста небольшой.
PIM Sparse Mode
Совершенно другой подход применяет PIM SM. Несмотря на название (разреженный режим), он с успехом может применяться в любой сети с эффективностью как минимум не хуже, чем у PIM DM.
Здесь отказались от идеи безусловного наводнения мультикастом сети. Заинтересованные узлы самостоятельно запрашивают подключение к дереву с помощью сообщений PIM Join. Если маршрутизатор не посылал Join, то и трафик ему отправляться не будет.
Для того, чтобы понять, как работает PIM, начнём с уже знакомой нам простой сети с одним PIM-маршрутизатором:
Из настроек на R1 надо включить возможность маршрутизации мультикаста, PIM SM на двух интерфейсах (в сторону источника и в сторону клиента) и IGMP в сторону клиента. Помимо прочих базовых настроек, конечно (IP, IGP).
С этого момента вы можете расчехлить GNS и собирать лабораторию. Достаточно подробно о том, как собрать стенд для мультикаста я рассказал в этой статье.
R1(config)#ip multicast-routing
R1(config)#int fa0/0
R1(config-if)#ip pim sparse-mode
R1(config-if)#int fa1/0
R1(config-if)#ip pim sparse-mode
Cisco тут как обычно отличается своим особенным подходом: при активации PIM на интерфейсе, автоматически активируется и IGMP. На всех интерфейсах, где активирован PIM, работает и IGMP.
В то же время у других производителей два разных протокола включаются двумя разными командами: отдельно IGMP, отдельно PIM.
Простим Cisco эту странность? Вместе со всеми остальными?
Плюс, возможно, потребуется настроить адрес RP (ip pim rp-address 172.16.0.1
, например). Об этом позже, пока примите как данность и смиритесь.
Проверим текущее состояние таблицы мультикастовой маршрутизации для группы 224.2.2.4:
После того, как на источнике вы запустите вещание, надо проверить таблицу ещё раз.
Давайте разберём этот немногословный вывод.
Запись вида (*, 224.2.2.4) называется (*, G), /читается старкомаджи/ и сообщает нам о получателях. Причём не обязательно речь об одном клиенте-компьютере, вообще это может быть и, например, другой PIM-маршрутизатор. Важно то, в какие интерфейсы надо передавать трафик.
Если список нисходящих интерфейсов (OIL) пуст — Null, значит нет получателей — а мы их пока не запускали.
Запись (172.16.0.5, 224.2.2.4) называется (S, G), /читается эскомаджи/ и говорит о том, что известен источник. В нашем случае источник с адресом 172.16.0.5 вещает трафик для группы 224.2.2.4. Мультикастовый трафик приходит на интерфейс FE0/1 — это восходящий (Upstream) интерфейс.
Итак, нет клиентов. Трафик от источника доходит до маршрутизатора и на этом его жизнь кончается. Давайте добавим теперь получателя — настроим приём мультикаста на ПК.
ПК отсылает IGMP Report, маршрутизатор понимает, что появились клиенты и обновляет таблицу мультикастовой маршрутизации.
Теперь она выглядит так:
Появился и нисходящий интерфейс: FE0/0, что вполне ожидаемо. Причём он появился как в (*, G), так и в (S, G). Список нисходящих интерфейсов называется OIL — Outgoing Interface List.
Добавим ещё одного клиента на интерфейс FE1/0:
Если читать вывод дословно, то имеем:
- (*, G): Есть получатели мультикастового трафика для группы 224.2.2.4 за интерфейсами FE0/0, FE1/0. Причём совершенно неважно, кто отправитель, о чём и говорит знак «*».
- (S, G): Когда мультикастовый трафик с адресом назначения 224.2.2.4 от источника 172.16.0.5 приходит на интерфейс FE0/1, его копии нужно отправить в FE0/0 и FE1/0.
Но это был очень простой пример — один маршрутизатор сразу знает и адрес источника и где находятся получатели. Фактически даже деревьев тут никаких нет — разве что вырожденное. Но это помогло нам разобраться с тем, как взаимодействуют PIM и IGMP.
Чтобы разобраться с тем, что такое PIM, обратимся к сети гораздо более сложной
Предположим, что уже настроены все IP-адреса в соответствии со схемой. На сети запущен IGP для обычной юникастовой маршрутизации.
Клиент1, например, может пинговать Сервер-источник.
Но пока не запущен PIM, IGMP, клиенты не запрашивают каналы.
R1
interface Loopback0
ip address 1.1.1.1 255.255.255.255
ip router isis
!
interface FastEthernet0/0
ip address 172.16.0.1 255.255.255.0
ip router isis
!
interface FastEthernet1/0
ip address 10.0.12.1 255.255.255.0
ip router isis
!
interface FastEthernet1/1
ip address 10.0.13.1 255.255.255.0
ip router isis
!
router isis
net 10.0000.0000.0001.00
R2
interface Loopback0
ip address 2.2.2.2 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to R4
ip address 10.0.24.2 255.255.255.0
ip router isis
!
interface FastEthernet1/0
description to R3
ip address 10.0.23.2 255.255.255.0
ip router isis
!
interface FastEthernet1/1
description to R1
ip address 10.0.12.2 255.255.255.0
ip router isis
!
router isis
net 10.0000.0000.0002.00
R3
interface Loopback0
ip address 3.3.3.3 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to R5
ip address 10.0.35.3 255.255.255.0
ip router isis
!
interface FastEthernet1/0
description to R1
ip address 10.0.13.3 255.255.255.0
ip router isis
!
interface FastEthernet1/1
ip address 10.0.23.3 255.255.255.0
ip router isis
!
router isis
net 10.0000.0000.0003.00
R4
interface Loopback0
ip address 4.4.4.4 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client1
ip address 192.168.4.1 255.255.255.0
ip router isis
!
interface FastEthernet0/1
description to R2
ip address 10.0.24.4 255.255.255.0
ip router isis
!
router isis
net 10.0000.0000.0004.00
R5
interface Loopback0
ip address 5.5.5.5 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client2
ip address 192.168.5.1 255.255.255.0
ip router isis
!
interface FastEthernet0/1
description to R3
ip address 10.0.35.5 255.255.255.0
ip router isis
!
router isis
net 10.0000.0000.0005.00
Итак, момент времени 0.
Включаем мультикастовую маршрутизацию на всех пяти маршрутизаторах:
RX(config)#ip multicast-routing
PIM включается непосредственно на всех интерфейсах всех маршрутизаторов (в том числе на интерфейсе в сторону Сервера-источника и клиентов):
RX(config)#int FEX/X
RX(config-if)#ip pim sparse-mode
IGMP, по идее должен включаться на интерфейсах в сторону клиентов, но, как мы уже отметили выше, на оборудовании Cisco он включается автоматически вместе с PIM.
Первое, что делает PIM — устанавливает соседство. Для этого используются сообщения PIM Hello. При активации PIM на интерфейсе с него отправляется PIM Hello на адрес 224.0.0.13 с TTL равным 1. Это означает, что соседями могут быть только маршрутизаторы, находящиеся в одном широковещательном домене.
Как только соседи получили приветствия друг от друга:
Теперь они готовы принимать заявки на мультикастовые группы.
Если мы сейчас запустим в вольер клиентов с одной стороны и включим мультикастовый поток с сервера с другой, то R1 получит поток трафика, а R4 получит IGMP Report при попытке клиента подключиться. В итоге R1 не будет знать ничего о получателях, а R4 об источнике.
Неплохо было бы если бы информация об источнике и о клиентах группы была собрана где-то в одном месте. Но в каком?
Такая точка встречи называется Rendezvous Point — RP. Это центральное понятие PIM SM. Без неё ничего бы не работало. Здесь встречаются источник и получатели.
Все PIM-маршрутизаторы должны знать, кто является RP в домене, то есть знать её IP-адрес.
Чтобы построить дерево MDT, в сети выбирается в качестве RP некая центральная точка, которая,
- отвечает за изучение источника,
- является точкой притяжения сообщений Join от всех заинтересованных.
Существует два способа задания RP: статический и динамический. Мы рассмотрим оба в этой статье, но начнём со статического, поскольку чего уж проще статики?
Пусть пока R2 будет выполнять роль RP.
Чтобы увеличить надёжность, обычно выбирается адрес Loopback-интерфейса. Поэтому на всех маршрутизаторах выполняется команда:
RX(config)#ip pim rp-address 2.2.2.2
Естественно, этот адрес должен быть доступен по таблице маршрутизации со всех точек.
Ну и поскольку адрес 2.2.2.2 является RP, на интерфейсе Loopback 0 на R2 желательно тоже активировать PIM.
R2(config)#interface Loopback 0
RX(config-if)#ip pim sparse-mode
Сразу после этого R4 узнает об источнике трафика для группы 224.2.2.4:
и даже передаёт трафик:
На интерфейс FE0/1 приходит 362000 б/с, и через интерфейс FE0/0 они передаются.
Всё, что мы сделали:
- Включили возможность маршрутизации мультикастового трафика (ip multicast-routing)
- Активировали PIM на интерфейсах (ip pim sparse-mode)
- Указали адрес RP (ip pim rp-adress X.X.X.X)
Всё, это уже рабочая конфигурация и можно приступать к разбору, ведь за кулисами скрывается гораздо больше, чем видно на сцене.
R1
ip multicast-routing
!
interface Loopback0
ip address 1.1.1.1 255.255.255.255
ip router isis
!
interface FastEthernet0/0
ip address 172.16.0.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
ip address 10.0.12.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
ip address 10.0.13.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0001.00
!
ip pim rp-address 2.2.2.2
R2
ip multicast-routing
interface Loopback0
ip address 2.2.2.2 255.255.255.255
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/0
description to R4
ip address 10.0.24.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
description to R3
ip address 10.0.23.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
description to R1
ip address 10.0.12.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0002.00
!
ip pim rp-address 2.2.2.2
R3
ip multicast-routing
!
interface Loopback0
ip address 3.3.3.3 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to R5
ip address 10.0.35.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
description to R1
ip address 10.0.13.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
ip address 10.0.23.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0003.00
!
ip pim rp-address 2.2.2.2
R4
ip multicast-routing
!
interface Loopback0
ip address 4.4.4.4 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client1
ip address 192.168.4.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/1
description to R2
ip address 10.0.24.4 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0004.00
!
ip pim rp-address 2.2.2.2
R5
ip multicast-routing
!
interface Loopback0
ip address 5.5.5.5 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client2
ip address 192.168.5.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/1
description to R3
ip address 10.0.35.5 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0005.00
!
ip pim rp-address 2.2.2.2
Разбор полётов
Ну так и как же в итоге всё работает? Как RP узнаёт где источник, где клиенты и обеспечивает связь между ними?
Поскольку всё затевается ради наших любимых клиентов, то, начав с них, рассмотрим в деталях весь процесс.
1) Клиент 1 отправляет IGMP Report для группы 224.2.2.4
2) R4 получает этот запрос, понимает, что есть клиент за интерфейсом FE0/0, добавляет этот интерфейс в OIL и формирует запись (*, G).
Здесь видно восходящий интерфейс FE0/1, но это не значит, что R4 получает трафик для группы 224.2.2.4. Это говорит лишь о том, что единственное место, откуда сейчас он может получать — FE0/1, потому что именно там находится RP. Кстати, здесь же указан и сосед, который прошёл RPF-Check — R2: 10.0.2.24. Ожидаемо.
R4 называется — LHR (Last Hop Router) — последний маршрутизатор на пути мультикастового трафика, если считать от источника. Иными словами — это маршрутизатор, ближайший к получателю. Для Клиента1 — это R4, для Клиента2 — это R5.
3) Поскольку на R4 пока нет мультикастового потока (он его не запрашивал прежде), он формирует сообщение PIM Join и отправляет его в сторону RP (2.2.2.2).
PIM Join отправляется мультикастом на адрес 224.0.0.13. «В сторону RP» означает через интерфейс, который указан в таблице маршрутизации, как outbound для того адреса, который указан внутри пакета. В нашем случае это 2.2.2.2 — адрес RP. Такой Join обозначается ещё как Join (*,G) и говорит: «Не важно, кто источник, мне нужен трафик группы 224.2.2.4».
То есть каждый маршрутизатор на пути должен обработать такой Join и при необходимости отправить новый Join в сторону RP. (Важно понимать, что если на маршрутизаторе уже есть эта группа, он не будет отправлять выше Join — он просто добавит интерфейс, с которого пришёл Join, в OIL и начнёт передавать трафик).
В нашем случае Join ушёл в FE0/1:
4) R2, получив Join, формирует запись (*, G) и добавляет интерфейс FE0/0 в OIL. Но Join отсылать уже некуда — он сам уже RP, а про источник пока ничего не известно.
Таким образом RP узнаёт о том, где находятся клиенты.
Если Клиент 2 тоже захочет получать мультикастовый трафик для той же группы, R5 отправит PIM Join в FE0/1, потому что за ним находится RP, R3, получив его, формирует новый PIM Join и отправляет в FE1/1 — туда, где находится RP.
То есть Join путешествует так узел за узлом, пока не доберётся до RP или до другого маршрутизатора, где уже есть клиенты этой группы.
Итак, R2 — наш RP — сейчас знает о том, что за FE0/0 и FE1/0 у него есть получатели для группы 224.2.2.4. Причём неважно, сколько их там — по одному за каждым интерфейсом или по сто — поток трафика всё равно будет один на интерфейс.
Если изобразить графически то, что мы получили, то это будет выглядеть так:
Отдалённо напоминает дерево, не так ли? Поэтому оно так и называется — RPT — Rendezvous Point Tree. Это дерево с корнем в RP, а ветви которого простираются до клиентов.
Более общий термин, как мы упоминали выше, — MDT — Multicast Distribution Tree — дерево, вдоль которого распространяется мультикастовый поток. Позже вы увидите разницу между MDT и RPT.
5) Теперь врубаем сервер. Как мы уже выше обсуждали, он не волнуется о PIM, RP, IGMP — он просто вещает. А R1 получает этот поток. Его задача — доставить мультикаст до RP.
В PIM есть специальный тип сообщений — Register. Он нужен для того, чтобы зарегистрировать источник мультикаста на RP.
Итак, R1 получает мультикастовый поток группы 224.2.2.4:
R1 является FHR (First Hop Router) — первый маршрутизатор на пути мультикастового трафика или ближайший к источнику.
6) Далее он инкапсулирует каждый полученный от источника мультикастовый пакет в юникастовый PIM Register и отправляет его прямиком на RP.
Обратите внимание на стек протоколов. Поверх юникастового IP и заголовка PIM идёт изначальный мультикастовый IP, UDP и данные.
Теперь, в отличие от всех других, пока известных нам сообщений PIM, в адресе получателя указан 2.2.2.2, а не мультикастовый адрес.
Такой пакет доставляется до RP по стандартным правилам юникастовой маршрутизации и несёт в себе изначальный мультикастовый пакет, то есть это… это же туннелирование!
Задача № 1
На сервере 172.16.0.5 работает приложение, которое может передавать пакеты только на широковещательный адрес 255.255.255.255, с портом получателя UDP 10999.
Этот трафик надо доставить к клиентам 1 и 2:
- Клиенту 1 в виде мультикаст трафика с адресом группы 239.9.9.9.
- А в сегмент клиента 2, в виде широковещательных пакетов на адрес 255.255.255.255.
R1
ip multicast-routing
!
interface Loopback0
ip address 1.1.1.1 255.255.255.255
ip router isis
!
interface FastEthernet0/0
ip address 172.16.0.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
ip address 10.0.12.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
ip address 10.0.13.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0001.00
!
ip pim rp-address 2.2.2.2
R2
ip multicast-routing
interface Loopback0
ip address 2.2.2.2 255.255.255.255
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/0
description to R4
ip address 10.0.24.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
description to R3
ip address 10.0.23.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
description to R1
ip address 10.0.12.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0002.00
!
ip pim rp-address 2.2.2.2
R3
ip multicast-routing
!
interface Loopback0
ip address 3.3.3.3 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to R5
ip address 10.0.35.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
description to R1
ip address 10.0.13.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
ip address 10.0.23.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0003.00
!
ip pim rp-address 2.2.2.2
R4
ip multicast-routing
!
interface Loopback0
ip address 4.4.4.4 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client1
ip address 192.168.4.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/1
description to R2
ip address 10.0.24.4 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0004.00
!
ip pim rp-address 2.2.2.2
R5
ip multicast-routing
!
interface Loopback0
ip address 5.5.5.5 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client2
ip address 192.168.5.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/1
description to R3
ip address 10.0.35.5 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0005.00
!
ip pim rp-address 2.2.2.2
R1
ip forward-protocol udp 10999
ip access-list extended BR-to-MULT
permit udp any any eq 10999
interface Ethernet0/0
description to SERVER
ip multicast helper-map broadcast 239.9.9.9 BR-to-MULT
R5
ip access-list extended BR-to-MULT
permit udp any any eq 10999
interface Ethernet0/1
description to R3
ip multicast helper-map 239.9.9.9 192.168.5.255 BR-to-MULT
interface Ethernet0/0
description to CLIENT2
ip directed-broadcast
Проверка
Для того чтобы проверить преобразование пакетов, нам нужно сгенерировать UDP пакеты на порт 10999 и IP 255.255.255.255.
К сожалению, в IP SLA уже нет возможности так сделать, поэтому, для проверки, мы воспользуемся DNS-запросами, которые отправляет IOS, когда мы неправильно вводим команду.
Для этого нам нужно добавить на R1 и R5 в ACL строку:
ip access-list extended BR-to-MULT
permit udp any any eq 10999
permit udp any any eq domain
На R6 (маршрутизаторе, который у нас в роли сервера) надо включить:
ip domain-lookup
Сначала проверим получает ли клиент 1 мультикаст.
Для этого, на интерфейсе клиента, который смотрит на R4 (в роли клиента тоже маршрутизатор), настроим:
interface Ethernet0/0
ip address 192.168.4.2 255.255.255.0
ip igmp join-group 239.9.9.9
Теперь на клиенте 1 включаем debug ip packet. И на сервере набираем неправильную команду:
SERVER#ds
Translating "ds"...domain server (255.255.255.255)
(255.255.255.255)
Translating "ds"...domain server (255.255.255.255)
% Bad IP address or host name
% Unknown command or computer name, or unable to find computer address
На клиенте 1 видим:
CLIENT1#
IP: s=172.16.0.5 (Ethernet0/0), d=239.9.9.9, len 48, input feature, MCI Check(82), rtype 0, forus FALSE, sendself FALSE, mtu 0, fwdchk FALSE
IP: s=172.16.0.5 (Ethernet0/0), d=239.9.9.9, len 48, rcvd 2
IP: s=172.16.0.5 (Ethernet0/0), d=239.9.9.9, len 48, stop process pak for forus packet
IP: s=172.16.0.5 (Ethernet0/0), d=239.9.9.9, len 48, input feature, MCI Check(82), rtype 0, forus FALSE, sendself FALSE, mtu 0, fwdchk FALSE
IP: s=172.16.0.5 (Ethernet0/0), d=239.9.9.9, len 48, rcvd 2
IP: s=172.16.0.5 (Ethernet0/0), d=239.9.9.9, len 48, stop process pak for forus packet
CLIENT1#
Мы видим, что к клиенту 1 пакеты приходят с адресом отправителя 172.16.0.5 и получателем 239.9.9.9.
Соответственно, на промежуточных устройствах, например, на R2:
R2#sh ip mroute
...
(*, 239.9.9.9), 02:23:06/stopped, RP 2.2.2.2, flags: S
Incoming interface: Null, RPF nbr 0.0.0.0
Outgoing interface list:
Ethernet0/0, Forward/Sparse, 02:05:01/00:03:21
Ethernet0/2, Forward/Sparse, 02:21:18/00:02:52
(172.16.0.5, 239.9.9.9), 00:00:03/00:03:29, flags: T
Incoming interface: Ethernet0/1, RPF nbr 10.0.12.1
Outgoing interface list:
Ethernet0/2, Forward/Sparse, 00:00:03/00:03:26
Теперь проверим приходит ли к клиенту 2 бродкаст.
Аналогичным образом на клиенте 2 включаем debug ip packet. И на сервере набираем неправильную команду.
На клиенте 2 получаем:
CLIENT2#
IP: s=172.16.0.5 (Ethernet0/0), d=255.255.255.255, len 48, input feature, MCI Check(82), rtype 0, forus FALSE, sendself FALSE, mtu 0, fwdchk FALSE
IP: s=172.16.0.5 (Ethernet0/0), d=255.255.255.255, len 48, rcvd 2
IP: s=172.16.0.5 (Ethernet0/0), d=255.255.255.255, len 48, stop process pak for forus packet
IP: s=172.16.0.5 (Ethernet0/0), d=255.255.255.255, len 48, input feature, MCI Check(82), rtype 0, forus FALSE, sendself FALSE, mtu 0, fwdchk FALSE
IP: s=172.16.0.5 (Ethernet0/0), d=255.255.255.255, len 48, rcvd 2
IP: s=172.16.0.5 (Ethernet0/0), d=255.255.255.255, len 48, stop process pak for forus packet
CLIENT2#
Мы видим, что к клиенту 2 пакеты приходят с адресом отправителя 172.16.0.5 и получателем 255.255.255.255.
Вывод debug ip packet на R5:
R5#
IP: s=172.16.0.5 (Ethernet0/1), d=239.9.9.9, len 48, input feature, MCI Check(82), rtype 0, forus FALSE, sendself FALSE, mtu 0, fwdchk FALSE
IP: tableid=0, s=172.16.0.5 (Ethernet0/1), d=192.168.5.255 (Ethernet0/0), routed via RIB
IP: s=172.16.0.5 (Ethernet0/1), d=255.255.255.255 (Ethernet0/0), len 48, sending full packet
7) RP получает PIM Register, распаковывает его и обнаруживает под обёрткой трафик для группы 224.2.2.4.
Информацию об этом он сразу заносит в свою таблицу мультикастовой маршрутизации:
Появилась запись (S, G) — (172.16.0.5, 224.2.2.4).
Распакованные пакеты RP дальше отправляет в RPT в интерфейсы FE0/0 и FE1/0, по которому трафик доходит до клиентов.
В принципе, на этом можно было бы и остановиться. Всё работает — клиенты получают трафик. Но есть две проблемы:
- Процессы инкапсуляции и декапсуляции — весьма затратные действия для маршрутизаторов. Кроме того, дополнительные заголовки увеличивают размер пакета, и он может просто не пролезть в MTU где-то на промежуточном узле (вспоминаем все проблемы туннелирования).
- Если вдруг где-то между источником и RP есть ещё получатели для группы, мультикастовому трафику придётся пройти один путь дважды.
Возьмём для примера вот такую топологию:
Трафик в сообщениях Register сначала дойдёт до RP по линии R1-R42-R2, затем чистый мультикаст вернётся по линии R2-R42. Таким образом на линии R42-R2 будет ходить две копии одного трафика, пусть и в противоположных направлениях.
Поэтому лучше от источника до RP тоже передавать чистый мультикаст, а для этого нужно построить дерево — Source Tree.
8) Поэтому RP отправляет на R1 сообщение PIM Join. Но теперь уже в нём указывается для группы адрес не RP, а источника, изученный из сообщения Register. Такое сообщение называется Join (S, G) — Source Specific Join.
Цель у него точно такая же, как у PIM Join (*, G) — построить дерево, только на этот раз от источника до RP.
Join (S, G) распространяется также узел за узлом, как обычный Join (*, G). Только Join (*, G) стремится к RP, а Join (S, G) к S — источнику. В качестве адрес получателя также служебный адрес 224.0.0.13 и TTL=1.
Если существуют промежуточные узлы, например, R42, они также формируют запись (S, G) и список нисходящих интерфейсов для данной группы и пересылают Join дальше к источнику.
Путь, по которому прошёл Join от RP до источника, превращается в Source Tree — дерево от источника. Но более распространённое название — SPT — Shortest Path Tree — ведь трафик от источника до RP пойдёт по кратчайшему пути.
9) R1, получив Join (S, G), добавляет интерфейс FE1/0, откуда пакет пришёл, в список нисходящих интерфейсов OIL и начинает туда вещать чистый мультикастовый трафик, незамутнённый инкапсуляцией. Запись (S, G) на R1 уже была, как только он получил первый мультикастовый пакет от Сервера-источника.
По построенному Source Tree мультикаст передаётся RP (и всем промежуточным клиентам, если они есть, например, R42).
Но надо иметь ввиду, что сообщения Register передавались всё это время и передаются до сих пор. То есть фактически R1 отправляет две копии трафика сейчас: один — чистый мультикаст по SPT, другой — инкапсулированный в юникастовый Register.
Сначала R1 отправляет мультикаст в Register — пакет 231. Потом R2 (RP) хочет подключиться к дереву, отправляет Join — пакет 232. R1 ещё какое-то время, пока обрабатывает запрос от R2, отправляет мультикаст в Register (пакеты с 233 по 238). Далее, когда нисходящий интерфейс добавлен в OIL на R1, он начинает передавать чистый мультикаст — пакеты 239 и 242, но пока не прекращает и Register — пакеты 241 и 243. А пакет 240 — это R2 не выдержал и ещё раз попросил построить дерево.
10) Итак, незамутнённый мультикаст достигает RP. Она понимает, что это тот же самый трафик, который приходит в Register, потому что одинаковый адрес группы, одинаковый адрес источника и с одного интерфейса. Чтобы не получать две копии, он отправляет на R1 юникастовый PIM Register-Stop.
Register-Stop не означает, что R2 отказывается от трафика или не признаёт больше этот источник, это говорит лишь о том, что надо прекратить посылать инкапсулированный трафик.
Далее идёт ожесточённая борьба — R1 продолжает передавать накопившийся в буфере трафик, пока обрабатывает Register-Stop, и обычным мультикастом, и внутри сообщений Register:
Но, рано или поздно R1 начинает вещать только чистый мультикастовый трафик.
При подготовке у меня возник, как мне казалось, закономерный вопрос: ну и к чему все эти туннелирования, PIM Register? Почему бы не поступать с мультикастовым трафиком, как с PIM Join — отправлять хоп за хопом с TTL=1 в сторону RP — рано или поздно ведь дойдёт? Так бы и дерево построилось бы заодно без лишних телодвижений.
Тут возникает несколько нюансов.
Во-первых, нарушается главный принцип PIM SM — трафик посылать только туда, откуда он был запрошен. Нет Join — Нет дерева!
Во-вторых, если клиентов для данной группы нет, FHR не узнает об этом и будет продолжать слать трафик по «своему дереву». К чему такое бездумное использование полосы пропускания? В мире связи такой протокол просто не выжил бы, как не выжил PIM DM или DVMRP.
Таким образом, мы имеем одно большое дерево MDT для группы 224.2.2.4 от Cервера-источника до Клиента 1 и Клиента 2. И это MDT составлено из двух кусков, которые строились независимо друг от друга: Source Tree (от источника до RP) и RPT (от RP до клиентов). Вот оно отличие MDT от RPT и SPT. MDT — это довольно общий термин, означающий дерево передачи мультикаста вообще, в то время, как RPT/SPT — это его очень конкретный вид.
А что делать, если сервер уже вещает, а клиентов всё нет и нет? Мультикаст так и будет засорять участок между отправителем и RP?
Нет, в этом случае также поможет PIM Register-Stop. Если на RP начали приходить сообщения Register для какой-то группы, а для неё ещё нет получателей, то RP не заинтересован в получении этого трафика, поэтому, не отправляя PIM Join (S, G), RP сразу посылает Register-Stop на R1.
R1, получив Register-Stop и видя, что дерева для этой группы пока нет (нет клиентов), начинает отбрасывать мультикастовый трафик от сервера.
То есть сам сервер по этому поводу совершенно не беспокоится и продолжает посылать поток, но, дойдя до интерфейса маршрутизатора, поток будет отброшен.
При этом RP продолжает хранить запись (S, G). То есть трафик он не получает, но где находится источник для группы знает. Если в группе появляются получатели, RP узнаёт о них и посылает на источник Join (S, G), который строит дерево.
Кроме того, каждые 3 минуты R1 будет пытаться повторно зарегистрировать источник на RP, то есть отправлять пакеты Register. Это нужно для того, чтобы уведомить RP о том, что этот источник ещё живой.
У особо пытливых читателей обязан возникнуть вопрос — а как быть с RPF? Этот механизм ведь проверяет адрес отправителя мультикастового пакета и, если трафик идёт не с правильного интерфейса, он будет отброшен. При этом RP и источник могут находиться за разными интерфейсам. Вот и в нашем примере для R3 RP — за FE1/1, а источник — за FE1/0.
Ответ предсказуем — в таком случае проверяется не адрес источника, а RP. То есть трафик должен придти с интерфейса в сторону RP.
Но, как вы увидите далее, это тоже не нерушимое правило.
Важно понимать, что RP — это не универсальный магнит — для каждой группы может бытья своя RP. То есть в сети их может быть и две, и три, и сто — одна RP отвечает за один набор групп, другая — за другой. Более того, есть такое понятие, как Anycast RP и тогда разные RP могут обслуживать одну и ту же группу.
Задача № 2
Замечание к топологии: в этой задаче только маршрутизаторы R1, R2, R3 находятся под управлением администраторов нашей сети. То есть, конфигурацию изменять можно только на них.
Сервер 172.16.0.5 передает мультикаст трафик на группы 239.1.1.1 и 239.2.2.2.
Настроить сеть таким образом, чтобы трафик группы 239.1.1.1 не передавался в сегмент между R3 и R5, и во все сегменты ниже R5.
Но при этом, трафик группы 239.2.2.2 должен передаваться без проблем.
R1
ip multicast-routing
!
interface Loopback0
ip address 1.1.1.1 255.255.255.255
ip router isis
!
interface FastEthernet0/0
ip address 172.16.0.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
ip address 10.0.12.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
ip address 10.0.13.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0001.00
!
ip pim rp-address 2.2.2.2
R2
ip multicast-routing
interface Loopback0
ip address 2.2.2.2 255.255.255.255
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/0
description to R4
ip address 10.0.24.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
description to R3
ip address 10.0.23.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
description to R1
ip address 10.0.12.2 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0002.00
!
ip pim rp-address 2.2.2.2
R3
ip multicast-routing
!
interface Loopback0
ip address 3.3.3.3 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to R5
ip address 10.0.35.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/0
description to R1
ip address 10.0.13.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet1/1
ip address 10.0.23.3 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0003.00
!
ip pim rp-address 2.2.2.2
R4
ip multicast-routing
!
interface Loopback0
ip address 4.4.4.4 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client1
ip address 192.168.4.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/1
description to R2
ip address 10.0.24.4 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0004.00
!
ip pim rp-address 2.2.2.2
R5
ip multicast-routing
!
interface Loopback0
ip address 5.5.5.5 255.255.255.255
ip router isis
!
interface FastEthernet0/0
description to Client2
ip address 192.168.5.1 255.255.255.0
ip pim sparse-mode
ip router isis
!
interface FastEthernet0/1
description to R3
ip address 10.0.35.5 255.255.255.0
ip pim sparse-mode
ip router isis
!
router isis
net 10.0000.0000.0005.00
!
ip pim rp-address 2.2.2.2
Бритва Оккама или отключение ненужных ветвей
После того, как последний клиент в сегменте отказался от подписки, PIM должен отрезать лишнюю ветку RPT.
Пусть, например, единственный клиент на R4 выключил компьютер. Маршрутизатор по сообщению IGMP Leave или после трёх безответных IGMP Query понимает, что клиентов за FE0/0 больше нет, и отправляет в сторону RP сообщение PIM Prune. По формату оно точно такое же, как Join, но выполняет противоположную функцию.
Адрес назначения также 224.0.0.13, и TTL равен 1.
Но маршрутизатор, получивший PIM Prune, перед тем, как удалить подписку, ждёт некоторое время (обычно 3 секунды — Join Delay Timer).
Это сделано вот для такой ситуации:
В одном широковещательном домене 3 маршрутизатора. Один из них стоит выше и именно он передаёт в сегмент мультикастовый трафик. Это R1.
Для обоих маршрутизаторов (R2 и R3) его OIL содержит только одну запись.
Если теперь R2 решит отключиться и отправит PIM Prune, то он может подставить своего коллегу R3 — R1 ведь перестанет вещать в интерфейс вообще.
Так вот, чтобы этого не произошло, R1 и даёт таймаут в 3 секунды. За это время R3 должен успеть среагировать. Учитывая широковещательность сети, он тоже получит Prune от R2 и поэтому, если хочет продолжать получать трафик, он мгновенно отправляет обычный PIM Join в сегмент, уведомляя R1, что не надо удалять интерфейс.
Этот процесс называется — Prune Override. R2 как бы объегорил R1, перехватил инициативу.
SPT Switchover — переключение RPT-SPT
До сих пор мы преимущественно рассматривали только Клиента 1. Теперь обратимся к Клиенту 2.
По началу всё для него идентично Клиенту 1 — он пользуется RPT от RP, который мы рассматривали ранее. Кстати, поскольку оба — и Клиент 1, и Клиент 2 — используют одно дерево, такое дерево называется Shared Tree — это довольно общее название. Shared tree = RPT.
Вот как выглядит таблица мультикастовой маршрутизации на R5 в самом начале, сразу после построения дерева:
Здесь нет записи (S, G), но это не значит, что мультикастовый трафик не передаётся. Просто R5 не заботится о том, кто отправитель.
Обратите внимание по какому пути должен идти в этом случае трафик — R1-R2-R3-R5. Хотя ведь короче путь R1-R3-R5.
А если сеть посложнее?
Как-то неаккуратненько.
Дело в том, что пока мы привязаны к RP — она корень RPT, только она поначалу знает, где кто находится. Однако если вдуматься, то после первого же мультикастового пакета все маршрутизаторы по пути трафика будут знать адрес источника, ведь он указан в заголовке IP.
Почему бы кому-нибудь не отправить самому Join в сторону источника и оптимизировать маршрут?
Зрите в корень. Такое переключение может инициировать LHR (Last Hop Router) — R5. После получения первого мультикастового пакета от R3 R5 отправляет уже знакомый нам Source Specific Join (S, G) в интерфейс FE0/1, который указан в его таблице маршрутизации, как исходящий для сети 172.16.0.0/24.
Получив такой Join, R3 отправляет его не на RP, как делал это с обычным Join (*, G), а в сторону источника (через интерфейс согласно таблице маршрутизации).
То есть в данном случае R3 отправляет Join (172.16.0.5, 224.2.2.4) в интерфейс FE1/0.
Далее этот Join попадает на R1. А R1 по большому счёту без разницы, кто его отправлял — RP или кто-то другой — он просто добавляет FE1/1 в свой OIL для группы 224.2.2.4.
В этот момент между источником и получателем два пути и R3 получает два потока.
Время сделать выбор, чтобы обрезать лишнее. Причём именно R3 его делает, потому что R5 уже не сможет различить эти два потока — они оба придут через один интерфейс.
Как только R3 зафиксировал два одинаковых потока с разных интерфейсов, он выбирает предпочтительный согласно таблице маршрутизации. В данном случае прямой, лучше, чем через RP. В этот момент R3 посылает Prune (S, G) в сторону RP, обрубая эту ветку RPT. И с этого момент остаётся только один поток напрямую от источника.
Таким образом PIM построил SPT — Shortest Path Tree. Оно же Source Tree. Это кратчайший путь от клиента до источника. Кстати, дерево от источника до RP, которое мы уже рассматривали выше, — по сути ровно то же самое SPT. Оно характеризуется записью (S, G). Если маршрутизатор имеет такую запись, значит он знает, что S является источником для группы G и построено дерево SPT.
Корнем дерева SPT является источник и очень хочется сказать «кратчайший путь от источника до клиента». Но это технически некорректно, поскольку пути от источника до клиента и от клиента до источника могут быть разными. А именно от клиента начинает строиться ветка дерева: маршрутизатор отправляет PIM Join в сторону источника/RP, и RPF также проверяет правильность интерфейса при получении трафика.
Вы помните, что вначале этого параграфа на R5 была только запись (*, G), теперь после всех этих событий их станет две: (*, G) и (S, G).
Между прочим, даже если вы посмотрите на мультикастовую таблицу маршрутизации R3 в ту же секунду, как нажали Play в VLC, то увидите, что он уже получает трафик от R1 напрямую, о чём говорит наличие записи (S, G).
То есть SPT Switchover уже произошёл — это действие по умолчанию на оборудовании многих производителей — инициировать переключение после получения первого же мультикастового пакета.
Вообще говоря, происходить такое переключение может в нескольких случаях:
- Не происходить вообще никогда (команда
ip pim spt-threshold infinity
). - При достижении определённой утилизации полосы пропускания (команда
ip pim spt-threshold X
). - Безусловно — сразу после получения первого пакета (действие по умолчанию или no
ip pim spt-threshold X
)
Как правило, решение о том, что «пора», принимает LHR.
В этом случае во второй раз изменяется правило работы RPF — он снова проверяет местонахождение источника. То есть из двух потоков мультикаста — от RP и от источника — предпочтение отдаётся трафику от источника.
DR, Assert, Forwarder
Ещё несколько важных моментов при рассмотрении PIM.
DR — Designated Router. Это выделенный маршрутизатор, который ответственен за отправку служебных пакетов на RP.
Source DR — отвечает за принятие мультикастовых пакетов непосредственно от источника и его регистрацию на RP.
Вот пример топологии:
Здесь ни к чему, чтобы оба маршрутизатора передавали трафик на RP, пусть они резервируют друг друга, но ответственный должен быть только один.
Поскольку оба маршрутизатора подключены в одну широковещательную сеть, они получают друг от друга PIM-Hello. На основе него они и делают свой выбор.
PIM Hello несёт значение приоритета данного маршрутизатора на данном интерфейсе.
Чем больше значение, тем выше приоритет. Если они одинаковы, то выбирается узел с наибольшим IP-адресом (тоже из сообщения Hello).
Если другой маршрутизатор (не DR) в течение Holdtime (по умолчанию 105 с) не получал Hello от соседа, он автоматически берёт на себя роль DR.
По сути Source DR — это FHR — First Hop Router.
Receiver DR — то же, что Source DR, только для получателей мультикастового трафика — LHR (Last Hop Router).
Пример топологии:
Receiver DR ответственен за отправку на RP PIM Join. В вышеприведённой топологии, если оба маршрутизатора отправят Join, то оба будут получать мультикастовый трафик, но в этом нет необходимости. Только DR отправляет Join. Второй просто мониторит доступность DR.
Поскольку DR отправляет Join, то он же и будет вещать трафик в LAN. Но тут возникает закономерный вопрос — а что, если PIM DR'ом стал один, а IGMP Querier'ом другой? А ситуация-то вполне возможна, ведь для Querier чем меньше IP, тем лучше, а для DR, наоборот.
В этом случае DR'ом выбирается тот маршрутизатор, который уже является Querier и такая проблема не возникает.
Правила выбора Receiver DR точно такие же, как и Source DR.
Assert и PIM Forwarder
Проблема двух одновременно передающих маршрутизаторов может возникнуть и в середине сети, где нет ни конечных клиентов, ни источников — только маршрутизаторы.
Очень остро этот вопрос стоял в PIM DM, где это была совершенно рядовая ситуация из-за механизма Flood and Prune.
Но и в PIM SM она не исключена.
Рассмотрим такую сеть:
Здесь три маршрутизатора находятся в одном сегменте сети и, соответственно, являются соседями по PIM. R1 выступает в роли RP.
R4 отправляет PIM Join в сторону RP. Поскольку этот пакет мультикастовый он попадает и на R2 и на R3, и оба они обработав его, добавляют нисходящий интерфейс в OIL.
Тут бы должен сработать механизм выбора DR, но и на R2 и на R3 есть другие клиенты этой группы, и обоим маршрутизаторам так или иначе придётся отправлять PIM Join.
Когда мультикастовый трафик приходит от источника на R2 и R3, в сегмент он передаётся обоими маршрутизаторами и задваивается там. PIM не пытается предотвратить такую ситуацию — тут он действует по факту свершившегося преступления — как только в свой нисходящий интерфейс для определённой группы (из списка OIL) маршрутизатор получает мультикастовый трафик этой самой группы, он понимает: что-то не так — другой отправитель уже есть в этом сегменте.
Тогда маршрутизатор отправляет специальное сообщение PIM Assert.
Такое сообщение помогает выбрать PIM Forwarder — тот маршрутизатор, который вправе вещать в данном сегменте.
Не надо его путать с PIM DR. Во-первых, PIM DR отвечает за отправку сообщений PIM Join и Prune, а PIM Forwarder — за отправку трафика. Второе отличие — PIM DR выбирается всегда и в любых сетях при установлении соседства, А PIM Forwarder только при необходимости — когда получен мультикастовый трафик с интерфейса из списка OIL.
Выбор RP
Выше мы для простоты задавали RP вручную командой ip pim rp-address X.X.X.X
.
И вот как выглядела команда show ip pim rp
:
Но представим совершенно невозможную в современных сетях ситуацию — R2 вышел из строя. Это всё — финиш. Клиент 2 ещё будет работать, поскольку произошёл SPT Switchover, а вот всё новое и всё, что шло через RP сломается, даже если есть альтернативный путь.
Ну и нагрузка на администратора домена. Представьте себе: на 50 маршрутизаторах перебить вручную как минимум одну команду (а для разных групп ведь могут быть разные RP).
Динамический выбор RP позволяет и избежать ручной работы и обеспечить надёжность — если одна RP станет недоступна, в бой вступит сразу же другая.
В данный момент существует один общепризнанный протокол, позволяющий это сделать — Bootstrap. Циска в прежние времена продвигала несколько неуклюжий Auto-RP, но сейчас он почти не используется, хотя циска этого не признаёт, и в show ip mroute
мы имеем раздражающий рудимент в виде группы 224.0.1.40.
Надо на самом деле отдать должное протоколу Auto-RP. Он был спасением в прежние времена. Но с появлением открытого и гибкого Bootstrap, он закономерно уступил свои позиции.
Итак, предположим, что в нашей сети мы хотим, чтобы R3 подхватывал функции RP в случае выхода из строя R2.
R2 и R3 определяются как кандидаты на роль RP — так они и называются C-RP. На этих маршрутизаторах настраиваем:
RX(config)#interface Loopback 0
RX(config-if)#ip pim sparse-mode
RX(config-if)#exit
RX(config)#ip pim rp-candidate loopback 0
Но пока ничего не происходит — кандидаты пока не знают, как уведомить всех о себе.
Чтобы информировать все мультикастовые маршрутизаторы домена о существующих RP вводится механизм BSR — BootStrap Router. Претендентов может быть несколько, как и C-RP. Они называются соответственно C-BSR. Настраиваются они похожим образом.
Пусть BSR у нас будет один и для теста (исключительно) это будет R1.
R1(config)#interface Loopback 0
R1(config-if)#ip pim sparse-mode
R1(config-if)#exit
R1(config)#ip pim bsr-candidate loopback 0
Сначала из всех C-BSR выбирается один главный BSR, который и будет всем заправлять. Для этого каждый C-BSR отправляет в сеть мультикастовый BootStrap Message (BSM) на адрес 224.0.0.13 — это тоже пакет протокола PIM. Его должны принять и обработать все мультикастовые маршрутизаторы и после разослать во все порты, где активирован PIM. BSM передаётся не в сторону чего-то (RP или источника), в отличии, от PIM Join, а во все стороны. Такая веерная рассылка помогает достигнуть BSM всех уголков сети, в том числе всех C-BSR и всех C-RP. Для того, чтобы BSM не блуждали по сети бесконечно, применяется всё тот же механизм RPF — если BSM пришёл не с того интерфейса, за которым находится сеть отправителя этого сообщения, такое сообщение отбрасывается.
С помощью этих BSM все мультикастовые маршрутизаторы определяют самого достойного кандидата на основе приоритетов. Как только C-BSR получает BSM от другого маршрутизатора с бОльшим приоритетом, он прекращает рассылать свои сообщения. В результате все обладают одинаковой информацией.
На этом этапе, когда выбран BSR, благодаря тому, что его BSM разошлись уже по всей сети, C-RP знают его адрес и юникастом отправляют на него сообщения Candidte-RP-Advertisement, в которых они несут список групп, которые они обслуживают — это называется group-to-RP mapping. BSR все эти сообщения агрегирует и создаёт RP-Set — информационную таблицу: какие RP каждую группу обслуживают.
Далее BSR в прежней веерной манере рассылает те же BootStrap Message, которые на этот раз содержат RP-Set. Эти сообщения успешно достигают всех мультикастовых маршрутизаторов, каждый из которых самостоятельно делает выбор, какую RP нужно использовать для каждой конкретной группы.
BSR периодически делает такие рассылки, чтобы с одной стороны все знали, что информация по RP ещё актуальна, а с другой C-BSR были в курсе, что сам главный BSR ещё жив.
RP, кстати, тоже периодически шлют на BSR свои анонсы Candidate-RP-Advertisement.
Фактически всё, что нужно сделать для настройки автоматического выбора RP — указать C-RP и указать C-BSR — не так уж много работы, всё остальное за вас сделает PIM.
Как всегда, в целях повышения надёжности рекомендуется указывать интерфейсы Loopback в качестве кандидатов.
Завершая главу PIM SM, давайте ещё раз отметим важнейшие моменты
- Должна быть обеспечена обычная юникастовая связность с помощью IGP или статических маршрутов. Это лежит в основе алгоритма RPF.
- Дерево строится только после появления клиента. Именно клиент инициирует построение дерева. Нет клиента — нет дерева.
- RPF помогает избежать петель.
- Все маршрутизаторы должны знать о том, кто является RP — только с её помощью можно построить дерево.
- Точка RP может быть указана статически, а может выбираться автоматически с помощью протокола BootStrap.
- В первой фазе строится RPT — дерево от клиентов до RP — и Source Tree — дерево от источника до RP. Во второй фазе происходит переключение с построенного RPT на SPT — кратчайший путь от получателя до источника.
Ещё перечислим все типы деревьев и сообщений, которые нам теперь известны.
- MDT — Multicast Distribution Tree
- Общий термин, описывающий любое дерево передачи мультикаста.
- SPT — Shortest Path Tree
- Дерево с кратчайшим путём от клиента или RP до источника. В PIM DM есть только SPT. В PIM SM SPT может быть от источника до RP или от источника до получателя после того, как произошёл SPT Switchover. Обозначается записью (S, G) — известен источник для группы.
- Source Tree
- То же самое, что SPT.
- RPT — Rendezvous Point Tree
- Дерево от RP до получателей. Используется только в PIM SM. Обозначается записью (*, G).
- Shared Tree
- То же, что RPT. Называется так потому, что все клиенты подключены к одному общему дереву с корнем в RP.
Типы сообщений PIM Sparse Mode
- Hello
- Для установления соседства и поддержания этих отношений. Также необходимы для выбора DR.
- Join (*, G)
- Запрос на подключение к дереву группы G. Не важно кто источник. Отправляется в сторону RP. С их помощью строится дерево RPT.
- Join (S, G)
- Source Specific Join. Это запрос на подключение к дереву группы G с определённым источником — S. Отправляется в сторону источника — S. С их помощью строится дерево SPT.
- Prune (*, G)
- Запрос на отключение от дерева группы G, какие бы источники для неё не были. Отправляется в сторону RP. Так обрезается ветвь RPT.
- Prune (S, G)
- Запрос на отключение от дерева группы G, корнем которого является источник S. Отправляется в сторону источника. Так обрезается ветвь SPT.
- Register
- Специальное сообщение, внутри которого передаётся мультикаст на RP, пока не будет построено SPT от источника до RP. Передаётся юникастом от FHR на RP.
- Register-Stop
- Отправляется юникастом с RP на FHR, приказывая прекратить посылать мультикастовый трафик, инкапсулированный в Register.
- Bootstrap
- Пакеты механизма BSR, которые позволяют выбрать маршрутизатор на роль BSR, а также передают информацию о существующих RP и группах.
- Assert
- Сообщение для выбора PIM Forwarder, чтобы в один сегмент не передавали трафик два маршрутизатора.
- Candidate-RP-Advertisement
- Сообщение, в котором RP отсылает на BSR информацию о том, какие группы он обслуживает.
- RP-Reachable
- Сообщение от RP, которым она уведомляет всех о своей доступности.
*Есть и другие типы сообщений в PIM, но это уже детали*
А давайте теперь попытаемся абстрагироваться от деталей протокола? И тогда становится очевидной его сложность.
- определение RP,
- регистрация источника на RP,
- переключение на дерево SPT.
Много состояний протокола, много записей в таблице мультикастовой маршрутизации. Можно ли что-то с этим сделать?
На сегодняшний день существует два диаметрально противоположных подхода к упрощению PIM: SSM и BIDIR PIM.
SSM
Всё, что мы описывали до сих пор — это ASM — Any Source Multicast. Клиентам безразлично, кто является источником трафика для группы — главное, что они его получают. Как вы помните в сообщении IGMPv2 Report запрашивается просто подключение к группе.
SSM — Source Specific Multicast — альтернативный подход. В этом случае клиенты при подключении указывают группу и источник.
Что же это даёт? Ни много ни мало: возможность полностью избавиться от RP. LHR сразу знает адрес источника — нет необходимости слать Join на RP, маршрутизатор может сразу же отправить Join (S, G) в направлении источника и построить SPT.
Таким образом мы избавляемся от
- поиска RP (протоколы Bootstrap и Auto-RP),
- регистрации источника на RP (а это лишнее время, двойное использование полосы пропускания и туннелирование)
- переключения на SPT.
Поскольку нет RP, то нет и RPT, соответственно ни на одном маршрутизаторе уже не будет записей (*, G) — только (S, G).
Ещё одна проблема, которая решается с помощью SSM — наличие нескольких источников. В ASM рекомендуется, чтобы адрес мультикастовой группы был уникален и только один источник вещал на него, поскольку в дереве RPT несколько потоков сольются, а клиент, получая два потока от разных источников, вероятно, не сможет их разобрать.
В SSM трафик от различных источников распространяется независимо, каждый по своему дереву SPT, и это уже становится не проблемой, а преимуществом — несколько серверов могут вещать одновременно. Если вдруг клиент начал фиксировать потери от основного источника, он может переключиться на резервный, даже не перезапрашивая его — он и так получал два потока.
Кроме того, возможный вектор атаки в сети с активированной мультикастовой маршрутизацией — подключение злоумышленником своего источника и генерирование большого объёма мультикастового трафика, который перегрузит сеть. В SSM такое практически исключено.
Для SSM выделен специальный диапазон IP-адресов: 232.0.0.0/8.
На маршрутизаторах для поддержки SSM включается режим PIM SSM.
Router(config)# ip pim ssm
IGMPv3 и MLDv2 поддерживают SSM в чистом виде.
При их использовании клиент может
- Запрашивать подключение к просто группе, без указания источников. То есть работает как типичный ASM.
- Запрашивать подключение к группе с определённым источником. Источников можно указать несколько — до каждого из них будет построено дерево.
- Запрашивать подключение к группе и указать список источников, от которых клиент не хотел бы получать трафик
IGMPv1/v2, MLDv1 не поддерживают SSM, но имеет место такое понятие, как SSM Mapping. На ближайшем к клиенту маршрутизаторе (LHR) каждой группе ставится в соответствие адрес источника (или несколько). Поэтому если в сети есть клиенты, не поддерживающие IGMPv3/MLDv2, для них также будет построено SPT, а не RPT, благодаря тому, что адрес источника всё равно известен.
SSM Mapping может быть реализован как статической настройкой на LHR, так и посредством обращения к DNS-серверу.
Проблема SSM в том, что клиенты должны заранее знать адреса источников — никакой сигнализацией они им не сообщаются.
Поэтому SSM хорош в тех ситуациях, когда в сети определённый набор источников, их адреса заведомо известны и не будут меняться. А клиентские терминалы или приложения жёстко привязаны к ним.
Иными словами IPTV — весьма пригодная среда для внедрения SSM. Это хорошо описывает концепцию One-to-Many — один источник, много получателей.
BIDIR PIM
А что если в сети источники могут появляться спонтанно то там, то тут, вещать на одинаковые группы, быстро прекращать передачу и исчезать?
Например, такая ситуация возможна в сетевых играх или в ЦОД, где происходит репликация данных между различными серверами. Это концепция Many-to-Many — много источников, много клиентов.
Как на это смотрит обычный PIM SM? Понятное дело, что инертный PIM SSM здесь совсем не подходит?
Вы только подумайте, какой хаос начнётся: бесконечные регистрации источников, перестроение деревьев, огромное количество записей (S, G) живущих по несколько минут из-за таймеров протокола.
На выручку идёт двунаправленный PIM (Bidirectional PIM, BIDIR PIM). В отличие от SSM в нём напротив полностью отказываются от SPT и записей (S,G) — остаются только Shared Tree с корнем в RP.
И если в обычном PIM, дерево является односторонним — трафик всегда передаётся от источника вниз по SPT и от RP вниз по RPT — есть чёткое деление, где источник, где клиенты, то в двунаправленном от источника трафик к RP передаётся также вверх по Shared Tree — по тому же самому, по которому трафик течёт вниз к клиентам.
Это позволяет отказаться от регистрации источника на RP — трафик передаётся безусловно, без какой бы то ни было сигнализации и изменения состояний. Поскольку деревьев SPT нет вообще, то и SPT Switchover тоже не происходит.
Вот например:
Источник1 начал передавать в сеть трафик группы 224.2.2.4 одновременно с Источником2. Потоки от них просто полились в сторону RP. Часть клиентов, которые находятся рядом начали получать трафик сразу, потому что на маршрутизаторах есть запись (*, G) (есть клиенты). Другая часть получает трафик по Shared Tree от RP. Причём получают они трафик от обоих источников одновременно.
То есть, если взять для примера умозрительную сетевую игру, Источник1 это первый игрок в стрелялке, который сделал выстрел, а Источник2 — это другой игрок, который сделал шаг в сторону. Информация об этих двух событиях распространилась по всей сети. И каждый другой игрок (Получатель) должен узнать об обоих этих событиях.
Если помните, то чуть раньше мы объяснили, зачем нужен процесс регистрации источника на RP — чтобы трафик не занимал канал, когда нет клиентов, то есть RP просто отказывался от него. Почему над этой проблемой мы не задумываемся сейчас? Причина проста: BIDIR PIM для ситуаций, когда источников много, но они вещают не постоянно, а периодически, относительно небольшими кусками данных. То есть канал от источника до RP не будет утилизироваться понапрасну.
Обратите внимание, что на изображении выше между R5 и R7 есть прямая линия, гораздо более короткая, чем путь через RP, но она не была использована, потому что Join идут в сторону RP согласно таблице маршрутизации, в которой данный путь не является оптимальным.
Выглядит довольно просто — нужно отправлять мультикастовые пакеты в направлении RP и всё, но есть один нюанс, который всё портит — RPF. В дереве RPT он требует, чтобы трафик приходил от RP и не иначе. А у нас он может приходить откуда угодно. Взять и отказаться от RPF мы, конечно, не можем — это единственный механизм, который позволяет избежать образования петель.
Поэтому в BIDIR PIM вводится понятие DF — Designated Forwarder. В каждом сегменте сети, на каждой линии на эту роль выбирается тот маршрутизатор, чей маршрут до RP лучше.
В том числе это делается и на тех линиях, куда непосредственно подключены клиенты. В BIDIR PIM DF автоматически является DR.
Список OIL формируется только из тех интерфейсов, на которых маршрутизатор был выбран на роль DF.
Правила довольно прозрачны:
- Если запрос PIM Join/Leave приходит на тот интерфейс, который в данном сегменте является DF, он передаётся в сторону RP по стандартным правилам.
Вот, например, R3. Если запросы пришли в DF интерфейсы, что помечены красным кругом, он их передаёт на RP (через R1 или R2, в зависимости от таблицы маршрутизации). - Если запрос PIM Join/Leave пришёл на не DF интерфейс, он будет проигнорирован.
Допустим, что клиент, находящийся между R1 и R3, решил подключиться и отправил IGMP Report. R1 получает его через интерфейс, где он выбран DF (помечен красным кругом), и мы возвращаемся к предыдущему сценарию. А R3 получает запрос на интерфейс, который не является DF. R3 видит, что тут он не лучший, и игнорирует запрос. - Если мультикастовый трафик пришёл на DF интерфейс, он будет отправлен в интерфейсы из списка OIL и в сторону RP.
Например, Источник1 начал передавать трафик. R4 получает его в свой DF интерфейс и передаёт его и в другой DF-интерфейс — в сторону клиента и в сторону RP, — это важно, потому что трафик должен попасть на RP и распространиться по всем получателям. Также поступает и R3 — одна копия в интерфейсы из списка OIL — то есть на R5, где он будет отброшен из-за проверки RPF, и другая — в сторону RP. - Если мультикастовый трафик пришёл на не DF интерфейс, он должен быть отправлен в интерфейсы из списка OIL, но не будет отправлен в сторону RP.
К примеру, Источник2 начал вещать, трафик дошёл до RP и начал распространяться вниз по RPT. R3 получает трафик от R1, и он не передаст его на R2 — только вниз на R4 и на R5.
Таким образом DF гарантирует, что на RP в итоге будет отправлена только одна копия мультикастового пакета и образование петель исключено. При этом то общее дерево, в котором находится источник, естественно, получит этот трафик ещё до попадания на RP. RP, согласно обычным правилам разошлёт трафик во все порты OIL, кроме того, откуда пришёл трафик.
Кстати, нет нужды более и в сообщениях Assert, ведь DF выбирается в каждом сегменте. В отличие от DR он отвечает не только за отправку Join к RP, но и за передачу трафика в сегмент, то есть ситуация, когда два маршрутизатора передают в одну подсеть трафик, исключена в BIDIR PIM.
Пожалуй, последнее, что нужно сказать о двунаправленном PIM, это особенности работы RP. Если в PIM SM RP выполнял вполне конкретную функцию — регистрация источника, то в BIDIR PIM RP — это некая весьма условная точка, к которой стремится трафик с одной стороны и Join от клиентов с другой. Никто не должен выполнять декапсуляцию, запрашивать построение дерева SPT. Просто на каком-то маршрутизаторе вдруг трафик от источников начинает передаваться в Shared Tree. Почему я говорю «на каком-то»? Дело в том, что в BIDIR PIM RP — абстрактная точка, а не конкретный маршрутизатор, в качестве адреса RP вообще может выступать несуществующий IP-адрес — главное, чтобы он был маршрутизируемый (такая RP называется Phantom RP).