Showing posts with label hsrp. Show all posts
Showing posts with label hsrp. Show all posts

Monday, 20 April 2015

DHCP, RPF verify, FHRP and ECMP - when protocols collide

I've been gradually enabling ECMP (Equal-Cost MultiPath) routing on parts of the University network as part of a prelude to the new data centre network and to improve performance generally (by making use of the dual downstream interfaces into institutions).

For the most part, this is fairly straightforward and just worked - I'll explain what was needed in each case in a future post (as MPLS VPN works slightly differently and needs some special consideration), but I did get a nasty problem which broke DHCP relaying in some places that I'll cover here.

How DHCP relaying works


First, let's review how DHCP relaying works (what you get when you do ip helper-address ... on a Cisco router interface towards clients).  Consider the following network:
When a client on the subnet 192.168.1.0/24 wants to DHCP, the following happens initially:
  1. The client sends out a DHCP DISCOVER message from 0.0.0.0 (as it doesn't know its IP address or even subnet, yet) on UDP port 68 (the DHCP client port) to all-hosts broadcast (255.255.255.255) port 67 (DHCP server).
  2. The DHCP relay agent (which is normally the router) will receive this broadcast and forward it as a unicast packet to the DHCP server listed in the ip helper-address ... interface command.  This will be from the router's interface address (this is the critical bit) - 192.168.1.253, in the above example, port 67 to the DHCP server, port 67.
  3. The DHCP server will receive the DISCOVER and, assuming it has an address (and other information) to give to the client, it will send a DHCP OFFER message back to the router to be relayed onto it.  This will be the reverse of the packet just received: going from the DHCP server's address, port 67 to the router's interface address, port 67.
  4. The router will receive the reply and unicast it back to the client, sending it from its interface IP address, port 67 to the client's prospective IP address, port 68.
This all works fine and, assuming the client wants to take the address, it will send a DHCP REQUEST (using the same process) and receive a DHCP ACK back from the server so it can begin using the address.

How DHCP relaying doesn't work


Now consider what happens when the same DHCP DISCOVER is relayed by the other client subnet router, without ECMP:
Here, something goes wrong at step 3, trying to return the DHCP OFFER to the relaying router:
  1. Because the backbone network (depicted with the cloud symbol) only knows about routing to the client subnet as a whole /24 (not the individual routers' addresses), it routes the packet via 192.168.1.253.
  2. 192.168.1.253 treats 192.168.1.252 as just another host on the client subnet and forwards it out of its interface onto that subnet.
  3. Because 192.168.1.252 has anti-spoofing blocks in place on the client subnet interface, it rejects this packet as the source address is that of the DHCP server: an invalid address from the client subnet.
With this configuration, typical for a network with a FHRP (First Hop Redundancy Protocol) such as HSRP or VRRP is in use, half of the DHCP replies (the ones relayed via one of the two routers) will be lost when they're returned to the relaying routers.

However, this in itself isn't particularly a problem in that both routers will relay the same packet to the DHCP server, resulting it receiving two copies of each DISCOVER [but with different relay agent / forwarder addresses], causing two OFFERs to be returned; the clients will not miss out as they'll get one of the two copies.  This is why I've never noticed this problem, even though it's been going on for years: the clients have still got their address and worked.

(Actually, I was sort-of aware of this problem, as it prevented pinging one of the routers' own addresses on a particular interface, if the source of the ping was elsewhere on the network.  However, that's just been a minor inconvenience and not service-affecting; I never realised that would also be affecting DHCP.)

Combining with ECMP


When this situation is combined with ECMP this can get messy: the returned DHCP OFFERs (and ACKs) might be returned to either of the two client subnet routers.  The routers' addresses are often 1 number offset (e.g. 192.168.1.252 vs .253) which will likely mean they each take a different path.

If the path for packets to the .253 relay address happen to go directly to the .253 router, all is fine.  Same with .252.

However, if you're really unlucky (and, of course, we were, in some situations), ECMP will return the .253 packet via the .252 router and the .252 packet via .253.  This results in both replies being rejected and the client getting neither of the responses.

Fixing the problem and creating another


I couldn't find any way to direct the replies back to the correct router (e.g. by advertising the router's interface IP address into OSPF as a /32), so dealing with them being rejected by the anti-spoofing protection seemed the only solution.

As I've written, I've been looking at the ip verify unicast source ... command recently, and it seemed a good opportunity to employ that, rather than modify lots of access control lists.  According to Cisco's documentation, that command has a special feature in to handle DHCP:
"Unicast RPF will allow packets with 0.0.0.0 source and 255.255.255.255 destination to pass so that Bootstrap Protocol (BOOTP) and Dynamic Host Configuration Protocol (DHCP) functions work properly."
— from the IOS Security Configuration Guide for IOS 12.2SX
Sounds good, except that doesn't handle the source addresses of relayed DHCP replies.  It would be nice if this included "packets with a source address of the interface ip helper-address and port 67, destined for the router's interface address port 67", but it doesn't.

However, the command has a feature to allow packets matching an access list to be accepted, even if they fail the RPF check.  It's configured as follows:

ip access-list extended 1301
 permit udp host DHCP-SERVER eq 67 192.168.1.0 0.0.0.255 eq 67
!
interface ...
 ip address 192.168.1.253 255.255.255.0
 standby ip 192.168.1.254
 ip verify unicast source reachable-via rx 1301

This will allow the initial DHCP DISCOVER in (as described in the Cisco documentation), regular 192.168.1.0/24 traffic (due to the RPF check) AND traffic from the DHCP server on port 67 to an address on the same subnet port 67 (which is less tedious than putting the interface IP address itself as it can be copied to the other router without modification).  This change can be combined with a simplification of the interface access lists (if used).  So, I implemented a few of these and all looked hunky dory.

The IP Input process - my old nemesis


However, a little while later, we started getting alarms for CPU usage on the Catalyst 6500-E routers.  A show process cpu sorted command showed high load caused by the IP Input process.

This is usually caused by excessive traffic being forwarded ("punted" in Cisco parlance) to the Route Processor (RP) for handling.  We can capture and display these with the following commands:

router# debug netdr capture rx
router# show netdr captured-packets

(Use debug netdr clear-capture to clear the buffer and our old friend undebug all to switch it off.)

The packets being punted all appeared to be regular data - nothing complicated like DHCP which needs special processing, so I started doing some more reading and found a document on Cisco's website explaining how this configuration is handled on a 6500:
"For unicast RPF check without ACL filtering, the PFC3 provides hardware support for the RPF check of traffic from multiple interfaces. 
For unicast RPF check with ACL filtering, the PFC determines whether or not traffic matches the ACL. The PFC sends the traffic denied by the RPF ACL to the route processor (RP) for the unicast RPF check. Packets permitted by the ACL are forwarded in hardware without a unicast RPF check." 
— from the IOS Network Security guide for IOS 12.2SX on Catalyst 6500 with PFC3
So it appears that, when you use an ACL, all the traffic not matching the ACL will get punted to the RP.  Excellent.

Fixing the problem for good


So, I backtracked on using the ip verify unicast ... command and reverted to using our old inbound access lists to protect against address spoofing.  These now have an extra entry and look as follows:

ip access-list extended in-subnet
 permit ip 192.168.1.0 0.0.0.255 any
 permit udp any eq bootpc host 255.255.255.255 eq bootps
 permit udp host DHCP-SERVER eq bootps 192.168.1.0 0.0.0.255 eq bootps
 deny ip any any

This appears to do the trick and doesn't involve the RP on the router going bananas.  Given this problem, I think I'll abandon using the ip verify unicast ... command!

(Update 2018-02-01 — we have since installed Catalyst 6807-XLs with Supervisor 6Ts and came up with a final solution.  I've described that on a separate blog post.)

Friday, 27 March 2015

NAT in a VRF on a 7200 (in GNS3)

An interesting aside here — I've been updating my GNS3 model of the University of Cambridge network to include a second connection to Janet (the UK Education and Research network).  We want to run the links and NAT boxes (which are ASA5580-20s) in active-active mode so I've had to add those.

I can't be bothered trying to wrestle with a pair of ASAs in multi-context mode (which you need for active-active) so I looked at using NAT under IOS on a 7200 (the platform we use as the router equivalent of our Catalyst 6500-Es in GNS3).  I don't need stateful switchover, but I do want the basic service to failover in the simulation.

This turns out to be very simple as the 7200s support NAT in VRFs and we can use HSRP to do the active-active balancing.

Background

CUDN border and NAT from GNS3
Our NAT service works by putting an ASA on a stick, attached to the border routers.  Some PBR (Policy Based Routing) redirects traffic destined for the internet (via Janet) to the ASA that comes from University-wide private addresses (which are RFC1918 addresses we route internally and NAT when they leave).

This arrangement means that only traffic to be NATed needs to go through the ASAs: IPv4 public IP addresses and IPv6 flow straight through, so we don't have to worry about handling those, which not only reduces load on the ASAs but also means we don't have to work out how to get things like multicast through them.

There are two ASAs operating in a pair, handling roughly half of the private addresses each.  This is done by putting half of the private addresses through one context, normally active on one box, and the other half through a second context, normally active on the other.  If either fail, one ASA takes over all the load.

The inside of the ASAs is on a /29 link subnet with static routing: the ASAs provide a redundant first hop address for traffic to them for the router to redirect traffic two.  The outside is a /24 block to provide a pool of public IP addresses to NAT behind.  That subnet is a effectively a regular client subnet.

NATed traffic coming back in goes to the public range, gets de-NATed by the ASAs and sent back into the network on the inside /29.

The router provides first hop redundant gateways on both the inside and outside networks, although in practice there is only one at present.

There are separate inside /29s and outside /24s for each half of the private addresses to be NATed.

In the GNS3 simulation, we're going to replace the ASAs with IOS routers doing NAT.

Router configuration

The configuration of the routers doing the PBR is identical to the real production ones.

First, we create the interfaces to link to the NAT - this is the configuration for the first router, which is going to handle the outside range 131.111.184.0/24 by default (the other outside range will go through 131.111.185.0/24 to load balance - see the BGP configuration later):

interface Ethernet1/2.1981
 description nat-1-outside
 encapsulation dot1Q 1981
 ip address 131.111.184.253 255.255.255.0
 no ip proxy-arp
 standby version 2
 standby 81 ip 131.111.184.254
 standby 81 timers 1 3
 standby 81 priority 200
 standby 81 preempt
 standby 81 track 30 decrement 50
!
interface Ethernet1/2.1982
 description nat-1-inside
 encapsulation dot1Q 1982
 ip address 193.60.92.34 255.255.255.248
 no ip proxy-arp
 standby version 2
 standby 82 ip 193.60.92.33
 standby 82 timers 1 3
 standby 82 priority 200
 standby 82 preempt
 standby 82 track 30 decrement 50
!
interface Ethernet1/2.1983
 description nat-2-outside
 encapsulation dot1Q 1983
 ip address 131.111.185.253 255.255.255.0
 no ip proxy-arp
 standby version 2
 standby 83 ip 131.111.185.254
 standby 83 timers 1 3
 standby 83 priority 190
 standby 83 preempt
 standby 83 track 30 decrement 50
!
interface Ethernet1/2.1984
 description nat-2-inside
 encapsulation dot1Q 1984
 ip address 193.60.92.42 255.255.255.248
 no ip proxy-arp
 standby version 2
 standby 84 ip 193.60.92.41
 standby 84 timers 1 3
 standby 84 priority 190
 standby 84 preempt
 standby 84 track 30 decrement 50

Then we create access lists to match the private address to be NATed - we use all of 172.16.0.0/12, except for 172.31.0.0/16 (don't ask!):

ip access-list extended nat-1_clients
 deny   ip any 128.232.0.0 0.0.255.255
 deny   ip any 129.169.0.0 0.0.255.255
 deny   ip any 131.111.0.0 0.0.255.255
 deny   ip any 192.18.195.0 0.0.0.255
 deny   ip any 193.60.80.0 0.0.15.255
 deny   ip any 193.63.252.0 0.0.1.255
 permit ip 172.16.0.0 0.7.255.255 any
 deny   ip any any
!
ip access-list extended nat-2_clients
 deny   ip any 128.232.0.0 0.0.255.255
 deny   ip any 129.169.0.0 0.0.255.255
 deny   ip any 131.111.0.0 0.0.255.255
 deny   ip any 192.18.195.0 0.0.0.255
 deny   ip any 193.60.80.0 0.0.15.255
 deny   ip any 193.63.252.0 0.0.1.255
 permit ip 172.24.0.0 0.3.255.255 any
 permit ip 172.28.0.0 0.1.255.255 any
 permit ip 172.30.0.0 0.0.255.255 any
 deny   ip any any

We then create the route-maps to do PBR and redirect traffic across the /29 'inside' links:

route-map nat_redirect permit 110
 match ip address nat-1_clients
 set ip next-hop 193.60.92.38
!
route-map nat_redirect permit 120
 match ip address nat-2_clients
 set ip next-hop 193.60.92.46

... and attach them to the inside interfaces (linking to the core routers):

interface Ethernet1/0
 description CORE-CENT
 ip policy route-map nat_redirect
!
interface Ethernet1/1
 description CORE-MILL
 ip policy route-map nat_redirect

I mentioned we were going to use this router to handle the outside range 131.111.184.0/24 and the other 131.111.185.0/24.  To steer inbound traffic via this router, we want to advertise that prefix to Janet explicitly, so we need to add this to our BGP configuration:

router bgp 64602
 address-family ipv4 unicast
  network 131.111.184.0 mask 255.255.255.0
 exit-address-family
 !
 address-family ipv4 multicast
  network 131.111.184.0 mask 255.255.255.0
 exit-address-family

And also add that range to the outbound prefix list - I've created a new prefix-list under a specific name as I think it best to keep lists the same across routers, if their names are the same - these are not, so I've changed it on each:

ip prefix-list janetc-out_prefixes seq 5 permit 128.232.0.0/16
ip prefix-list janetc-out_prefixes seq 10 permit 129.169.0.0/16
ip prefix-list janetc-out_prefixes seq 15 permit 131.111.0.0/16
ip prefix-list janetc-out_prefixes seq 20 permit 192.18.195.0/24
ip prefix-list janetc-out_prefixes seq 25 permit 192.84.5.0/24
ip prefix-list janetc-out_prefixes seq 30 permit 192.153.213.0/24
ip prefix-list janetc-out_prefixes seq 35 permit 193.60.80.0/20
ip prefix-list janetc-out_prefixes seq 40 permit 193.63.252.0/23
ip prefix-list janetc-out_prefixes seq 45 permit 131.111.184.0/24

Finally, you may have spotted the track directive to HSRP above, in the interface definitions.  This is to cause HSRP to lower its priority, if this router loses direct connectivity to Janet.  The 7200 can't track the metric of a BGP router (unlike a Catalyst 6500), so I've just made it track the interface connecting to Janet:

track 30 interface Ethernet1/3 ip routing

This causes the gateways on the outside and inside interfaces to be handled by the router which has the best connectivity to Janet.

NAT configuration

The 7200 supports NAT in VRFs - while we don't strictly need to use them, it is a nice way of keeping the routing tables for the two NAT context separate (otherwise it wouldn't be clear which outside gateway was going to be used as the default route back to the router to go on to Janet).

First, create the VRFs:

vrf definition nat-1_vrf
 rd 64602:1981
 address-family ipv4
 exit-address-family
!
vrf definition nat-2_vrf
 rd 64602:1983
 address-family ipv4
 exit-address-family

Then some access lists to identify the clients to be NATed:

ip access-list standard nat-1-clients
 permit 172.16.0.0 0.7.255.255
!
ip access-list standard nat-2-clients
 permit 172.24.0.0 0.3.255.255
 permit 172.28.0.0 0.1.255.255
 permit 172.30.0.0 0.0.255.255

Create the two NAT pools and mappings (note the 'vrf' option and  'match-in-vrf' which is essential when using VRFs):

ip nat pool nat-1c-pool 131.111.184.1 131.111.184.1 netmask 255.255.255.0
ip nat inside source list nat-1-clients pool nat-1c-pool vrf nat-1_vrf match-in-vrf overload
!
ip nat pool nat-2c-pool 131.111.185.1 131.111.185.1 netmask 255.255.255.0
ip nat inside source list nat-2-clients pool nat-2c-pool vrf nat-2_vrf match-in-vrf overload

The configure the outside and inside interfaces, putting them in the appropriate VRFs and configuring NAT.  Note that we need HSRP (with different priorities across both contexts, to balance load) on the inside as that is used as a static route destination by the connecting router.  However, we don't need this on the outside as we're using different outside addresses on each router (131.111.184.2 and 131.111.185.2, respectively):

interface Ethernet1/0.1981
 description nat-1-outside
 vrf forwarding nat-1_vrf
 encapsulation dot1Q 1981
 ip address 131.111.184.250 255.255.255.0
 no ip proxy-arp
 ip nat outside
!
interface Ethernet1/0.1982
 description nat-1-inside
 vrf forwarding nat-1_vrf
 encapsulation dot1Q 1982
 ip address 193.60.92.37 255.255.255.248
 no ip proxy-arp
 ip nat inside
 standby version 2
 standby 162 ip 193.60.92.38
 standby 162 timers 1 3
 standby 162 priority 200
 standby 162 preempt
!
interface Ethernet1/0.1983
 description nat-2-outside
 vrf forwarding nat-2_vrf
 encapsulation dot1Q 1983
 ip address 131.111.185.250 255.255.255.0
 ip nat outside
!
interface Ethernet1/0.1984
 description nat-2-inside
 vrf forwarding nat-2_vrf
 encapsulation dot1Q 1984
 ip address 193.60.92.45 255.255.255.248
 no ip proxy-arp
 ip nat inside
 standby version 2
 standby 164 ip 193.60.92.46
 standby 164 timers 1 3
 standby 164 priority 190
 standby 164 preempt

Finally, a bit of static routing for the inside and outside destinations, across both VRFs:

ip route vrf nat-1_vrf 0.0.0.0 0.0.0.0 Ethernet1/0.1981 131.111.184.254
ip route vrf nat-1_vrf 172.16.0.0 255.248.0.0 Ethernet1/0.1982 193.60.92.33
ip route vrf nat-1_vrf 172.24.0.0 255.252.0.0 Ethernet1/0.1982 193.60.92.33
ip route vrf nat-1_vrf 172.28.0.0 255.254.0.0 Ethernet1/0.1982 193.60.92.33
ip route vrf nat-1_vrf 172.30.0.0 255.255.0.0 Ethernet1/0.1982 193.60.92.33
!
ip route vrf nat-2_vrf 0.0.0.0 0.0.0.0 Ethernet1/0.1983 131.111.185.254
ip route vrf nat-2_vrf 172.16.0.0 255.248.0.0 Ethernet1/0.1984 193.60.92.41
ip route vrf nat-2_vrf 172.24.0.0 255.252.0.0 Ethernet1/0.1984 193.60.92.41
ip route vrf nat-2_vrf 172.28.0.0 255.254.0.0 Ethernet1/0.1984 193.60.92.41
ip route vrf nat-2_vrf 172.30.0.0 255.255.0.0 Ethernet1/0.1984 193.60.92.41

And that's all there is to it!

This doesn't give stateful failover (preserving translations), but my simulation only needs to pass traceroutes and pings, so it seems a lot of unnecessary work, as that's completely different on the ASAs.

Sunday, 25 August 2013

PIM-SM and multiple edge routers - suboptimal forwarding

I had a problem reported by Martyn Johnson in the University Computer Laboratory (CL) regarding multicast (running PIM-SM) - he had a host on a subnet (by "subnet", I mean a VLAN or other layer 2 domain which might have multiple unicast subnets, of course) which had subscribed to a multicast group; the subnet had redundant routers (using HSRP, I guess, but maybe VRRP) and traffic was being forwarded onto the network by the least optimal of these routers:



The multicast source - server "S" - (top left - 1.3.0.2 in my example, sending to group 239.0.0.1) was actually somewhere across the University backbone and from the internet and was sourced via MSDP, but the principle is the same: the traffic was coming in via R1 (which was also the RP), over to R2 and then being forwarded on to the member/receiver - host "M" (bottom left):

R1#show ip mroute 239.0.0.1
...

(*, 239.0.0.1), 00:08:34/stopped, RP 1.9.0.1, flags: S
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
    Ethernet1/0, Forward/Sparse, 00:07:44/00:02:38

(1.3.0.2, 239.0.0.1), 00:00:23/00:03:27, flags: T
  Incoming interface: Ethernet1/2, RPF nbr 0.0.0.0
  Outgoing interface list:
    Ethernet1/0, Forward/Sparse, 00:00:23/00:03:06

And R2:

R2#show ip mroute 239.0.0.1

(*, 239.0.0.1), 00:08:38/stopped, RP 1.9.0.1, flags: SJC
  Incoming interface: Ethernet1/0, RPF nbr 1.1.0.1
  Outgoing interface list:
    Ethernet1/1, Forward/Sparse, 00:08:38/00:02:22

(1.3.0.2, 239.0.0.1), 00:00:27/00:02:51, flags: JT
  Incoming interface: Ethernet1/0, RPF nbr 1.1.0.1
  Outgoing interface list:
    Ethernet1/1, Forward/Sparse, 00:00:27/00:02:32

The optimal path would be directly from R1 onto the subnet: I would have expected R1 to detect R2 sending traffic out onto the subnet and send a PIM Assert, then win that to be the forwarder for that source on that subnet.  However, that didn't happen.

The PIM DR

I had to remind myself how all this worked and then, of course, realised I didn't understand it as well as I thought I did.

First up, I got a bit muddled with IGMP, but after a bit of re-reading, answered one of my long-standing queries that the IGMP Querier has nothing to do with the actual multicast forwarding router (at least for IGMPv2 onwards - in IGMPv1 there is no mechanism to elect a Querier, so the choice of that is left up to the multicast routing protocol).  IGMPv2 has no way to force the selection of a Querier but defaults to the router with the highest IP address.

Then there's the PIM-SM - that elects a DR on a subnet which will, by default, be responsible for forwarding traffic onto that subnet - this defaults to the PIM router with the lowest IP address.  The reason these two differ is the distribute the work of supporting multicast on a subnet, but it's important to remember that the PIM DR is the one that actually forwards the traffic for directly-connected members; the IGMP Querier is just responsible for soliciting periodical group membership from receivers.  You can force a particular router to be the PIM DR by setting the DR priority (ip pim dr-priority ...).

You can check these both with show ip igmp interface ... | inc router - or you can just look at the PIM stuff with show ip pim interface.

The DR is also responsible for forwarding received multicast traffic from the directly-connected subnet onto the routed backbone network, but that can change when the Shortest Path Tree (SPT) is built later.

So, in Martyn's case I guessed (but haven't verified yet) that the IGMP Querier would be R1 and the PIM DR would be R2.

So, when M sends an IGMP Membership Report (colloquially "IGMP Join") then R2 is the one which responds by joining the shared tree for and forwarding traffic onto the subnet.  Once the traffic started flowing, R2 joins the SPT for each source, which it did.

Here, it's important to remember that R2 will still be the DR serving the M's subnet: even if the SPT results in a shorter path to the source, it will still be begun (at the receiving end) from DR:

  • the shared tree starts at the DR for the source's subnet and goes up to the RP, then down to the DRs for the members' subnets
  • the SPT starts at the receiver's subnet's DR and uses the RPF table to connect it back to a PIM router connected to the source's subnet, which may or may not be the DR for that subnet, depending on how the IGP has converged

(When investigating this on the University backbone network, this caused me some confusion because our OSPF is set with maximum-paths 1 and static/connected routes distributed as E1s, so they are "sticky" - it can be the case that the active route for a particular source leads to a different router than the DR on it's subnet, meaning the SPT will not come from the same router that the shared tree does.  This is particularly confusing because changes in the order routes get advertised can cause the SPTs can be different, just as with unicast routes.)

I thought a PIM Assert would step in here, resulting in R1 taking over duties for the receiver's subnet, but it didn't.

Trying PIM-DM

Switching things over to PIM-DM on M's subnet and link between R1 and R2 DID solve the problem: here, the traffic flows out of both R1 and R2 onto the subnet and the routers detect that traffic is arriving on that interface which doesn't match the Reverse Path Forwarding check for S.  We get an Assert and R1 wins:

R1#show ip mroute 239.0.0.1 1.3.0.2
...
(1.3.0.2, 239.0.0.1), 00:00:33/00:02:50, flags: T
  Incoming interface: Ethernet1/2, RPF nbr 0.0.0.0
  Outgoing interface list:
    Ethernet1/0, Forward/Dense, 00:00:09/00:00:00
    Ethernet1/1, Forward/Dense, 00:00:33/00:00:00, A

And R2 has pruned the interface, having lost the Assert:

R2#show ip mroute 239.0.0.1
...
(1.3.0.2, 239.0.0.1), 00:00:32/00:02:30, flags: PJT
  Incoming interface: Ethernet1/0, RPF nbr 1.1.0.1
  Outgoing interface list:
    Ethernet1/1, Prune/Dense, 00:00:32/00:02:27

So maybe PIM-DM would work better than PIM-SM here!

Introducing a downstream PIM-SM router

The examples in Cisco's Developing IP Multicast Networks, Volume I don't cover the situation which we have here, which is why I don't think it's explained there.  They do, however, cover the following situation (in the PIM-DM section), with R3 added to the client subnet and a member, M2, added downstream of that:


With no source, once everything has converged (with R3 joining the shared tree for the group), the multicast forwarding tables will look as follows for 239.0.0.1 on R1:

R1#show ip mroute 239.0.0.1
...
(*, 239.0.0.1), 00:05:43/00:02:54, RP 1.9.0.1, flags: SJC
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
    Ethernet1/0, Forward/Sparse, 00:04:17/00:03:10
    Ethernet1/1, Forward/Sparse, 00:05:43/00:02:56

And R2:

R2#show ip mroute 239.0.0.1
...
(*, 239.0.0.1), 00:11:04/00:02:59, RP 1.9.0.1, flags: SC
  Incoming interface: Ethernet1/0, RPF nbr 1.1.0.1
  Outgoing interface list:
    Ethernet1/1, Forward/Sparse, 00:11:04/00:02:59

And R3 is how you would expect:

R3#show ip mroute 239.0.0.1
...
(*, 239.0.0.1), 00:28:37/00:02:29, RP 1.9.0.1, flags: SC
  Incoming interface: Ethernet1/0, RPF nbr 1.2.0.253
  Outgoing interface list:
    Ethernet1/1, Forward/Sparse, 00:28:37/00:02:29

Note that both R1 and R2 have added their link to the subnet with M3 and R3 into their outgoing interface list (highlighted), but for two different reasons:

  • R2 has added it because M has joined the group (via IGMP) and it is the DR for that subnet, as before, and
  • R1 because R3 has sent a join (via PIM-SM) for the shared tree towards the RP (which would be best reached directly across the shared network)
This duplication of forwarding onto the shared subnet is not resolved at this point: only when traffic is actually forwarded and detected by one (or both) of the routers which are forwarding is a PIM Assert generated and an election takes place to determine the winning forwarder for a particular (S, G).

So, when S starts to send traffic to the group, R1 and R2 will forward traffic onto the shared subnet and an Assert will be triggered, which R1 will win for (1.3.0.2, 239.0.0.1):

R1#show ip mroute 239.0.0.1
...
(*, 239.0.0.1), 00:03:54/00:02:36, RP 1.9.0.1, flags: SJC
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
    Ethernet1/0, Forward/Sparse, 00:03:51/00:02:36
    Ethernet1/1, Forward/Sparse, 00:03:54/00:02:33

(1.3.0.2, 239.0.0.1), 00:01:24/00:03:21, flags: T
  Incoming interface: Ethernet1/2, RPF nbr 0.0.0.0
  Outgoing interface list:
    Ethernet1/0, Forward/Sparse, 00:00:53/00:02:36
    Ethernet1/1, Forward/Sparse, 00:01:24/00:03:03, A

And R2 loses and prunes (1.3.0.2, 239.0.0.1) to that subnet from its forwarding table:

R2#show ip mroute 239.0.0.1
...
(*, 239.0.0.1), 00:05:28/stopped, RP 1.9.0.1, flags: SJC
  Incoming interface: Ethernet1/0, RPF nbr 1.1.0.1
  Outgoing interface list:
    Ethernet1/1, Forward/Sparse, 00:05:28/00:02:25

(1.3.0.2, 239.0.0.1), 00:03:01/00:02:57, flags: PJT
  Incoming interface: Ethernet1/0, RPF nbr 1.1.0.1
  Outgoing interface list: Null

So here, it seems that having a downstream router running PIM-SM helps the traffic flow to optimise.