Troubleshooting IPv6 Connectivity: Why Pinging Default Gateway is Required Before IPv6 Works


4 views

After configuring IPv6 on my Debian squeeze server with a /64 block from my provider, I encountered a peculiar behavior: IPv6 connectivity only works after manually pinging the default gateway. The network interface appears properly configured with both global and link-local addresses:

# /etc/network/interfaces snippet
iface eth0 inet6 static
  address 2a01:4f8:a0:aaaa::2
  netmask 64
  gateway fe80::1

The key symptom was receiving "Destination unreachable: Address unreachable" when attempting IPv6 connections. Examining the neighbor cache revealed the root cause:

$ ip -6 neigh
fe80::1 dev eth0  router FAILED

tcpdump showed the NDP (Neighbor Discovery Protocol) process failing to automatically resolve the gateway's MAC address:

00:29:05.386500 IP6 2a01:4f8:a0:aaaa::2 > ff02::1:ff00:1: ICMP6, neighbor solicitation
00:29:05.390869 IP6 2a01:4f8:a0:bbbb::1 > 2a01:4f8:a0:aaaa::2: ICMP6, neighbor advertisement

Manually pinging the gateway triggers proper neighbor discovery:

$ ping6 -I eth0 fe80::1
PING fe80::1(fe80::1) from fe80::bbbb:cccc:dddd:eeee eth0: 56 data bytes
64 bytes from fe80::1: icmp_seq=1 ttl=64 time=0.356 ms

To make this automatic, we need to properly configure the IPv6 neighbor discovery process. Add these settings to /etc/sysctl.conf:

# Enable IPv6 forwarding (if this is a router)
net.ipv6.conf.all.forwarding=0

# Optimize neighbor discovery
net.ipv6.conf.default.accept_ra=1
net.ipv6.conf.eth0.accept_ra=2  # Important for router advertisements
net.ipv6.conf.default.autoconf=1
net.ipv6.conf.eth0.router_solicitations=3
net.ipv6.conf.eth0.router_solicitation_interval=10

For some setups, explicitly configuring the gateway's link-local address with its MAC address works better:

# First get the MAC address:
$ ping6 fe80::1
$ ip -6 neigh show

# Then add static neighbor entry:
$ ip -6 neigh add fe80::1 lladdr 00:11:22:33:44:55 dev eth0 nud permanent

For a persistent solution, create a network script that runs at boot:

#!/bin/sh
# /etc/network/if-up.d/ipv6-neigh
ip -6 neigh add fe80::1 lladdr 00:11:22:33:44:55 dev eth0 nud permanent

After implementing these changes, verify with:

$ ip -6 route show
$ ip -6 neigh show
$ ping6 -c 3 ipv6.google.com
$ traceroute6 ipv6.google.com

The neighbor cache should now show the gateway as REACHABLE without manual intervention.


When setting up IPv6 on Debian with a provider-allocated /64 block, many administrators encounter a peculiar behavior where IPv6 connectivity only works after pinging the default gateway. Let's examine a real-world case and its solution:

# /etc/network/interfaces configuration
iface eth0 inet6 static
  address 2a01:4f8:a0:aaaa::2
  netmask 64
  gateway fe80::1

The key observation here is that initial IPv6 connectivity fails with "Destination unreachable" errors until we manually ping the link-local gateway address.

Running ip -6 neigh reveals the core problem:

fe80::1 dev eth0 router FAILED

The Neighbor Discovery Protocol (NDP) cache shows the gateway as unreachable. This explains why external IPv6 connectivity fails - the system doesn't know how to reach its default gateway.

Manually pinging the gateway address populates the NDP cache:

ping6 -I eth0 fe80::1

After which ip -6 neigh shows:

fe80::1 dev eth0 lladdr ll:mm:nn:oo:pp:qq router REACHABLE

Here are three approaches to solve this permanently:

1. Pre-populate NDP Cache

# Add to /etc/network/interfaces
up ip -6 neigh add fe80::1 lladdr ll:mm:nn:oo:pp:qq dev eth0 nud permanent

2. Use Global Address as Gateway

# Change gateway in /etc/network/interfaces
gateway 2a01:4f8:a0:bbbb::1

3. Enable Router Advertisements

# Add to /etc/sysctl.conf
net.ipv6.conf.all.accept_ra = 2
net.ipv6.conf.default.accept_ra = 2
net.ipv6.conf.eth0.accept_ra = 2

The root cause lies in how IPv6 neighbor discovery works. Unlike IPv4 ARP, IPv6 NDP requires successful neighbor discovery before routing can occur. When using link-local addresses as gateways, the system needs the MAC address resolution to complete before packets can be routed.

After applying fixes, verify with:

ping6 -c 3 ipv6.google.com
traceroute6 ipv6.google.com
ip -6 route show
ip -6 neigh show