Showing posts with label forwarding. Show all posts
Showing posts with label forwarding. Show all posts

Wednesday, September 24, 2014

Advanced Cisco Routing -- MPLS VRFs

Several years ago, I worked for a telecommunications provider that was rolling out what I believe was one of the very first -- if the THE very first -- MPLS network in the state of Alaska. The network admins often joked that their network was not just cutting edge; it was bleeding edge. At that time, the network admins worked very closely with Cisco to build and troubleshoot the network, since Cisco was still making sure the tech worked as advertised. Since then, technology has changed, and MPLS has become much more common, even though one of the major drivers that led to the development of MPLS has become more or less a moot point: hardware has improved to the point, where it is no longer significantly faster to switch or route traffic based upon labels than IP or MAC addresses.

For example, the company I currently work for has implemented a ring (!) network with an MPLS core, simply because using MPLS makes it easier for us to configure customer networks across our service provider network. Rather than visiting each node in the ring to create a VLAN for that customer, then adding the VLAN to a topology group (again, on every node in the network), we simply create a VLL or VPLS on the endpoints, and we're done. It's a configuration change on two nodes in the case of a VLL, rather than every node in the ring (with VPLS, it depends upon how many endpoints the client requires, so in some cases, there isn't much to be gained by using MPLS rather than a plain VLAN, and a VPLS introduces some overhead into the network that a VLAN doesn't).

In this lab, we'll create a "service-provider" network in GNS3 consisting of three routers, R1, R2 and R3, and two customer networks, R4 and R5 belonging to one customer, and R6 and R7 belonging to a second customer. The network topology looks like this:


Disclaimer: This lab was created using Cisco 2600-series routers with IOS version 12.3. This is a really, really old version of code, on really, really old (virtual) hardware, since that's all I have access to, currently. Consequently, Cisco's implementation of MPLS may be somewhat different on modern hardware and firmware versions. Hopefully, this will be close enough to get you started, however.

Since both customer networks are Layer-3 (routed) networks, we will use VRF's to logically separate the two customer networks from each other. In this sense, a VRF can more or less be considered to be the Layer-3 equivalent of a VLAN: the VRF's will partition the service provider network into to separate logical networks, including routing tables, that keep addressing and routing from the customer networks from interfering with each other. This has two major implications: first, the two customers in our lab don't have to coordinate IP addressing with each other (in fact, in our example, R4 and R7 have the exact same IP address and subnet!); second, the service provider will participate in the customer's routing!

Let's get started. First, we'll set up the service provider network, including the routing process for the network core. On R1:
interface Loopback0
ip address 10.10.10.1 255.255.255.255
!
interface Serial0/0
ip address 192.168.12.1 255.255.255.0
!
interface Serial0/1
ip address 192.168.13.1 255.255.255.0
!
router ospf 1138
router-id 10.10.10.1
log-adjacency-changes
network 10.10.10.1 0.0.0.0 area 0.0.0.0
network 192.168.12.0 0.0.0.255 area 0.0.0.0
network 192.168.13.0 0.0.0.255 area 0.0.0.0
!

R2 and R3 have similar configurations, and none of this is new, so I won't repeat their configs here.

Next, on a Cisco router, we have to enable CEF (Cisco Express Forwarding). It's trivial to do:
R1(config)#ip cef

Next, we create the two VRFs. Technically, you don't need MPLS to create a VRF (Cisco calls this "VRF Lite"), nor do you need VRFs to run MPLS (for instance, if you are using VLLs or VPLS'). However, VRFs and MPLS work very well together, and for this lab, they solve the problem we have quite handily:
ip vrf left
rd 100:1
route-target export 100:1
route-target import 100:1
!
ip vrf right
rd 200:1
route-target export 200:1
route-target import 200:1
!

As you can see in the configuration above, I was highly original with the name of the VRFs, using "left" for routers R4 and R5, and "right" for R6 and R7. When implementing your own MPLS networks, I'd recommend keeping the VRF names short, easy to type, and easy to remember, as you'll be using them quite a bit in the router configurations. After creating the two VRFs, we use the "rd <AS:nn" command to create the "route distinguisher," using AS 100 for VRF left and AS 200 for VRF right. This is the label that you will be using in various places to differentiate between the two customer routing tables that you will be using in this network. According to Cisco's context-sensitive help function, you can also use an IP address rather than an AS number for the route distinguisher, but why type more than you have to? AS numbers are shorter! ;)

After creating your two VRFs, you next enable MPLS on the network interfaces that will be part of your MPLS core. In this case, that is S0/0 and S0/1 on R1, R2 and R3: interface Serial0/0
mpls ip

Just for giggles, exit out of configuration mode (or stay in config mode and prepend the following command with the word "do") and run "sho run":
interface Serial0/0
ip address 192.168.12.1 255.255.255.0
tag-switching ip
!
interface Serial0/1
ip address 192.168.13.1 255.255.255.0
tag-switching ip
!

Wait a minute...we didn't type "tag-switching ip" in the Serial interface configuration! We used "mpls ip!" What gives? Well, way back when MPLS was still being developed, Cisco was doing essentially the same thing, but called it "tag switching." When the standard was formalized, the technology was given the name MPLS, and Cisco implemented both the tag-switching and mpls commands on the command line. As I understand, there are some slight differences between the tag-switching and mpls command -- and I'm not sure what, exactly those difference might be, so I won't elaborate on that rather vague statement, except to say that you should probably stick with the mpls command, if that's what you are actually trying to build -- but the "show run" output rewrites either command as "tag-switching."

At this point, you know have a working MPLS core, as can be proven by running the "show mpls ldp neighbor" command:
R1#sho mpls ldp neighbor
    Peer TDP Ident: 10.10.10.3:0; Local TDP Ident 10.10.10.1:0
        TCP connection: 10.10.10.3.11008 - 10.10.10.1.711
        State: Oper; PIEs sent/rcvd: 165/165; Downstream
        Up time: 02:19:39
        TDP discovery sources:
          Serial0/1, Src IP addr: 192.168.13.3
        Addresses bound to peer TDP Ident:
          192.168.13.3    10.10.10.3      192.168.23.3    
    Peer TDP Ident: 10.10.10.2:0; Local TDP Ident 10.10.10.1:0
        TCP connection: 10.10.10.2.11004 - 10.10.10.1.711
        State: Oper; PIEs sent/rcvd: 167/166; Downstream
        Up time: 02:19:38
        TDP discovery sources:
          Serial0/0, Src IP addr: 192.168.12.2
        Addresses bound to peer TDP Ident:
          192.168.12.2    10.10.10.2      192.168.23.2    
