Multicast with PIM-SM
This lab shows a multicast routing example using PIM in Sparse Mode.
Overview¶
Network diagram¶
Here is the logical and physical view:

Setting up the lab¶
Downloading BSD Router Project images¶
Download the BSDRP serial image (to avoid needing an X display) from SourceForge.
Download lab scripts¶
More information on the BSDRP lab scripts is available in How to build a BSDRP router lab.
Start the lab with 4 routers:
tools/BSDRP-lab-bhyve.sh -n 4 -i BSDRP-2.0-full-amd64.img.xz
BSD Router Project (https://bsdrp.net) - bhyve full-meshed lab script
Setting-up a virtual lab with 4 VM(s):
- Working directory: /home/olivier/BSDRP-VMs
- Each VM has a total of 1 (1 cores and 1 threads) and 1G RAM
- Emulated NIC: virtio-net
- Boot mode: UEFI
- Switch mode: bridge + tap
- 0 LAN(s) between all VM
- Full mesh Ethernet links between each VM
VM 1 has the following NIC:
- vtnet0 connected to VM 2
- vtnet1 connected to VM 3
- vtnet2 connected to VM 4
VM 2 has the following NIC:
- vtnet0 connected to VM 1
- vtnet1 connected to VM 3
- vtnet2 connected to VM 4
VM 3 has the following NIC:
- vtnet0 connected to VM 1
- vtnet1 connected to VM 2
- vtnet2 connected to VM 4
VM 4 has the following NIC:
- vtnet0 connected to VM 1
- vtnet1 connected to VM 2
- vtnet2 connected to VM 3
To connect VM'serial console, you can use:
- VM 1 : sudo cu -l /dev/nmdm-BSDRP.1B
- VM 2 : sudo cu -l /dev/nmdm-BSDRP.2B
- VM 3 : sudo cu -l /dev/nmdm-BSDRP.3B
- VM 4 : sudo cu -l /dev/nmdm-BSDRP.4B
Router configuration¶
Router 1¶
Configuration:
sysrc hostname=VM1 \
gateway_enable=no \
ipv6_gateway_enable=no \
ifconfig_vtnet0="inet 10.0.12.1/24" \
defaultrouter=10.0.12.254
service hostname restart
service netif restart
service routing restart
config save
Router 2¶
VM2 is a PIM router that announces itself (10.0.23.2) as Candidate RP with an advertisement period of 10 seconds and high priority (it will be the rendezvous point).
sysrc hostname=VM2 \
ifconfig_vtnet0="inet 10.0.12.254/24" \
ifconfig_vtnet1="inet 10.0.23.2/24" \
defaultrouter=10.0.23.3 \
pimd_enable=yes
cat > /usr/local/etc/pimd.conf <<EOF
rp-candidate 10.0.23.2 time 10 priority 1
#rp-address 10.0.23.2
EOF
service hostname restart
service netif restart
service routing restart
service pimd start
config save
Router 3¶
VM3 announces itself (10.0.23.3) as a Candidate Bootstrap Router with high priority.
sysrc hostname=VM3 \
ifconfig_vtnet1="inet 10.0.23.3/24" \
ifconfig_vtnet2="inet 10.0.34.254/24" \
defaultrouter=10.0.23.2 \
pimd_enable=yes
cat > /usr/local/etc/pimd.conf <<EOF
bsr-candidate 10.0.23.3 priority 1
#rp-address 10.0.23.2
EOF
service hostname restart
service netif restart
service routing restart
service pimd start
config save
Router 4¶
sysrc hostname=VM4 \
gateway_enable=no \
ipv6_gateway_enable=no \
ifconfig_vnet2="inet 10.0.34.4/24" \
defaultrouter=10.0.34.254
service hostname restart
service netif restart
service routing restart
config save
Checking NIC drivers and bhyve compatibility with multicast¶
Before moving to the advanced routing setup, test simple multicast between two directly connected hosts. Some NICs (such as vtnet) or hypervisor network setups do not handle even basic multicast correctly.
On VM1, start a multicast generator (an iperf client emitting multicast):
[root@VM1]~# iperf -c 239.1.1.1 -u -T 32 -t 3000 -i 1
------------------------------------------------------------
Client connecting to 239.1.1.1, UDP port 5001
Sending 1470 byte datagrams, IPG target: 11215.21 us (kalman adjust)
Setting multicast TTL to 32
UDP buffer size: 9.00 KByte (default)
------------------------------------------------------------
[ 3] local 10.0.12.1 port 46636 connected with 239.1.1.1 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 131 KBytes 1.07 Mbits/sec
[ 3] 1.0- 2.0 sec 128 KBytes 1.05 Mbits/sec
[ 3] 2.0- 3.0 sec 128 KBytes 1.05 Mbits/sec
[ 3] 0.0- 3.5 sec 446 KBytes 1.05 Mbits/sec
[ 3] Sent 311 datagrams
(...)
On the directly connected VM2, check whether it sees multicast packets in non-promiscuous mode:
[root@VM2]~# tcpdump -pni vtnet0 -c 2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vtnet0, link-type EN10MB (Ethernet), capture size 262144 bytes
15:22:32.517270 IP 10.0.12.1.33482 > 239.1.1.1.5001: UDP, length 1470
15:22:32.528668 IP 10.0.12.1.33482 > 239.1.1.1.5001: UDP, length 1470
2 packets captured
2 packets received by filter
0 packets dropped by kernel
VM2 receives multicast packets from 10.0.12.1 to multicast group 239.1.1.1. Now start a multicast listener on VM2 (an iperf server); it should receive the multicast flow:
[root@VM2]~# iperf -s -u -B 239.1.1.1%vtnet0 -i 1
------------------------------------------------------------
Server listening on UDP port 5001
Binding to local address 239.1.1.1
Joining multicast group 239.1.1.1
Receiving 1470 byte datagrams
UDP buffer size: 41.1 KByte (default)
------------------------------------------------------------
[ 3] local 239.1.1.1 port 5001 connected with 192.168.100.149 port 35181
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 3] 0.0- 1.0 sec 129 KBytes 1.06 Mbits/sec 0.038 ms 107/ 197 (54%)
[ 3] 1.0- 2.0 sec 128 KBytes 1.05 Mbits/sec 0.054 ms 0/ 89 (0%)
[ 3] 2.0- 3.0 sec 128 KBytes 1.05 Mbits/sec 0.021 ms 0/ 89 (0%)
[ 3] 3.0- 4.0 sec 128 KBytes 1.05 Mbits/sec 0.025 ms 0/ 89 (0%)
[ 3] 4.0- 5.0 sec 128 KBytes 1.05 Mbits/sec 0.024 ms 0/ 89 (0%)
[ 3] 5.0- 6.0 sec 129 KBytes 1.06 Mbits/sec 0.024 ms 0/ 90 (0%)
[ 3] 6.0- 7.0 sec 128 KBytes 1.05 Mbits/sec 0.024 ms 0/ 89 (0%)
(...)
The multicast receiver is correctly receiving at 1 Mb/s.
Here is a non-working example (the source interface is not given, so iperf binds to the other one):
[root@VM2]~# iperf -s -u -B 239.1.1.1 -i 1
------------------------------------------------------------
Server listening on UDP port 5001
Binding to local address 239.1.1.1
Joining multicast group 239.1.1.1
Receiving 1470 byte datagrams
UDP buffer size: 41.1 KByte (default)
------------------------------------------------------------
(...)
No traffic is received and the server stays in "waiting" mode forever.
Checking pimd behavior¶
PIM neighbors¶
Do the PIM routers see each other?
root@VM2:~ # pimctl show
PIM Interface Table
Interface State Address Priority Hello Nbr DR Address DR Priority
vtnet0 Up 10.0.12.2 1 30 0 10.0.12.2 1
vtnet1 Up 10.0.23.2 1 30 1 10.0.23.3 1
PIM Neighbor Table
Interface Address Priority Mode Uptime/Expires
vtnet1 10.0.23.3 1 DR 0h2m51s/0h1m25s
Multicast Routing Table
Source Group RP Address Flags
10.0.12.1 239.1.1.1 10.0.23.2 SG
Number of Groups : 1
Number of Cache MIRRORs : 0
PIM Candidate Rendez-Vous Point Table
Group Address RP Address Prio Holdtime Expires
232.0.0.0/8 169.254.0.1 1 Forever Never
224.0.0.0/4 10.0.23.2 1 150 0h1m45s
Current BSR address: 10.0.23.3
PIM Rendez-Vous Point Set Table
Group Address RP Address Prio Holdtime Type
232.0.0.0/8 169.254.0.1 1 Forever Static
224.0.0.0/4 10.0.23.2 1 105 Dynamic
VM2 sees VM3 as a PIM neighbor.
root@VM3:~ # pimctl show
PIM Interface Table
Interface State Address Priority Hello Nbr DR Address DR Priority
vtnet1 Up 10.0.23.3 1 30 1 10.0.23.3 1
vtnet2 Up 10.0.34.3 1 30 0 10.0.34.3 1
PIM Neighbor Table
Interface Address Priority Mode Uptime/Expires
vtnet1 10.0.23.2 1 0h3m55s/0h1m15s
Multicast Routing Table
Source Group RP Address Flags
Number of Groups : 0
Number of Cache MIRRORs : 0
PIM Candidate Rendez-Vous Point Table
Group Address RP Address Prio Holdtime Expires
232.0.0.0/8 169.254.0.1 1 Forever Never
224.0.0.0/4 10.0.23.2 1 150 0h2m25s
Current BSR address: 10.0.23.3
PIM Rendez-Vous Point Set Table
Group Address RP Address Prio Holdtime Type
232.0.0.0/8 169.254.0.1 1 Forever Static
224.0.0.0/4 10.0.23.2 1 145 Dynamic
VM3 sees VM2 as a PIM Designated Router neighbor.
Does the PIM daemon register to the PIM multicast group?¶
A PIM router must register to the 224.0.0.13 multicast group. Check that all PIM routers list this group on their enabled interfaces:
[root@VM2]~# ifmcstat
vtnet0:
inet 10.0.12.2
igmpv2
group 224.0.0.22 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:16 refcnt 1
group 224.0.0.2 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:02 refcnt 1
group 224.0.0.13 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:0d refcnt 1
group 224.0.0.1 refcnt 1 state silent mode exclude
mcast-macaddr 01:00:5e:00:00:01 refcnt 1
inet6 fe80:1::a8aa:ff:fe00:212
mldv2 flags=2<USEALLOW> rv 2 qi 125 qri 10 uri 3
group ff01:1::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:1::2:54c6:805c refcnt 1
mcast-macaddr 33:33:54:c6:80:5c refcnt 1
group ff02:1::2:ff54:c680 refcnt 1
mcast-macaddr 33:33:ff:54:c6:80 refcnt 1
group ff02:1::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:1::1:ff00:212 refcnt 1
mcast-macaddr 33:33:ff:00:02:12 refcnt 1
vtnet1:
inet 10.0.23.2
igmpv2
group 224.0.0.22 refcnt 1 state sleeping mode exclude
mcast-macaddr 01:00:5e:00:00:16 refcnt 1
group 224.0.0.2 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:02 refcnt 1
group 224.0.0.13 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:0d refcnt 1
group 224.0.0.1 refcnt 1 state silent mode exclude
mcast-macaddr 01:00:5e:00:00:01 refcnt 1
inet6 fe80:2::a8aa:ff:fe02:202
mldv2 flags=2<USEALLOW> rv 2 qi 125 qri 10 uri 3
group ff01:2::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:2::2:54c6:805c refcnt 1
mcast-macaddr 33:33:54:c6:80:5c refcnt 1
group ff02:2::2:ff54:c680 refcnt 1
mcast-macaddr 33:33:ff:54:c6:80 refcnt 1
group ff02:2::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:2::1:ff02:202 refcnt 1
mcast-macaddr 33:33:ff:02:02:02 refcnt 1
[root@VM3]~# ifmcstat
em0:
em1:
inet 10.0.23.3
igmpv2
group 224.0.0.22 refcnt 1 state sleeping mode exclude
mcast-macaddr 01:00:5e:00:00:16 refcnt 1
group 224.0.0.2 refcnt 1 state sleeping mode exclude
mcast-macaddr 01:00:5e:00:00:02 refcnt 1
group 224.0.0.13 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:0d refcnt 1
group 224.0.0.1 refcnt 1 state silent mode exclude
mcast-macaddr 01:00:5e:00:00:01 refcnt 1
inet6 fe80:2::a8aa:ff:fe00:323
mldv2 flags=2<USEALLOW> rv 2 qi 125 qri 10 uri 3
group ff01:2::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:2::2:1124:9296 refcnt 1
mcast-macaddr 33:33:11:24:92:96 refcnt 1
group ff02:2::2:ff11:2492 refcnt 1
mcast-macaddr 33:33:ff:11:24:92 refcnt 1
group ff02:2::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:2::1:ff00:323 refcnt 1
mcast-macaddr 33:33:ff:00:03:23 refcnt 1
em2:
inet 10.0.34.3
igmpv2
group 224.0.0.22 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:16 refcnt 1
group 224.0.0.2 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:02 refcnt 1
group 224.0.0.13 refcnt 1 state lazy mode exclude
mcast-macaddr 01:00:5e:00:00:0d refcnt 1
group 224.0.0.1 refcnt 1 state silent mode exclude
mcast-macaddr 01:00:5e:00:00:01 refcnt 1
inet6 fe80:3::a8aa:ff:fe03:303
mldv2 flags=2<USEALLOW> rv 2 qi 125 qri 10 uri 3
group ff01:3::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:3::2:1124:9296 refcnt 1
mcast-macaddr 33:33:11:24:92:96 refcnt 1
group ff02:3::2:ff11:2492 refcnt 1
mcast-macaddr 33:33:ff:11:24:92 refcnt 1
group ff02:3::1 refcnt 1
mcast-macaddr 33:33:00:00:00:01 refcnt 1
group ff02:3::1:ff03:303 refcnt 1
mcast-macaddr 33:33:ff:03:03:03 refcnt 1
The multicast group 224.0.0.13 is correctly subscribed on PIM-enabled interfaces.
Testing¶
1. Start a multicast generator (iperf client) on VM1¶
Start an iperf client toward 239.1.1.1:
[root@VM1]~# iperf -c 239.1.1.1 -u -T 32 -t 3000 -i 1
------------------------------------------------------------
Client connecting to 239.1.1.1, UDP port 5001
Sending 1470 byte datagrams
Setting multicast TTL to 32
UDP buffer size: 9.00 KByte (default)
------------------------------------------------------------
[ 3] local 10.0.12.1 port 41484 connected with 239.1.1.1 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 129 KBytes 1.06 Mbits/sec
[ 3] 1.0- 2.0 sec 128 KBytes 1.05 Mbits/sec
[ 3] 2.0- 3.0 sec 128 KBytes 1.05 Mbits/sec
[ 3] 3.0- 4.0 sec 128 KBytes 1.05 Mbits/sec
2. Check that VM2 updates its mroute table with the discovered multicast source¶
The PIM daemon should be updated:
[root@VM2]~# pimctl -r
pimctl: Sending cmd show: No error: 0
PIM Interface Table
Interface State Address Priority Hello Nbr DR Address DR Priority
vtnet0 Up 10.0.12.2 1 30 0 10.0.12.2 1
vtnet1 Up 10.0.23.2 1 30 1 10.0.23.3 1
PIM Neighbor Table
Interface Address Priority Mode Uptime/Expires
vtnet1 10.0.23.3 1 DR 0h8m36s/0h1m40s
Multicast Routing Table
Source Group RP Address Flags
10.0.12.1 239.1.1.1 10.0.23.2 SPT SG
Number of Groups : 1
Number of Cache MIRRORs : 0
PIM Candidate Rendez-Vous Point Table
Group Address RP Address Prio Holdtime Expires
232.0.0.0/8 169.254.0.1 1 Forever Never
224.0.0.0/4 10.0.23.2 1 150 0h2m0s
Current BSR address: 10.0.23.3
PIM Rendez-Vous Point Set Table
Group Address RP Address Prio Holdtime Type
232.0.0.0/8 169.254.0.1 1 Forever Static
224.0.0.0/4 10.0.23.2 1 120 Dynamic
And the multicast routing table too:
[root@VM2]~# netstat -g
IPv4 Virtual Interface Table
Vif Thresh Local-Address Remote-Address Pkts-In Pkts-Out
0 1 10.0.12.2 0 0
1 1 10.0.12.2 18267 0
2 1 10.0.23.2 0 18267
IPv4 Multicast Forwarding Table
Origin Group Packets In-Vif Out-Vifs:Ttls
10.0.12.1 239.1.1.1 0 65535
IPv6 Multicast Interface Table is empty
IPv6 Multicast Forwarding Table is empty
VM2 has updated its mroute table to add a source for group 239.1.1.1 coming from ‘65535’ (?).
3. Start a multicast receiver (iperf server) on VM4¶
The iperf server subscribes to multicast group 239.1.1.1 and receives the multicast traffic:
[root@VM4]~# iperf -s -u -B 239.1.1.1 -i 1
------------------------------------------------------------
Server listening on UDP port 5001
Binding to local address 239.1.1.1
Joining multicast group 239.1.1.1
Receiving 1470 byte datagrams
UDP buffer size: 41.1 KByte (default)
------------------------------------------------------------
[ 3] local 239.1.1.1 port 5001 connected with 10.0.12.1 port 41484
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 3] 0.0- 1.0 sec 128 KBytes 1.05 Mbits/sec 0.313 ms 16336/16425 (99%)
[ 3] 1.0- 2.0 sec 128 KBytes 1.05 Mbits/sec 0.250 ms 0/ 89 (0%)
[ 3] 2.0- 3.0 sec 128 KBytes 1.05 Mbits/sec 0.307 ms 0/ 89 (0%)
[ 3] 3.0- 4.0 sec 128 KBytes 1.05 Mbits/sec 0.262 ms 0/ 89 (0%)
[ 3] 4.0- 5.0 sec 128 KBytes 1.05 Mbits/sec 0.188 ms 0/ 89 (0%)
[ 3] 5.0- 6.0 sec 129 KBytes 1.06 Mbits/sec 0.347 ms 0/ 90 (0%)
[ 3] 6.0- 7.0 sec 128 KBytes 1.05 Mbits/sec 0.238 ms 0/ 89 (0%)
[ 3] 7.0- 8.0 sec 128 KBytes 1.05 Mbits/sec 0.234 ms 0/ 89 (0%)
[ 3] 8.0- 9.0 sec 128 KBytes 1.05 Mbits/sec 0.241 ms 0/ 89 (0%)
[ 3] 9.0-10.0 sec 128 KBytes 1.05 Mbits/sec 0.210 ms 0/ 89 (0%)
[ 3] 10.0-11.0 sec 128 KBytes 1.05 Mbits/sec 0.289 ms 0/ 89 (0%)
[ 3] 11.0-12.0 sec 129 KBytes 1.06 Mbits/sec 0.309 ms 0/ 90 (0%)
4. Check that VM3 correctly notices this multicast subscriber¶
VM3’s mroute table is updated and knows it has a customer:
[root@VM3]~# pimctl -d
pimctl: Sending cmd show: No error: 0
PIM Interface Table
Interface State Address Priority Hello Nbr DR Address DR Priority
vtnet1 Up 10.0.23.3 1 30 1 10.0.23.3 1
vtnet2 Up 10.0.34.3 1 30 0 10.0.34.3 1
PIM Neighbor Table
Interface Address Priority Mode Uptime/Expires
vtnet1 10.0.23.2 1 0h14m40s/0h1m35s
Multicast Routing Table
Source Group RP Address Flags
ANY 239.1.1.1 10.0.23.2 WC RP
10.0.12.1 239.1.1.1 10.0.23.2 CACHE SG
Number of Groups : 1
Number of Cache MIRRORs : 1
PIM Candidate Rendez-Vous Point Table
Group Address RP Address Prio Holdtime Expires
232.0.0.0/8 169.254.0.1 1 Forever Never
224.0.0.0/4 10.0.23.2 1 150 0h2m25s
Current BSR address: 10.0.23.3
PIM Rendez-Vous Point Set Table
Group Address RP Address Prio Holdtime Type
232.0.0.0/8 169.254.0.1 1 Forever Static
224.0.0.0/4 10.0.23.2 1 145 Dynamic
And its multicast routing table is updated too:
[root@VM3]~# netstat -g
IPv4 Virtual Interface Table
Vif Thresh Local-Address Remote-Address Pkts-In Pkts-Out
0 1 10.0.23.3 0 0
1 1 10.0.23.3 30739 0
2 1 10.0.34.3 0 29215
IPv4 Multicast Forwarding Table
Origin Group Packets In-Vif Out-Vifs:Ttls
10.0.12.1 239.1.1.1 29215 1 2:1
IPv6 Multicast Interface Table is empty
IPv6 Multicast Forwarding Table is empty
VM3 correctly learns that there is a subscriber to group 239.1.1.1 on vif1 (toward VM4) and that the source is on vif0 (toward VM2).