Spanning tree protects our layer 2 network from broadcast storms and helps to create a loop free layer 2 topology. STP takes advantage of additional features that have been added over the years help prevent unnecessary changes to the network or to help prevent unintentional or sometimes malicious activities from occurring on our networks. Some of these features include
- UDLD (Unidirectional Link Detection)
I've talked about portfast in some previous posts but what exactly is it? Portfast is an STP mechanism that helps a port transition from Blocking to Forwarding by skipping the Listening and Learning states. Portfast also prevents a switch from generating a TCN BPDU when a port goes up or down. Portfast can be enabled in one of two ways. You can enable portfast globally using the command spanning-tree portfast default or on a per-interface basis using the interface configuration subcommand spanning-tree portfast. When you first configure portfast, either globally or on an interface, you receive a warning about ensuring that it is not enabled on interfaces that are connected to other switches.
Notice the message saying that portfast will only take effect when the interface is in a non-trunking mode. This helps to prevent a network engineer from enabling portfast on interfaces that might have other switches connected. There are however times where you may want portfast enabled on a trunk port. For example if you have a router connected to a switch via trunk port or an AP that has multiple SSIDs over multiple VLANs. In modern networks we use Servers running VMWare or other virtualisation platform that supports VLANs and would require a Trunk port configured on a switch. For this we can use the interface configuration subcommand spanning-tree portfast trunk.
Rootguard does exactly what the name suggests, it guards a port from becoming the Root Port. Rootguard is enabled on an interface by interface basis and should be placed on ports that the switch should net receive a superior BPDU from. If the switch hears a superior BPDU on a rootguard enabled port, the port is put in either an err-disable state or in STP Broken Root_Inc state depending on platform/IOS version. To enable rootguard, use the interface configuration command spanning-tree guard root.
In our topology if i place rootguard on SW2's G1/0/2 interface, and cause SW2 to attempt to become the root by changing it's priority to 0, we should see the port transition to the STP Broken state with Root_Inc.
BPDUGuard again is pretty self explanatory in what it does. It protects the switch from receiving BPDUs on ports that it shouldn't. BPDUGuard prevents another switch or device from being chosen as the Root or even participating in the Spanning-tree topology by placing the port in an err-disable state if a BPDU is received. BPDUGuard can be enabled both globally, or on a port by port basis by using either the global configuration command spanning-tree portfast bpduguard default or the interface configuration subcommand spanning-tree bpduguard enable. When you enable BPDUGuard globally, it enables it on all portfast enabled ports on the switch. I will talk a little more about error disable and the recovery mechanisms later in this article.
To show what happens when a port hears a BPDU on a bpduguard enabled interface I will enable it on G1/0/2 on SW3 which is receiving BPDUs but is currently in the STP block state.
You can see here that after enabling BPDUGuard the port status shows as err-disable in the output of the show int status command and in the output of the sh int status error-disable command you can see the reason is bpduguard. To fix an err-disable port you need to both fix the issue that caused the port to err-disable and shut and no shut the interface.
You can verify that a switch port has BPDUGuard enabled by using the command show spanning-tree interface <int> detail.
Loopguard aids in preventing an accidental bridging loop. When you have a redundant path in a Layer 2 topology, STP decides which ports are forwarding and which are blocking. In our topology we have SW2 forwarding and SW3 as blocking. SW3 however still receives BPDUs on the blocking interfaces as this is a requirement for a port to stay blocked. Now say for some reason, an indirect failure occurs and BPDUs step being received on SW3's redundant path. SW3 will normally keep the BPDU in its cache for a period of Max Age before flushing it, and transitioning the ports to a forwarding state creating a loop. Loopguard prevents this type of STP loop from happening by putting the port in an STP Loop_Inc state which effectively shuts the port down. When BPDU's are heard on the interface again, Loopguard allows the port to transition through the normal STP states to the blocking state again.
Loopguard can be enabled either globally or on a port by port basis. When enabling loopguard globally, the switch will automatically work out which ports are non designated ports and need to be monitored for BPDUs. Even though loopguard is configured for a switchport, the action that is taken is on a per-VLAN basis meaning that loopguard doesn't block the entire port, only the offending VLANs. To enable loopguard globally, use the configuration command spanning-tree loopguard default or the interface configuration subcommand spanning-tree guard loop. You can verify that loopguard is enabled on an interface by using the command show spanning-tree interface <int> detail.
To confirm that loopguard is working as expected and that the port will transition to the Loop_Inc state, I have enabled BPDUFilter on the G1/0/4 interface on SW2. If we look at the output of the show spanning-tree [vlan <id>] command we can see that the port was placed in a Loop_Inc state.
Like most of the other STP protection mechanisms, BPDUFilter does what the name suggests, it filters BPDUs from being sent or received on a switch port. If a switchport receives a BPDU with BPDUFilter enabled, the portfast status of that port is removed and BPDUs are processed as normal. Like BPDUGuard there are two ways to enable BPDUFilter. You can configure it globally using the command spanning-tree portfast bpdufilter default or on a port by port basis using the interface configuration subcommand spanning-tree bpdufilter enable. When BPDUFilter is enabled it will behave differently depending on the method chosen:
- Globally: When enabled globally the switch will send a series of 10-12 BPDUs and wait for a response. If the switch receives a BPDU it checks to see which switch is preferred:
- The preferred switch does not process any BPDUs that it receives but still transmits BPDUs to the inferior downstream switch
- The non preferred switch receives PBDUs and processes them but does not transmit BPDUs.
- Interface based: When enabled on an interface, BPDUFilter prevents the port from sending BPDUs or processing received BPDUs.
There are very few reasons why you would actually need to use BPDUFilter in a production network however I used it in another article to simulate an indirect failure for STP and also to simulate the Loop_Inc state for loopguard earlier.
UDLD or Unidirectional Link Detection is a Cisco proprietary feature that is used to detect layer 2 issues with a link that cause it to be unidirectional. A unidirectional link is a link that can send or receive but not both on at least one end of a segment. While UDLD works with both copper and fibre links, fibre links have a sending cable and a receiving cable, having a link that appears up but has no data traversing it in one direction due to a broken lead is very possible. UDLD helps to prevent this type of problem by exchanging hello packets between connected devices.
UDLD hello packets use what's called an echo algorithm. The hello packets contain the device and port ID of local switch and also echo back the device and port ID of the remote switch and are sent using the mac address 0100.0ccc.cccc. If the switch stops receiving these hellos for a period of time, the link is determine to be unidirectional and the port is put in an err-disable state until such time as it is either manually bought back online or err-disable recovery has kicked in.
UDLD has two modes, normal and aggressive. If UDLD is configured to use normal mode and stops receiving those hello messages with its own device and port ID for the duration of the hold time, the port is considered in an undetermined state but no action is taken and the port still uses its STP state. In aggressive mode, if the port stops receiving the hello packets with its own device and port ID for a period of the hold time, the switch will try to re-establish communication with the neighbour by sending a hello packet every second for 8 seconds. If no response is received with the switches own device and port ID, the port is considered unidirectional and the port is put in an err-disable state.
The hold time for a UDLD age out is 3 x hello time. The default hello time for a UDLD packet is 15 seconds giving a total fail over time of 45 seconds. It's recommended the UDLD hold time should be configured to be slightly faster than that of STP in order to prevent STP loops.
To configure UDLD you can use either the global configuration command udld [aggressive|enable|message time <time>] where time is a range from 1 to 90 seconds, or the interface, or the interface configuration subcommand udld [aggressive]. When enabling UDLD globally, it is only enabled for fibre ports not twisted pair. In order to enable for a twisted pair link you need to use the interface configuration command.
Error-Disable and Recovery
I've mentioned a few times in the above features that a port is put in an err-disable state if a certain type of error on the port is found but what exactly is error disable? Switches have ways built into them to detect layer 1 issues and some of the features above help detect layer 2 issues and error disable works with those features and others in order to protect the network from layer 2 faults. Error disable was originally developed to detect special collision issues on a switch port with excessive or late collisions. Error disable has since grown to detect many other types of layer 2 issues including:
- Port-channel misconfiguration
- Port security
- Dhcp snooping
- Link flapping
- Incorrect gbic/sfp
- Link flapping
Below is the output of a list of possible error detection features that are supported on a catalyst 3650 platform using the command show errordisable detect.
Error-disable is enabled by default for all of the above reasons and needs to be disabled if you don't want it on. To disable error-disable for a specific reason use the global configuration command no errdisable detect cause <reason>. Note that you cannot disable error disable for all of the above detections.
If a port has been put in the err-disable state, there are 2 ways to recover from it. Once you have discovered the root cause of the err-disable state and the issue has been resolved, you can either shut down and the bring back up the interface with the shut and no shut interface commands, or by configuring error-disable recovery. Error disable recovery is configured to automatically recover from an err-disable state after a certain time period.
To determine why an interface has been put in the err-disable state you can use the commands show int status err-disable.
Error-disable recovery is enabled on a per error basis and is configured using the global configuration command errordisable recovery cause <cause> and the interval that error-disable recovery checks and recovers is set using the global configuration command errordisable recover interval <time>. the default time for error-disable recovery is 300 seconds.
The below example I have enabled BPDUGuard on SW3's g1/0/3 interface in order to place it in an err-disabled state due to hearing BPDUs. I have also configured error disable recovery for BPDUGuard on SW3 with a timer of 60 seconds. Once I enable BPDUGuard on the interface you can see the port is placed in an err-disable state due to BPDUGuard. I then removed BPDUGuard from the interface and waited for error disable recovery to bring the port back up.
Uplinkfast allows an access layer switch at the leaves of the Spanning-Tree to immediately move to another potential root port if the primary RP fails. This feature bypasses all timers and transitions the ALT port immediately. Uplink fast is enabled globally on a switch using the command spanning-tree uplinkfast. When enabled, uplink fast monitors all ports and keeps track of all possible paths to the Root Bridge. Uplink fast cannot be enabled on a root bridge. Uplink fast also takes additional measures to ensure that the switch does not become the root and does not become a transit switch to the Root Bridge. When uplinkfast is enabled, it raises the switches priority to 49152, and the port cost for each port is increased by 3000 ensuring that it is not likely to be selected as a path to the root.
When the RP fails on the switch, one of the ALT ports will immediately take over. Uplinkfast causes the local switch to flush its MAC table quickly after the failover. Uplinkfast also provides a mechanism for the local switch to notify the upstream switches that stations downstream can be reached via the new uplink. Uplink fast achieves this by sending dummy multicast frames to the MAC address 0100.0ccd.cdcd. These frames appear to be coming from the hosts themselves and allow the upstream switches to update their CAM tables. To view the status of uplinkfast on the switch, use the command show spanning-tree uplinkfast.
Backbone fast provides a mechanism for a switch to keep track of alternate paths to the Root Bridge in case of an indirect failure occurs on a link that is not directly connected to the local switch. Normally a switch must wait for the Max aGe timer to expire before looking for a new Root Port when it hears an inferior BPDU on a link. If a backbonefast enabled switch hears an inferior BPDU, a new Root Bridge path will be considered depending on what port the inferior BPDU was heard on.
- Blocked Port: If the inferior BPDU is heard on a blocked port, the switch considers its current RP and all other Blocked Ports, as potential alternative paths to the Root.
- Root Port: If the inferior BPDU arrives on the Root Port, the switch assumes all Blocked ports to be alternative paths to the root.
- Root port with no Blocked ports: In this case, the switch assumes that it has lost connectivity to the Root and that it is now the new Root bridge.
In order for a backbonefast enabled switch the keep track of alternative paths to the root bridge. If the backbonefast switch has blocked ports, it makes use of a Root Link Query (RLQ) packets by sending them out all upstream switches in the network. When a switch receives an RLQ packet and is the root bridge or has lost its connection to the Root Bridge, an RLQ Reply is sent. Otherwise, the RLQ Query is forwarded to all other switches until an RLQ Reply is heard. For this reason, backbonefast must be enabled on all switches in the network. Of the local switch hears an RLQ reply on it's RP, then the current path to the root is stable. If it is received on a non RP, then an alternative path to the root must be found and the Max Age timer is expired. In a single sentence, backbone fast bypasses the STP Max Age timer due to an indirect failure of the RP. Note that in a failure event, the Switch must still transition it's ports through the Listening and Learning states using the Forward Delay timer.
To configure BackboneFast, use the global configuration command spanning-tree backbonefast.
To verify backbone fast configuration, use the show command show spanning-tree backbonefast. This output was taken after I caused an indirect failure.