R1#

Now, we need to tell MPLS which interfaces will be accepting traffic that should be encapsulated inside the MPLS label. This is done with the "ip vrf forwarding..." command. Let's also configure the IP addresses on the customer-facing Ethernet interfaces as we do this:
R1(config)#int eth0/0
R1(config-if)#ip vrf forwaring left
R1(config-if)#ip address 172.16.0.1 255.255.255.252
R1(config-if)#no shut

The only difference between a typical interface configuration and what we did here is that we used the "ip vrf forwarding left" command to tell the MPLS process that this interface is an endpoint of the VRF "left" tunnel(s). Do the same thing for Eth0/1 on R1, and for both E0/0 and E0/1 on R2 and R3, as well.

Be careful here! If you apply the IP address before you run the "ip vrf forwarding..." command, IOS will display an error message telling you that the IP address has been removed from the interface configuration! If you don't see the warning, you can spend quite a while trying to figure out why you aren't seeing the routes you expect across your MPLS core (DAMHIKT!)

This is where things start to get fun. You've basically got a complete MPLS configuration now -- you've enabled MPLS on the various network interfaces, you've got MPLS distributing labels for the various routes, and you can see the MPLS peering is working as it should. However, there is one last piece of the puzzle left: now, you need a way to distribute routes across your MPLS core. First, apply the IP addresses and routing processes to your "customer" routers just as you normally would if R4/R5 and R6/R7 were directly connected to each other. For example, on R4:
interface Loopback0
ip address 10.10.10.4 255.255.255.255
!
interface Ethernet0/0
ip address 172.16.0.2 255.255.255.252
half-duplex
!
router ospf 42
router-id 10.10.10.4
log-adjacency-changes
redistribute connected subnets
network 172.16.0.0 0.0.0.3 area 0.0.0.0
!

If you're paying attention, this is the point where you might scratch your head and object, "Wait a minute...with the 'network 172.16.0.0 0.0.0.3 area 0.0.0.0' command, I'm advertising my OSPF routing process to the service provider!" And you'd be exactly right. With MPLS, the service provider participates in your routing process, but because your traffic is being encapsulated in MPLS, that routing process is only participating with your other endpoints. In this example, R4 and R5 will share routes through the service provider's network, but will not see routes from R6 and R7 (and vice versa).

To accomplish this task on the service provider's network, the service provider will need to turn up separate OSPF process for each customer. In the lab, I also created separate loopback interfaces for each OSPF process because OSPF will complain if you try to enable OSPF without including any local interfaces in the process -- for example, on R2, if I try to turn up an OSPF process for VRF "right" (Edit: I'm not sure it's necessary to turn up OSPF for VRF "right" on R2 or VRF "left" on R3, as we will be setting up BGP to share routes between the OSPF processes; I'll investigate this in a later post). However, when turning up a separate OSPF process, you must tell OSPF which VRF this routing process belongs to:
interface Loopback1
description loopback for OSPF 100 -- VRF LEFT
ip vrf forwarding left
ip address 10.0.100.1 255.255.255.255
!
interface Loopback2
description loopback for OSPF 200 -- VRF RIGHT
ip vrf forwarding right
ip address 10.0.200.1 255.255.255.255
!
router ospf 100 vrf left
router-id 10.0.100.1
network 172.16.0.0 0.0.0.3 area 0.0.0.0
!
router ospf 200 vrf right
router-id 10.0.200.1
network 172.16.0.0 0.0.0.3 area 0.0.0.0
!

Notice that I included the "ip vrf forwaring..." command on the loopback interfaces!

If you execute the "sho route" command on any of the customer routers now, however, you will see that they are only aware of the locally connected routes and the loopback interface of the locally connected service provider router (i.e., R4 will only see the IP address of loopback1 on R1, R7 will only see the IP address of loopback2 on R1, etc.). This is because the OSPF processes that we just turned up are only sharing routes with the customer router connected to their Ethernet interface (OSPF 100 on R1 is only sharing routes through eth0/0 to R4, etc.). To enable routing across the MPLS core, we need to enable another routing process (!) to redistribute routes between these routing processes. If that sounds like a perfect job for BGP, you are exactly right:
router bgp 65510
no synchronization
bgp log-neighbor-changes
neighbor 10.10.10.2 remote-as 65510
neighbor 10.10.10.2 update-source Loopback0
neighbor 10.10.10.3 remote-as 65510
neighbor 10.10.10.3 update-source Loopback0
no auto-summary
!
address-family vpnv4
neighbor 10.10.10.2 activate
neighbor 10.10.10.2 send-community extended
neighbor 10.10.10.3 activate
neighbor 10.10.10.3 send-community extended
exit-address-family
!
address-family ipv4 vrf right
redistribute ospf 200
no auto-summary
no synchronization
exit-address-family
! address-family ipv4 vrf left
redistribute ospf 100
no auto-summary
no synchronization
exit-address-family
!

Notice the "address-family ipv4 vrf left" and "address-family ipv4 vrf right" statements. Under these statements, we have "redistribute ospf <process ID>" commands. These commands tell BGP to share routes learned via these OSPF process to the appropriate VRFs. That is, BGP should share routes learned via OSPF process 100 with VRF "left" and OSPF process 200 with VRF "right." This is good, but not sufficient. BGP will now know about any routes that OSPF knows, but OSPF doesn't yet know about all of the routes that BGP has in its routing table (you can verify this by running the "show ip route vrf left" and "show ip route vrf right" commands on any of the service provider routers). Let's take care of that now:
R1(config)#router ospf 100
R1(config-router)#redistribute bgp 65510 subnets
R1(config-router)#router ospf 200
R1(config-router)#redistribute bgp 65510 subnets

With this final configuration command, you should now have routes across the MPLS core between the customer routers. R4 should be able to ping/telnet/etc. to R5 (and vice versa) and R6 should be able to ping/telnet/etc. to R7 (and vice versa). However, neither R4 nor R5 should be able to communicate with R6 or R7.

Troubleshooting:
Enabling MPLS introduces a couple of complications to troubleshooting. As I mentioned earlier, I was fortunate enough to be an admin at a telco that was building out an MPLS core back in my early days of system and network administration. On one occasion, I saw an alarm for a customer's network, and logged into one of the MPLS edge routers to try to troubleshoot. However, when I tried to ping the customer's router, I was dismayed to find that my router apparently didn't have a route to that host. You can see this for yourself by attempting to ping a customer router from R1, R2 or R3:
R1#ping 172.16.2.2

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
.....
Success rate is 0 percent (0/5)
R1#
If you try "show route," you'll see a similar issue:
R1#sho ip route
<...snip...>
C    192.168.12.0/24 is directly connected, Serial0/0
C    192.168.13.0/24 is directly connected, Serial0/1
     10.0.0.0/32 is subnetted, 3 subnets
