Loading learning content...
Every networked device maintains an ARP table—a dynamic database mapping IP addresses to MAC addresses. Think of it as the device's address book: when you want to send a letter (packet) to someone (IP address), you look up their street address (MAC address) in your contacts (ARP table).
The ARP table is one of the most frequently consulted data structures in any networked system. Every outbound IP packet requires an ARP table lookup. Understanding how to view, interpret, and manage ARP tables is essential knowledge for network administrators, security professionals, and system engineers.
By the end of this page, you will understand ARP table structure across operating systems, how to analyze table contents for troubleshooting, management commands for every major platform, table size limits and optimization, integration with other system components, and real-world scenarios requiring ARP table manipulation.
The ARP table consists of individual entries, each representing a resolved IP-to-MAC binding. While conceptually simple, modern implementations add significant metadata to each entry.
Comprehensive Entry Fields:
| Field | Description | Example |
|---|---|---|
| IP Address | The Layer 3 address that was resolved | 192.168.1.1 |
| MAC Address | The corresponding Layer 2 hardware address | a0:b1:c2:d3:e4:f5 |
| Interface | Network interface the entry is associated with | eth0, en0, Ethernet |
| Type/Flags | Static (manually configured) vs Dynamic (learned) | static, dynamic |
| State | Current entry state (varies by OS) | REACHABLE, STALE, PERMANENT |
| Age/TTL | Time since creation or last confirmation | 45s, 2m, expired |
| Reference Count | Number of active connections using this entry | 4 (Linux) |
| Queue Length | Packets waiting for this entry to complete | 0 (or N during resolution) |
Entry Types:
Dynamic Entries
Static Entries
Permanent Entries
Incomplete Entries
The terms 'ARP table' and 'ARP cache' are used interchangeably in most contexts. 'Table' emphasizes the database aspect; 'cache' emphasizes the temporary, performance-oriented nature. Linux documentation uses 'neighbor table' (shared with IPv6 NDP). Windows uses 'ARP cache' in netsh but 'Neighbor' in PowerShell.
Every network professional must know how to inspect ARP tables on various platforms. Each presents information slightly differently.
Linux:
1234567891011121314151617181920
# Classic arp command (deprecated but universal)$ arp -arouter.local (192.168.1.1) at a0:b1:c2:d3:e4:f5 [ether] on eth0webserver (192.168.1.50) at 00:11:22:33:44:55 [ether] on eth0? (192.168.1.75) at <incomplete> on eth0 # Modern ip neigh command (recommended)$ ip neigh show192.168.1.1 dev eth0 lladdr a0:b1:c2:d3:e4:f5 REACHABLE192.168.1.50 dev eth0 lladdr 00:11:22:33:44:55 STALE192.168.1.75 dev eth0 FAILED192.168.1.2 dev eth0 lladdr de:ad:be:ef:00:01 PERMANENT # Detailed statistics (usage counts, probes)$ ip -s neigh show192.168.1.1 dev eth0 lladdr a0:b1:c2:d3:e4:f5 ref 4 used 0/0/0 probes 0 REACHABLE# ref=reference count, used=used/confirmed/updated times, probes=pending probes # JSON output for scripting$ ip -j neigh show | jq '.[] | {ip: .dst, mac: .lladdr, state: .state}'Windows:
12345678910111213141516171819202122232425
# Command Prompt - classic arpC:\> arp -a Interface: 192.168.1.100 --- 0x4 Internet Address Physical Address Type 192.168.1.1 a0-b1-c2-d3-e4-f5 dynamic 192.168.1.50 00-11-22-33-44-55 dynamic 192.168.1.255 ff-ff-ff-ff-ff-ff static 224.0.0.22 01-00-5e-00-00-16 static 255.255.255.255 ff-ff-ff-ff-ff-ff static # PowerShell - more detailedPS C:\> Get-NetNeighbor | Format-Table -AutoSize ifIndex IPAddress LinkLayerAddress State PolicyStore------- --------- ---------------- ----- -----------4 192.168.1.1 A0-B1-C2-D3-E4-F5 Reachable ActiveStore4 192.168.1.50 00-11-22-33-44-55 Stale ActiveStore4 192.168.1.255 FF-FF-FF-FF-FF-FF Permanent ActiveStore # Filter by statePS C:\> Get-NetNeighbor -State Reachable # Export to CSV for analysisPS C:\> Get-NetNeighbor | Export-Csv -Path arp_table.csvmacOS:
123456789101112
# Standard arp command$ arp -arouter (192.168.1.1) at a0:b1:c2:d3:e4:f5 on en0 ifscope [ethernet]webserver (192.168.1.50) at 00:11:22:33:44:55 on en0 ifscope [ethernet]? (192.168.1.75) at (incomplete) on en0 ifscope [ethernet] # On specific interface$ arp -a -i en0 # Numeric output (no DNS resolution)$ arp -an(192.168.1.1) at a0:b1:c2:d3:e4:f5 on en0 ifscope [ethernet]Network Devices (Cisco IOS):
123456789101112131415
! Show complete ARP tableRouter# show ip arpProtocol Address Age (min) Hardware Addr Type InterfaceInternet 192.168.1.1 - a0b1.c2d3.e4f5 ARPA GigabitEthernet0/0Internet 192.168.1.100 45 0011.2233.4455 ARPA GigabitEthernet0/0Internet 192.168.1.200 180 aabb.ccdd.eeff ARPA GigabitEthernet0/0 ! Age of "-" means static/self entry (router's own interface)! Age in minutes since entry was last refreshed ! Filter by interfaceRouter# show ip arp GigabitEthernet0/0 ! Filter by IPRouter# show ip arp 192.168.1.100When reviewing ARP tables, look for: (1) 'incomplete' entries indicating resolution failures, (2) unexpected MAC addresses that might indicate spoofing, (3) multiple IPs mapping to the same MAC (normal for aliases, suspicious otherwise), (4) stale entries for hosts that should be actively communicating.
Administrators frequently need to modify ARP tables—adding static entries for security, removing stale entries for troubleshooting, or flushing entire tables after network changes.
Adding Static Entries:
1234567891011121314151617
# Linux - using ip neigh (recommended)sudo ip neigh add 192.168.1.1 lladdr a0:b1:c2:d3:e4:f5 nud permanent dev eth0 # Linux - using arp (legacy)sudo arp -s 192.168.1.1 a0:b1:c2:d3:e4:f5 # Windows - Command Promptarp -s 192.168.1.1 a0-b1-c2-d3-e4-f5 # Windows - PowerShellNew-NetNeighbor -InterfaceIndex 4 -IPAddress 192.168.1.1 -LinkLayerAddress "A0-B1-C2-D3-E4-F5" -State Permanent # macOSsudo arp -s 192.168.1.1 a0:b1:c2:d3:e4:f5 permanent # Cisco IOSRouter(config)# arp 192.168.1.100 0011.2233.4455 arpaDeleting Entries:
1234567891011121314151617
# Linux - using ip neighsudo ip neigh del 192.168.1.50 dev eth0 # Linux - using arpsudo arp -d 192.168.1.50 # Windows - Command Promptarp -d 192.168.1.50 # Windows - PowerShellRemove-NetNeighbor -InterfaceIndex 4 -IPAddress 192.168.1.50 # macOSsudo arp -d 192.168.1.50 # Cisco IOSRouter# clear ip arp 192.168.1.50Flushing the Entire Table:
1234567891011121314151617
# Linux - flush all neighbor entriessudo ip neigh flush all # Linux - flush specific interfacesudo ip neigh flush dev eth0 # Windows - flush ARP cachenetsh interface ip delete arpcache # Windows - PowerShell (remove all non-permanent)Get-NetNeighbor | Where-Object { $_.State -ne 'Permanent' } | Remove-NetNeighbor # macOS - delete all entriessudo arp -a -d # Cisco IOS - clear dynamic entriesRouter# clear ip arpFlushing the ARP table causes temporary connectivity interruption as all entries must be re-resolved. On busy servers, this may cause noticeable latency spikes. Plan flushes during maintenance windows or low-traffic periods. Note: Static entries may or may not be affected depending on the command used.
ARP tables have size limits that can impact large-scale networks. Understanding these limits helps prevent 'neighbor table overflow' errors.
Default Limits by Platform:
| Platform | Default Maximum | Configurable? | Configuration Method |
|---|---|---|---|
| Linux | 1024 entries (gc_thresh3) | Yes | sysctl net.ipv4.neigh.default.gc_thresh* |
| Windows | Dynamic (memory-based) | Limited | Registry HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters |
| macOS | Dynamic | No | System-managed |
| Cisco IOS | Platform-dependent (thousands) | Yes | arp cache-limit command |
| Juniper Junos | Platform-dependent | Yes | system arp policer |
Linux Garbage Collection Thresholds:
Linux uses three thresholds for ARP table management:
123456789101112131415161718192021222324
# View current thresholds$ sysctl net.ipv4.neigh.default.gc_thresh1net.ipv4.neigh.default.gc_thresh1 = 128 $ sysctl net.ipv4.neigh.default.gc_thresh2net.ipv4.neigh.default.gc_thresh2 = 512 $ sysctl net.ipv4.neigh.default.gc_thresh3net.ipv4.neigh.default.gc_thresh3 = 1024 # Meaning:# gc_thresh1: Minimum entries before garbage collection starts (soft floor)# gc_thresh2: When to start considering aggressive garbage collection# gc_thresh3: Hard maximum - new entries rejected above this # For large networks (data centers, cloud), increase limits:$ sudo sysctl -w net.ipv4.neigh.default.gc_thresh1=4096$ sudo sysctl -w net.ipv4.neigh.default.gc_thresh2=8192$ sudo sysctl -w net.ipv4.neigh.default.gc_thresh3=16384 # Make permanent in /etc/sysctl.conf:# net.ipv4.neigh.default.gc_thresh1 = 4096# net.ipv4.neigh.default.gc_thresh2 = 8192# net.ipv4.neigh.default.gc_thresh3 = 16384Symptoms of Table Exhaustion:
A typical office might have 50-200 hosts per VLAN—default limits are fine. Data center environments with thousands of hosts per broadcast domain require significantly higher limits. Container/Kubernetes environments with many ephemeral IPs also stress ARP tables. Size based on: (peak hosts per broadcast domain) × 1.5 safety margin.
Many network connectivity issues trace back to ARP table problems. Here's a systematic troubleshooting approach.
Common ARP-Related Problems and Diagnosis:
Troubleshooting Workflow:
1234567891011121314151617181920212223
# Step 1: Check if entry exists and its state$ ip neigh show | grep 192.168.1.50192.168.1.50 dev eth0 FAILED # Bad: resolution failed192.168.1.50 dev eth0 lladdr 00:... STALE # Okay: just aged # Step 2: If FAILED, try manual ping to trigger re-resolution$ ping -c 1 192.168.1.50 # Step 3: Check again$ ip neigh show | grep 192.168.1.50 # Step 4: If still failing, capture ARP traffic$ sudo tcpdump -i eth0 arp and host 192.168.1.50 -n# Look for: requests but no replies (target down/unreachable)# replies with unexpected MAC (spoofing/conflict) # Step 5: Verify from network side# On the switch, check MAC address tableSwitch# show mac address-table address 0011.2233.4455# Verify the MAC is seen on expected port # Step 6: Verify target is actually up# Physically check, or query via out-of-band managementMany ARP 'problems' are actually Layer 1 (cable, physical) or Layer 2 (VLAN, switch port) issues. ARP failures are often the symptom, not the cause. Always verify physical connectivity and switch port status before concluding ARP is at fault.
The ARP table doesn't exist in isolation—it interacts with routing tables, firewall rules, switch MAC tables, and network monitoring systems.
Routing Table Integration:
When the IP routing table indicates a directly connected destination, the ARP table provides the next step:
1234567891011121314
# Routing decision determines WHAT to resolve$ ip route get 192.168.1.50192.168.1.50 dev eth0 src 192.168.1.100 # "via eth0" means local, ARP for 192.168.1.50 needed $ ip route get 8.8.8.88.8.8.8 via 192.168.1.1 dev eth0 src 192.168.1.100 # "via 192.168.1.1" means gateway, ARP for 192.168.1.1 needed # ARP table provides HOW to reach it$ ip neigh show 192.168.1.1192.168.1.1 dev eth0 lladdr a0:b1:c2:d3:e4:f5 REACHABLE # Together: 8.8.8.8 → route via 192.168.1.1 → ARP to a0:b1:c2:d3:e4:f5Switch MAC Table Correlation:
ARP tables on hosts correlate with MAC address tables on switches. This relationship is crucial for troubleshooting:
| Host ARP Table | Switch MAC Table | Network View |
|---|---|---|
| 192.168.1.50 → 00:11:22:33:44:55 | 00:11:22:33:44:55 on port Gi0/1 | Complete path from IP to physical port |
If the switch has no entry for a MAC that appears in a host's ARP table, either:
DHCP Integration:
DHCP servers often maintain IP-to-MAC bindings that mirror (and pre-populate) ARP table information:
When tracking down connectivity issues, cross-reference: (1) Host ARP table → What MAC do I think this IP has? (2) Switch MAC table → Where is that MAC physically connected? (3) DHCP leases → What IP should that MAC have? Discrepancies between these reveal the problem.
The ARP table is a prime target for attackers because it controls Layer 2 traffic steering. Compromising the ARP table enables powerful attacks.
Attack Vectors:
Defense Mechanisms:
Static ARP Entries For critical hosts (gateway, DNS servers), static ARP entries prevent spoofing:
# Prevent gateway spoofing
sudo ip neigh add 192.168.1.1 lladdr a0:b1:c2:d3:e4:f5 nud permanent dev eth0
Dynamic ARP Inspection (DAI) Switch feature that validates ARP packets against DHCP snooping database:
! Cisco configuration
Switch(config)# ip arp inspection vlan 10
Switch(config)# ip arp inspection validate src-mac dst-mac ip
ARP Rate Limiting Limit ARP packets per port to prevent flooding:
! Limit ARP to 50 packets/second per port
Switch(config-if)# ip arp inspection limit rate 50
Private VLANs Isolate hosts so they can't directly ARP-spoof each other:
No single defense fully protects against ARP attacks. Use multiple layers: static entries for critical hosts, DAI on switches, port security, private VLANs where applicable, and network monitoring to detect anomalies. Regularly audit ARP tables for unexpected entries.
In production environments, ARP tables should be monitored for anomalies and automated for consistency.
Monitoring Approaches:
123456789101112131415161718192021222324
#!/bin/bash# arp_monitor.sh - Alert on ARP anomalies # Known gateway MAC (should never change)GATEWAY_IP="192.168.1.1"EXPECTED_MAC="a0:b1:c2:d3:e4:f5" # Get current MAC for gatewayCURRENT_MAC=$(ip neigh show $GATEWAY_IP | awk '{print $5}') if [ "$CURRENT_MAC" != "$EXPECTED_MAC" ]; then echo "ALERT: Gateway MAC changed!" echo "Expected: $EXPECTED_MAC" echo "Current: $CURRENT_MAC" # Send to monitoring system logger -p security.alert "ARP spoofing detected: gateway MAC changed"fi # Check for duplicate IPs (same IP, different MAC seen recently)# Check for excessive incomplete entries (possible attack)INCOMPLETE=$(ip neigh show | grep -c FAILED)if [ $INCOMPLETE -gt 100 ]; then echo "ALERT: $INCOMPLETE failed ARP entries - possible scan or attack"fiAutomation for Consistency:
Ansible Playbook for Static ARP:
12345678910111213141516171819202122232425262728
# arp_static_entries.yml---- name: Configure static ARP entries hosts: all become: yes vars: static_arp_entries: - ip: 192.168.1.1 mac: "a0:b1:c2:d3:e4:f5" interface: eth0 - ip: 192.168.1.2 mac: "00:11:22:33:44:55" interface: eth0 tasks: - name: Add static ARP entries ansible.builtin.command: > ip neigh replace {{ item.ip }} lladdr {{ item.mac }} nud permanent dev {{ item.interface }} loop: "{{ static_arp_entries }}" - name: Persist in network configuration ansible.builtin.lineinfile: path: /etc/rc.local line: "ip neigh add {{ item.ip }} lladdr {{ item.mac }} nud permanent dev {{ item.interface }}" loop: "{{ static_arp_entries }}"The standard MIB for ARP is ipNetToMediaTable (OID 1.3.6.1.2.1.4.22). SNMP-based monitoring tools can poll this table, store history, and alert on changes. This is particularly useful for correlating host ARP tables with switch MAC tables across the network.
We've comprehensively explored the ARP table—from structure and viewing commands to management, troubleshooting, security, and automation. This knowledge is foundational for network administration and security. Let's consolidate the key takeaways:
Module Complete:
You've now completed the ARP module. You understand the Address Resolution Protocol from purpose through operation, caching, request/reply mechanics, and table management. This knowledge directly applies to network troubleshooting, security analysis, and system administration in any IP networking environment.
Congratulations! You've mastered the Address Resolution Protocol. From the fundamental two-address problem through practical table management and security, you now have comprehensive knowledge of how IP networks discover and use hardware addresses. This knowledge is essential for network troubleshooting, security work, and system administration.