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.
Switch SW1 has PC1 and PC2 on VLAN 10 and PC3 and PC4 on VLAN 20, all on access ports. A trunk from SW1 to SW2 carries both VLANs with 802.1Q tags. VLAN 10 · SALES VLAN 20 · ENGINEERING Trunk (802.1Q) carries VLAN 10 and 20, tagged access ports SW2 SW1 PC1 PC2 PC3 PC4
One physical switch, two broadcast domains. A broadcast from PC1 reaches PC2 (and VLAN 10 on SW2), but never PC3 or PC4.

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.

An Ethernet frame with an 802.1Q tag: destination MAC (6 bytes), source MAC (6 bytes), the 4-byte tag, EtherType (2 bytes), payload and FCS (4 bytes). The tag contains the TPID 0x8100 (16 bits), priority PCP (3 bits), DEI (1 bit) and the VLAN ID (12 bits). Dest. MAC 6 bytes Source MAC 6 bytes 802.1Q tag 4 bytes Type 2 bytes Payload 46–1500 bytes FCS 4 bytes TPID 0x8100 16 bits PCP 3 bits DEI 1 bit VLAN ID 12 bits
The 802.1Q tag sits between the source MAC address and the EtherType. The preamble, sent before the frame, is not shown.

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 10 creates VLAN 10 (or opens it if it exists) and enters VLAN configuration mode; name gives it a readable name. You can go straight on to the next vlan command.
  • interface range configures several ports at once.
  • switchport mode access fixes the port as an access port, so it never negotiates a trunk.
  • switchport access vlan 10 puts 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 trunk makes the port a permanent trunk. On switches that still support both ISL and 802.1Q you first need switchport trunk encapsulation dot1q.
  • switchport trunk native vlan 99 moves the native VLAN to the unused VLAN 99. Configure the same on the other end.
  • switchport trunk allowed vlan limits the trunk to the listed VLANs; by default it carries all of them. To add one later, use switchport trunk allowed vlan add 30: without add, the list is replaced.
  • switchport nonegotiate turns 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:

  1. 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.
  2. Choose root ports. Every other switch picks the one port with the lowest-cost path to the root bridge.
  3. 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.