O       10.10.10.2 [110/65] via 192.168.12.2, 01:09:36, Serial0/0
O       10.10.10.3 [110/65] via 192.168.13.3, 01:09:36, Serial0/1
C       10.10.10.1 is directly connected, Loopback0
O    192.168.23.0/24 [110/128] via 192.168.13.3, 01:09:36, Serial0/1
                     [110/128] via 192.168.12.2, 01:09:36, Serial0/0
R1#

If you'll notice, all of the customer routers were configured with 172.16.x.y IP addresses, but there are no 172.16.x.y IP addresses in the routing table on R1. Yet, if you try a ping from R4 to R5 (or R6 to R7), you will see that it works:
R4#ping 172.16.2.2

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 8/19/52 ms
R4#

How is this possible?

If you'll recall, I commented earlier that MPLS is rather like the Layer-3 equivalent of a VLAN, in that MPLS encapsulates the routing tables of the various VRFs into their own logical partitions, and that these routing tables are not shared amongst other VRFs. Nor are they shared with the global routing table of the service provider routers. If you want to view the routing tables inside a VRF or ping across the VRF, you have to explicitly tell the router so:
R1#ping vrf left 172.16.2.2

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 8/36/140 ms
R1#sho ip route vrf left

Routing Table: left
<...snip...&rt;
Gateway of last resort is not set

     172.16.0.0/30 is subnetted, 2 subnets
C       172.16.0.0 is directly connected, Ethernet0/0
B       172.16.2.0 [200/0] via 10.10.10.2, 03:01:06
     10.0.0.0/32 is subnetted, 2 subnets
O E2    10.10.10.4 [110/20] via 172.16.0.2, 01:17:46, Ethernet0/0
C       10.0.100.1 is directly connected, Loopback1
R1#

As a fellow network admin and blogger so eloquently put it, "Pretty much any command that you would normally use, add 'vrf <vrf name>' to it." This tells the router that you are specifically asking about the routing tables inside the specified VRF, which makes sense, if you think about it. In this lab, both R4 and R7 have the same IP address. From the service provider router's standpoint, how would it know whether it should ping R4 or R7 if all you did was "ping 172.16.0.2?" Consequently, you have to explicitly tell the router that it is to ping 172.16.0.2 inside VRF "left" (for example).

For more on the subject, check out the following web pages that I found to be helpful while trying to learn how to configure MPLS on Cisco routers:
Packet Life: Creating MPLS VPNs
Cisco Dreamer: MPLS Basics
Router Jockey: Cisco MPLS VRF Configuration and Demo

Tuesday, November 12, 2013

JNCIA Lesson 6 -- Spanning Tree, Rapid Spanning Tree and Multiple Spanning Tree

In our network design, we have two EX3200 switches at the main office, connected through a single copper cross-over cable. A savvy network administrator would probably look at our design and ask, "What would happen if either Ethernet port, or more likely, the Ethernet cable itself were to fail?" The link from our main3200 switch to our main2-3200 switch is indeed a single point of failure on our network. Many a junior network admin have had the sudden realization that such a design is a problem waiting to happen, and in their eagerness to show how pro-active and fore-sighted they are, have then run a second Ethernet cable between the two switches in order to create a redundant connection between them.

If the junior admin was lucky, (s)he probably just spent a while wondering why one of the redundant Ethernet ports suddenly went off-line (had a customer do that to me once, on a Metro-Ethernet ring, in fact). If the junior admin was not so lucky, however, (s)he created a broadcast storm, crashing the entire Layer-2 network with (her)his well-intentioned, but naive, blunder:



