Why Unicast Breaks Down at Scale
Streaming a live video feed to dozens of workstations over unicast wastes massive amounts of bandwidth. Suppose 120 staff members tune into an 8 Mbps 1080p company broadcast. Your media server must pump nearly 1 Gbps (960 Mbps) out of a single network interface. Switch uplinks saturate, latency spikes, and frame drops follow quickly.
Broadcast cannot solve this problem either. Routers deliberately drop broadcast packets at subnet boundaries to stop broadcast storms from crippling entire sites.
Multicast bridges this gap. The media server sends exactly one stream to a class D multicast address (such as 239.255.1.100). Downstream switches and routers replicate those packets only onto physical segments where active subscribers live, tracking memberships via IGMP (Internet Group Management Protocol).
Stock Linux kernels handle unicast routing effortlessly. However, they will not forward multicast traffic between interfaces without a dedicated routing daemon. PIM-SM (Protocol Independent Multicast – Sparse Mode) serves as the standard protocol here. It assumes subscribers are rare and builds a distribution tree back to the source only when a host asks for the feed.
We use pimd, a battle-tested PIM-SM daemon originally written for BSD and now maintained for Linux by Joachim Nilsson (troglobit). It handles high-bitrate MPEG-TS feeds, surveillance cameras, and RTSP relay traffic with minimal CPU overhead.
Prerequisites & Kernel Setup
Before configuring pimd, verify your kernel build flags and tune system parameters.
1. Check Kernel Multicast Support
Ensure your running kernel was compiled with multicast routing support:
grep -E "CONFIG_IP_MROUTE|CONFIG_IP_PIMSM" /boot/config-$(uname -r)
Ubuntu, Debian, AlmaLinux, and Rocky Linux enable these options by default. Confirm both flags return =y or =m:
CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
2. Configure Sysctl Settings
Multicast routing has two common sysctl traps: reverse path filtering and the read-only status of mc_forwarding. Do not attempt to force net.ipv4.conf.all.mc_forwarding = 1 directly; the kernel rejects manual writes and enables it automatically when pimd initializes the multicast routing socket (MRT_INIT).
You must, however, enable standard IPv4 forwarding and disable strict Reverse Path Filtering (RPF). Strict RPF often causes the kernel to drop incoming multicast streams if your unicast routing table does not maintain a symmetric return route back to the encoder.
Create /etc/sysctl.d/99-multicast.conf:
sudo bash -c 'cat <<EOF > /etc/sysctl.d/99-multicast.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.eth1.rp_filter = 0
net.ipv4.conf.eth2.rp_filter = 0
EOF'
sudo sysctl --system
3. Install pimd
On Debian 11/12 and Ubuntu 22.04/24.04, install the package directly:
sudo apt update
sudo apt install -y pimd
To compile the latest upstream release from source on RHEL-based or minimal systems:
sudo apt install -y build-essential automake autoconf pkg-config
git clone https://github.com/troglobit/pimd.git
cd pimd
./autogen.sh
./configure --prefix=/usr --sysconfdir=/etc
make
sudo make install
Network Topology & Configuration
Here is our deployment layout:
- eth1 (192.168.10.1/24): Video Source Subnet (Encoder IP:
192.168.10.50) - eth2 (192.168.20.1/24): Client Subnet (Receiving workstations:
192.168.20.0/24) - Multicast Channel:
239.255.1.100listening on UDP port5004
1. Edit /etc/pimd.conf
By default, pimd tries to run on every active interface it detects, including loopback and management ports. Disable all interfaces initially, then explicitly enable only your streaming interfaces:
sudo nano /etc/pimd.conf
Populate the file with the following rules:
# /etc/pimd.conf
# Ignore interfaces unless explicitly declared
default-phyint-status disable
# Ingress interface from the IPTV encoder
phyint eth1 enable
# Egress interface to client workstations
phyint eth2 enable
# Configure this host as the Rendezvous Point (RP)
# Handles the 239.0.0.0/8 administratively scoped multicast range
rp-candidate eth1 priority 20 time 30
group-prefix 239.0.0.0 masklen 8
# Configure this host as a Bootstrap Router (BSR) candidate
bsr-candidate eth1 priority 5
2. Configure Netfilter / iptables Rules
Linux firewalls drop unsolicited multicast packets and control signaling by default. You need to permit IGMP (protocol 2), PIM control messages (protocol 103), and the routed UDP multicast packets:
# Accept local IGMP and PIM control traffic
sudo iptables -A INPUT -p igmp -j ACCEPT
sudo iptables -A INPUT -p 103 -j ACCEPT
# Allow PIM forwarding between routing peers
sudo iptables -A FORWARD -p 103 -j ACCEPT
# Forward UDP multicast packets from the source subnet to the client subnet
sudo iptables -A FORWARD -i eth1 -o eth2 -d 239.0.0.0/8 -p udp --dport 5004 -j ACCEPT
3. Start and Enable the Daemon
Launch pimd and inspect systemd to verify that the daemon bound to your interfaces:
sudo systemctl restart pimd
sudo systemctl enable pimd
sudo systemctl status pimd
Verification & Troubleshooting
Run these checks to confirm multicast packets cross between subnets without drops.
1. Verify Multicast Virtual Interfaces (VIFs)
Check the kernel’s virtual multicast interface table:
cat /proc/net/ip_mr_vif
You should see eth1 assigned to VIF 0 and eth2 assigned to VIF 1. As streaming starts, the PktsIn column on eth1 and the PktsOut column on eth2 will climb.
2. Check Kernel Multicast Forwarding Cache
Inspect current multicast routes via iproute2:
ip mroute show
When a client joins the group and the source is active, the kernel displays an installed (S,G) route:
(192.168.10.50, 239.255.1.100) Iif: eth1 Oifs: eth2
If the output shows Oifs: unresolved or fails to list eth2, your client has not sent an IGMP report, or your firewall blocked it.
3. Inspect pimd Internal State
Force pimd to dump its routing table, group timers, and neighbor lists by sending a USR1 signal:
sudo killall -USR1 pimd
cat /var/run/pimd/pimd.dump 2>/dev/null || cat /var/tmp/pimd.dump
Look for the (*,G) and (S,G) sections. They confirm whether the router elected itself as RP and registered the upstream encoder.
4. Run an End-to-End Test
You do not need an expensive hardware encoder to test this setup. Two test commands will prove whether your router works.
Step 1: Join the group on a client (192.168.20.50)
# Request membership and listen on UDP 5004 using socat
socat - UDP4-RECV:5004,ip-add-membership=239.255.1.100:192.168.20.50
Alternatively, open VLC on the client machine and navigate to Media > Open Network Stream with URL udp://@239.255.1.100:5004.
Step 2: Stream test color bars from the source machine (192.168.10.50)
Crucial detail: set your multicast TTL higher than 1. The default multicast TTL for many tools is 1, meaning the first router will drop packets immediately.
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
-vcodec libx264 -preset ultrafast -b:v 2500k -f mpegts \
"udp://239.255.1.100:5004?pkt_size=1316&ttl=16"
Confirm delivery on the router’s egress interface with tcpdump:
sudo tcpdump -n -i eth2 host 239.255.1.100 and udp port 5004
If packets appear on eth2, your Linux host is successfully routing multicast video across boundaries with low latency and zero unnecessary subnet flooding.

