Post

IPv6 Addressing Explained

IPv4 served the internet for decades, but its 32-bit address space — roughly 4.3 billion addresses — ran out. IANA exhausted the last blocks in 2011. The long-term answer is IPv6, which uses 128-bit addresses and provides approximately 340 undecillion (3.4 × 10³⁸) unique addresses — enough to assign billions of addresses to every grain of sand on Earth.

Beyond sheer quantity, IPv6 brings architectural improvements: built-in autoconfiguration, mandatory IPsec support, simplified headers for faster routing, and the elimination of NAT for most use cases. As a Linux administrator you will increasingly encounter IPv6 in cloud environments, ISP allocations, and modern data centres, so understanding it thoroughly is essential.

Why IPv6?

Problem with IPv4 IPv6 Solution
4.3 billion addresses — exhausted 340 undecillion addresses
NAT required for private networks Every device can have a globally routable address
Manual or DHCP-only configuration Stateless autoconfiguration (SLAAC) built in
Optional IPsec IPsec support mandatory in the specification
Complex header with many fields Simplified fixed-length header (40 bytes)
Broadcast traffic No broadcast — uses multicast instead
Fragmentation by routers Only source hosts fragment; routers do not

Address Structure

An IPv6 address is 128 bits long, written as eight groups of four hexadecimal digits separated by colons:

1
2001:0db8:85a3:0000:0000:8a2e:0370:7334

Each group (called a hextet or quartet) represents 16 bits. Hexadecimal uses digits 0–9 and letters a–f, so each hex digit represents 4 bits.

1
2
3
4
Full address:
2001 : 0db8 : 85a3 : 0000 : 0000 : 8a2e : 0370 : 7334
 16b    16b    16b    16b    16b    16b    16b    16b
                    = 128 bits total

Hex to Binary Mapping

Hex Binary Hex Binary
0 0000 8 1000
1 0001 9 1001
2 0010 a 1010
3 0011 b 1011
4 0100 c 1100
5 0101 d 1101
6 0110 e 1110
7 0111 f 1111

Address Notation Rules

Writing 32 hex characters with colons is verbose. Two abbreviation rules keep addresses manageable.

Rule 1: Omit Leading Zeros Within a Group

Each group of four hex digits can drop its leading zeros:

1
2
2001:0db8:0000:0042  →  2001:db8:0:42
     ^^^^ ^^^^ ^^^^

Note that 0000 becomes 0 (not empty — at least one digit must remain).

Rule 2: Replace One Run of Consecutive All-Zero Groups with ::

The double-colon :: can replace one or more consecutive groups of all zeros, but only once per address (using it twice would make the address ambiguous):

1
2
3
4
5
6
7
8
9
10
11
2001:0db8:0000:0000:0000:0000:0000:0001
→  2001:db8::1

fe80:0000:0000:0000:0204:61ff:fe9d:f156
→  fe80::204:61ff:fe9d:f156

0000:0000:0000:0000:0000:0000:0000:0001
→  ::1   (loopback)

0000:0000:0000:0000:0000:0000:0000:0000
→  ::    (unspecified)

Expanding a Compressed Address

To expand :: back to full form, count the existing groups, then fill in enough 0000 groups to make eight total:

1
2
3
4
5
2001:db8::1
Groups present: 2001, db8, 1  →  3 groups
Groups needed:  8 − 3 = 5 zero groups inserted at ::

Full: 2001:0db8:0000:0000:0000:0000:0000:0001

Tip: When in doubt, expand the address to all 8 groups before analysing it. The python3 -c "import ipaddress; print(ipaddress.ip_address('2001:db8::1').exploded)" one-liner does this instantly on any Linux system.


Address Anatomy: Prefix and Interface ID

Like IPv4’s network/host split, an IPv6 address has two parts:

1
2
3
| ← Prefix (network portion) → | ← Interface ID (host portion) → |
  2001:0db8:85a3:0001           :  0000:0000:abcd:1234
  ←————— 64 bits ——————→           ←————— 64 bits ——————→

The standard allocation for end-user networks is a /64 prefix, leaving 64 bits for the interface identifier. This means a single /64 subnet has 2⁶⁴ ≈ 18.4 quintillion addresses — far more than any subnet will ever need.

ISPs typically assign:

  • /48 to organisations (65,536 possible /64 subnets)
  • /56 to home users (256 possible /64 subnets)
  • /64 to individual links
1
2
3
4
5
6
Organisation gets: 2001:db8:abcd::/48
                   ←— 48-bit prefix —→
Can create subnets: 2001:db8:abcd:0001::/64
                    2001:db8:abcd:0002::/64
                    ...
                    2001:db8:abcd:ffff::/64   (65,536 subnets)

