There are so many web pages and blogs post for multicast traffic under linux and how to enable it, but in most of them something always is missing and if you follow them probably you’ll end up with not working setup and you’ll have to search the Internet again – some do need tuning of the linux kernel variables not to drop packets, some need tuning the firewall to allow protocols.
Here we present a real working example of a server under CentOS 7, our server has two network ports:
- eno1 – local unicast traffic with local IP
- eno2 – multicast traffic
We have multicast TV streams, which we can use through our second network interface and we want to use ffmpeg to encode the video. We have “Multicast Group:port” for every stream, which is like “IP:PORT” and in our case the port is always the same 5000. Here are the steps you need to do if you want to receive these streams.
STEP 1) Set networking and make the configuration permanent.
In CentOS 7 the network of eno2, set a local IP, in fact it does not matter the exact IP, we used 10.10.10.0/24 local network.
/etc/sysconfig/network-scripts/ifcfg-eno2
TYPE=Ethernet BOOTPROTO=none DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no NAME=eno2 UUID=2481b907-5e6e-45f9-ab96-7091e4e7d6d1 ONBOOT=yes HWADDR=0c:c4:7a:44:87:a5 IPADDR0=10.10.10.152 PREFIX0=24 IPV6_PEERDNS=yes IPV6_PEERROUTES=yes NM_CONTROLLED=no
The important lines are highlighted. Configure the network adapter on boot and set 10.10.10.152.
Second and very important add a static route for the multicast traffic for the network interface, which is supposed to have the multicast streams (in our case “eno2”). Use file:
/etc/sysconfig/network-scripts/route-eno2
224.0.0.0/4 dev eno2
STEP 2) Kernel variables tuning
[srv@local ~]# for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > "$i"; done [srv@local ~]# echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
Turn off “Reverse Path Filtering” for all interfaces (rp_filter) and ping for the multicast address to work properly we need to disable icmp_echo_ignore_broadcasts. By default kernel drops these packets so you need this tuning or your application will not receive a single udp packet.
You could save the above two lines in
/etc/rc.local
and do not forget to set proper access rights:
[srv@local ~]# chmod 755 /etc/rc.local
Or you can use
/etc/sysctl.conf
Add the following lines in it:
net.ipv4.conf.default.rp_filter=0 net.ipv4.conf.all.rp_filter=0 net.ipv4.conf.eno2.rp_filter=0 net.ipv4.icmp_echo_ignore_broadcasts=0
STEP 3) Allow UDP traffic (and/or IGMP) if you have firewall
Here the port is the “Multicast Group:port” of the IP your application will join (look the example below)
- firewalld – the default with CentOS 7:
[srv@local ~]# firewall-cmd --new-zone=multicast --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-interface=eno2 --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-protocol=igmp --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-protocol=icmp --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-source=224.0.0.0/4 --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-source=10.10.10.0/24 --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-port=5000/udp --permanent [srv@local ~]# firewall-cmd --reload
We make a new zone for the multicast streams and add our interface, the sources and the port we use. We added IGMP, because in some use cases it is needed (in our it could work without IGMP added)
- iptables – if you have disabled firewall and still you wanted to have a firewall:
# allow multicast addresses [srv@local ~]# iptables -A INPUT -p udp -d 5000 -j ACCEPT [srv@local ~]# iptables -A INPUT -s 224.0.0.0/4 -j ACCEPT [srv@local ~]# iptables -A INPUT -p igmp -d 224.0.0.0/4 -j ACCEPT [srv@local ~]# iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT
Probably it is a good idea to see if you have current rules (with “iptables -L -v -n” or even “iptables-save”) and to see if you should use “-A” (above) or “-I” to insert the rules above the DROP rule(s).
* Example with ffmpeg joining to a multicast group
[srv@local ~]# ffmpeg -i 'udp://239.100.10.5:5000' ffmpeg version 2.8.6 Copyright (c) 2000-2016 the FFmpeg developers built with gcc 5.3.0 (Gentoo 5.3.0 p1.0, pie-0.6.5) configuration: --prefix=/usr --libdir=/usr/lib64 --shlibdir=/usr/lib64 --mandir=/usr/share/man --enable-shared --cc=x86_64-pc-linux-gnu-gcc --cxx=x86_64-pc-linux-gnu-g++ --ar=x86_64-pc-linux-gnu-ar --optflags='-march=native -O2 -msse3 -fomit-frame-pointer -pipe' --disable-static --enable-avfilter --enable-avresample --disable-stripping --enable-nonfree --enable-version3 --enable-nonfree --disable-indev=alsa --disable-indev=oss --disable-outdev=alsa --disable-outdev=oss --enable-version3 --enable-bzlib --disable-runtime-cpudetect --disable-debug --disable-doc --disable-gnutls --enable-gpl --enable-hardcoded-tables --enable-iconv --disable-lzma --enable-network --enable-openssl --enable-postproc --disable-libsmbclient --enable-ffplay --enable-sdl --disable-vaapi --disable-vdpau --enable-xlib --disable-libxcb --disable-libxcb-shm --disable-libxcb-xfixes --enable-zlib --disable-libcdio --disable-libiec61883 --disable-libdc1394 --enable-libcaca --disable-openal --disable-opengl --disable-libv4l2 --disable-libpulse --enable-libopencore-amrwb --enable-libopencore-amrnb --disable-libfdk-aac --enable-libopenjpeg --disable-libbluray --disable-libcelt --disable-libgme --enable-libgsm --disable-libmodplug --disable-libopus --disable-libquvi --disable-librtmp --disable-libssh --disable-libschroedinger --disable-libspeex --enable-libvorbis --enable-libvpx --disable-libzvbi --disable-libbs2b --disable-libflite --disable-frei0r --disable-libfribidi --enable-fontconfig --disable-ladspa --disable-libass --enable-libfreetype --disable-libsoxr --enable-pthreads --enable-libvo-aacenc --disable-libvo-amrwbenc --enable-libmp3lame --disable-libaacplus --enable-libfaac --disable-libsnappy --enable-libtheora --disable-libtwolame --disable-libwavpack --disable-libwebp --enable-libx264 --disable-libx265 --enable-libxvid --enable-x11grab --disable-amd3dnow --disable-amd3dnowext --disable-fma4 --disable-xop --cpu=host libavutil 54. 31.100 / 54. 31.100 libavcodec 56. 60.100 / 56. 60.100 libavformat 56. 40.101 / 56. 40.101 libavdevice 56. 4.100 / 56. 4.100 libavfilter 5. 40.101 / 5. 40.101 libavresample 2. 1. 0 / 2. 1. 0 libswscale 3. 1.101 / 3. 1.101 libswresample 1. 2.101 / 1. 2.101 libpostproc 53. 3.100 / 53. 3.100 [mpeg2video @ 0xf2fa80] Invalid frame dimensions 0x0. Last message repeated 10 times Input #0, mpegts, from 'udp://239.100.10.5:5000': Duration: N/A, start: 87846.990933, bitrate: 5659 kb/s Program 5 Metadata: service_name : ?TVtest service_provider: ?ss Stream #0:0[0x33]: Video: mpeg2video (Main) ([2][0][0][0] / 0x0002), yuv420p(tv), 720x576 [SAR 64:45 DAR 16:9], 5467 kb/s, 25 fps, 25 tbr, 90k tbn, 50 tbc Stream #0:1[0x34](bul): Audio: mp2 ([3][0][0][0] / 0x0003), 48000 Hz, stereo, s16p, 192 kb/s At least one output file must be specified
As you can see to join the multicast group and ffmpeg to start encoding you use “udp://239.100.10.5:5000” for input stream parameter. Here ffmpeg joins the group and receives packets successfully.
* Generic example to receive UDP multicast stream
You may use the following example in any linux distro like Ubuntu, CentOS 7, Gentoo, OpenSuse and many others to receive muticast streams
[srv@local ~]# #ifconfig or ip - use one of them [srv@local ~]# #ifconfig [srv@local ~]# ifconfig eno1 10.10.10.152/24 up [srv@local ~]# route add -net 224.0.0.0 netmask 240.0.0.0 eno2 [srv@local ~]# #or ip [srv@local ~]# ip addr add 10.10.10.152/24 dev eno2 [srv@local ~]# ip link set eno2 up [srv@local ~]# #allow multicast packets to the server [srv@local ~]# for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > "$i"; done [srv@local ~]# echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts [srv@local ~]# #if you have firewall use the following for the iptables OR firewalld after that - use only one of them! [srv@local ~]# iptables -A INPUT -p udp -d 5000 -j ACCEPT [srv@local ~]# iptables -A INPUT -s 224.0.0.0/4 -j ACCEPT [srv@local ~]# iptables -A INPUT -p igmp -d 224.0.0.0/4 -j ACCEPT [srv@local ~]# iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT [srv@local ~]# #firewalld setup [srv@local ~]# firewall-cmd --new-zone=multicast --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-interface=eno2 --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-protocol=igmp --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-protocol=icmp --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-source=224.0.0.0/4 --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-source=10.10.10.0/24 --permanent [srv@local ~]# firewall-cmd --zone=multicast --add-port=5000/udp --permanent [srv@local ~]# firewall-cmd --reload
Super useful and solved my issue. CentOS 7 kernel was not passing multicast traffic.
great article… was strugling for couple of days and this article solved my issue
Migrating from CentOS 6.5 to 8. Apps compiled and running with no errors but no data being delivered. Knew my iptables transpose to firewalld had to be incorrect. This article saved me lots time and effort. Thanx.
Thank you! This was very helpful.