Маршрутизация multicast в Linux

В современных реалиях, скорее всего, нет смысла заниматься маршрутизацией(репликацией) multicast-трафика с помощью софтроутеров(будь то ядро Linux или что-то иное). Причина довольно простая – даже дешёвые свитчи умеют L2/L3-multicast(хоть и с ограничениями по количеству групп/маршрутов, но всё же это делается в asic-ах). Однако, существует ряд задач, которые могут быть не решены в “железе” (нет поддержки со стороны ПО/невозможно реализовать ввиду возможностей asic), например ренамберинг(изменение destination ip), внесение случайных задержек(перемешивание), отправка multicast в тунель, резервирование источника по произвольному критерию.

Зачем может потребоваться ренамберинг мультикаст группы? Во-первых, маппинг IP-mac неодназначен(например, группам 238.1.1.1 и 239.1.1.1 соответствует один и тот же mac-адрес), что может вызвать проблемы в L2-сегменте. Конечно, такая коллизия маловероятна, однако возможна, когда вы берёте multicast из разных внешних источников(в принципе, IP-адреса могут даже полностью совпасть). Во-вторых, вы можете захотеть скрыть свой источник, изменив и destination и source адрес. В destination может быть “спрятан” номер AS источника(RFC3180), по source тоже можно догадаться об источнике, если он не серый. В третьих, перенумеровать группу может потребоваться для избежания коллизии на оборудовании, где заканчивается TCAM под multicast (как временное решение до замены оборудования/изменения схемы сети). И наконец, вы решили зарезервировать ТВ-каналы путём их получения из разных источников(т.е. вливать на сервер 2 разных группы(но одинаковых по контенту) и забирать из него одну, результирующую(работающую))

Внести случайную задержку(reordering) или потери может потребоваться для проверки поведения используемых STB/soft-плееров. Например, вам интересно, как будет выглядеть картинка, если где-то на сети мультикаст пройдёт через per-packet балансировку и не зависнет ли плеер при наличии потери пакетов, будут ли издаваться неприятные скрипящие звуки или же просто квадратики и тишина.

При написании этой заметки использовался Ubuntu Linux 14.04 LTS (ядро 3.13.0-24-generic), но применимо для большинства современных дистрибутивов, однако необходимо проверить поддержку IPv4 multicast в ядре:

# cat /boot/config-`uname -r` | grep -E '(IP_MULTICAST|IP_MROUTE)'
CONFIG_IP_MULTICAST=y
CONFIG_IP_MROUTE=y
# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set

В отличии от unicast роутинга, утилиты ip недостаточно даже для статической (S, G) маршрутизации, не говоря уже про динамическую. Для формирования таблицы мультикаст-репликации требуются “сторонние” userspace-утилиты. Например, для статических маршрутов это smcroute, для построения таблицы по igmp-запросам с даунлинк-интерфейсов – igmpproxy(маршрут добавляется в ядро тогда, когда “снизу” приходит igmp-запрос), для работы с PIM-SM сигнализацией – pimd(требуется поддержка PIMSM_V2 со стороны ядра).

Статическая маршрутизация multicast

схема для статической маршрутизации multicast

Рассмотрим следующую задачу: осуществить репликацию мультикаст-трафика (*, 233.251.240.1) с интерфейса eth1 на интерфейсы eth2 и eth3, при этом на eth1 эта группа приходит только по igmpv2-запросу.

Конфигурация интерфейсов выглядет следующим образом:

# ip route show
default via 198.50.100.1 dev eth0 
198.50.100.0/24 dev eth0  proto kernel  scope link  src 198.50.100.15 
192.0.2.0/30 dev eth1  proto kernel  scope link  src 192.0.2.1 
192.0.2.4/30 dev eth2  proto kernel  scope link  src 192.0.2.5 
192.0.2.8/30 dev eth3  proto kernel  scope link  src 192.0.2.9

К сожаленью, smcroute в ubuntu 14.04 не поддерживает (*, G)-форму, поэтому придётся скомпилировать из исходников:

apt-get install build-essential
mkdir /usr/local/src/smcroute
cd /usr/local/src/smcroute
wget ftp://troglobit.com/smcroute/smcroute-1.99.2.tar.bz2
tar -xf smcroute-1.99.2.tar.bz2
cd smcroute-1.99.2/
./configure --prefix=/opt/smcroute
make
make install
ln -s /opt/smcroute/sbin/smcroute /usr/sbin/smcroute 