Address Types

IPv6 has three fundamental address types — broadcast no longer exists.

Unicast

A unicast address identifies one specific interface. Traffic sent to a unicast address is delivered to exactly one destination.

Global Unicast (GUA) — routable on the public internet. Always starts with 2 or 3 in the first hex digit (prefix 2000::/3):

1
2
2001:db8:1:1::10/64
2600:1400:d:5a4::17de

Link-Local — automatically assigned to every IPv6-enabled interface. Only valid within a single network segment (not routed). Always starts with fe80::/10:

1
2
fe80::1%eth0
fe80::204:61ff:fe9d:f156

The %eth0 suffix (called a zone ID or scope ID) is required when using link-local addresses in commands because the same fe80:: prefix appears on every interface — the zone ID tells the OS which one to use.

Unique Local Address (ULA) — the IPv6 equivalent of RFC 1918 private space. Not routed on the public internet. Starts with fc00::/7 (in practice almost always fd00::/8):

1
fd12:3456:789a:1::1/64

Loopback — always ::1/128. Equivalent to IPv4’s 127.0.0.1:

1
::1

Unspecified:: (all zeros). Used as a source address before an address is assigned, or to mean “any address” in a server bind context. Equivalent to IPv4’s 0.0.0.0.

Multicast

A multicast address identifies a group of interfaces. Traffic is delivered to all members of the group. Always starts with ff:

Address Group Scope
ff02::1 All nodes Link-local
ff02::2 All routers Link-local
ff02::fb mDNS Link-local
ff02::1:2 All DHCP agents Link-local
ff05::2 All routers Site-local

IPv6 uses multicast where IPv4 used broadcast. For example, a router discovery request goes to ff02::2 (all routers on the link) rather than a broadcast address.

Anycast

An anycast address is assigned to multiple interfaces (typically on different routers). Traffic is delivered to the nearest one according to the routing protocol. Anycast addresses look identical to unicast addresses — the difference is in how they are assigned and advertised.


Prefix Notation and Subnetting

IPv6 uses the same CIDR /n notation as IPv4.

1
2
3
4
2001:db8::/32     — a /32 prefix (e.g. assigned to an ISP)
2001:db8:1::/48   — a /48 prefix (e.g. assigned to an organisation)
2001:db8:1:a::/64 — a /64 prefix (a single subnet)
::1/128           — a /128 host route (one specific interface)

Subnet Planning Example

Organisation receives 2001:db8:acad::/48. Plan subnets for four departments:

The 48-bit prefix leaves 16 bits for subnetting (bits 49–64) before the 64-bit interface ID begins. That gives 2¹⁶ = 65,536 possible /64 subnets.

Department Subnet Prefix
HQ 2001:db8:acad:0001::/64 Subnet 1
Engineering 2001:db8:acad:0002::/64 Subnet 2
Sales 2001:db8:acad:0003::/64 Subnet 3
DMZ 2001:db8:acad:0100::/64 Subnet 256

Each /64 subnet accommodates 2⁶⁴ − 2 ≈ 18.4 quintillion hosts. In practice, only the /128 host route and the subnet-router anycast address (all interface ID bits = 0) are special — there is no broadcast address to subtract.


Interface ID Generation

The 64-bit interface ID can be generated in several ways:

EUI-64 (Extended Unique Identifier)

Derived automatically from the interface’s 48-bit MAC address:

  1. Split the MAC in half and insert ff:fe in the middle
  2. Flip bit 7 (the Universal/Local bit) of the first byte
1
2
3
4
5
6
7
MAC:        00:1a:2b:3c:4d:5e
Split:      00:1a:2b  |  3c:4d:5e
Insert:     00:1a:2b:ff:fe:3c:4d:5e
Flip bit 7: 02:1a:2b:ff:fe:3c:4d:5e

Interface ID: 021a:2bff:fe3c:4d5e
Full address: fe80::21a:2bff:fe3c:4d5e

Privacy concern: EUI-64 embeds the MAC address in the IPv6 address, making a device trackable across networks. RFC 4941 Privacy Extensions generate a random, temporary interface ID instead and rotate it periodically. Most modern operating systems enable privacy extensions by default.

RFC 4941 Privacy Extensions (Random)

The OS generates a random 64-bit interface ID and replaces it periodically (typically every 24 hours for temporary addresses). This is the default on Linux, Windows, and macOS for outbound connections.

Manually Configured

You assign the interface ID explicitly — useful for servers and routers where a predictable, stable address is required:

1
2001:db8:1:1::10/64     ← ::10 is the manually chosen interface ID

Autoconfiguration: SLAAC and DHCPv6

