Skip to content

ARP (Address Resolution Protocol) - Primer

Why This Matters

Every packet on an Ethernet segment needs a MAC address to reach the next hop. ARP is the mechanism that maps Layer 3 (IP) addresses to Layer 2 (MAC) addresses. When ARP breaks, hosts go dark even though routing looks fine. ARP issues are among the most confusing to troubleshoot because pings fail silently and everything above Layer 2 looks correct.

Name origin: ARP was defined in RFC 826 (1982) by David Plummer. It operates at the boundary between Layer 2 (Ethernet) and Layer 3 (IP) and is technically not part of either the TCP/IP or OSI model — it is a glue protocol.

Fun fact: IPv6 does not use ARP at all. It replaces ARP with NDP (Neighbor Discovery Protocol, RFC 4861), which uses ICMPv6 multicast instead of broadcast, making it more efficient on large segments.

How ARP Works

The Resolution Process

  1. Host A wants to send a packet to 10.0.0.5
  2. Host A checks its ARP cache — no entry for 10.0.0.5
  3. Host A broadcasts an ARP request: "Who has 10.0.0.5? Tell 10.0.0.1"
  4. Host B (10.0.0.5) responds with a unicast ARP reply containing its MAC
  5. Host A caches the mapping and sends the packet

Under the hood: ARP requests are broadcast (destination MAC ff:ff:ff:ff:ff:ff), but ARP replies are unicast — sent directly to the requester's MAC. This is a deliberate optimization: only the request needs to flood the network. The ARP packet itself is only 28 bytes (for IPv4 over Ethernet), making it one of the simplest protocols in the TCP/IP stack. See RFC 826 for the full 1-page spec.

ARP Table

View and manage the ARP cache:

# Modern (iproute2)
ip neigh show
ip neigh add 10.0.0.5 lladdr aa:bb:cc:dd:ee:ff dev eth0
ip neigh del 10.0.0.5 dev eth0
ip neigh flush dev eth0

# Legacy
arp -a
arp -d 10.0.0.5

ARP entries have states:

State Meaning
REACHABLE Confirmed recently
STALE Not confirmed, will re-probe on next use
DELAY Waiting for confirmation probe
FAILED Resolution failed
PERMANENT Manually added static entry

Gratuitous ARP

A gratuitous ARP is an ARP reply sent without being requested. The sender announces its own IP-to-MAC mapping. Used for:

  • IP failover: VRRP/keepalived sends gratuitous ARP when VIP moves to a new host
  • Duplicate IP detection: Host sends gratuitous ARP on boot; if someone replies, there is a conflict
  • Updating stale caches: After NIC replacement, gratuitous ARP updates neighbors
# Send gratuitous ARP with arping
arping -U -I eth0 10.0.0.1        # unsolicited ARP reply
arping -A -I eth0 10.0.0.1        # ARP announcement

Proxy ARP

A router answers ARP requests on behalf of hosts on another subnet. This allows hosts without proper routing to communicate across subnets. Common in legacy networks and VPN setups.

# Enable proxy ARP on an interface
echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp

# Or via sysctl
sysctl -w net.ipv4.conf.eth0.proxy_arp=1

Proxy ARP masks misconfigured subnets. It works but hides the real problem.

War story: Proxy ARP silently "fixing" a broken subnet mask is a classic gotcha. A host with a /24 mask on a /16 network still works because the router answers ARP on its behalf. Everything looks fine until the router goes down and half the network goes dark. The real fix: correct the subnet masks.

ARP Flux

On multi-homed Linux hosts (multiple NICs), the kernel may respond to ARP requests on the wrong interface. Host has eth0 (10.0.0.1) and eth1 (10.0.1.1), but answers ARP for 10.0.0.1 on eth1.

Fix with arp_filter or arp_ignore:

# arp_filter: only respond if the route for the source goes out this interface
sysctl -w net.ipv4.conf.all.arp_filter=1

# arp_ignore: only respond if the address is configured on the receiving interface
sysctl -w net.ipv4.conf.all.arp_ignore=1

# arp_announce: restrict source IP in ARP requests to match outgoing interface
sysctl -w net.ipv4.conf.all.arp_announce=2

ARP in Cloud/Container Environments

  • Cloud VPCs: ARP is handled by the hypervisor. You rarely see traditional ARP broadcasts
  • Docker bridge: Containers ARP normally within the bridge network
  • Kubernetes: CNI plugins handle ARP for pod IPs; calico uses proxy ARP for its routing model

Debugging ARP Issues

Symptoms

  • Ping fails to hosts on the same subnet
  • ip neigh shows FAILED or INCOMPLETE entries
  • Intermittent connectivity (stale ARP entries pointing to old MACs)

Diagnostic Commands

# Watch ARP traffic in real-time
tcpdump -i eth0 -nn arp

# Check for duplicate IPs
arping -D -I eth0 10.0.0.5

# Flush and re-learn
ip neigh flush dev eth0

# Check ARP table size (default 1024 on Linux)
sysctl net.ipv4.neigh.default.gc_thresh1   # soft minimum
sysctl net.ipv4.neigh.default.gc_thresh2   # soft maximum
sysctl net.ipv4.neigh.default.gc_thresh3   # hard maximum

ARP Table Overflow

In large flat networks (1000+ hosts), the ARP table can overflow:

# Increase ARP table limits
sysctl -w net.ipv4.neigh.default.gc_thresh1=4096
sysctl -w net.ipv4.neigh.default.gc_thresh2=8192
sysctl -w net.ipv4.neigh.default.gc_thresh3=16384

Symptoms: neighbour table overflow in dmesg, random connectivity drops.

Debug clue: If you see neighbour table overflow in dmesg, check sysctl net.ipv4.neigh.default.gc_thresh3 — that is the hard ceiling. On Kubernetes nodes with many pod IPs, this limit is commonly hit with the default of 1024. Set it to 4096+ and add monitoring for ip neigh show | wc -l.

Security Considerations

  • ARP spoofing: Attacker sends fake ARP replies to redirect traffic. Mitigated by Dynamic ARP Inspection (DAI) on switches
  • Static ARP entries: Use ip neigh add ... nud permanent for critical infrastructure (gateways)
  • ARP rate limiting: Some switches limit ARP broadcast rate to prevent storms

Remember: ARP troubleshooting mnemonic: "CFTD" — Cache (ip neigh show), Flush (ip neigh flush), Trace (tcpdump -nn arp), Detect (arping -D). Run these four in order when diagnosing ARP issues.

Quick Reference

Task Command
Show ARP table ip neigh show
Add static entry ip neigh add 10.0.0.1 lladdr aa:bb:cc:dd:ee:ff dev eth0 nud permanent
Delete entry ip neigh del 10.0.0.1 dev eth0
Flush interface ip neigh flush dev eth0
Send gratuitous ARP arping -U -I eth0 10.0.0.1
Detect duplicate IP arping -D -I eth0 10.0.0.5
Watch ARP traffic tcpdump -i eth0 -nn arp

Wiki Navigation