IPv6
128-bit addresses — solving exhaustion and simplifying the protocol
Why IPv6 Exists
The IPv4 Exhaustion Problem
IPv4 provides 232 = 4,294,967,296 addresses. That sounds like a lot until you consider:
- IANA exhausted its free pool of /8 blocks on February 3, 2011
- APNIC (Asia-Pacific) ran out first; RIPE (Europe) followed in 2012
- ARIN (North America) exhausted its free pool in September 2015
- Large chunks are reserved (private, multicast, loopback, etc.), leaving ~3.7 billion routable addresses
- NAT (Network Address Translation) allows many private hosts to share one public IP
- Breaks end-to-end connectivity (peer-to-peer, VoIP, gaming)
- Requires connection tracking state (memory, CPU)
- Makes protocols that embed IP addresses in payloads painful (SIP, FTP active mode)
- Carrier-grade NAT (CGNAT) stacks NAT on NAT — debugging nightmares
- 2128 = 340 undecillion addresses (~3.4 x 1038)
- Every device gets a globally unique address — NAT becomes unnecessary
- Restores true end-to-end connectivity
- Simplified header (fixed 40 bytes, no checksum, no fragmentation fields)
- Built-in autoconfiguration (SLAAC)
- Mandatory IPsec support in the spec (though not always enforced)
128-bit Address Notation
IPv6 addresses are written as 8 groups of 4 hexadecimal digits, separated by colons.
Full vs Abbreviated Notation
# Full notation (all 32 hex digits)
2001:0db8:0000:0000:0000:0000:0000:0001
# Rule 1: Leading zeros in each group can be dropped
2001:db8:0:0:0:0:0:1
# Rule 2: One consecutive run of all-zero groups → "::" (once per address)
2001:db8::1Abbreviation Rules
| Rule | Description | Example |
|---|---|---|
| Leading zero suppression | Remove leading zeros in each 16-bit group | 0db8 becomes db8, 0001 becomes 1 |
| :: (double colon) | Replace one longest consecutive run of all-zero groups | fe80:0:0:0:0:0:0:1 becomes fe80::1 |
| :: used only once | Using :: twice would be ambiguous (can't tell how many zero groups each replaces) | 2001:db8::1::2 is INVALID |
Expansion Practice
| Abbreviated | Expanded |
|---|---|
::1 |
0000:0000:0000:0000:0000:0000:0000:0001 (loopback) |
:: |
0000:0000:0000:0000:0000:0000:0000:0000 (unspecified) |
fe80::1 |
fe80:0000:0000:0000:0000:0000:0000:0001 |
2001:db8:85a3::8a2e:370:7334 |
2001:0db8:85a3:0000:0000:8a2e:0370:7334 |
Note
URLs with IPv6: Because colons conflict with port notation, wrap the address in brackets: http://[2001:db8::1]:8080/path
IPv6 Address Types
| Type | Prefix | Scope | Description |
|---|---|---|---|
| Link-Local | fe80::/10 |
Single link only | Auto-assigned on every interface. Not routable. Used for NDP, routing protocol adjacencies. Equivalent to IPv4 169.254.x.x but always present and required. |
| Global Unicast (GUA) | 2000::/3 |
Global (internet-routable) | The equivalent of public IPv4 addresses. Currently most allocations are from 2001::/16 (IANA) and 2400::/6 through 2c00::/6 (RIRs). |
| Unique Local (ULA) | fc00::/7 (in practice fd00::/8) |
Private (not internet-routable) | Like RFC 1918 for IPv6. Use fd + 40 random bits as the prefix. Suitable for internal services that should never be publicly reachable. |
| Multicast | ff00::/8 |
Varies by scope | Replaces IPv4 broadcast (no broadcast in IPv6). Examples: ff02::1 (all nodes on link), ff02::2 (all routers on link), ff02::1:ff00:0/104 (solicited-node multicast). |
| Loopback | ::1/128 |
Host-only | Single address, equivalent to 127.0.0.1. |
| Unspecified | ::/128 |
N/A | Equivalent to 0.0.0.0. Used as source before address assignment. |
Tip
K8s dual-stack: When running dual-stack K8s, pods get both a 10.x.x.x (or similar) IPv4 and a GUA or ULA IPv6 address. Services can have both ClusterIP families. Cilium and Calico both support dual-stack natively.
IPv6 Header Format
The IPv6 header is a fixed 40 bytes — no options field, no header length field needed. Simpler than IPv4, faster to process.
IPv6 Header Fields Explained
| Field | Purpose |
|---|---|
| Version | Always 6. Same position/size as IPv4's version field — this is how the stack knows which header to parse. |
| Traffic Class | Equivalent to IPv4's DSCP + ECN. Used for QoS differentiation. |
| Flow Label | Identifies a flow of packets. Routers can use it for fast-path forwarding without inspecting upper-layer headers. Set to 0 if unused. |
| Payload Length | Length of everything after the 40-byte header (extension headers + data). Unlike IPv4's Total Length, which includes the header. |
| Next Header | Replaces IPv4's Protocol field. Identifies the next header: could be TCP (6), UDP (17), ICMPv6 (58), or an extension header (e.g., 0 = Hop-by-Hop, 43 = Routing, 44 = Fragment). |
| Hop Limit | Equivalent to IPv4's TTL. Decremented by 1 at each hop. Packet discarded at 0. |
IPv4 vs IPv6 Header Comparison
- Variable size: 20-60 bytes (IHL field encodes length)
- Header checksum: present, recomputed at every hop
- Fragmentation: built into the header (ID, Flags, Fragment Offset)
- Options: variable-length, in the main header
- 13 fields in the base header
- Protocol field: identifies upper layer
- TTL: hop counter
- Broadcast addresses exist
- Fixed 40 bytes: no IHL field needed, simpler parsing
- No header checksum: relies on L2 (Ethernet CRC) and L4 (TCP/UDP checksum) — faster forwarding
- No fragmentation in header: uses Fragment extension header; only the source fragments (not routers)
- Extension headers: daisy-chained via Next Header, not in the base header
- 8 fields in the base header
- Next Header: identifies upper layer or extension header
- Hop Limit: renamed TTL (same behavior)
- No broadcast — uses multicast instead
| Feature | IPv4 | IPv6 |
|---|---|---|
| Address size | 32 bits (4 bytes) | 128 bits (16 bytes) |
| Address count | ~4.3 billion | ~3.4 x 1038 |
| Header size | 20-60 bytes (variable) | 40 bytes (fixed) |
| Checksum | Yes (recalculated per hop) | No |
| Fragmentation | By routers or source | Source only (extension header) |
| ARP | Separate protocol (L2) | Replaced by NDP (ICMPv6) |
| Autoconfiguration | DHCP (optional APIPA) | SLAAC (built-in) + optional DHCPv6 |
| NAT | Ubiquitous | Generally unnecessary (but NAT66 exists) |
| IPsec | Optional | Mandatory in spec (optional in practice) |
NDP: Neighbor Discovery Protocol
NDP replaces ARP, ICMP Router Discovery, and ICMP Redirect from IPv4. It runs over ICMPv6 and handles address resolution, router discovery, duplicate address detection, and autoconfiguration.
NDP Message Types
| Message | ICMPv6 Type | Direction | Purpose |
|---|---|---|---|
| Router Solicitation (RS) | 133 | Host --> Routers | Host asks "any routers on this link?" Sent to ff02::2 (all-routers multicast) |
| Router Advertisement (RA) | 134 | Router --> Hosts | Router announces prefix, default gateway, MTU, flags (M/O for DHCPv6). Sent periodically and in response to RS, to ff02::1 (all-nodes multicast) |
| Neighbor Solicitation (NS) | 135 | Host --> Target | Like ARP Request. "What is the MAC for this IPv6 address?" Sent to the target's solicited-node multicast address. Also used for Duplicate Address Detection (DAD). |
| Neighbor Advertisement (NA) | 136 | Target --> Host | Like ARP Reply. "Here is my MAC address." Can be solicited or unsolicited (gratuitous). |
| Redirect | 137 | Router --> Host | Router tells host a better first-hop for a specific destination. |
SLAAC (Stateless Address Autoconfiguration)
A host can configure its own globally routable IPv6 address without any DHCP server.
Generate link-local
fe80:: + interface ID (EUI-64 or random)
DAD
Send NS for own address — check no one else has it
Send RS
Solicit router advertisement
Receive RA
Get prefix (e.g., 2001:db8::/64)
Form GUA
prefix + interface ID = full address
Note
Privacy extensions (RFC 4941): Using a MAC-based EUI-64 interface ID allows tracking devices across networks. Modern OSes generate random interface IDs by default (the "privacy extension"). Linux: net.ipv6.conf.all.use_tempaddr=2.
SLAAC vs DHCPv6
| Feature | SLAAC | Stateless DHCPv6 | Stateful DHCPv6 |
|---|---|---|---|
| Address assignment | Yes (from RA prefix) | No (SLAAC does it) | Yes (server assigns) |
| DNS servers | RDNSS in RA (limited support) | Yes | Yes |
| Other options (NTP, search domain) | No | Yes | Yes |
| Address tracking on server | No (stateless) | No (stateless) | Yes (lease table) |
| RA flags | M=0, O=0 | M=0, O=1 | M=1 |
Dual-Stack
The simplest transition mechanism: run both IPv4 and IPv6 simultaneously on every device and network. Each interface has both an IPv4 and an IPv6 address. DNS returns both A (IPv4) and AAAA (IPv6) records; the client chooses which to use.
Dual-Stack in Practice
# A dual-stack interface on Linux
$ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500
inet 10.0.1.5/24 brd 10.0.1.255 scope global eth0
inet6 2001:db8:1::5/64 scope global
inet6 fe80::a00:27ff:fe3c:1234/64 scope link
# DNS returns both record types
$ dig example.com A +short
93.184.216.34
$ dig example.com AAAA +short
2606:2800:220:1:248:1893:25c8:1946Happy Eyeballs (RFC 8305): Modern clients try IPv6 and IPv4 in parallel, preferring IPv6 but falling back to IPv4 if the IPv6 connection is slow or fails. Avoids the latency penalty of serial attempts.
Tip
AWS/GCP/Azure: All major clouds support dual-stack VPCs. AWS added dual-stack support for ELB, EC2, and EKS. In K8s, dual-stack is GA since v1.23 — pods can get both IPv4 and IPv6 addresses, and Services can expose both families.
Transition Mechanisms
Not all networks support IPv6. These mechanisms bridge the gap during the transition period.
Tunneling: IPv6 over IPv4
| Mechanism | How It Works | Status |
|---|---|---|
| 6to4 (RFC 3056) | Encapsulates IPv6 in IPv4 using protocol 41. Auto-derives a 2002::/16 IPv6 prefix from the public IPv4 address. Uses anycast relay routers. | Deprecated (RFC 7526). Unreliable — depends on relay routers out of your control, no guarantee of reachability. |
| Teredo (RFC 4380) | Tunnels IPv6 over UDP/IPv4. Designed to work behind NAT. Uses Teredo servers for setup and Teredo relays for communication. | Legacy. Windows supported it for years. Being phased out as native IPv6 adoption grows. |
| ISATAP | Intra-Site Automatic Tunnel Addressing Protocol. IPv6-in-IPv4 tunnel within a single site. | Rarely used. Not suitable for internet connectivity. |
Translation: NAT64 / DNS64
For IPv6-only networks that need to reach IPv4 servers:
- DNS64: The DNS resolver synthesizes AAAA records for IPv4-only destinations. If a domain only has an A record (e.g.,
93.184.216.34), DNS64 returns64:ff9b::5db8:d822(the IPv4 address embedded in a well-known IPv6 prefix). - NAT64: A NAT64 gateway translates between IPv6 and IPv4 packets. The IPv6 client sends to the synthesized address; the gateway extracts the IPv4 address and forwards natively.
This is the dominant approach for mobile carriers (T-Mobile, many Asian carriers) running IPv6-only on mobile devices. It works transparently for most apps.
Warning
NAT64 limitations: Breaks protocols that embed literal IPv4 addresses in payloads (same problem as NAT44). Application-layer gateways (ALGs) are needed for some protocols. Also, you need DNSSEC-aware DNS64 to avoid validation failures.