Switching and VLANs
How a switch learns where devices are, how VLANs split one switch into several networks, and how Spanning Tree prevents loops.
How a switch forwards frames
A switch has one job: get each Ethernet frame to the port where its destination lives, and nowhere else. It does this with a single table and three possible decisions.
The MAC address table
The MAC address table is the list a switch keeps of which MAC address was last seen on which port, per VLAN. Cisco also calls it the CAM table, after the content-addressable memory chips that make lookups in it fast. The switch builds the table by itself: every time a frame arrives, it reads the frame's source MAC address and records "this address lives behind this port". Nobody has to configure it.
Then it looks up the frame's destination MAC address and takes one of three actions:
- Forward: the destination is in the table on another port, so the frame goes out of that port only.
- Filter: the destination is in the table on the same port the frame came in on, so the switch drops it; the destination has already received it on that segment.
- Flood: the destination is a broadcast, a multicast, or a unicast address not yet in the table.
Flooding
Flooding means the switch sends a frame out of every port in the same VLAN except the one it arrived on. It is how a switch handles destinations it does not know: the frame reaches every host, the right one answers, and from that answer's source address the switch learns where the host is. After that, frames to the host are forwarded, not flooded.
This simulation follows five frames through a four-port switch. The MAC addresses come from the documentation range and are written in Cisco's dotted format:
BROADCAST = "ffff.ffff.ffff"
PORTS = ["Gi0/1", "Gi0/2", "Gi0/3", "Gi0/4"]
mac_table = {} # MAC address -> port
def receive(src, dst, in_port):
mac_table[src] = in_port # 1. learn the source
out_port = mac_table.get(dst) # 2. look up the destination
if dst == BROADCAST or out_port is None:
others = [p for p in PORTS if p != in_port]
return "flood to " + ", ".join(others)
if out_port == in_port:
return "filter (destination is on the incoming port)"
return "forward to " + out_port
frames = [
("0000.5e00.5301", "0000.5e00.5302", "Gi0/1"), # A to B: B unknown yet
("0000.5e00.5302", "0000.5e00.5301", "Gi0/2"), # B answers A
("0000.5e00.5301", "0000.5e00.5302", "Gi0/1"), # A to B again
("0000.5e00.5303", BROADCAST, "Gi0/3"), # C sends a broadcast
("0000.5e00.5304", "0000.5e00.5301", "Gi0/1"), # D shares Gi0/1 with A
]
for number, (src, dst, port) in enumerate(frames, start=1):
action = receive(src, dst, port)
print(f"Frame {number} in {port}, to {dst}: {action}")
print()
print("MAC address table:")
for mac, port in sorted(mac_table.items()):
print(f" {mac} {port}")
Frame 1 in Gi0/1, to 0000.5e00.5302: flood to Gi0/2, Gi0/3, Gi0/4 Frame 2 in Gi0/2, to 0000.5e00.5301: forward to Gi0/1 Frame 3 in Gi0/1, to 0000.5e00.5302: forward to Gi0/2 Frame 4 in Gi0/3, to ffff.ffff.ffff: flood to Gi0/1, Gi0/2, Gi0/4 Frame 5 in Gi0/1, to 0000.5e00.5301: filter (destination is on the incoming port) MAC address table: 0000.5e00.5301 Gi0/1 0000.5e00.5302 Gi0/2 0000.5e00.5303 Gi0/3 0000.5e00.5304 Gi0/1
Frame 1 is flooded because B is unknown. B's reply (frame 2) teaches the switch where B is, so frame 3 is forwarded. The broadcast in frame 4 is always flooded. Frame 5 is filtered: host D is connected to the same port as A (behind an old hub), so A has already received it. Notice that two MAC addresses on one port is perfectly normal; the same is true for a port that connects to another switch.
Aging and the show command
Entries that are learned dynamically do not stay forever. Each one has an aging timer, 300 seconds by default on Cisco switches, that restarts whenever a frame from that address arrives. When a host is silent for longer, its entry is removed. This keeps the table from filling up with devices that left, and lets the switch learn the new port quickly when a laptop moves to another desk. On the command-line interface (CLI) you look at the table like this:
Switch1# show mac address-table dynamic
Mac Address Table
-------------------------------------------
Vlan Mac Address Type Ports
---- ----------- -------- -----
10 0000.5e00.5301 DYNAMIC Gi0/1
10 0000.5e00.5302 DYNAMIC Gi0/2
20 0000.5e00.5303 DYNAMIC Gi0/9
20 0000.5e00.5310 DYNAMIC Gi0/24
Total Mac Addresses for this criterion: 4
Each line shows the VLAN, the MAC address, how it got there (DYNAMIC
= learned, STATIC = configured) and the port. A network
operations (NetOps) engineer uses this constantly to answer "which
switch port is this device on?": look up its MAC address, and if the
port is an uplink to another switch (such as
Gi0/24 here), repeat on that switch.
show mac address-table address 0000.5e00.5301 filters
for a single address.
VLANs
Without further configuration, all ports of a switch form one broadcast domain. A VLAN (virtual local area network) splits a switch, or a group of switches, into several separate layer 2 networks. Each VLAN is its own broadcast domain and normally its own IP subnet. A frame never leaves its VLAN on its own: traffic between VLANs has to go through a router or a layer 3 switch.
Organizations use VLANs for three reasons:
- Smaller broadcast domains. Broadcasts such as Address Resolution Protocol (ARP) and Dynamic Host Configuration Protocol (DHCP) requests stay within one VLAN instead of reaching every device in the building.
- Security. Guests, cameras, servers and staff can share switches but not a network. Because traffic between VLANs passes a router or firewall, it can be filtered there.
- Organization. Networks follow function rather than location: the finance VLAN can span three floors, and moving a user means changing one port's VLAN, not recabling.
Access ports and trunk ports
Access ports
An access port is a switch port that belongs to exactly one VLAN and sends and receives ordinary, untagged Ethernet frames. End devices such as PCs, printers and access points in simple setups connect to access ports; they have no idea that VLANs exist. The switch knows which VLAN a frame belongs to simply from the port it arrived on. (An IP phone port is a common exception: it adds a separate voice VLAN for the phone, while the PC behind the phone stays in the data VLAN.)
Trunk ports
A trunk port carries frames of many VLANs over a single link, typically between two switches or between a switch and a router, firewall or hypervisor host. Without trunks, two switches that share ten VLANs would need ten cables between them. Because frames of different VLANs share the cable, every frame needs a label saying which VLAN it belongs to.
IEEE 802.1Q tagging
802.1Q is the IEEE standard for VLAN tagging on Ethernet trunks. The sending switch inserts a 4-byte tag into the frame, between the source MAC address and the EtherType field, and recalculates the frame check sequence. The receiving switch reads the tag, removes it, and handles the frame in that VLAN. The older Cisco-only alternative, ISL (Inter-Switch Link), is no longer supported on current switches.
The tag has four fields:
-
TPID (Tag Protocol Identifier), always
0x8100. It sits where the EtherType would be, so a receiver instantly sees that a tag follows. - PCP (Priority Code Point), 3 bits for quality of service: eight priority levels, used for example to put voice traffic first (this is the "802.1p" priority).
- DEI (Drop Eligible Indicator), 1 bit that marks a frame as a candidate for dropping when the network is congested.
- VID (VLAN Identifier), 12 bits. 212 = 4096 values, of which 0 and 4095 are reserved, which leaves the 4094 usable VLANs 1 to 4094.
The tag makes the largest frame 4 bytes longer: 1522 instead of 1518 bytes. Switches handle that automatically.
The native VLAN
The native VLAN is the one VLAN on an 802.1Q trunk whose frames are sent without a tag. A switch that receives an untagged frame on a trunk puts it in the native VLAN. By default this is VLAN 1. Both ends of a trunk must agree on it; a mismatch leaks frames from one VLAN into the other. On Cisco switches the Cisco Discovery Protocol (CDP) logs a "native VLAN mismatch", and PVST+ (Per-VLAN Spanning Tree Plus) blocks the affected VLANs on that port (PVID inconsistent).
Configuring VLANs on a Cisco switch
The example below is a 24-port access switch. Ports 1 to 8 go to the sales department, 9 to 12 to engineering, and port 24 is the uplink trunk to the distribution switch.
Creating VLANs and access ports
Switch1(config)# vlan 10
Switch1(config-vlan)# name SALES
Switch1(config-vlan)# vlan 20
Switch1(config-vlan)# name ENGINEERING
Switch1(config-vlan)# vlan 99
Switch1(config-vlan)# name NATIVE-UNUSED
Switch1(config-vlan)# exit
Switch1(config)# interface range GigabitEthernet0/1 - 8
Switch1(config-if-range)# switchport mode access
Switch1(config-if-range)# switchport access vlan 10
Switch1(config-if-range)# exit
Switch1(config)# interface range GigabitEthernet0/9 - 12
Switch1(config-if-range)# switchport mode access
Switch1(config-if-range)# switchport access vlan 20
-
vlan 10creates VLAN 10 (or opens it if it exists) and enters VLAN configuration mode;namegives it a readable name. You can go straight on to the nextvlancommand. -
interface rangeconfigures several ports at once. -
switchport mode accessfixes the port as an access port, so it never negotiates a trunk. -
switchport access vlan 10puts the port in VLAN 10. If the VLAN did not exist yet, the switch creates it.
Configuring a trunk
Switch1(config)# interface GigabitEthernet0/24
Switch1(config-if)# switchport mode trunk
Switch1(config-if)# switchport trunk native vlan 99
Switch1(config-if)# switchport trunk allowed vlan 10,20,99
Switch1(config-if)# switchport nonegotiate
-
switchport mode trunkmakes the port a permanent trunk. On switches that still support both ISL and 802.1Q you first needswitchport trunk encapsulation dot1q. -
switchport trunk native vlan 99moves the native VLAN to the unused VLAN 99. Configure the same on the other end. -
switchport trunk allowed vlanlimits the trunk to the listed VLANs; by default it carries all of them. To add one later, useswitchport trunk allowed vlan add 30: withoutadd, the list is replaced. -
switchport nonegotiateturns off DTP on the link.
Verifying
Switch1# show vlan brief
VLAN Name Status Ports
---- -------------------------------- --------- -------------------------------
1 default active Gi0/13, Gi0/14, Gi0/15, Gi0/16
Gi0/17, Gi0/18, Gi0/19, Gi0/20
Gi0/21, Gi0/22, Gi0/23
10 SALES active Gi0/1, Gi0/2, Gi0/3, Gi0/4
Gi0/5, Gi0/6, Gi0/7, Gi0/8
20 ENGINEERING active Gi0/9, Gi0/10, Gi0/11, Gi0/12
99 NATIVE-UNUSED active
1002 fddi-default act/unsup
1003 token-ring-default act/unsup
1004 fddinet-default act/unsup
1005 trnet-default act/unsup
show vlan brief lists each VLAN with its name, status
and access ports. Gi0/24 is missing on purpose: trunk ports
do not appear in this list. To see trunks, use:
Switch1# show interfaces trunk
Port Mode Encapsulation Status Native vlan
Gi0/24 on 802.1q trunking 99
Port Vlans allowed on trunk
Gi0/24 10,20,99
Port Vlans allowed and active in management domain
Gi0/24 10,20,99
Port Vlans in spanning tree forwarding state and not pruned
Gi0/24 10,20,99
The first block shows the mode (on = configured as a
permanent trunk), the tagging standard and the native VLAN. The last
block is the one that tells you which VLANs actually pass traffic
over the link. If a VLAN works on one switch but not across the
trunk, check here first.
Inter-VLAN routing
Since each VLAN is a separate network, a PC in VLAN 10 needs a router to reach a PC in VLAN 20, exactly as if they were on different switches. There are two common designs:
- Router-on-a-stick: one router interface connects to a trunk port and is split into subinterfaces, one per VLAN, each with its own tag and IP address. Cheap and simple, but all traffic between VLANs crosses one link twice.
-
Switch virtual interfaces (SVIs) on a layer 3 switch: the switch gets a virtual interface per VLAN (
interface vlan 10) and routes between them internally, at full speed. This is the normal choice in a campus network.
R1(config)# interface GigabitEthernet0/0.10
R1(config-subif)# encapsulation dot1Q 10
R1(config-subif)# ip address 192.168.10.1 255.255.255.0
R1(config-subif)# interface GigabitEthernet0/0.20
R1(config-subif)# encapsulation dot1Q 20
R1(config-subif)# ip address 192.168.20.1 255.255.255.0
encapsulation dot1Q 10 ties the subinterface to VLAN
10's tag; its IP address becomes the default gateway of the hosts in
that VLAN. The physical interface Gi0/0 itself needs
no shutdown and no IP address. How the router then
chooses a path is covered in
Routing Basics.
Spanning Tree Protocol
Networks need redundant links: if the one cable between an access switch and the core fails, a whole floor goes offline. But two switches connected by two paths form a loop, and at layer 2 a loop is fatal.
Why layer 2 loops are fatal
An IP packet has a time-to-live counter that routers decrease, so a packet caught in a routing loop dies eventually. An Ethernet frame has no such field. A single broadcast sent into a switching loop is flooded by every switch, comes back, and is flooded again, forever, multiplying at every branch. Within seconds this broadcast storm fills every link and overloads the switches' CPUs. MAC address tables become unstable too, because the same source address keeps arriving on different ports ("MAC flapping"). The network stops working until someone pulls a cable.
How STP works
Spanning Tree Protocol (STP, IEEE 802.1D) lets switches find redundant paths and block just enough ports that exactly one active path remains between any two points: a loop-free tree. Switches exchange messages called BPDUs (bridge protocol data units) and follow three steps:
- Elect a root bridge. The switch with the lowest bridge ID wins. The bridge ID is a priority (default 32768, plus the VLAN number on Cisco switches) followed by the switch's MAC address, so without configuration the switch with the lowest MAC address wins, which is often the oldest one. Set the priority on purpose so a core switch becomes root.
- Choose root ports. Every other switch picks the one port with the lowest-cost path to the root bridge.
- Choose designated ports and block the rest. On every link, one port is designated to forward toward the segment. Any port that is neither a root port nor a designated port is blocked: it drops user traffic, but keeps listening to BPDUs so it can take over when a link fails.
Classic 802.1D is slow: a port goes through listening and learning states and needs 30 to 50 seconds before it forwards after a change. RSTP (Rapid Spanning Tree Protocol, IEEE 802.1w, now part of 802.1D-2004 and 802.1Q) converges in a second or so in most cases. Cisco runs a separate tree per VLAN: PVST+ and its rapid version Rapid PVST+.
PortFast and BPDU Guard
A port to a single PC can never create a loop, so waiting 30 seconds (two forward-delay periods of 15 s, also under Rapid PVST+ when the port is not an edge port) is pointless, and can make DHCP or PXE (Preboot Execution Environment) boot time out on some clients, leaving them with an Automatic Private IP Addressing (APIPA) address. PortFast lets such an access port forward immediately. BPDU Guard protects it: if a BPDU ever arrives on the port, meaning someone plugged in a switch, the port is shut down (err-disabled) before a loop can form.
Switch1(config)# spanning-tree mode rapid-pvst
Switch1(config)# interface range GigabitEthernet0/1 - 12
Switch1(config-if-range)# spanning-tree portfast
Switch1(config-if-range)# spanning-tree bpduguard enable
The first line switches the whole switch to Rapid PVST+. The other
lines enable PortFast and BPDU Guard on the user ports only; IOS
prints a warning reminding you that PortFast belongs on ports to a
single host. Never enable PortFast on a link to another switch.
show spanning-tree vlan 10 shows the root bridge and
the role and state of every port.