Configuring Multicast routing (Part 4): PIM Assert, Designated Router, Null Register

We extend our previous topology with a few new routers to demostrate how the PIM Assert mechanism work.

Multicast Topology part 4

This time we configure PIM with dense-mode on all of the interfaces like this on CSR5:

CSR5(config)#int range g1 - 2
CSR5(config-if-range)#ip pim dense-mode 

R6, the receiver sends an IGMP Join for the group 239.1.1.1:

R6(config-if)#ip igmp join-group 239.1.1.1

Both CSR5 and CSR8 create a (*,G) entry in their mroute table:

CSR8(config)#do show ip mroute | sec 239
(*, 239.1.1.1), 00:02:50/00:02:50, RP 0.0.0.0, flags: DC
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
    GigabitEthernet2, Forward/Dense, 00:02:50/stopped
    GigabitEthernet1, Forward/Dense, 00:02:50/stopped

CSR5(config)#do show ip mroute | sec 239
(*, 239.1.1.1), 00:03:06/00:02:34, RP 0.0.0.0, flags: DC
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
    GigabitEthernet2, Forward/Dense, 00:03:06/stopped
    GigabitEthernet1, Forward/Dense, 00:03:06/stopped

Remember we use dense-mode here, so the routers don't build the (*,G) tree towards the RP, since we don't have an RP at all. Instead we use the flood and prune mechanism when R7 starts sending the multicast stream:

R7#ping 239.1.1.1 rep 10
Type escape sequence to abort.
Sending 10, 100-byte ICMP Echos to 239.1.1.1, timeout is 2 seconds:

Reply to request 0 from 10.0.56.6, 108 ms
Reply to request 0 from 10.0.56.6, 110 ms
Reply to request 1 from 10.0.56.6, 9 ms
Reply to request 2 from 10.0.56.6, 6 ms
Reply to request 3 from 10.0.56.6, 6 ms

PIM Assert

The multicast traffic eventually gets to the receiver as we can see, but let's focus on the last segment where our receiver is located (10.0.56.0/24): when the source starts sending the multicast stream both CSR5 and CSR8 forward the ICMP Echoes to the receiver since both have a (*,G) entry in their mroute table, so the receiver gets the first ICMP Echo twice. Look at the ICMP Replies: we received two replies for the first ICMP Echo (with sequence number 0). When CSR5 and CSR8 receive the multicast traffic of each other they trigger the PIM Assert mechanism: they elect a single PIM forwarder and the other router won't forward the multicast traffic, so our receiver won't receive duplicate packets. So CSR8 and CSR5 exchange PIM Assert messages to decide who will be the PIM Forwarder. Here is how a PIM Assert message looks like:

PIM Assert message sent by CSR8
PIM Assert message sent by CSR8

The PIM forwarder is elected based on the unicast routing table: the router with the lowest AD to the source (10.0.47.7) is preferred. Both routers are running OSPF with an AD of 110, if the ADs (Metric Preference in the PIM Assert) are equal the IGP metric is the next tiebreaker: both routers have a cost of 3 to the source. If we have the same IGP metric on both routers, we elect the PIM forwarder based on the highest IP address: CSR8's IP address (10.0.56.8) is higher, so CSR8 becomes the PIM Forwarder, and CSR5 stops flooding traffic on this segment, so that the receiver won't receive duplicate packets. Here is a debug from CSR5:

CSR5#debug ip pim
*Jul 25 08:33:26.390: PIM(0): Received v2 Assert on GigabitEthernet2 from 10.0.56.8
*Jul 25 08:33:26.390: PIM(0): Assert metric to source 10.0.47.7 is [110/3]
*Jul 25 08:33:26.390: PIM(0): We lose, our metric [110/3]
*Jul 25 08:33:26.390: PIM(0): Prune GigabitEthernet2/239.1.1.1 from (10.0.47.7/32, 239.1.1.1)
*Jul 25 08:33:26.390: PIM(0): Insert (10.0.47.7,239.1.1.1) prune in nbr 10.0.235.3's queue
*Jul 25 08:33:26.390: PIM(0): Insert (10.0.47.7,239.1.1.1) prune in nbr 10.0.56.8(GigabitEthernet2)'s queueold_nbr(10.0.235.3)(GigabitEthernet1)
*Jul 25 08:33:26.390: PIM(0): Insert (10.0.47.7,239.1.1.1) prune in nbr 10.0.56.8's queue
*Jul 25 08:33:26.390: PIM(0): Send (10.0.47.7, 239.1.1.1) PIM-DM prune to oif GigabitEthernet2 in Prune state
*Jul 25 08:33:26.390: PIM(0): (10.0.47.7/32, 239.1.1.1) oif GigabitEthernet2 in Prune state
*Jul 25 08:33:26.390: PIM(0): Building Join/Prune packet for nbr 10.0.56.8
*Jul 25 08:33:26.390: PIM(0):  Adding v2 (10.0.47.7/32, 239.1.1.1) Prune
*Jul 25 08:33:26.390: PIM(0): Send v2 join/prune to 10.0.56.8 (GigabitEthernet2)

