When working with Linux networking in scenarios involving both physical interfaces (like eth10) and virtual TAP interfaces (tap0), we sometimes encounter unexpected ARP behavior. Here's what's happening at the protocol level:
# Typical interface configuration
ip addr add 10.11.0.1/24 dev eth10
ip addr add 0.0.0.1/32 dev tap0
The Linux kernel maintains a global ARP table and considers all IP addresses assigned to the system as "local." When it sees an ARP request for any local IP (regardless of which interface the request arrived on), it will respond. This behavior is defined in:
net/ipv4/arp.c (Linux kernel source):
/*
* Check if we can use the cached hardware header.
*/
static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
{
/* Default is to reply unless configured otherwise */
return IN_DEV_ARP_IGNORE(in_dev);
}
1. Using sysctl to Modify ARP Behavior
The most elegant solution is to use kernel parameters:
# Make the kernel only respond to ARP requests on the interface
# where the IP is configured
sysctl -w net.ipv4.conf.all.arp_ignore=1
sysctl -w net.ipv4.conf.tap0.arp_ignore=1
2. Network Namespace Isolation
For more complete isolation, consider using network namespaces:
# Create new namespace
ip netns add testns
# Move tap0 to the namespace
ip link set tap0 netns testns
# Now the main system won't see ARP requests on tap0
3. Alternative: ARPFILTER
Another approach using the arp_filter setting:
sysctl -w net.ipv4.conf.all.arp_filter=1
sysctl -w net.ipv4.conf.tap0.arp_filter=1
Verify the solution works by sending a test ARP request:
# On another machine in the same network:
arping -I eth0 10.11.0.1
# You should now only see one response (from eth10)
To make these changes persistent across reboots:
# Add to /etc/sysctl.conf or /etc/sysctl.d/99-arp.conf
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.tap0.arp_ignore = 1
If you frequently need this level of control over networking behavior, consider:
- Using dedicated test machines
- Virtual machines with isolated networking
- Network namespaces (as mentioned above)
- Userspace networking stacks (like DPDK)
If you're still seeing unexpected ARP replies:
# Check current ARP settings
sysctl -a | grep arp_
# Monitor ARP traffic
tcpdump -i any -n arp
# Verify interface configurations
ip addr show
During recent network testing, I encountered a puzzling behavior where Linux responds to ARP requests on interfaces that shouldn't handle the target IP address. The scenario involved:
# Interface configuration example
ip addr add 10.11.0.1/24 dev eth10
ip addr add 0.0.0.1/32 dev tap0 # Dummy address to bring interface up
When sending an ARP request for 10.11.0.1 through tap0, I received two replies:
- From my userspace raw socket program (expected)
- From the Linux kernel itself (unexpected)
The kernel appears to respond to ARP requests for any IP address assigned to the system, regardless of which interface owns that address.
This behavior stems from Linux's ARP implementation in net/ipv4/arp.c
. The kernel maintains a global ARP table and responds based on:
/* Simplified logic from arp_process() */
if (arp->ar_op == htons(ARPOP_REQUEST) &&
inet_addr_type(net, tip) == RTN_LOCAL) {
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha);
}
The key condition is RTN_LOCAL
- the kernel responds if the IP is "local" to any interface.
Solution 1: ARP Filtering with sysctl
The most effective fix is to enable ARP filtering:
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
echo 1 > /proc/sys/net/ipv4/conf/tap0/arp_filter
This makes the kernel consider the incoming interface when deciding whether to respond.
Solution 2: Network Namespace Isolation
For more complete isolation:
# Create new network namespace
unshare --net bash
# Bring up tap0 in the new namespace
ip link set tap0 netns $PID
Solution 3: Userspace ARP Control
Disable kernel ARP entirely on the interface:
ip link set tap0 arp off
To verify ARP behavior, use this test script:
#!/bin/bash
# ARP test script
ping -c 1 10.11.0.1
arp -an | grep 10.11.0.1
tcpdump -i tap0 -nn 'arp' # Should only show your userspace responses
While the kernel's behavior might seem counterintuitive, it's actually by design for most common networking scenarios. The solutions above provide different levels of control depending on your specific requirements for interface isolation.