Mental model
A hub broadcasts every frame out every port. Dumb but works. A switch is smarter: it remembers where each device lives and forwards frames only to the port where the destination actually is.
How does it know? It learns from the source MAC of every frame it sees:
“This frame arrived on port Gi0/3 with source MAC aa:aa:aa. Therefore aa:aa:aa lives on port Gi0/3. I’ll remember that.”
The MAC address table (also called the CAM table — Content-Addressable Memory) is just that memory: a list of MAC ↔ port mappings, per VLAN.
When a new frame arrives, the switch:
- Records the source MAC + port (learning)
- Looks up the destination MAC
- If known → sends out the one matching port (unicast)
- If unknown → floods to all other ports in the same VLAN (let the network figure it out)
- The destination eventually replies → switch learns its location too
That’s the whole protocol. Plug-and-play, no configuration.
Reading the table
SW1# show mac address-table
Mac Address Table
-------------------------------------------
Vlan Mac Address Type Ports
---- ----------- -------- -----
10 aaaa.aaaa.aaaa DYNAMIC Gi0/1
10 bbbb.bbbb.bbbb DYNAMIC Gi0/2
20 cccc.cccc.cccc DYNAMIC Gi0/5
99 1234.5678.9abc STATIC Gi0/24
Read aloud: “MAC aaaa.aaaa.aaaa is on port Gi0/1 in VLAN 10. Learned dynamically. Use this entry to forward frames addressed to it.”
Types:
- DYNAMIC — learned from observed traffic. Ages out after 300 seconds of no activity.
- STATIC — manually configured (or learned via port-security sticky).
Aging — entries don’t live forever
If a switch hasn’t seen any frames from aaaa.aaaa.aaaa for 300 seconds (default), the entry ages out. The switch forgets where it lives.
This is intentional — if a device moves from port Gi0/1 to Gi0/3, the old entry needs to expire so the new one can take over. But it also means: 5 minutes of silence and the switch will flood the next frame addressed to that MAC.
Adjust the aging timer:
SW1(config)# mac address-table aging-time 600 ! 10 minutes
Static MAC entries
Pin a specific MAC to a specific port permanently:
SW1(config)# mac address-table static aaaa.bbbb.cccc vlan 10 interface GigabitEthernet0/5
Used for:
- Critical servers that should always live on a specific port
- Some security setups (combined with port security)
- Workarounds for unusual gear
Use sparingly. Static entries don’t age, so a moved device → table mismatch → traffic blackhole until you fix it.
Unknown unicast flooding — the “broken silence” problem
If a server is quiet for >5 minutes (no outbound traffic), its MAC ages out. Now when a client tries to talk to it, the switch doesn’t know where it lives → floods to every port in the VLAN. Bandwidth waste, security exposure.
Mitigations:
- Raise the aging timer beyond your longest silent server (
mac address-table aging-time 1800= 30 min) - Or: pin critical servers with static entries
- Or: configure devices to send periodic heartbeats (most do automatically)
Commands
! View the entire table
SW1# show mac address-table
! Filter by VLAN, MAC, or interface
SW1# show mac address-table vlan 10
SW1# show mac address-table address aaaa.bbbb.cccc
SW1# show mac address-table interface GigabitEthernet0/1
! Count entries
SW1# show mac address-table count
! Manually clear (forces re-learning on next traffic)
SW1# clear mac address-table dynamic
SW1# clear mac address-table dynamic interface GigabitEthernet0/1
! Static entry
SW1(config)# mac address-table static aaaa.bbbb.cccc vlan 10 interface Gi0/5
! Adjust aging
SW1(config)# mac address-table aging-time 600
Common mistakes
-
Confusing MAC table with ARP table. Both contain MAC addresses, but they’re different layers and different devices. MAC table = on switches, maps MAC → port. ARP table = on hosts and routers, maps IP → MAC. Don’t mix them up.
-
Forgetting MAC addresses are per-VLAN. The same MAC can theoretically appear in two VLANs (rare but possible) — the table tracks them separately. Always include
vlanwhen troubleshooting. -
Assuming flooding only happens at boot. Any aged-out entry causes flooding when traffic resumes. On a 50-port switch in a chatty environment, this can be constant low-level flooding.
-
Setting aging too low (or zero). Aging time of 30 seconds = constant flooding. Aging time of 0 = entries never age, but mobile devices that move ports get stuck. Default 300s is sane.
-
Trying to filter by MAC at L2. Filtering on a switch is by port (port security) or by Layer-3 ACL on a routed interface. There’s no native “block traffic from MAC X” command on basic IOS switches.
-
Not recognizing the MAC flooding attack. An attacker rapidly sends frames with millions of bogus source MACs → fills the CAM table → switch starts flooding everything to all ports (because it can’t learn new entries). Defend with port security to cap learned MACs per port.
Lab to try tonight
- One switch, three PCs in the same VLAN. Connect them.
- Don’t generate any traffic yet. Run
show mac address-table— likely empty for those ports. - Ping from PC-A to PC-B. Re-run the command. Now both MACs appear.
- Open Wireshark on PC-C. Ping PC-A → PC-B. Confirm PC-C does NOT see the ping traffic (switch sent it only to PC-B’s port — that’s the whole point of a switch).
- Wait 5 minutes (or
clear mac address-table dynamic). Re-ping. With an empty table, the switch initially floods — PC-C briefly sees the first frame in Wireshark before the table re-populates. - Add a static entry pinning PC-B’s MAC. Verify it survives
clear mac address-table dynamic.
Cheat strip
| Concept | Plain English |
|---|---|
| MAC table / CAM | Switch’s memory of “who lives on which port” |
| Learning | From source MAC of incoming frames |
| Forwarding | Looking up destination MAC |
| Unknown unicast flooding | Forward to all ports in VLAN if dest is unknown |
| Aging time | Default 300s. Entries expire if no traffic. |
| Static entry | Manually pinned. Doesn’t age. |
| MAC flooding attack | Overflow the table → forced flooding. Defend with port-security. |
| Per-VLAN | Same MAC can appear in different VLANs separately |