Прежде чем запускать маршрутизацию(инсталлировать маршруты в ядро), нужно отключить RPF на интерфейсе eth1(поскольку по условию задачи считаем, что source ip multicast-группы может быть произвольным):

sysctl net.ipv4.conf.all.rp_filter=0
sysctl net.ipv4.conf.eth1.rp_filter=0

Кроме того, устанавливаем явным образом режим работы igmp на интерфейсе eth1:

sysctl net.ipv4.conf.eth1.force_igmp_version=2

Теперь переходим к конфигурации smcroute(/etc/smcroute.conf):

mgroup from eth1 group 233.251.240.1
mroute from eth1 group 233.251.240.1 to eth2 eth3

(необходим перевод строки в конце конфигурации)
Первая строчка – подключить группу по протоколу igmp(залить эту информацию в ядро), вторая – собственно мультикаст-маршрут.
Запускаем smcroute:

smcroute -d

(логи пишутся в syslog)
Проверяем таблицу igmp:

# cat /proc/net/igmp
Idx Device    : Count Querier   Group    Users Timer      Reporter
1   lo        :     1      V3
                                010000E0     1 0:00000000        0
2   eth0      :     1      V3
                                010000E0     1 0:00000000        0
4   eth1      :     2      V2
                                01F0FBE9     1 0:00000000        1
                                010000E0     1 0:00000000        0
6   eth2      :     1      V3
                                010000E0     1 0:00000000        0
8   eth3      :     1      V3
                                010000E0     1 0:00000000        0

Всё верно, 01F0FBE9 это наша группа 233.251.240.1.

До того, как в eth1 польётся мультикаст, таблица маршрутизации в ядре будет выглядеть таким образом:

ip mroute show
(192.0.2.1, 233.251.240.1)       Iif: eth1       Oifs: eth2 eth3

Затем примет такой вид:

# ip mroute show
(192.0.2.1, 233.251.240.1)       Iif: eth1       Oifs: eth2 eth3 
(203.0.113.1, 233.251.240.1)     Iif: eth1       Oifs: eth2 eth3

Проверяем работу репликации:

# tcpdump -i eth1 -e -n -nn -v -vv -s 0 -c 1
22:55:13.159720 0e:48:46:48:4b:6f > 01:00:5e:7b:f0:01, ethertype IPv4 (0x0800), length 1342: (tos 0x0, ttl 32, id 28469, offset 0, flags [DF], proto UDP (17), length 1328)
    203.0.113.1.5000 > 233.251.240.1.5000: [bad udp cksum 0x1b2d -> 0x9d0b!] UDP, length 1300

# tcpdump -i eth2 -e -n -nn -v -vv -s 0 -c 1
22:55:17.315373 3a:02:02:bf:35:70 > 01:00:5e:7b:f0:01, ethertype IPv4 (0x0800), length 1342: (tos 0x0, ttl 31, id 28888, offset 0, flags [DF], proto UDP (17), length 1328)
    203.0.113.1.5000 > 233.251.240.1.5000: [bad udp cksum 0x1b2d -> 0x3b68!] UDP, length 1300

# tcpdump -i eth3 -e -n -nn -v -vv -s 0 -c 1
22:55:21.639625 fe:e9:33:d3:c9:07 > 01:00:5e:7b:f0:01, ethertype IPv4 (0x0800), length 1342: (tos 0x0, ttl 31, id 29324, offset 0, flags [DF], proto UDP (17), length 1328)
    203.0.113.1.5000 > 233.251.240.1.5000: [bad udp cksum 0x1b2d -> 0x470a!] UDP, length 1300

Ренамберинг мультикаст групп

Для того, чтобы изменить IP multicast группы используем DNAT. Например, мы хотим изменить 233.251.240.1 на 233.251.250.5:

iptables -t nat -I PREROUTING -i eth1 -d 233.251.240.1 -j DNAT --to-destination 233.251.250.5

/etc/smcroute.conf будет выглядеть следующим образом:

mgroup from eth1 group 233.251.240.1
mroute from eth1 group 233.251.250.5 to eth2 eth3

(в маршруте фигурирует новый адрес по причине того, что DNAT делается в PREROUTING-е)

Далее, чистим conntrack(командой “conntrack -F”) и проверяем:

# tcpdump -i eth3 -e -n -nn -v -vv -s 0 -c 1
23:24:40.739832 fe:e9:33:d3:c9:07 > 01:00:5e:7b:fa:05, ethertype IPv4 (0x0800), length 1342: (tos 0x0, ttl 31, id 9130, offset 0, flags [DF], proto UDP (17), length 1328)
    203.0.113.1.5000 > 233.251.250.5.5000: [bad udp cksum 0x2531 -> 0x8781!] UDP, length 1300