CSR5 acknowledges CSR8 as the PIM Forwarder: *Jul 25 08:33:26.390: PIM(0): We lose, our metric [110/3] This is by the way one of the funniest debug message you can get on IOS (WE lose :( ). CSR5 prunes its G2 interface from his OIL:

CSR5#show ip mroute | sec 239
(*, 239.1.1.1), 01:22:21/stopped, RP 0.0.0.0, flags: DC
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
    GigabitEthernet2, Forward/Dense, 01:22:21/stopped
    GigabitEthernet1, Forward/Dense, 01:22:21/stopped
(10.0.47.7, 239.1.1.1), 00:02:39/00:00:20, flags: PT
  Incoming interface: GigabitEthernet1, RPF nbr 10.0.235.3
  Outgoing interface list:
    GigabitEthernet2, Prune/Dense, 00:02:39/00:00:22

Now let's make CSR5 the PIM Forwarder: we could do that by lowering the OSPF cost or lowering the AD of OSPF, but instead I'm going to create a static mroute towards the source (10.0.47.7):

CSR5(config)#ip mroute 10.0.47.7 255.255.255.255 10.0.235.3 ?
  <1-255>  Administrative distance for mroute
  <cr>     <cr>

CSR5(config)#ip mroute 10.0.47.7 255.255.255.255 10.0.235.3 10

Like with unicast static routes we can specifiy a custom AD (the default is 1), I created this static mroute with the AD of 10:

PIM Assert from CSR5
PIM Assert from CSR5 after configuring the static mroute

Because the CSR5's AD is lower, CSR5 will be elected as the PIM Forwarder:

CSR5#debug ip pim
PIM debugging is on
*Jul 25 08:51:42.578: PIM(0): Send v2 Assert on GigabitEthernet2 for 239.1.1.1, source 10.0.47.7, metric [10/0] 
*Jul 25 08:51:42.578: PIM(0): Assert metric to source 10.0.47.7 is [10/0]
*Jul 25 08:51:42.578: PIM(0): We win, our metric [10/0]
*Jul 25 08:51:42.578: PIM(0): (10.0.47.7/32, 239.1.1.1) oif GigabitEthernet2 in Forward state
*Jul 25 08:51:42.581: PIM(0): Received v2 Join/Prune on GigabitEthernet2 from 10.0.56.8, to us
*Jul 25 08:51:42.581: PIM(0): Prune-list: (10.0.47.7/32, 239.1.1.1) 
*Jul 25 08:51:42.582: PIM(0): Received v2 Join/Prune on GigabitEthernet1 from 10.0.235.8, not to us
*Jul 25 08:51:42.582: PIM(0): Prune-list: (10.0.47.7/32, 239.1.1.1) 

CS8#debug ip pim
PIM debugging is on
*Jul 25 08:51:42.586: PIM(0): Received v2 Assert on GigabitEthernet2 from 10.0.56.5
*Jul 25 08:51:42.587: PIM(0): Assert metric to source 10.0.47.7 is [10/0]
*Jul 25 08:51:42.587: PIM(0): We lose, our metric [110/3]
*Jul 25 08:51:42.587: PIM(0): Prune GigabitEthernet2/239.1.1.1 from (10.0.47.7/32, 239.1.1.1)
*Jul 25 08:51:42.587: PIM(0): Insert (10.0.47.7,239.1.1.1) prune in nbr 10.0.235.3's queue
*Jul 25 08:51:42.587: PIM(0): Insert (10.0.47.7,239.1.1.1) prune in nbr 10.0.56.5(GigabitEthernet2)'s queueold_nbr(10.0.235.3)(GigabitEthernet

CSR8 prunes its interface G2, and CSR5 forwards the multicast stream towards the receiver.

PIM Designated Router (DR)

I switched back to PIM SM with CSR1 as the RP, with this setup we're going to demonstrate why do we need a DR with PIM. Like OSPF, PIM elects a single DR per segment. Higher priority router is preferred to the lower priority, in case of a tie, the router with the highest IP address wins. How do routers learn about their neighbors priority? It's trasmitted in the PIM Hello messages:

PIM Hello
PIM Hello from CSR8 with a DR priority of 0

By default every router has the interface priority of 1. Because of this CSR8 gets elected as the DR on the receiver's segment (10.0.56.0/24). We can verify it with the following command:

CSR5(config)#do show ip pim neighbor
PIM Neighbor Table
Mode: B - Bidir Capable, DR - Designated Router, N - Default DR Priority,
      P - Proxy Capable, S - State Refresh Capable, G - GenID Capable,
      L - DR Load-balancing Capable
Neighbor          Interface                Uptime/Expires    Ver   DR
Address                                                            Prio/Mode
10.0.235.8        GigabitEthernet1         02:02:05/00:01:38 v2    1 / DR S P G
10.0.235.2        GigabitEthernet1         02:08:45/00:01:43 v2    1 / S P G
10.0.235.3        GigabitEthernet1         02:08:45/00:01:43 v2    1 / S P G
10.0.56.8         GigabitEthernet2         02:02:05/00:01:42 v2    1 / DR S P G

What's the role of the DR? It's very easy: the DR is responsible for sending the PIM Join and build the (*,G) tree towards the RP. Here is the mroute tables of CSR5 and CSR8, we can see that the OIL of CSR5 is empty:

CSR5#show ip mroute | sec 239
(*, 239.1.1.1), 00:22:19/00:02:41, RP 10.1.1.1, flags: SP
  Incoming interface: GigabitEthernet1, RPF nbr 10.0.235.3
  Outgoing interface list: Null

CS8(config)#do show ip mroute | sec 239
(*, 239.1.1.1), 00:22:02/00:02:58, RP 10.1.1.1, flags: SJC
  Incoming interface: GigabitEthernet1, RPF nbr 10.0.235.3
  Outgoing interface list:
    GigabitEthernet2, Forward/Sparse, 00:03:47/00:02:58

Let's say instead of CSR8, we want CSR5 to be the DR, we can change the roles by increasing the interface priority on CSR5 like this:

CSR5(config-if)#ip pim dr-priority 500
*Jul 25 09:25:17.880: PIM(0): Changing DR for GigabitEthernet2, from 10.0.56.8 to 10.0.56.5 (this system)
*Jul 25 09:25:17.880: %PIM-5-DRCHG: DR change from neighbor 10.0.56.8 to 10.0.56.5 on interface GigabitEthernet2

Now CSR5 sends the PIM Join towards the RP:

PIM Join sent by the DR
PIM (*,G) Join sent by CSR5 towards the RP to build the shared tree

CSR8 doesn't send PIM Join, the shared tree is built from the RP to CSR5. Besides sending the PIM Join from the receivers side, the PIM DR is also responsible for sending the PIM Register messages from the side of the source if we have multiple routers.

PIM Null Registers

Finally let's discuss one more thing that I've missed from the spare-mode post. What happens if we don't have any interested receivers for a multicast stream? None of the PIM routers have received an IGMP Join message for a given group, still the source sends the stream. As we have seen in the previous post the first packet is encapsulated in a unicast packet and sent to the RP by the FHR, if we have any interested receivers the RP builds the (S,G) tree towards the FHR and the multicast stream starts flowing natively. If we don't have any interested receivers the FHR still keeps sending the PIM Register packets as unicast towards the RP:

PIM Register Null packets
PIM Register-Null packets sent by the FHR to the RP

These are called Null-Register packets, because they are empty, they doesn't carry any payload. Their purpose is basically to notify the RP periodically that there is a source for the given multicast group. If the RP doesn't have a (*,G) entry for this group it simply refuses the Register packet with a Register-Stop (like in the example above). If it does it builds the (S,G) tree towards the FHR with a PIM Join, and once the multicast traffic starts flowing natively it sends a Register-Stop to the FHR to stop the unicast stream.