Использование Source Specific Multicast (SSM) (IGMPv3)

Введение (можно пропустить)

Отличие Source Specific Multicast от “обычного”(Any Source Multicast(ASM)) в его сигнализации и фильтрации. Формально, существует 3 модели распространения multicast – ASM, SFM(source filtered multicast) и SSM. Но в действительности, с точки зрения запроса мультикаст-трафика со стороны клиента, SSM можно рассматривать как частный случай SFM. Модель SSM подразумевает, что мультикаст группы принадлежат к диапазону адресов 232.0.0.0/8, а IGMPv3 exclude mode запросы не отправляются клиентом и игнорируются свитчами и роутерами, их обрабатывающими.

В классическом варианте, внутри сети оператора используется протокол PIM для распространения мультикаста между роутерами, при этом задействуются RP(точка(и) рандеву) для регистрации источников (S,G) и получения информации о них роутерами, у которых клиенты запросили мультикаст. Использование IGMPv3 в режиме include mode и отказ от exclude mode позволяет избавиться от этих RP, что упрощает конфигурацию сети и, вообще говоря, повышает надёжность(за счёт понижения сложности). Использование адресов 232.0.0.0/8 позволяет роутерам понять что от них хотят, когда вещают или запрашивают мультикаст от них. Получая такой мультикаст(data-трафик), роутер знает, что его не надо регистрировать на RP (сеть может быть смешанная и использовать 1, 2 или 3 модели распространения multicast), а получая IGMPv3 запрос от клиента(include mode) на запрос канала из сети 232.0.0.0/8, роутер не пытается его интерпретировать как ASM с фильтром(т.е. SFM), а сразу шлёт PIM JOIN для построения SPT, если канал (S,G) ранее не был подключен. В терминологии SSM канал определён как (S,G). В общем случае(в зависимости от оборудования) можно изменить диапазон адресов, относящийся к SSM.

IGMPv3 клиент и генератор multicast

Рассмотрим IGMPv3 в контексте CE-устройства, т.е. как запросить SSM по IGMPv3 и как его обработать.

Сначала речь пойдёт о кроссплатформенных средствах, будет написано простейшее приложение на python (клиент) и использован iperf как генератор мультикаста. Это должно работать в современных версиях Linux, Windows, MacOS, FreeBSD и, возможно, в других ОС. Проверялось на Ubuntu Linux 14.04.

Для того, чтобы нагенерировать трафик с ip.src=192.0.2.1, ip.dst=232.252.0.100, dst.udp_port=12345 можно запустить iperf:

iperf -c 232.252.0.100 -B 192.0.2.1 -u -p 12345 -t 0.2 -l 12

Код приложения-клиента:

#!/usr/bin/env python

import socket

if not hasattr(socket, 'IP_ADD_SOURCE_MEMBERSHIP'):
    setattr(socket, 'IP_ADD_SOURCE_MEMBERSHIP', 39)

group = '232.252.0.100'
port = 12345
bind = '0.0.0.0'
source = '192.0.2.1'

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

imr = (socket.inet_pton(socket.AF_INET, group) +
        socket.inet_pton(socket.AF_INET, bind) +
        socket.inet_pton(socket.AF_INET, source))

s.setsockopt(socket.SOL_IP, socket.IP_ADD_SOURCE_MEMBERSHIP, imr)
s.bind((group,port))

for i in range(0, 3):
    msg = s.recv(16384)
    print ":".join("{:02x}".format(ord(c)) for c in msg)
    #print msg

Это приложение подключается (строки 13-20) к каналу (192.0.2.1, 232.252.0.100), ожидая данные на порту udp/12345 (строки 9 и 20), ждёт 3 таких пакета (строки 22-23), распечатывая их в шестнадцатеричной форме (строка 24). На C это будет выглядеть аналогично, только с кучей кода, не относящегося к бизнес логике(работа с памятью), пример реализации можно подсмотреть в коде VLC-плеера.

Запуска клиента и генератора multicast в Linux

Существует несколько нюансов, относительно запуска клиента и генератора. Например, генератор должен отправлять трафик в нужный интерфейс, клиент же должен отправлять IGMP-запросы в интерфейс в сторону генератора, требуется unicast маршрут для прохождения RPF-проверки или она должна быть отключена. Схема проверки выглядит следующим образом:

igmpv3-use

Чтобы это сконфигурировать нужно выполнить следующие команды:

// создание nets, интерфейсов и конфигурирование IP-адресов
# ip netns add G
# ip link add veth0 type veth peer name veth1
# ip link set dev veth1 netns G
# ip netns exec G ifconfig veth1 192.0.2.1/30 up
# ip netns exec G ifconfig veth1:1 192.0.2.2/30 up
# ifconfig veth0 198.51.100.1/30 up

