Chapter: 3 (Switching)
Duration: 90 minutes
Tools: Containerlab, Linux bridge, tcpdump, Wireshark
Points: 10
Objectives
- Configure 802.1Q VLAN trunks between switches
- Observe STP BPDU exchange and Root Bridge election
- Measure STP convergence time after a topology change
- Enable RSTP and compare convergence time
- Configure a 2-port LACP bond
Topology
sw1 ---- sw2
/ | |
h1 h2 h3
V10 V10 V10
All hosts in VLAN 10. sw1-sw2 link is a trunk. Objective: observe Root Bridge election, then force a failure.
Setup
# topo-stp.clab.yml
name: stp
topology:
nodes:
sw1:
kind: linux
image: alpine:latest
sw2:
kind: linux
image: alpine:latest
h1:
kind: linux
image: alpine:latest
h2:
kind: linux
image: alpine:latest
h3:
kind: linux
image: alpine:latest
links:
- endpoints: ["sw1:eth1", "sw2:eth1"] # trunk
- endpoints: ["sw1:eth2", "h1:eth1"] # access VLAN 10
- endpoints: ["sw1:eth3", "h2:eth1"] # access VLAN 10
- endpoints: ["sw2:eth2", "h3:eth1"] # access VLAN 10
containerlab deploy -t topo-stp.clab.yml
Configure sw1 as a Linux bridge with VLAN filtering:
docker exec clab-stp-sw1 bash -c "
# Create bridge with VLAN filtering
ip link add br0 type bridge
ip link set br0 type bridge vlan_filtering 1
# Add trunk port (tagged)
ip link set eth1 master br0
bridge vlan add vid 10 dev eth1
# Add access ports for VLAN 10 (untagged)
ip link set eth2 master br0
bridge vlan add vid 10 dev eth2 pvid untagged
bridge vlan del vid 1 dev eth2
ip link set eth3 master br0
bridge vlan add vid 10 dev eth3 pvid untagged
bridge vlan del vid 1 dev eth3
ip link set br0 up
ip link set eth1 up
ip link set eth2 up
ip link set eth3 up"
Repeat analogously for sw2 (eth1=trunk, eth2=access VLAN 10).
Configure host IPs:
docker exec clab-stp-h1 ip addr add 10.10.10.1/24 dev eth1
docker exec clab-stp-h2 ip addr add 10.10.10.2/24 dev eth1
docker exec clab-stp-h3 ip addr add 10.10.10.3/24 dev eth1
Exercises
Exercise 1: BPDU Capture and Root Bridge Election (20 min)
# Capture BPDUs on the trunk link
docker exec clab-stp-sw1 tcpdump -i eth1 -w /tmp/bpdu_capture.pcap &
# Wait 30 seconds for STP to converge
sleep 30
# Stop capture
docker exec clab-stp-sw1 killall tcpdump 2>/dev/null
# Copy capture to host for Wireshark
docker cp clab-stp-sw1:/tmp/bpdu_capture.pcap /tmp/
Open in Wireshark. Filter: stp
Record:
- Which switch became the Root Bridge? (Lowest Bridge ID = priority + MAC)
- What is the Root Bridge's MAC address?
- Which port on the non-root switch is the Root Port? How did you determine this?
- Are any ports in Blocking state? Which ones?
Exercise 2: Convergence Measurement under STP (25 min)
Start a continuous ping from h1 to h3:
docker exec -it clab-stp-h1 ping -i 0.1 -c 600 10.10.10.3 > /tmp/ping_stp.txt &
Force a topology change by disabling the trunk link:
docker exec clab-stp-sw1 ip link set eth1 down
Record:
- How many consecutive ping packets failed?
- Estimate the convergence time (seconds from link down to pings resuming)
- Does the measured convergence match the expected STP convergence time (Listening 15s + Learning 15s = ~30s)?
Restore the link:
docker exec clab-stp-sw1 ip link set eth1 up
Exercise 3: Enable RSTP and Repeat Measurement (20 min)
Enable RSTP on both switches (Linux bridge uses stp_state 1 which defaults to RSTP in modern kernels):
# Verify STP state and protocol version
docker exec clab-stp-sw1 bridge -d stp show br0
# Look for "rapid" in the output
If not already using RSTP, explicitly configure:
docker exec clab-stp-sw1 bash -c "ip link set br0 type bridge stp_state 1 && ip link set br0 type bridge hello_time 2 forward_delay 4 max_age 6"
Repeat the ping + link-down test:
docker exec -it clab-stp-h1 ping -i 0.1 -c 300 10.10.10.3 > /tmp/ping_rstp.txt &
docker exec clab-stp-sw1 ip link set eth1 down
sleep 5
docker exec clab-stp-sw1 ip link set eth1 up
Record:
- How many ping packets failed with RSTP?
- Estimated convergence time with RSTP vs. STP?
- Why is RSTP faster? What mechanism replaces the timer-driven state transitions?
Exercise 4: 802.1Q Trunk Verification (10 min)
Capture traffic on the sw1-sw2 trunk and verify 802.1Q tagging:
docker exec clab-stp-sw1 tcpdump -i eth1 -n -e -w /tmp/trunk.pcap &
docker exec clab-stp-h1 ping -c 5 10.10.10.3
docker exec clab-stp-sw1 killall tcpdump 2>/dev/null
docker cp clab-stp-sw1:/tmp/trunk.pcap /tmp/
In Wireshark: filter vlan to show only 802.1Q-tagged frames.
Record:
- What VLAN ID (VID) appears in the 802.1Q tag?
- What is the 802.1Q TPID value in the Ethernet header?
- Are the ARP frames also tagged with the VLAN ID?
Exercise 5: LACP Bond (15 min)
Add a second link between sw1 and sw2 and configure LACP:
Add to topology YAML: - endpoints: ["sw1:eth4", "sw2:eth3"]
Redeploy and configure bonding:
# Configure LACP bond on sw1
docker exec clab-stp-sw1 bash -c "
ip link add bond0 type bond
ip link set bond0 type bond mode 802.3ad
ip link set eth1 master bond0
ip link set eth4 master bond0
ip link set bond0 up
cat /proc/net/bonding/bond0"
Record:
- Does the bond show both interfaces as "Active"?
- Disable eth1 on sw1:
ip link set eth1 down. Do pings from h1 to h3 continue? - How does LACP eliminate the need for STP on these ports?
Lab Report
- Why is RSTP faster than STP on point-to-point links? Describe the proposal/agreement mechanism.
- What happens if PortFast is configured on a switch-to-switch trunk port? Why is this dangerous?
- A switch has priority 32768 + MAC 00:aa:bb:cc:dd:01. Another has priority 28672 + MAC 00:ff:ee:cc:bb:01. Which becomes Root Bridge? Show your calculation.
Cleanup
containerlab destroy -t topo-stp.clab.yml
Grading (10 points)
| Item | Points |
|---|---|
| BPDU capture: Root Bridge correctly identified with MAC and Bridge ID | 2 |
| STP convergence: measured time ~30s; explanation of Listening+Learning | 2 |
| RSTP convergence: sub-second measurement; correct explanation of proposal/agreement | 2 |
| 802.1Q trunk verification: VID field and TPID identified in Wireshark | 2 |
| Lab report: PortFast danger explained; Bridge ID calculation correct | 2 |