In this article we are going to talk about The Port-Security feature in Cisco Switches, which is a Layer 2 First Hop Security Mechanism.
Port-Security
Port-Security is a feature on Cisco Layer 2 and Multi-Layer Switches (MLS), which in simple words, it is helping us to limit the number of MAC addresses that the device can learn on each of the ports, we can mitigate MAC Flooding and MAC Spoofing attacks by securing down (Secure Shutdown) the port, Droping the Frames coming from illegitimate Source MAC Addresses. After enabling this feature, the switch will check each and every Frame entering to the switch on a specific port and it makes the descision based on the configuration you have done on the port. This is a simple Topology connecting a PC to a Cisco Virtual MLS Switch:

How to Configure Port-Security?
In this example, We have used a Virtual Cisco Switch (vIOS L2) and vIOS L3 (Virtual Cisco Router) as a PC to implement and test this feature. First of all let’s check the maximum number of MAC Addresses which this switch can keep in the TCAM:
Switch#show mac address-table count
Mac Entries for Vlan 1:
---------------------------
Dynamic Address Count : 1
Static Address Count : 0
Total Mac Addresses : 1
Total Mac Address Space Available: 77818696
At the first glance, it seems a little bit odd!, because the numbers are too high! the reason is because of Virtual and Test only nature of this platform (vIOS), in a physical Catalyst switch you get much less numbers, as an example this is the same command output on a Cisco Catalyst 9300 switch:
Switch#show mac address-table count
Mac Entries for Vlan 1:
---------------------------
Dynamic Address Count : 11
Static Address Count : 0
Total Mac Addresses : 11
Total Dynamic Address Count : 11
Total Static Address Count : 0
Total Mac Address In Use : 11
Total Mac Address Space Available: 32757
Switch#show sdm prefer
Showing SDM Template Info
This is the Access template.
Number of VLANs: 4094
Unicast MAC addresses: 32768
Overflow Unicast MAC addresses: 1024
L2 Multicast entries: 8192
Overflow L2 Multicast entries: 512
L3 Multicast entries: 8192
Overflow L3 Multicast entries: 512
Directly connected routes: 24576
Indirect routes: 8192
STP Instances: 1024
Security Access Control Entries: 5120
QoS Access Control Entries: 5120
Policy Based Routing ACEs: 1024
Netflow Input ACEs: 256
Netflow Output ACEs: 768
Ingress Netflow ACEs: 256
Egress Netflow ACEs: 768
Flow SPAN ACEs: 1024
Tunnels: 512
LISP Instance Mapping Entries: 512
Control Plane Entries: 512
Input Netflow flows: 32768
Output Netflow flows: 32768
SGT/DGT (or) MPLS VPN entries: 8192
SGT/DGT (or) MPLS VPN Overflow entries: 512
Wired clients: 2048
MACSec SPD Entries: 256
MPLS L3 VPN VRF: 255
MPLS Labels: 2048
MPLS L3 VPN Routes VRF Mode: 7168
MPLS L3 VPN Routes Prefix Mode: 3072
MVPN MDT Tunnels: 256
L2 VPN EOMPLS Attachment Circuit: 256
MAX VPLS Bridge Domains : 128
MAX VPLS Peers Per Bridge Domain: 32
MAX VPLS/VPWS Pseudowires : 1024
These numbers are typical for L2 and IPv4 features.
Some features such as IPv6, use up double the entry size;
so only half as many entries can be created.
* values can be modified by sdm cli.
As you have realized from the above output, the switches have limited resources to learn Unicast MAC Addresses, and an attacker can exhaust the MAC Address Table of the device by doing MAC Flooding attack, As the result of this attack, the switch will not be able to learn new MAC Addresses, so it will flood every frame coming from it’s port to all the ports which are part of the same VLAN (Exact default behavior of a switch dealing with BUM Traffic), so the attacker can easily sniff the frames coming from all sources and they may do Man In The Middle Attack.
Mac Flood with macof is described here.
Let’s configure and verify the Port-Security feature on a Cisco Switch:
Switch(config)#do sh run int g0/0
Building configuration...
Current configuration : 140 bytes
!
interface GigabitEthernet0/0
switchport mode access
switchport port-security maximum 2
switchport port-security
end
Switch(config)#do sh port-security
Secure Port MaxSecureAddr CurrentAddr SecurityViolation Security Action
(Count) (Count) (Count)
---------------------------------------------------------------------------
Gi0/0 2 1 0 Shutdown
---------------------------------------------------------------------------
Total Addresses in System (excluding one mac per port) : 0
Max Addresses limit in System (excluding one mac per port) : 4096
At the moment only 1 MAC Address is learned on this port, let’s change the MAC Address on the PC (It is a vIOS L3 node for testing purpose) and do the verification again:
PC(config-if)#do sh run int g0/0
Building configuration...
Current configuration : 145 bytes
!
interface GigabitEthernet0/0
mac-address 0000.1111.1111
ip address 10.10.10.100 255.255.255.0
!
Switch(config)#do sh port-security
Secure Port MaxSecureAddr CurrentAddr SecurityViolation Security Action
(Count) (Count) (Count)
Switch(config)#do sh port-security address
Secure Mac Address Table
-----------------------------------------------------------------------------
Vlan Mac Address Type Ports Remaining Age
(mins)
---- ----------- ---- ----- -------------
1 0000.1111.1111 SecureDynamic Gi0/0 -
1 5000.0002.0000 SecureDynamic Gi0/0 -
-----------------------------------------------------------------------------
Total Addresses in System (excluding one mac per port) : 1
Max Addresses limit in System (excluding one mac per port) : 4096
Switch(config)#do sh interface status
Port Name Status Vlan Duplex Speed Type
Gi0/0 connected 1 a-full auto RJ45
Gi0/1 notconnect 1 a-full auto RJ45
Gi0/2 notconnect 1 a-full auto RJ45
Gi0/3 notconnect 1 a-full auto RJ45
Gi1/0 notconnect 1 a-full auto RJ45
Gi1/1 notconnect 1 a-full auto RJ45
Gi1/2 notconnect 1 a-full auto RJ45
Gi1/3 notconnect 1 a-full auto RJ45
The Port Status (Gi0/0) is connected at the moment, because we are not violating the Maximum MAC Address number of the Port-Security (By default it is 1), Let’s change the PC MAC Address one more time:
PC(config-if)#do sh run int g0/0
Building configuration...
Current configuration : 145 bytes
!
interface GigabitEthernet0/0
mac-address 0000.2222.2222
!
Switch(config)#
*Apr 8 12:51:23.511: %PM-4-ERR_DISABLE: psecure-violation error detected on Gi0/0, putting Gi0/0 in err-disable sstatus
*Apr 8 12:51:23.511: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 0000.2222.2222 on port GigabitEthernet0/0.
*Apr 8 12:51:24.511: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/0, changed state to down
Switch(config)#do sh port-security
Secure Port MaxSecureAddr CurrentAddr SecurityViolation Security Action
(Count) (Count) (Count)
---------------------------------------------------------------------------
Gi0/0 2 0 1 Shutdown
---------------------------------------------------------------------------
Total Addresses in System (excluding one mac per port) : 0
Max Addresses limit in System (excluding one mac per port) : 4096
Switch(config)#do sh int status
Port Name Status Vlan Duplex Speed Type
Gi0/0 err-disabled 1 auto auto RJ45
Gi0/1 notconnect 1 a-full auto RJ45
Gi0/2 notconnect 1 a-full auto RJ45
Gi0/3 notconnect 1 a-full auto RJ45
Gi1/0 notconnect 1 a-full auto RJ45
Gi1/1 notconnect 1 a-full auto RJ45
Gi1/2 notconnect 1 a-full auto RJ45
Gi1/3 notconnect 1 a-full auto RJ45
In order to put the port back in normal state we can shutdown and no shutdown it or to use the errdisable feature :
Switch(config)#int g0/0
Switch(config-if)#shutdown
Switch(config-if)#no shutdown
Switch(config-if)#
*Apr 8 13:00:30.281: %LINK-5-CHANGED: Interface GigabitEthernet0/0, changed state to administratively down
*Apr 8 13:00:32.910: %LINK-3-UPDOWN: Interface GigabitEthernet0/0, changed state to up
*Apr 8 13:00:33.910: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/0, changed state to up
Switch(config)#do sh run | sec errdisable
errdisable recovery cause psecure-violation
errdisable recovery interval 30
Switch(config)#
*Apr 8 13:04:10.654: %PM-4-ERR_RECOVER: Attempting to recover from psecure-violation err-disable state on Gi0/0
*Apr 8 13:04:12.678: %LINK-3-UPDOWN: Interface GigabitEthernet0/0, changed state to up
*Apr 8 13:04:13.678: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/0, changed state to up
Now, it is being recovered to the normal mode automatically (After 30 seconds), thanks to the errdisable feature of IOS.
Port-Security command includes more options such as:
- Specifying a Static Legitimate/Forbidden MAC Address on a port
- Sticky Learning and saving MAC Address in the Running Configuration of the device
- Changing the Aging time
- Changing the Action whenever a violation happens
Switch(config-if)#do sh run int g0/0
Building configuration...
Current configuration : 256 bytes
!
interface GigabitEthernet0/0
switchport mode access
switchport port-security maximum 2
switchport port-security mac-address 0000.1111.1111
switchport port-security mac-address 0000.2222.2222
switchport port-security
!
With above commands, only those two MAC addresses could be learned on Gi0/0:
PC(config-if)#do sh run int g0/0
Building configuration...
Current configuration : 145 bytes
!
interface GigabitEthernet0/0
mac-address 0000.3333.3333
!
Switch(config-if)#
*Apr 8 13:13:10.966: %LINK-3-UPDOWN: Interface GigabitEthernet0/0, changed state to up
*Apr 8 13:13:11.966: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/0, changed state to up
Switch(config-if)#
*Apr 8 13:15:23.490: %PM-4-ERR_DISABLE: psecure-violation error detected on Gi0/0, putting Gi0/0 in err-disable state
*Apr 8 13:15:23.491: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 0000.3333.3333 on port GigabitEthernet0/0.
*Apr 8 13:15:24.491: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/0, changed state to down
*Apr 8 13:15:25.491: %LINK-3-UPDOWN: Interface GigabitEthernet0/0, changed state to down
The MAC Addresses can be learned in a Sticky way (Device Dynamically learns them and puts into the Running Configuration).
Note: In order to save the Sticky Learned MAC Addresses in the Startup-Configuration you have to issue “Write or Copy Runn Startup” commands in the Priv Exec Mode”.
PC(config-if)#mac-address 0000.2222.2222
PC(config-if)#mac-address 0000.1111.1111
Switch(config-if)#do sh run int g0/0
Building configuration...
Current configuration : 305 bytes
!
interface GigabitEthernet0/0
switchport mode access
switchport port-security maximum 2
switchport port-security mac-address sticky
switchport port-security mac-address sticky 0000.1111.1111
switchport port-security mac-address sticky 0000.2222.2222
switchport port-security
!
Switch(config-if)#do sh startup | begin Gig
interface GigabitEthernet0/0
switchport mode access
switchport port-security maximum 2
switchport port-security
!
Switch(config-if)#do write
Building configuration...
Compressed configuration from 3325 bytes to 1620 bytes[OK]
Switch(config-if)#do sh startup | begin Gig
interface GigabitEthernet0/0
switchport mode access
switchport port-security maximum 2
switchport port-security mac-address sticky
switchport port-security mac-address sticky 0000.1111.1111
switchport port-security mac-address sticky 0000.2222.2222
switchport port-security
!
The last thing We want to try is changing the violation action:
By default the Port-Security Violation is set to Shutdown and you have seen what has happened with above examples.
There are two more options:
- Protect
- Restrict
They are doing the same job with a slight difference:
Instead of Securing Down the port (Secure Shutdown), the incoming illegitimate frames will be dropped.
Protect mode, silently drops the frames.
Restrict mode, drops the frames and generates the syslog message.
Here is the example:
Switch(config-if)#do sh run int g0/0
Building configuration...
Current configuration : 350 bytes
!
interface GigabitEthernet0/0
switchport mode access
switchport port-security maximum 2
switchport port-security violation restrict
switchport port-security mac-address sticky
switchport port-security mac-address sticky 0000.1111.1111
switchport port-security mac-address sticky 0000.2222.2222
!
PC(config-if)#mac-address 0000.3333.3333
Switch(config-if)#
*Apr 8 13:27:13.493: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 0000.3333.3333 on port GigabitEthernet0/0.
*Apr 8 13:27:23.493: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 0000.3333.3333 on port GigabitEthernet0/0.
*Apr 8 13:27:33.493: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 0000.3333.3333 on port GigabitEthernet0/0.