//маршрут для прохождения RPF-проверки при получении data-трафика
# ip route add 192.0.2.0/30 dev veth0

//маршрут для отправки IGMP-запроса клиентом в нужный интерфейс
# ip route add 232.252.0.100/32 dev veth0

//маршрут для отправки data-трафика генератором мультикаста
# ip netns exec G ip route add 232.252.0.100/32 dev veth1

Теперь запускаем tcpdump на интерфейсе veth1 и клиентское приложение:

// терминал 1 (вывод появится после запуска приложения из терминала 2)
# ip netns exec G tcpdump -i veth1 -n -nn -v -vv -s 0
21:48:58.687747 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP (2), length 56, options (RA))
    198.51.100.1 > 224.0.0.22: igmp v3 report, 2 group record(s) [gaddr 232.252.0.100 allow { 192.0.2.1 }] [gaddr 232.252.0.100 to_in { 192.0.2.1 }]

// терминал 2 (запуска приложения)
$ ./ssm-client.py

// терминал 3 (просмотр multicast фильтра, заданного include mode-ом)
# cat /proc/net/mcfilter
Idx Device        MCA        SRC    INC    EXC
  7  veth0 0xe8fc0064 0xc0000201      1      0
# echo 'e8 fc 00 64' | perl -ne 'printf "%d.%d.%d.%d\n", map { hex($_)} split unless /^\s$/'
232.252.0.100
# echo 'c0 00 02 01' | perl -ne 'printf "%d.%d.%d.%d\n", map { hex($_)} split unless /^\s$/'
192.0.2.1

И, наконец, запускам генератор и смотрим что выдаст клиент в терминал:

//терминал 3
# ip netns exec G iperf -c 232.252.0.100 -B 192.0.2.1 -u -p 12345 -t 0.2 -l 12
WARNING: option -l has implied compatibility mode
------------------------------------------------------------
Client connecting to 232.252.0.100, UDP port 12345
Binding to local address 192.0.2.1
Sending 12 byte datagrams
Setting multicast TTL to 1
UDP buffer size:  160 KByte (default)
------------------------------------------------------------
[  5] local 192.0.2.1 port 12345 connected with 232.252.0.100 port 12345
[ ID] Interval       Transfer     Bandwidth
[  5]  0.0- 0.2 sec  25.3 KBytes  1.04 Mbits/sec
[  5] Sent 2158 datagrams

//терминал 2 (ssm-client.py был запущен ранее, см. выше)
$ ./ssm-client.py 
00:00:00:00:53:cc:07:9a:00:0d:fc:de
00:00:00:01:53:cc:07:9a:00:0e:02:01
00:00:00:02:53:cc:07:9a:00:0e:02:63

Всё ок. Теперь попробуем отправить мультикаст с другого ip.src(192.0.2.2), при этом запрашивать (192.0.2.1, 232.252.0.100), чтобы посмотреть как работает mcfilter:

//терминал 2
$ ./ssm-client.py 

//терминал 3
# ip netns exec G iperf -c 232.252.0.100 -B 192.0.2.2 -u -p 12345 -t 0.2 -l 12
WARNING: option -l has implied compatibility mode
------------------------------------------------------------
Client connecting to 232.252.0.100, UDP port 12345
Binding to local address 192.0.2.2
Sending 12 byte datagrams
Setting multicast TTL to 1
UDP buffer size:  160 KByte (default)
------------------------------------------------------------
[  5] local 192.0.2.2 port 12345 connected with 232.252.0.100 port 12345
[ ID] Interval       Transfer     Bandwidth
[  5]  0.0- 0.2 sec  25.7 KBytes  1.05 Mbits/sec
[  5] Sent 2193 datagrams

Трафик отправлен, но не прошёл через mcfiler, приложение его не видит, как и ожидалось.

В идеальном случае, клиент не должен получать незапрашиваемого трафика, однако в случае наличия в сети 2ух каналов вида (S1, G1) и (S2, G1) и подключения двух клиентов(которые запрашивают эти группы) к свитчу, умеющему только L2-мультикаст(на уровне dataplane), такая ситуация будет иметь место, поэтому фильтр трафика на стороне клиента, в общем случае, нужен.

В одной из следующих статей будет рассмотрена маршрутизации мультикаст с помощью IGMPv3-сигнализации, в продолжение предыдущей статьи о статической мультикаст маршрутизации в Linux.

Advertisements

One thought on “Использование Source Specific Multicast (SSM) (IGMPv3)

  1. Pingback: Маршрутизация multicast в Linux | Net-Labs.in

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s