IPv6 Fundamentals
IPv6 isn't "IPv4 with more bits". It changes how hosts find their address, how they discover their neighbours, and how they negotiate the link layer. By the time you finish this guide you should be able to read an IPv6 address at a glance, predict whether SLAAC or DHCPv6 is in play, understand why blocking ICMPv6 breaks things, and use the Linux ip -6 family to inspect any of it.
128-Bit Addresses and Shorthand
An IPv6 address is 128 bits, written as eight 16-bit groups of hexadecimal separated by colons. The full form is unwieldy, so two rules let us compress it:
- Drop leading zeros within each group.
- Replace exactly one run of all-zero groups with
::— but only one such replacement per address.
Shorthand in action
Full : 2001:0db8:0000:0000:0000:ff00:0042:8329 Leading 0 : 2001:db8:0:0:0:ff00:42:8329 Run of 0 : 2001:db8::ff00:42:8329 Other examples: fe80:0000:0000:0000:0204:61ff:fe9d:f156 → fe80::204:61ff:fe9d:f156 0000:0000:0000:0000:0000:0000:0000:0001 → ::1 0000:0000:0000:0000:0000:0000:0000:0000 → ::
You'll see the :: at the start, middle, or end. The only constraint is "exactly one"; otherwise the address would be ambiguous. RFC 5952 also recommends always using lower-case hex and not abbreviating a single zero group as :: — useful conventions when you're generating output for logs.
Prefix length
Subnetting uses CIDR-style notation: 2001:db8:abcd:0012::/64 is a /64 prefix. End-host subnets are almost always /64 in IPv6 — many features (notably SLAAC) assume it. Provider allocations to customers are typically /48 or /56; the link-prefix /64 is sliced out of that.
Unicast, Multicast, Anycast
IPv6 has three address scopes/types — broadcast is gone:
- Unicast — identifies a single interface. Standard host addresses.
- Multicast — identifies a group of interfaces; a packet to a multicast address is delivered to every member. The whole
ff00::/8prefix is reserved for multicast. - Anycast — identifies a group of interfaces, but the packet is delivered to one of them (usually the topologically nearest). Anycast and unicast addresses are syntactically identical; the difference is whether multiple hosts share it.
There is no broadcast address. Anything IPv4 did with broadcasts, IPv6 does with well-known multicast groups instead.
The Prefixes You Must Recognise
Knowing what an address means at a glance comes down to memorising six prefixes:
::1/128— loopback. The IPv6 equivalent of127.0.0.1.::/128— unspecified address. Used as a source while a host doesn't yet have an address (RFC 4291 §2.5.2).fe80::/10— link-local. Every IPv6 interface auto-configures one of these on its link. They are valid only on the local link; routers never forward them. You'll see them used for routing protocol next-hops, NDP, and a lot more.fc00::/7— Unique Local Addresses (ULA, RFC 4193). The rough equivalent of RFC 1918 in IPv4: private-use, not routable on the public internet. In practice you generate addresses infd00::/8(the L=1 half offc00::/7).2000::/3— global unicast. Every public, internet-routable IPv6 address falls inside this range (covering2000::through3fff::).ff00::/8— multicast. Subdivided by scope flags so a multicast group can be link-local, organisation-local, global, etc.
Notable well-known multicast groups
ff02::1 All nodes on the link ff02::2 All routers on the link ff02::5 OSPFv3 all routers ff02::a EIGRP for IPv6 ff02::1:ffXX:XXXX Solicited-node group (used by NDP — see below)
Interface Identifiers and EUI-64
The low-order 64 bits of a typical unicast address are the interface identifier. There are two common ways to derive it:
- EUI-64 — historic method. Take the 48-bit MAC, insert
FF:FEin the middle, and flip the universal/local bit (bit 7 of the first octet). So MAC00:0c:29:9d:f1:56becomes interface ID020c:29ff:fe9d:f156. Combined withfe80::/64that gives a link-local address offe80::20c:29ff:fe9d:f156. - RFC 7217 / RFC 8981 (privacy extensions) — modern method. The interface ID is generated randomly or pseudorandomly so it doesn't leak the hardware MAC. Linux and Windows both default to this for global addresses; EUI-64 is mostly seen on link-local and some embedded devices.
Privacy extensions also rotate temporary global addresses periodically so outbound connections don't all share a stable identifier.
SLAAC, DHCPv6, and Prefix Delegation
IPv6 has multiple ways to acquire an address — sometimes used together. The three you must know:
- SLAAC (Stateless Address Autoconfiguration, RFC 4862) — the host listens for a Router Advertisement (RA) carrying a /64 prefix, generates its own interface ID, and combines them into a global address. No server tracks who has what.
- DHCPv6 (RFC 8415) — like DHCP for IPv4: a server hands out addresses and configuration. Two modes: stateful (addresses + other config) and stateless (only the extra config like DNS, while addresses still come from SLAAC).
- DHCPv6 Prefix Delegation (DHCPv6-PD, RFC 8415) — a CPE router asks its upstream "give me a prefix I can subnet to my LANs" and gets back, say, a /56. The CPE then sub-divides into /64s for each downstream interface. This is how home and SME routers receive IPv6 from ISPs.
The M and O flags
Routers advertise two flags in every RA that tell hosts what to do:
- M (Managed) — if set, hosts should use stateful DHCPv6 for address configuration.
- O (Other) — if set, hosts should use stateless DHCPv6 for other information (DNS servers, NTP, etc.), even if the address itself came from SLAAC.
Common combinations
M=0 O=0 SLAAC only. Address from RA, no DHCPv6 contact. RDNSS option in RA carries DNS. M=0 O=1 SLAAC for address, DHCPv6 for DNS/NTP/etc. M=1 O=1 DHCPv6 for both address and other config (stateful). M=1 O=0 Rare. Address from DHCPv6, no other config.
NDP: How IPv6 Replaces ARP
ARP is gone. Its job is done by the Neighbor Discovery Protocol (NDP, RFC 4861), which runs entirely over ICMPv6. NDP uses five message types:
- Router Solicitation (RS) — "are there any routers on this link?"
- Router Advertisement (RA) — sent by routers, advertising prefixes, link MTU, M/O flags, DNS via RDNSS, etc.
- Neighbor Solicitation (NS) — "who has
2001:db8::1? Tell2001:db8::5." Sent to the solicited-node multicast group of the target. - Neighbor Advertisement (NA) — "I have
2001:db8::1, here's my MAC." Reply to NS. - Redirect — "use a better next-hop for this destination". Same purpose as ICMP Redirect in IPv4.
The solicited-node multicast trick is the key cleverness. Every IPv6 unicast address has a corresponding multicast group of the form ff02::1:ffXX:XXXX where XX:XXXX is the bottom 24 bits of the address. Instead of broadcasting NS to the whole link (the way ARP does), the asker sends NS to this multicast — which the NIC of the holder is already subscribed to. Many fewer hosts get woken up.
Duplicate Address Detection (DAD) uses an NS to its own tentative address before claiming it; if a NA comes back, that address is already taken.
ICMPv6 Is Not Optional
ICMPv6 (RFC 4443) carries NDP, MLD (multicast group membership), Path MTU Discovery, and the usual diagnostic echo. If you blindly block ICMPv6 at a host firewall, you also block:
- NDP (so neighbour resolution fails entirely on the link)
- Router Advertisements (so SLAAC can't happen)
- Packet-Too-Big messages (so Path MTU Discovery silently breaks — IPv6 routers don't fragment packets; the sender must learn the path MTU)
iptables -A INPUT -p ipv6-icmp -j DROP or the equivalent ip6tables rule. Read RFC 4890 ("Recommendations for Filtering ICMPv6 Messages in Firewalls") for the canonical list of which types to allow. Echo Request, Packet-Too-Big, Time-Exceeded, Parameter-Problem, NDP messages on the link, and MLD are all in the "must allow" category.
The 1280-Byte Minimum MTU
Every IPv6 link must support an MTU of at least 1280 bytes (RFC 8200 §5). This guarantees Path MTU Discovery can find a working size without IPv6 routers ever having to fragment. If a router on the path can't forward a packet, it sends an ICMPv6 Packet-Too-Big message back to the source — which then lowers its own MTU and retransmits. Block those messages and you get the dreaded "small requests work, large requests hang" failure mode.
Dual-Stack vs IPv6-Only
For most of the last decade, "deploy IPv6" has meant dual-stack: every host runs both protocols, and applications use Happy Eyeballs (RFC 8305) to race v4 and v6 connections and use whichever wins. Dual-stack is operationally simple but requires two sets of routing, two firewall policies, and double the address management.
IPv6-only with NAT64/DNS64 (RFC 6146, RFC 6147) is increasingly common for mobile and large datacenters. The host gets only IPv6; legacy IPv4 destinations are reached via a translator. Apple, T-Mobile and large enterprise networks all run this.
Address Scope
Every IPv6 address has a scope: where it's valid. Link-local addresses (fe80::/10) only have meaning on the link they're attached to, which means you need a "zone identifier" when there's more than one interface. On Linux:
Zone identifiers in practice
# Ping a link-local address — must say which interface ping6 fe80::1%eth0 ping -6 fe80::1%eth0 # In a URL (RFC 6874): percent becomes %25 http://[fe80::1%25eth0]/
Without the zone, the kernel can't know which interface to send out of. Global addresses don't need a zone — by definition they're routable across links.
Linux ip -6 Cheat Sheet
The iproute2 commands handle IPv6 with the same syntax as IPv4 — you just add -6:
Inspect IPv6 state
# Addresses ip -6 addr show ip -6 addr show dev eth0 # Routes (note "via" next-hops will often be link-local) ip -6 route show ip -6 route show table all # Neighbour cache (ARP's IPv6 equivalent) ip -6 neigh show # Default route & received RA info ip -6 route show default sysctl net.ipv6.conf.eth0.accept_ra # Tests ping6 -c 4 ipv6.google.com traceroute6 ipv6.google.com ss -6 -tulnp
Configure addresses and routes
# Add a static global address (use a /64 on a LAN segment) sudo ip -6 addr add 2001:db8:1::10/64 dev eth0 # Add a route via a link-local next-hop (note the %iface syntax) sudo ip -6 route add 2001:db8:2::/64 via fe80::1 dev eth0 # Remove sudo ip -6 addr del 2001:db8:1::10/64 dev eth0 # Disable SLAAC on an interface (for static-only setups) sudo sysctl -w net.ipv6.conf.eth0.accept_ra=0 # Toggle privacy extensions sudo sysctl -w net.ipv6.conf.all.use_tempaddr=2 # 2 = prefer temp address
Real-World Scenario
You ssh into a fresh cloud instance and ip -6 addr shows two global addresses on the interface — one with EUI-64 / stable IID, one that looks randomised. That's expected: the stable one is for inbound connections (DNS resolves to it) and the temporary one is sourced for outbound connections to reduce tracking. Both are valid; the kernel picks based on the source-selection rules in RFC 6724.
Quick Reference
- An IPv6 address is 8 × 16-bit hex groups; compress with
::once. - End-host subnets are
/64. Many protocols assume it. ::1loopback,fe80::/10link-local,fc00::/7ULA,2000::/3global,ff00::/8multicast.- Hosts learn addresses via SLAAC, DHCPv6, or both — driven by RA M/O flags.
- ARP is replaced by NDP, running over ICMPv6. Don't block ICMPv6 (RFC 4890).
- Minimum link MTU is 1280; Path MTU Discovery relies on ICMPv6 Packet-Too-Big.
- Link-local addresses need a zone identifier (
%iface) when used outside routing tables. - Use
ip -6for everything.ifconfigis deprecated and incomplete for IPv6.
IPv6 has been "ten years away" since the 1990s, and it has also been quietly taking over the internet for the last fifteen of those years. Every operator should be comfortable with the concepts above; the day a customer reports "your site doesn't work on my new ISP" is too late to start reading man ip-address.