Как нетрудно догадаться, чтобы подменить ещё и source ip, будем использовать SNAT:

iptables -t nat -I POSTROUTING -d 233.251.250.5 -j SNAT --to-source 192.0.2.111

Снова чистим conntrack(“conntrack -F”) и проверяем:

# tcpdump -i eth3 -e -n -nn -v -vv -s 0 -c 1
23:31:23.100313 fe:e9:33:d3:c9:07 > 01:00:5e:7b:fa:05, ethertype IPv4 (0x0800), length 1342: (tos 0x0, ttl 31, id 44639, offset 0, flags [DF], proto UDP (17), length 1328)
    192.0.2.111.5000 > 233.251.250.5.5000: [bad udp cksum 0xab9e -> 0x7c72!] UDP, length 1300

Прочее

С помощью iptables и tc можно ещё что-нибудь сделать с трафиком(внести задержки и потери, например). При желании, можно организовать резервирование ТВ-канала путём переключения источника вещания с помощью скриптов(smcroute-ом можно управлять “извне”), придумав произвольные критерии выбора лучшего источника(подобные решения для операторов существуют и стоят больших денег)

Продолжение
Использование Source Specific Multicast (SSM) (IGMPv3)
Маршрутизация multicast в Linux (IGMPv3 и IGMPv2)

Advertisements

11 thoughts on “Маршрутизация multicast в Linux

  1. shaly

    Статья интересная, узнала много нового. Вы знаете особенности настройки мультикаста для igmp v.3? Интересно было бы узнать еще и об этом?

    Reply
  2. shaly

    А если честно, меня интересует реализация multicast igmp-v3 с получением через pptp тоннель. Какик нюансы, особенности.

    Reply
    1. netblog0 Post author

      Само ядро linux умеет реплицировать трафик из eth-интерфейса в ppp-интерфейс(pptp-тоннель), при этом будет запись вида “(S, G) Iif: UPLINK Oifs: DOWNLINKS” в mroute-таблице. Нюансы в сигнализации. igmpv3 умеет igmpproxy с патчами(http://wl500g.googlecode.com/svn/trunk/igmpproxy/ ), насколько оно стабильно работает и годится ли для ISP сложно сказать, ещё igmpv3 заявлен в mcproxy и xorp, надо смотреть и тестировать.
      Кроме того, pptp-тоннели создаются динамически и нужно, чтоб демон, обрабатывающий igmp-запросы умел воспринимать эти запросы с интерфейсов, создаваемых после его запуска или хотя бы релодить конфиг без остановки сервиса.

      Reply
  3. shaly

    Как определить причину, по которой multicast не работает? При подписке на источник происходить присоединение к группе, igmp v3. Но при этом продолжения не следует, нет udp пакетов.

    Reply
    1. netblog0 Post author

      Сначала нужно убедиться, что igmp-запросы действительно уходят в тоннель (запустить на клиенте tcpdump -i ppp0 -n -nn -v -vv -s 0 igmp , где ppp0 – ваш тунельный интерфейс(pptp)). Если уходят, то смотреть на устройстве, которое этот тоннель терминирует (проверить версию igmp, включен ли multicast routing в сторону тоннелей)

      Reply
      1. shaly

        Результат команды;
        tcpdump: listening on ppp1, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
        20:48:17.942915 IP (tos 0xc0, ttl 1, id 38808, offset 0, flags [none], proto IGMP (2), length 36, options (RA))
        1.1.7.250 > 224.0.0.1: igmp query v3
        20:49:17.943727 IP (tos 0xc0, ttl 1, id 38913, offset 0, flags [none], proto IGMP (2), length 36, options (RA))
        1.1.7.250 > 224.0.0.1: igmp query v3
        20:50:17.944655 IP (tos 0xc0, ttl 1, id 39017, offset 0, flags [none], proto IGMP (2), length 36, options (RA))

      2. shaly

        если отправлять с клиента, то добавляется строка
        192.168.137.5 > 224.0.0.22: igmp v3 report, 1 group record(s) [gaddr 239.192.7.27 to _ex { }]

    1. netblog0 Post author

      не пользуюсь интернет-мессенджерами. пишите на email, он есть во whois на домен этого блога

      Reply
  4. Pingback: Использование Source Specific Multicast (SSM) (IGMPv3) | Net-Labs.in

  5. Pingback: Маршрутизация multicast в Linux (IGMPv3 и IGMPv2) | 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