Configuring Multicast routing with PIM Sparse-Mode (Part 2): RPF checks, static mroute

We continue the previous multicast lab. This time we take a look at how RPF check works, how we can prevent RPF failures, and how we can fix RPF issues with static mroutes.

Multicast Topology
Multicast Topology with PIM Sparse-Mode

PIM uses RPF checks to prevent multicast routing loops. If a router receives a multicast packet it does the following: it checks the source IP address of the packet and compares it against its unicast routing table. If the multicast packet arrived on the same interface which the router uses to reach the source IP address then the RPF check passes, otherwise the RPF check fails. So PIM uses the unicast routing table to do the RPF check, PIM doesn't care which routing protocol populates the routing table hence the name Protocol Independent Multicast.

Now we demonstrate how RPF check works, and cause an RPF failure on CSR5. The RPF neighbor of CSR5 is CSR3 to reach the source:

CSR5#show ip rpf 10.0.47.7
RPF information for ? (10.0.47.7)
  RPF interface: GigabitEthernet1
  RPF neighbor: ? (10.0.235.3)
  RPF route/mask: 10.0.47.0/24
  RPF type: unicast (ospf 1)
  Doing distance-preferred lookups across tables
  RPF topology: ipv4 multicast base, originated from ipv4 unicast base

CSR5 checks its unicast routing table and determines that it should go to CSR3 (10.0.235.3) to reach the source, in this case we used OSPF as the IGP to populate the routing table. So after the initial multicast packet (which goes though the RP) if we switch to the source tree we should receive the multicast stream through CSR3 (CSR4 -> CSR3 -> CSR5) according to OSPF (in this topology every interface has a cost of 1 by default). Now let's disable PIM on CSR3 and see what happens:

CSR3(config)#int range g1 - 2
CSR3(config-if-range)#no ip pim sparse-mode 

And let's send multicast from R7 to 239.1.1.1, to the group which R6 has joined before with the IGMP Membership Report:

R7_SOURCE#ping 239.1.1.1 repeat 999
Type escape sequence to abort.
Sending 999, 100-byte ICMP Echos to 239.1.1.1, timeout is 2 seconds:

Reply to request 0 from 10.0.56.6, 36 ms..............................................

We see that after the first multicast packet the multicast stream starts failing. That's because the first packet goes though the RP and from the RP through the (*,G) shared tree. After the SPT switchover (R6 learns the address of the source) CSR5 tries to build the source tree (shortest path tree) towards CSR3, because that's the shortest path towards the source according to the IGP. We can also verify it with a traceroute:

CSR5#traceroute 10.0.47.7 numeric
Type escape sequence to abort.
Tracing the route to 10.0.47.7
VRF info: (vrf in name/id, vrf out name/id)
  1 10.0.235.3 2 msec 1 msec 2 msec
  2 10.0.134.4 2 msec 3 msec 3 msec
  3 10.0.47.7 18 msec *  3 msec

So by default PIM and the (S,G) tree follows the IGP path, if PIM is not enabled everywhere on the IGP path we can have RPF issues. That's true for the (S,G) tree but also for the (*,G) shared tree as well. This time the RPF checks fails on CSR5 against the source tree. 

PIM SM RPF failure
RPF failure: PIM is not enabled on the (S,G) tree 

Actually some pings get to the destination after some time and then it starts failing again:

R7_SOURCE#ping 239.1.1.1 repeat 999
Type escape sequence to abort.
Sending 999, 100-byte ICMP Echos to 239.1.1.1, timeout is 2 seconds:

Reply to request 0 from 10.0.56.6, 36 ms.....................................................................
................
Reply to request 86 from 10.0.56.6, 39 ms..................…

That's because the the (*,G) tree is rebuilt from time to time periodically (around every 3 minutes by default), and some packets reach CSR5 through the RP. So how can we rectify this issue? The obvious solution is very easy: enable PIM on every OSPF interface, and we'll never have RPF issues. Now we won't do that. To demonstrate how RPF checks are performed on CSR5 let's manipulate the IGP to fix the issue. If we increase the OSPF cost on CSR3:

CSR3(config-if-range)#int g1
CSR3(config-if)#ip ospf cost 100

Now from CSR5's point of view the RPF neighbor is CSR2:

CSR5#traceroute 10.0.47.7 num
Type escape sequence to abort.
Tracing the route to 10.0.47.7
VRF info: (vrf in name/id, vrf out name/id)
  1 10.0.235.2 2 msec 2 msec 1 msec
  2 10.0.12.1 2 msec 2 msec 2 msec
  3 10.0.134.4 3 msec 3 msec 3 msec
  4 10.0.47.7 4 msec *  5 msec

And the shortest path tree is built towards CSR2 (CSR5 -> CSR2 -> CSR1 -> CSR4), and the pings start working again:

R7_SOURCE#ping 239.1.1.1 repeat 999
Type escape sequence to abort.
Sending 999, 100-byte ICMP Echos to 239.1.1.1, timeout is 2 seconds:

Reply to request 0 from 10.0.56.6, 36 ms.....................................................................
................
Reply to request 86 from 10.0.56.6, 39 ms.....................................................
....
Reply to request 144 from 10.0.56.6, 7 ms
Reply to request 145 from 10.0.56.6, 6 ms
Reply to request 146 from 10.0.56.6, 5 ms
Reply to request 147 from 10.0.56.6, 6 ms
Reply to request 148 from 10.0.56.6, 6 ms

That's one solution to modify the OSPF path towards the source so that the RPF neighbor will also change. Now I change back the OSPF cost on CSR3:

CSR3(config-if)#no ip ospf cost 100

The pings start failing again of course. A much better solution is to create a static mroute. This works very similarly to the unicast static routes: we basically manually overwrite the RPF check. Not OSPF but we define who the RPF neighbor should be for CSR5:

CSR5(config)#ip mroute 10.0.47.7 255.255.255.255 10.0.235.2

We tell CSR5 that for the source 10.0.47.7 (only for this exact source because we've used the /32 mask) the RPF neighbor is CSR2 (10.0.235.2). If we issue the show ip rpf command again for the source:

CSR5(config)#do show ip rpf 10.0.47.7
RPF information for ? (10.0.47.7)
  RPF interface: GigabitEthernet1
  RPF neighbor: ? (10.0.235.2)
  RPF route/mask: 10.0.47.7/32
  RPF type: multicast (static)
  Doing distance-preferred lookups across tables
  RPF topology: ipv4 multicast base

We can see that the RPF neighbor has changed: the static mroute has overwritten the OSPF route. And we start receiving the pings again:

Reply to request 150 from 10.0.56.6, 5 ms..........................................................
Reply to request 209 from 10.0.56.6, 5 ms
Reply to request 210 from 10.0.56.6, 5 ms
Reply to request 211 from 10.0.56.6, 5 ms

This is how we can fix RPF issues. But the most straighforward solution is to simply enable PIM on every OSPF interface. Notice that this time the RPF failure was on the (S,G) tree, if we simply turn off the SPT switchover on CSR5, the router won't simply build the (S,G) tree and the multicast traffic will flow on the (*,G) tree from the RP:

CSR5(config)#ip pim spt-threshold ?
  0         Always switch to source-tree
  infinity  Never switch to source-tree

CSR5(config)#ip pim spt-threshold infinity

But if the RPF failure is on the shared tree this solution does obviously not work.