IPv6 devices can configure themselves without any manual intervention.

SLAAC (Stateless Address Autoconfiguration — RFC 4862)

The most common method on LANs:

  1. The interface generates a link-local address (fe80::/10 + interface ID) at startup.
  2. It sends a Neighbour Solicitation to verify no other device uses that address (DAD — Duplicate Address Detection).
  3. It sends a Router Solicitation (ff02::2) asking for network information.
  4. A router responds with a Router Advertisement containing the network prefix (e.g. 2001:db8:1::/64), default gateway, and flags.
  5. The device combines the advertised prefix with its interface ID to form a global unicast address.
  6. It sends another DAD for the new GUA.

No DHCP server is needed. The router advertisement alone is sufficient to fully configure the interface.

DHCPv6 (Stateful)

Works like DHCPv4 — a DHCPv6 server leases specific addresses and provides additional options (DNS servers, domain names). The router advertisement sets flags to tell clients whether to use SLAAC, DHCPv6, or both:

RA Flag Meaning
M=0, O=0 SLAAC only — no DHCPv6
M=0, O=1 SLAAC for address + DHCPv6 for options (DNS, etc.)
M=1, O=1 Full DHCPv6 — address and options from server

Stateless DHCPv6

A common hybrid: SLAAC assigns the address, DHCPv6 provides only DNS server information (M=0, O=1). Many ISPs and enterprise networks use this model.


NDP: Neighbour Discovery Protocol

NDP (RFC 4861) replaces IPv4’s ARP. It uses ICMPv6 messages over multicast to perform address resolution, router discovery, and duplicate address detection.

ICMPv6 Type Message Purpose
133 Router Solicitation (RS) Host asks routers to send RA
134 Router Advertisement (RA) Router announces prefix, gateway, flags
135 Neighbour Solicitation (NS) Equivalent to ARP request
136 Neighbour Advertisement (NA) Equivalent to ARP reply
137 Redirect Router tells host of a better next-hop

Solicited-Node Multicast Address

Instead of broadcasting like ARP, NDP sends Neighbour Solicitations to a solicited-node multicast address derived from the target’s address:

1
2
3
4
5
Prefix:       ff02::1:ff00:0/104
Last 24 bits: taken from the target address

Target: 2001:db8::abcd:1234
Solicited-node: ff02::1:ffcd:1234

Only the device(s) whose address ends in cd:1234 listen on that multicast group — far more efficient than ARP’s link-layer broadcast.


Dual-Stack Operation

During the IPv4-to-IPv6 transition, most production systems run dual-stack — both protocols active simultaneously on the same interface. The OS chooses which to use based on the destination address and application preferences.

1
2
3
4
5
# A dual-stack interface shows both addresses
ip addr show eth0
# inet  192.168.1.100/24 brd 192.168.1.255 scope global eth0
# inet6 2001:db8:1::100/64 scope global
# inet6 fe80::1%eth0/64 scope link

Address selection preference (RFC 6724): IPv6 global unicast is preferred over IPv4 when both are available. Applications that explicitly bind to 0.0.0.0 (IPv4 only) will not use IPv6 even on a dual-stack system.


Configuring IPv6 on Linux

View Addresses and Routes

1
2
3
4
ip -6 addr show               # IPv6 addresses only
ip addr show eth0             # All addresses on eth0
ip -6 route show              # IPv6 routing table
ip -6 neigh show              # NDP neighbour cache (equivalent to ARP table)

Assign a Static Address (Temporary)

1
2
sudo ip -6 addr add 2001:db8:1::100/64 dev eth0
sudo ip -6 route add default via 2001:db8:1::1

Persistent Configuration (Netplan — Ubuntu 18.04+)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# /etc/netplan/01-netcfg.yaml
network:
  version: 2
  ethernets:
    eth0:
      addresses:
        - 192.168.1.100/24          # IPv4 static
        - 2001:db8:1::100/64        # IPv6 static
      routes:
        - to: default
          via: 192.168.1.1
        - to: ::/0
          via: 2001:db8:1::1
      nameservers:
        addresses:
          - 8.8.8.8
          - 2001:4860:4860::8888    # Google DNS over IPv6
1
sudo netplan apply

Persistent Configuration (nmcli — RHEL/CentOS)

1
2
3
4
5
sudo nmcli con mod eth0 ipv6.addresses "2001:db8:1::100/64"
sudo nmcli con mod eth0 ipv6.gateway "2001:db8:1::1"
sudo nmcli con mod eth0 ipv6.dns "2001:4860:4860::8888"
sudo nmcli con mod eth0 ipv6.method manual
sudo nmcli con up eth0