In actual practice, the diagrams above are an over-simplification: if Switch A was actually sending a broadcast, it would have forwarded the frame out the ports to *both* Switch B and Switch C, and both Switch B and Switch C would have forwarded the broadcast frame to each other, resulting in multiple copies of the same frame circulating through the network simultaneously. In fact, if there are four or more switches in the network connected in a full-mesh network, then with every cycle there are more and more frames circulating through the network until the switches can no longer keep up with traffic (with three or less switches, the number of frames circulating won't grow, since the switches will not forward a broadcast back out the interface upon which it was received).

In our example with the junior admin, (her)his instincts were good; the network, as originally designed, was vulnerable to failure, and it would be a good idea to design a redundant path between switches, if there were a way to prevent such loops from occurring. Fortunately, this is exactly the type of problem that the Spanning Tree protocol (STP), and it's later refinements, Rapid Spanning Tree (RSTP) and Muliple Spanning Tree (MSTP), were designed to solve.

The method through with STP prevents loops is quite simple: essentially, the protocol just shuts down redundant network ports until/unless the switches in the tree detect a failure on an active port. In our example above, and assuming that Switch A was the "root bridge" (we'll define that term shortly), Spanning Tree (or RSTP or MSTP) would put one of the ports on either Switch B or Switch C into a "blocking" state, thus breaking the loop. Now, if Switch A sends a broadcast frame to Switches B and C, they will each forward the packet to devices connected to their switch ports, but NOT to each other.

This (simplified) explanation of Spanning Tree raises an important question: how do the switches determine if there is a loop, or if there is a network port which needs to be shut down? When a switch (or group of switches) is first powered on, it sends a query out each of its enabled switch ports, called a "Bridge Protocol Data Unit." Routers and PCs ignore the BPDU, but other switches examine the BPDU to check for loops in the layer-2 topology. Some of the data transferred during this process is used to elect a "root bridge" -- the switch that will be the pinnacle of the spanning tree network. As we've already stated, spanning tree will shut down ports to break loops in the layer-2 network, but the root bridge is special: all enabled ports on the root bridge always remain active. On any switches with a single port connected to the root bridge, those ports will also always remain active, and are known as "root ports." If there are multiple ports to the root bridge, the switch will select a single port as a root port, and shut down the rest. Any ports that spanning tree uses to reach other switches, but which do not provide a path for that switch to reach the root bridge will are called "designated ports." Confused yet? Let's look a drawing to try to make it a little clearer:



As you can see, all of the switch ports that are directly connected to Switch A are root ports, all of the switch ports in a forwarding state that are NOT directly connected to Switch A are designated ports, and the ports in a blocking state are non-designated ports.

One other question that might come to mind at this point is, "how do the switches determine which switch is the root bridge?" Spanning Tree uses two metrics for electing a root bridge: first, the admin can set a value known as "root bridge priority" when configuring spanning tree, and lowest priority wins; second, if two or more switches have the same priority, then the switch with the lowest MAC address wins. In JunOS, the root bridge priority and MAC address are concatenated into a single value known as the "root ID" which can be shown with the "show spanning-tree bridge" command:

root@main3200# run show spanning-tree bridge

STP bridge parameters
Context ID                          : 0
Enabled protocol                    : RSTP
<...snip...>
  Local parameters
    Bridge ID                       : 32768.3c:8a:b0:99:df:c1
<...snip...>
root@main3200#


As you can see, the root ID on this switch is 32768.3c:8a:b0:99:df:c1. Suppose we had two other switches in a full-mesh, layer-2 network, and the other switches had root ID's of 32768.3c:8a:b0:99:e5:41 and 32768.3c:8a:b0:9a:22:01. Which switch would be elected root bridge? Let's connect these three switches together and find out! I'll connect ge-0/0/23 on the first switch to ge-0/0/22 on the second switch, connect ge-0/0/23 on the second switch to ge-0/0/22 on the third switch, then connect ge-0/0/23 on the third switch to ge-0/0/22 on the first switch. Once the switches are wired up to create a loop at layer-2, we'll re-run the "show spanning-tree bridge" command and see which switch was actually elected to be the root bridge:

root@main3200# run show spanning-tree bridge | match "Root ID"
  Root ID                           : 32768.3c:8a:b0:99:df:c1

[edit]
root@main3200#


root@branch1-3200# run show spanning-tree bridge | match "Root ID"
  Root ID                           : 32768.3c:8a:b0:99:df:c1

[edit]
root@branch1-3200#


root@branch2-3200# run show spanning-tree bridge | match "Root ID"
  Root ID                           : 32768.3c:8a:b0:99:df:c1

[edit]
root@branch2-3200#


Since all three switches have the same priority (JunOS' default of 32768), the election was determined by the lowest MAC address, which belongs to main3200.

If we wanted to know which ports were shut down, we would use the "show spanning-tree interface" command, but here, I have to make an admission: I couldn't actually find enough cross-over cables to connect all three switches in a full-mesh network, so I had to disconnect branch2-3200 for the following portion of the lab:

root@main3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:535  32768.3c8ab099dfc1     20000  FWD    DESG
ge-0/0/23.0    128:536      128:536  32768.3c8ab099dfc1     20000  FWD    DESG

[edit]
root@main3200#


root@branch1-3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:536  32768.3c8ab099dfc1     20000  BLK    ALT
ge-0/0/23.0    128:536      128:535  32768.3c8ab099dfc1     20000  FWD    ROOT

[edit]
root@branch1-3200#


If you notice, ge-0/0/22 on branch1-3200 is blocked by Spanning Tree, which shows that, when a link between two switches is determined to be redundant, if the path-cost back to the root bridge is equal, the lowest port number will be shut down (however, you can manually assign a port-cost to bias for or against a particular port, if you want).

RSTP is enabled on Juniper EX-series switches by default, but if you need to manually configure Spanning Tree, Rapid Spanning Tree or Multiple Spanning Tree, it's a very easy process. All three protocols are configured in exactly the same way, with just a couple of exceptions, which we'll cover in just a minute. Consequently, we'll only run through the configuration steps once, using RSTP. If you are using STP or MSTP, then rather than using "edit protocols rstp" (or "set protocols rstp ..."), you will use "edit protocols stp" or "edit protocols mstp" as appropriate.

First, we'll set the bridge priority to be lower on branch1-3200, to make it the root bridge instead of main3200:

root@branch1-3200# edit protocols rstp

[edit protocols rstp]
root@branch1-3200# set bridge-priority 20k

[edit protocols rstp]
root@branch1-3200#


Next, we will disable RSTP on ge-0/0/12.0 and commit the config:
root@branch1-3200# set interface ge-0/0/12.0 disable

[edit protocols rstp]
root@branch1-3200# commit
commit complete

[edit protocols rstp]
root@branch1-3200#


Now, one of the ports on main3200 should be in the blocking state, rather than on branch1-3200:

root@main3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:536  20480.3c8ab099e541     20000  BLK    ALT  
ge-0/0/23.0    128:536      128:535  20480.3c8ab099e541     20000  FWD    ROOT

[edit protocols rstp]
root@main3200#


...and sure enough, ge-0/0/22.0 on main3200 is now in the blocking state. Let's adjust the priority to put ge-0/0/23 in the blocking state, instead:

root@main3200# set interface ge-0/0/22 cost 1000

[edit protocols rstp]
root@main3200# commit
commit complete

[edit protocols rstp]
root@main3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:536  20480.3c8ab099e541      1000  FWD    ROOT
ge-0/0/23.0    128:536      128:535  20480.3c8ab099e541     20000  BLK    ALT  

[edit protocols rstp]
root@main3200#


One of the problems with spanning tree is the time it takes for the network to "converge" -- that is, the time it takes for the switches to elect a root bridge, determine if there are any loops in the topology, and then to shut down any redundant links. In STP, convergence can take almost a full minute, which is at least part of the reason RSTP was created. While RSTP is already quicker to converge than STP, it can converge even quicker if point-to-point links are declared as such with the "set protocols rstp interface ge-0/0/<whatever> mode point-to-point" command (Edit: if you are confused here, you are not alone. I'm not sure what a "point-to-point" link even means in a layer-2 network, but if I find out, I'll notate it here).

MSTP also differs from standard STP configuration in that you must add two more lines to the config:

root@main3200# set protocols mstp configuration-name jncia-example-1

[edit]
root@main3200# set protocols mstp msti 1 vlan [ 1 2 4 ]

[edit]
root@main3200# set protocols mstp msti 2 vlan [ 3 5 6 20 ]

[edit]
root@main3200#
<...etc...>


The only "gotcha" when putting VLANs into an MSTP instance (MSTI) is that every VLAN in a given instance must share a common topology.

Wednesday, November 6, 2013

JNCIA Lesson 3 -- Routing

Now that you've got your new EX3200 switches upgraded to the latest stable release, let's start working with the Layer-3 features of the switch. We'll start by reviewing a few basic concepts on how Juniper implements routing.

Juniper routers create two categories of databases while deciding how to forward packets from one network to another: the routing table and the forwarding table. The routing table is created by the routing engine, and contains the routes to various networks. The routing engine then copies the forwarding table to the packet forwarding engine, which uses the forwarding table to decide how to forward packets that come into the router.

Notice that I said JunOS creates two categories of databases. In truth, JunOS supports multiple routing instances, and therefore, multiple routing tables. If you run the "show route" command...:

root@main3200# run show route

inet.0: 14 destinations, 14 routes (14 active, 0 holddown, 0 hidden)
<...snip...>


...notice that it starts with the string, "inet.0." The inet.0 routing table is the default table for IPv4 routes. On some devices, you might also see...:

__juniper_private1__.inet.0


...which is a routing table used within JunOS to communicate with the router itself. There are also several other routing tables created by JunOS for various purposes:


There are two commands which are useful for troubleshooting routing and forwarding problems: "show route forwarding-table" and "show pfe route ip" (you can also use "show pfe route ipv6," "show pfe route mpls," and "show pfe route summary"). Since both of these commands produce a LOT of output, I won't show examples -- just go play with them :)

For a concise summary of the routes the router knows about, use the "show route" command:

root@main3200> show route

inet.0: 10 destinations, 10 routes (10 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

10.11.12.0/30      *[Direct/0] 22:36:20
                    > via ge-0/0/21.0
10.11.12.1/32      *[Local/0] 22:36:29
                      Local via ge-0/0/21.0
100.64.170.79/32   *[Local/0] 22:36:29
                      Reject
192.168.1.0/24     *[Direct/0] 22:36:20
                    > via vlan.0
192.168.1.1/32     *[Local/0] 22:36:31
                      Local via vlan.0
192.168.2.0/24     *[OSPF/10] 22:35:32, metric 2
                    > to 10.11.12.2 via ge-0/0/21.0
192.168.10.0/24    *[Direct/0] 22:36:20
                    > via vlan.20
192.168.10.1/32    *[Local/0] 22:36:31
                      Local via vlan.20
224.0.0.5/32       *[OSPF/10] 22:36:32, metric 1
                      MultiRecv
224.0.0.22/32      *[IGMP/0] 22:36:32
                      MultiRecv         

root@main3200>


As you can see, this router already has been configured with routes to various networks. Some of these routes are created automatically, because the networks are directly connected to the router...:

10.11.12.0/30      *[Direct/0] 22:36:20
                    > via ge-0/0/21.0
10.11.12.1/32      *[Local/0] 22:36:29
                      Local via ge-0/0/21.0
...
192.168.1.0/24     *[Direct/0] 22:36:20
                    > via vlan.0
192.168.1.1/32     *[Local/0] 22:36:31
                      Local via vlan.0


...and some of these routes are known through Dynamic Routing Protocols:

192.168.2.0/24     *[OSPF/10] 22:35:32, metric 2
                    > to 10.11.12.2 via ge-0/0/21.0


I'll clear out the routing configurations on this router, and we'll start over with a very simple example: routing from this switch to a second EX3200 that we will call "branch3200", which will be connected with an Ethernet crossover cable:

root@main3200# delete routing-options

[edit]
root@main3200# delete protocols ospf

[edit]
root@main3200# delete policy-options

[edit]
root@main3200# commit
commit complete

[edit]
root@main3200#


For the moment, don't worry too much about the meaning of each of those "delete..." statements. In short, all three statements were necessary to delete all of the routes and routing options that I had created on the switch earlier. By the end of this lesson, the reason for each of those "delete" statements should be clear :)

Back to routing...We will connect ge-0/0/21 on each switch via the crossover cable. Since routing occurs at Layer-3, we'll need to configure an IP address on each switch. I'll assume for now that you are familiar with the concept of subnetting a network; if you aren't, spend some quality time with Google before continuing with these lessons, as a lot of what we will be doing will require that you understand the concept. So, operating on that assumption, we'll create a /30 network between these two EX3200's, since we only need two IP addresses between them (one for each EX3200). I'll assign the IP address 10.11.12.1/30 to main3200 and 10.11.12.2/30 to branch3200:

root@main3200# delete interfaces ge-0/0/21 unit 0 family ethernet-switching

[edit]
root@main3200# set interfaces ge-0/0/21 unit 0 family inet address 10.11.12.1/30

[edit]
root@main3200#


...and...:

root@branch3200# delete interfaces ge-0/0/21 unit 0 family ethernet-switching

[edit]
root@branch3200# set interfaces ge-0/0/21 unit 0 family inet address 10.11.12.2/30

[edit]
root@branch3200#


At this point, we should be able to ping between the two switches:

root@main3200# run ping 10.11.12.2
PING 10.11.12.2 (10.11.12.2): 56 data bytes
64 bytes from 10.11.12.2: icmp_seq=0 ttl=64 time=5.879 ms
64 bytes from 10.11.12.2: icmp_seq=1 ttl=64 time=1.767 ms
^C
--- 10.11.12.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 1.767/3.823/5.879/2.056 ms

[edit]
root@main3200#


Success! Since these two switches are directly connected across a single broadcast domain, we don't have to configure any routing at all to communicate over the 10.11.12.0/30 network. In Lesson 1 we configured a management IP address of 192.168.1.1/24 on interface vlan.0 on the main3200 switch. Let's assume that we have a mangement IP address of 192.168.2.1/24 on interface vlan.0 on the branch3200 switch. Can we ping from 192.168.1.1 to 192.168.2.1? Let's try it and see:

root@main3200# run ping 192.168.2.1
PING 192.168.2.1 (192.168.2.1): 56 data bytes
ping: sendto: No route to host
ping: sendto: No route to host
^C
--- 192.168.2.1 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

[edit]
root@main3200#


Nope! By default a router (or layer-3 switch, like the EX3200's we are using) only knows directly connected routes. In other words, main3200 only knows how to reach 10.11.12.0/30 and 192.168.1.0/24, and branch3200 only knows how to reach 10.11.12.0/30 and 192.168.2.0/24. Since both switches know how to reach 10.11.12.0/30, they can communicate with each other over this network, but since they don't have the 192.168.x.0/24 networks in common, main3200 can't reach 192.168.2.x, nor can branch3200 reach 192.168.1.x. However, we can fix that very easily:

root@main3200# set routing-options static route 192.168.2.0/24 next-hop 10.11.12.2

[edit]
root@main3200# commit
commit complete

[edit]
root@main3200#


...and on the branch3200:

root@branch3200# set routing-options static route 192.168.1.0/24 next-hop 10.11.12.1

[edit]
root@branch3200# commit
commit complete

[edit]
root@branch3200#


Let's see how a ping from the main3200 switch to the management IP of the branch3200 switch works now:

root@main3200# run ping 192.168.2.1
PING 192.168.2.1 (192.168.2.1): 56 data bytes
64 bytes from 192.168.2.1: icmp_seq=0 ttl=64 time=2.043 ms
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=1.622 ms
^C
--- 192.168.2.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 1.622/1.833/2.043/0.211 ms

[edit]
root@main3200#


Much better! With that one line of code, we told the main3200 switch that, in order to reach the 192.168.2.0/24 network, we had to talk to the router (we'll use "router" synonymously with layer-3 switch, from here on) at 10.11.12.2, and we told the branch3200 switch to talk to 10.11.12.1 to communicate with 192.168.1.0/24. Even better, the two end-point routers don't have to be directly connected for this to work. You can have an arbitrary number of routers between end-points (sort of -- more on this later) and, as long as each router has a next-hop for the destination network, you can "chain" routes together to reach your destination.

For example, suppose you had three routers, router A, router B and router C. Each router has a 192.168.x.1 management IP, 192.168.1.1 for router A, 192.168.2.1 for router B and 192.168.3.1 for router C. Router A is connected to router B on the 10.11.12.0/30 network, just as we've described with main3200 and branch3200 above. Router B is connected to router C on the 172.16.0.0/30 network. In that case, on router A, you would run the command "set routing-options static route 192.168.3.0/24 next-hop 10.11.12.2", just as we did before. On router B, you would run TWO commands, "set routing-options static route 192.168.3.0/24 next-hop 172.16.0.2" and "set routing-options static route 192.168.1.0/24 next-hop 10.11.12.1." On router C, you would run a single command again, "set routing-options static route 192.168.1.0/24 next-hop 172.16.0.1." If router A wanted to communicate with the 192.168.2.0/24 network on router B, then on router A you would also need to add "set routing-options static route 192.168.2.0/24 next-hop 10.11.12.2" as well, and if router C wanted to communicate with the 192.168.2.0/24 network on router B, you would have to add the command "set routing-options static route 192.168.2.0/24 next-hop 172.16.0.1" also. Instead of two commands for two routers, we now have eight commands for three routers -- that's an exponential growth (2^n, where n is the number of routers in the network) for full communication across the network. Clearly, if you have a small network, static routes are fine, but for large networks (where "large" doesn't really have to be all that large at all), creating static routes is a very time-consuming and error-prone proposition.

Fortunately, there's a solution for this problem. Very early on, router manufacturers decided that, while there were scenarios where statically routing between networks was appropriate, this was actually the kind of work that a computer -- and an average router is nothing more than a low-powered computer with very specific software and two or more network ports -- is very good at performing. Consequently, they developed dynamic routing protocols: algorithms that share routes between devices automatically, relieving the network administrator of the necessity of statically configuring all of the routes between various network devices.

One of the most common routing protocols in use is OSPF (Open Shortest Path First). Let's delete our static routes and replace them with a simple OSPF configuration:

root@main3200# top

[edit]
root@main3200# edit protocols ospf

[edit protocols ospf]
root@main3200# set area 0.0.0.0 interface ge-0/0/21.0

[edit protocols ospf]
root@main3200# set area 0.0.0.0 interface vlan.0 passive

[edit protocols ospf]
root@main3200# commit
commit complete

[edit protocols ospf]
root@main3200#


Now, let's see if our configuration works:

root@main3200# run show route protocol ospf    

inet.0: 10 destinations, 10 routes (10 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

192.168.2.0/24     *[OSPF/10] 00:02:14, metric 2
                    > to 10.11.12.2 via ge-0/0/21.0
224.0.0.5/32       *[OSPF/10] 00:03:35, metric 1
                      MultiRecv

[edit protocols ospf]
root@main3200#


Perfect! We have a route to 192.168.2.0/24 on main3200.

One other tool that is useful for debugging OSPF routing problems is the "show ospf neighbor" command. Here is the output from immediately after committing the OSPF configuration. In particular, watch how the "State" changes as the two EX3200's begin to build the OSPF communications:

root@main3200# run show ospf neighbor
Address          Interface              State     ID               Pri  Dead
10.11.12.2       ge-0/0/21.0            2Way      10.11.12.2       128    39

[edit protocols ospf]
root@main3200# run show ospf neighbor          
Address          Interface              State     ID               Pri  Dead
10.11.12.2       ge-0/0/21.0            ExStart   10.11.12.2       128    33

[edit protocols ospf]
root@main3200# run show ospf neighbor          
Address          Interface              State     ID               Pri  Dead
10.11.12.2       ge-0/0/21.0            Full      10.11.12.2       128    36

[edit protocols ospf]
root@main3200#


In this sequence of captures, you can see the OSPF process begin establishing the OSPF adjacency with the neighbor router ("2Way"), exchanging routes with the neighbor ("ExStart") and fully converged ("Full"). If the routers don't move to the "Full" state after a couple of minutes, then something is wrong and you should make sure 1) that your configs are good, and 2) that you can ping from one router to the other. Once the state has changed to "Full", you can run the "show route protocol ospf" command to verify that all of the routes are being shared properly.

Let's discuss a couple of the statements in our OSPF configuration in a little more detail:

root@main3200# show
area 0.0.0.0 {
    interface ge-0/0/21.0;
    interface vlan.0 {
        passive;
    }
}

[edit protocols ospf]
root@main3200#


First, notice that all of our configuration statements fall under the "area 0.0.0.0" stanza. In OSPF, you can define multiple areas for OSPF to run in, although you always need an area 0.0.0.0 (sometimes shortened to "area 0" on some vendors' equipment, although Juniper will rewrite "area 0" as "area 0.0.0.0"). To understand areas, keep in mind that OSPF advertises routes within an area, so once a network becomes large, you can improve performance and reduce network overhead by segmenting your network into smaller subnetworks to reduce the number and size of advertisements. Area 0.0.0.0 is of particular importance because it is the "backbone network", that is, the portion of the network that connects all of the other areas (if any) together. In our case, the network is very small (just two switches), so we have put all of the networks in area 0.0.0.0.

Second, notice that under area 0.0.0.0, we have listed two interfaces, ge-0/0/21.0 and vlan.0. When we listed these interfaces, we told OSPF that we want to enable OSPF routing on these interfaces. For vlan.0, we further modified this statement by appending the "passive" parameter, which tells OSPF that, even though we want to make this interface part of the OSPF area, we don't want to form OSPF adjacencies through this interface.

That leaves us with one question remaining for this section: suppose we had multiple routes to a particular network, say one route that was defined statically, and another route to the same network that was defined through a dynamic routing protocol such as OSPF. Which patch would the router take to reach the destination? JunOS has predicted that such a scenario might occur, and has already addressed the issue through route preferences.

Basically, route preferences set a ranking of routes depending upon the way the route was derived. For example, directly connected routes are most preferable, statically defined routes are slightly less preferable, OSPF routes are even less preferable, RIP is less preferable than OSPF and BGP is the least preferable route of all (reference). These preferences aren't just academic, mind you. I once had to troubleshoot a routing problem with my upstream provider where I was experiencing a routing loop trying to reach a remote location from a second remote location in my network. My upstream provider spent several days claiming that he was advertising the proper routes through his core, until I finally asked him to check the static routing at one of the remote office locations. Since static routes are more preferable than dynamic routes, the old, incorrect static route was overriding the route he was advertising dynamically through his core, and was routing traffic to this one subnet back to my edge router, causing a loop.

This has only scratched the surface of routing on Juniper devices, but we'll save the more advanced topics for the next lesson.

Sunday, October 6, 2013

Appendix A -- More on Spanning Tree

Spanning Tree was enabled by default on the 2924 switches I have in my lab, but sometimes the network admin needs to tweak the settings a little. For example, the network admin may want to force a particular switch to be the root bridge -- wouldn't it make sense to have the most powerful switch in your network be the root bridge rather than a small, inexpensive, low-powered access switch in a wire closet in the hut next door to your main building on your campus?

Unfortunately, I have become quite frustrated with the documentation on Spanning Tree in the several CCNA test prep books I have purchased over the years (I started working on a CCNA over eight years ago, but circumstances changed, and I never took the exam). I don't know about you, but for me, I don't retain much by simply reading technical documentation. Since I can't afford to NOT know the correct answers when I take the CCNA exam this coming week, I decided the best way to get the straight scoop was to configure, tweak, and observe Spanning Tree on my switches.

Root Bridge Election: Let's start with manipulating the root bridge election process. This was an area where I got really frustrated with the documentation, so let's just play with it on the switches and see what happens. Here goes:

lab2924a#sho span

Spanning tree 1 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 32768, address 0003.e3e4.f887
  Configured hello time 2, max age 20, forward delay 15
  We are the root of the spanning tree
  Topology change flag not set, detected flag not set, changes 1
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 0, topology change 0, notification 0

Interface Fa0/1 (port 13) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 13, path cost 0
   Timers: message age 0, forward delay 0, hold 0
   BPDU: sent 1416, received 8

Interface Fa0/2 (port 14) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 14, path cost 0
   Timers: message age 0, forward delay 0, hold 0
   BPDU: sent 1383, received 2


...and lab2924b:

lab2924b#sho span

Spanning tree 1 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 32768, address 00d0.58dd.d186
  Configured hello time 2, max age 20, forward delay 15
  Current root has priority 32768, address 0003.e3e4.f887
  Root port is 13, cost of root path is 19
  Topology change flag not set, detected flag not set, changes 3
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 0, topology change 0, notification 0

Interface Fa0/1 (port 13) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 13, path cost 0
   Timers: message age 3, forward delay 0, hold 0
   BPDU: sent 39, received 3092

Interface Fa0/2 (port 14) in Spanning tree 1 is BLOCKING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 14, path cost 0
   Timers: message age 6, forward delay 0, hold 0
   BPDU: sent 1, received 2916


The rest of the ports on the two switches are just "leaf nodes" -- that is, they connect to routers and laptops, rather to switches, and therefore, they are incapable of creating loops in the layer-2 network. From the output above, we can see that lab2924a is the root bridge, that fa0/1 and fa0/2 on lab2924a are designated ports, that fa0/1 on lab2924b is a root port and that fa0/2 on lab2924b is a blocking port. What happens if I pull the Ethernet cable on fa0/1 on one of the switches? Let's find out! Here's what I see on lab2924a:

lab2924a#sho span

Spanning tree 1 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 32768, address 0003.e3e4.f887
  Configured hello time 2, max age 20, forward delay 15
  We are the root of the spanning tree
  Topology change flag set, detected flag set, changes 2
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 0, topology change 30, notification 0

Interface Fa0/1 (port 13) in Spanning tree 1 is down
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 13, path cost 0
   Timers: message age 0, forward delay 0, hold 0
   BPDU: sent 1734, received 8

Interface Fa0/2 (port 14) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 14, path cost 0
   Timers: message age 0, forward delay 0, hold 0
   BPDU: sent 1705, received 4


For almost a full minute, however, I couldn't see anything from lab2924b (since I was directly connected to 2924a), which underscores a big problem with STP -- the network will recover from failure of a redundant link, but users will definitely notice the outage while spanning tree reconverges. Eventually, however, my telnet session recovered, and here is what I saw on lab2924b:

lab2924b#sho span

Spanning tree 1 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 32768, address 00d0.58dd.d186
  Configured hello time 2, max age 20, forward delay 15
  Current root has priority 32768, address 0003.e3e4.f887
  Root port is 14, cost of root path is 19
  Topology change flag set, detected flag not set, changes 4
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 0, topology change 0, notification 0

Interface Fa0/1 (port 13) in Spanning tree 1 is down
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 00d0.58dd.d186
   Designated port is 13, path cost 19
   Timers: message age 0, forward delay 0, hold 0
   BPDU: sent 39, received 3474

Interface Fa0/2 (port 14) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 14, path cost 0
   Timers: message age 1, forward delay 0, hold 0
   BPDU: sent 3, received 3340


Now we see that fa0/1 is down on both switches, and fa0/2 is forwarding on both switches once again. No surprises, right?

From the output above, we can see that both switches have a priority of 32768. If both switches have the same priority, then the choice of root bridge is decided by MAC address. lab2924a has MAC 0003.e3e4.f887 and lab2924b has MAC 00d0.58dd.d186. 0x0003 < 0x00d0 so apparently the low MAC address wins the election process when the priority is the same. But what if I wanted lab2924b to be the root bridge? Would I set the STP priority on lab2924b higher or lower than lab2924a? Let's try it and find out:

lab2924b#conf t
lab2924b(config)#spanning-tree priority 4096
lab2924b(config)#exit
lab2924b#sho span

Spanning tree 1 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 4096, address 00d0.58dd.d186
  Configured hello time 2, max age 20, forward delay 15
  We are the root of the spanning tree
  Topology change flag set, detected flag set, changes 6
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 1, topology change 24, notification 0

Interface Fa0/1 (port 13) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 128
   Designated root has priority 4096, address 00d0.58dd.d186
   Designated bridge has priority 4096, address 00d0.58dd.d186
   Designated port is 13, path cost 0
   Timers: message age 0, forward delay 0, hold 0
   BPDU: sent 48, received 3744

Interface Fa0/2 (port 14) in Spanning tree 1 is LISTENING
   Port path cost 19, Port priority 128
   Designated root has priority 4096, address 00d0.58dd.d186
   Designated bridge has priority 4096, address 00d0.58dd.d186
   Designated port is 14, path cost 0
   Timers: message age 0, forward delay 3, hold 0
   BPDU: sent 10, received 4070


Wow...that was fast! Since STP takes almost a minute to move the ports to the forwarding state, I didn't expect lab2924b to assume its new role as root bridge quite so quickly, but it did. You can see that fa0/2 is still in the listening state as I ran the "sho span" command, but it already knows that it's the root bridge. Edit: I later reset lab2924b's priority back to 32768, and it seemed to take a few seconds to update its status, so it's not quite instantaneous -- say about 10 or 15 seconds, maybe?

How about lab2924a?

lab2924a#sho span

Spanning tree 1 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 32768, address 0003.e3e4.f887
  Configured hello time 2, max age 20, forward delay 15
  Current root has priority 4096, address 00d0.58dd.d186
  Root port is 13, cost of root path is 19
  Topology change flag set, detected flag not set, changes 4
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 0, topology change 0, notification 0

Interface Fa0/1 (port 13) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 128
   Designated root has priority 4096, address 00d0.58dd.d186
   Designated bridge has priority 4096, address 00d0.58dd.d186
   Designated port is 13, path cost 0
   Timers: message age 2, forward delay 0, hold 0
   BPDU: sent 1869, received 36

Interface Fa0/2 (port 14) in Spanning tree 1 is BLOCKING
   Port path cost 19, Port priority 128
   Designated root has priority 4096, address 00d0.58dd.d186
   Designated bridge has priority 4096, address 00d0.58dd.d186
   Designated port is 14, path cost 0
   Timers: message age 10, forward delay 0, hold 0
   BPDU: sent 2087, received 30


Yep, it has relinquished its role as root bridge already, and has fa0/2 in a blocking state. So apparently, a low priority and/or a low MAC address makes a switch a root bridge, and the lowest numbered redundant interface on a switch becomes the root port. Easy :)

Here's something even cooler. In our scenario, we have two switches with two redundant links. However, we are only using fa0/1 to carry traffic between the two switches. In effect, while fa0/2 is providing redundancy, it is essentially wasted bandwidth until a failure occurs. Wouldn't it be great if we could distribute the load between these two ports without setting up LAG or Etherchannel? As it turns out, we can.

You see, Spanning Tree runs a separate instance for each VLAN, which is often described as "Per-VLAN Spanning Tree" or "PVST." It turns out that we can tweak the priority of each VLAN on the FastEthernet port on each switch, making fa0/1 the designated/root port for some VLANs and fa0/2 the designated/root port for other VLANs. To keep it simple, I set this up with odd numbered VLANs on fa0/1 and even numbered VLANs on fa0/2. In a real environment, it would probably be better to do some traffic analysis and find out which VLANs typically have equal amounts of traffic and try to balance load intelligently. At any rate, here's how you do it:

lab2924b(config)#int fa0/1
lab2924b(config-if)#spanning-tree vlan 1 port-priority 64
lab2924b(config-if)#spanning-tree vlan 3 port-priority 64
lab2924b(config-if)#spanning-tree vlan 5 port-priority 64
lab2924b(config-if)#spanning-tree vlan 7 port-priority 64
lab2924b(config-if)#int fa0/2
lab2924b(config-if)#spanning-tree vlan 2 port-priority 64
lab2924b(config-if)#spanning-tree vlan 4 port-priority 64
lab2924b(config-if)#spanning-tree vlan 6 port-priority 64
lab2924b(config-if)#exit
lab2924b(config)#exit
lab2924b#sho spanning-tree vlan 2

Spanning tree 2 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 32768, address 00d0.58dd.d180
  Configured hello time 2, max age 20, forward delay 15
  Current root has priority 32768, address 0003.e3e4.f880
  Root port is 14, cost of root path is 19
  Topology change flag set, detected flag not set, changes 9
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 0, topology change 0, notification 0

Interface Fa0/1 (port 13) in Spanning tree 2 is BLOCKING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f880
   Designated bridge has priority 32768, address 0003.e3e4.f880
   Designated port is 13, path cost 0
   Timers: message age 1, forward delay 0, hold 0
   BPDU: sent 8, received 3274

Interface Fa0/2 (port 14) in Spanning tree 2 is FORWARDING
   Port path cost 19, Port priority 64
   Designated root has priority 32768, address 0003.e3e4.f880
   Designated bridge has priority 32768, address 0003.e3e4.f880
   Designated port is 14, path cost 0
   Timers: message age 2, forward delay 0, hold 0
   BPDU: sent 5, received 3376

lab2924b#sho span vlan 1

Spanning tree 1 is executing the IEEE compatible Spanning Tree protocol
  Bridge Identifier has priority 32768, address 00d0.58dd.d186
  Configured hello time 2, max age 20, forward delay 15
  Current root has priority 32768, address 0003.e3e4.f887
  Root port is 13, cost of root path is 19
  Topology change flag not set, detected flag not set, changes 7
  Times:  hold 1, topology change 35, notification 2
          hello 2, max age 20, forward delay 15
  Timers: hello 0, topology change 0, notification 0

Interface Fa0/1 (port 13) in Spanning tree 1 is FORWARDING
   Port path cost 19, Port priority 64
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 13, path cost 0
   Timers: message age 2, forward delay 0, hold 0
   BPDU: sent 347, received 6622

Interface Fa0/2 (port 14) in Spanning tree 1 is BLOCKING
   Port path cost 19, Port priority 128
   Designated root has priority 32768, address 0003.e3e4.f887
   Designated bridge has priority 32768, address 0003.e3e4.f887
   Designated port is 14, path cost 0
   Timers: message age 4, forward delay 0, hold 0
   BPDU: sent 309, received 6948


Important! I didn't show it in the config above, but I repeated the same configuration on lab2924a -- this doesn't seem to work if the priority is changed on only one switch!

Notice how fa0/1 is forwarding on VLAN 1, but is blocking on VLAN 2, and vice versa for fa0/2? You are now utilizing both 100M Ethernet ports on your switch while still avoiding loops!