Enable/Disable SLAAC

1
2
3
4
5
6
7
8
9
# Check if SLAAC is active (accept_ra = 1 means yes)
cat /proc/sys/net/ipv6/conf/eth0/accept_ra

# Disable SLAAC on an interface (use static only)
sudo sysctl -w net.ipv6.conf.eth0.accept_ra=0

# Make persistent
echo "net.ipv6.conf.eth0.accept_ra=0" | sudo tee -a /etc/sysctl.d/99-ipv6.conf
sudo sysctl -p /etc/sysctl.d/99-ipv6.conf

Enable IPv6 Forwarding (Router/Gateway)

1
2
3
4
sudo sysctl -w net.ipv6.conf.all.forwarding=1

# Persistent
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.d/99-ipv6.conf

Diagnostic Commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Test connectivity
ping6 ::1                          # Loopback test
ping6 fe80::1%eth0                 # Link-local (zone ID required)
ping6 2001:4860:4860::8888         # Google DNS (public IPv6)
ping6 -c 4 ipv6.google.com

# Trace route
traceroute6 2001:4860:4860::8888
tracepath6 ipv6.google.com

# DNS — query AAAA record (IPv6)
dig AAAA google.com
nslookup -type=AAAA google.com

# Show NDP neighbour cache
ip -6 neigh show

# Show listening IPv6 sockets
ss -tlnp6

# Check which address the OS selects for a destination
ip -6 route get 2001:4860:4860::8888

Common Issues and Solutions

Problem Cause Solution
No global unicast address Router not sending RA Check router config; radvd on Linux routers
ping6 fails to link-local Missing zone ID Add %ifname: ping6 fe80::1%eth0
Duplicate address detected (DAD failure) Address conflict Change interface ID; check for duplicate static assignments
IPv6 disabled on interface Kernel parameter sysctl -w net.ipv6.conf.eth0.disable_ipv6=0
Application only listening on IPv4 Bound to 0.0.0.0 Bind to :: (listens on both IPv4 and IPv6 on dual-stack)
Slow connections (Happy Eyeballs) DNS returns AAAA but IPv6 path broken Fix IPv6 routing or disable IPv6 on the interface
Cannot reach link-local address No zone ID specified Always include %interface for link-local addresses

IPv4 vs IPv6 Side-by-Side

Feature IPv4 IPv6
Address length 32 bits 128 bits
Notation Dotted decimal Colon-hexadecimal
Total addresses ~4.3 billion ~3.4 × 10³⁸
Header size 20–60 bytes (variable) 40 bytes (fixed)
Broadcast Yes No (multicast replaces it)
Address config Manual / DHCP SLAAC / DHCPv6 / manual
Fragmentation Routers and hosts Source hosts only
ARP Yes No (NDP replaces it)
NAT Required for private → public Not required
IPsec Optional Mandatory in spec
Loopback 127.0.0.1 ::1
Private range RFC 1918 ULA fc00::/7
Link-local 169.254.x.x APIPA fe80::/10 (always present)
Multicast 224.0.0.0/4 ff00::/8

Quick Reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Address length:    128 bits (8 groups × 16 bits, hex, colon-separated)
Abbreviation:      Drop leading zeros; :: for one consecutive run of all-zero groups
Standard prefix:   /64 for end-user subnets

Address types:
  ::1/128            Loopback
  ::/128             Unspecified
  fe80::/10          Link-local unicast (always present, not routed)
  fc00::/7 (fd::/8)  Unique local (ULA — private, not routed)
  2000::/3           Global unicast (internet routable)
  ff00::/8           Multicast

Key multicast groups:
  ff02::1   All nodes (link-local)
  ff02::2   All routers (link-local)

NDP replaces ARP:
  RS (133) / RA (134) — router discovery
  NS (135) / NA (136) — neighbour resolution

Linux commands:
  ip -6 addr show
  ip -6 route show
  ip -6 neigh show
  ping6 <address>%<iface>
  traceroute6 <address>
  dig AAAA <hostname>

Conclusion

IPv6 is no longer a future technology — it is the present. Major cloud providers, ISPs, and content networks are fully dual-stack, and many mobile networks run IPv6-only. The address structure, notation rules, and autoconfiguration mechanisms covered here give you the foundation to configure interfaces, design subnets, and troubleshoot connectivity on any modern Linux system.

The single most important habit to develop: always include the zone ID (%interface) when working with link-local addresses, and always prefer /64 prefixes for end-user subnets to keep SLAAC and EUI-64 working correctly. With those two rules in mind, IPv6 administration follows naturally from the IPv4 skills you already have.

Additional Resources


This post is licensed under CC BY 4.0 by the author.