13.1 IPv6 Data Packets, Addresses, and Subnets
IPv6 is not merely "increasing the address size from 32 to 128 bits." It changes the basic header, fragmentation, and neighbor discovery mechanisms, and makes it common for a host to maintain multiple addresses across different scopes and lifecycles.
Learning Objectives
- Explain the division of responsibilities between the IPv6 base header and extension headers;
- Correctly understand IPv6 fragmentation at the sender, Path MTU Discovery, and ICMPv6;
- Properly format and parse IPv6 addresses;
- Distinguish between global, ULA, link-local, multicast, and anycast address types;
- Design common
/64subnets, while recognizing that such rules are not absolute for all interfaces.
Why Do We Still Need IPv6?
IPv4's 32-bit address space offers only about 4.3 billion unique values, with significant portions reserved for special or private uses. While CIDR, private addressing, and NAT have delayed the exhaustion of available addresses, they have not increased the available end-to-end public address space.
IPv6 provides a vast address space that enables hierarchical prefix allocation and reduces reliance on address sharing. However, it does not automatically resolve issues like firewalls, network address translation (NAT), routing misconfigurations, or application compatibility. Having enough addresses is not the same as ensuring services are accessible over the internet.
Fixed 40-byte Basic Header
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-------+---------------+---------------------------------------+
|Version| Traffic Class | Flow Label |
+-------+---------------+---------------------------------------+
| Payload Length | Next Header | Hop Limit |
+---------------------------------------------------------------+
| Source Address |
| 128 bits |
+---------------------------------------------------------------+
| Destination Address |
| 128 bits |
+---------------------------------------------------------------+| Field | Bits | Purpose |
|---|---|---|
| Version | 4 | Value is 6 |
| Traffic Class | 8 | Traffic class bits used for DSCP and ECN |
| Flow Label | 20 | Identifies packets belonging to the same flow; usage depends on implementation and network policies |
| Payload Length | 16 | Length of data following the basic header; restricted in jumbogram scenarios |
| Next Header | 8 | Points to an extension header or an upper-layer protocol such as TCP, UDP, or ICMPv6 |
| Hop Limit | 8 | Decremented by one on each hop; discarded if forwarding reduces it to zero, similar in function to IPv4 TTL |
| Source/Destination | 128 bits each | 128-bit source and destination IPv6 addresses |
The following parser only processes the basic header and does not attempt to traverse extension headers:
from dataclasses import dataclass
import ipaddress
import struct
@dataclass(frozen=True)
class IPv6BaseHeader:
traffic_class: int
flow_label: int
payload_length: int
next_header: int
hop_limit: int
source: ipaddress.IPv6Address
destination: ipaddress.IPv6Address
def parse_ipv6_base_header(packet: bytes) -> IPv6BaseHeader:
if len(packet) < 40:
raise ValueError("truncated IPv6 base header")
first_word, length, next_header, hop_limit, source, destination = (
struct.unpack("!IHBB16s16s", packet[:40])
)
version = first_word >> 28
if version != 6:
raise ValueError(f"expected IPv6, got version={version}")
return IPv6BaseHeader(
traffic_class=(first_word >> 20) & 0xFF,
flow_label=first_word & 0xFFFFF,
payload_length=length,
next_header=next_header,
hop_limit=hop_limit,
source=ipaddress.IPv6Address(source),
destination=ipaddress.IPv6Address(destination),
)payload_length excludes the 40-byte base header. Returning successfully only establishes that the base header is readable, not that the payload is complete. Production parsers must check capture length, extension chains, and resource limits. Payload Length = 0 does not always mean an empty packet: valid jumbograms carry the length in a Hop-by-Hop Jumbo Payload option. A Flow Label also promises no bandwidth or priority by itself.
Extension Headers May Be Examined Along the Path
IPv6 places optional information in extension headers, chained together via Next Header. Common types include Hop-by-Hop Options, Routing, Fragment, Destination Options, and AH/ESP.
Most extension headers are processed only by the destination node; Hop-by-Hop Options have along-path processing semantics, but RFC 8200 allows nodes to inspect them only if explicitly configured. Real-world devices may also drop packets due to security policies, hardware limitations, or malformed header chains. Therefore, you cannot conclude from "the protocol supports extension headers" that any combination will successfully traverse the Internet.
What Does the Absence of an IPv6 Header Checksum Mean?
The basic IPv6 header lacks the header checksum found in IPv4. As a result, routers can modify the Hop Limit field without needing to recalculate the checksum. Link-layer protocols typically provide error detection, and both TCP and ICMPv6 include their own checksums. For UDP in IPv6, a non-zero checksum is generally required; exceptions exist only in a few explicitly defined tunneling scenarios.
This does not mean that any layer can guarantee data will remain uncorrupted. Checksums provide a certain level of error detection, not cryptographic integrity.
Send-Side Fragmentation and PMTUD
IPv6 routers do not fragment packets on behalf of the source host. When a packet exceeds the MTU of the next hop, the router discards it and sends back an ICMPv6 Packet Too Big message, which includes the available MTU. The source host then reduces the packet size accordingly. If IPv6 fragmentation is truly necessary, the Fragment header is added by the source node itself.
source -- packet too large --> router
source <-- ICMPv6 Packet Too Big, MTU=... -- router
source -- smaller packets or source fragments --> destinationEvery link must present IPv6 with an MTU of at least 1280 bytes. A lower layer unable to carry that size needs adaptation or fragmentation/reassembly below IPv6; IPv6 routers do not perform that fragmentation. While Ethernet commonly uses a 1500-byte MTU, the end-to-end path may be smaller. Suppressing Packet Too Big messages undermines PMTUD and creates a "small request works, large response stalls" black hole scenario.
The transport layer can also employ Packetization Layer PMTUD, which adjusts packet size through controlled probing without relying entirely on ICMP.
IPv6 Address Representation
An IPv6 address consists of 8 groups of 16-bit hexadecimal numbers:
2001:0db8:0000:0000:0000:ff00:0042:8329Compression rules:
- Leading zeros in each group can be omitted;
- A sequence of consecutive zero groups can be replaced with
::; ::may appear at most once in a single address;- According to RFC 5952, the longest zero run should be chosen for textual representation; if there are ties, the leftmost zero run is selected, and hexadecimal digits are lowercase. Canonical form does not compress a single zero group into
::.
2001:0db8:0000:0000:0000:ff00:0042:8329
2001:db8::ff00:42:8329These two lines represent the same 128-bit value. Textual equality can be easily misled by different notations; parse addresses into binary form first:
import ipaddress
left = ipaddress.IPv6Address("2001:0db8:0:0:0:ff00:42:8329")
right = ipaddress.IPv6Address("2001:db8::ff00:42:8329")
assert left == right
assert left.compressed == "2001:db8::ff00:42:8329"
assert left.exploded == "2001:0db8:0000:0000:0000:ff00:0042:8329"IPv6 literals in URLs must be enclosed in square brackets to avoid conflicts between colons in the address and the port separator:
http://[2001:db8::10]:8080/Link-local addresses often require a zone identifier to specify the interface, such as fe80::1%eth0 on Linux. The zone belongs to the scope of address usage at runtime and is not part of a globally resolvable DNS name. Interface names are local to a host. Zone-qualified addresses in URLs or user interfaces depend on tool support; Linux %eth0 syntax is not a universally portable URL.
Important Address Ranges
| Range | Name | Boundaries |
|---|---|---|
::/128 | unspecified | Can only serve as a source in scenarios where the address is not yet determined; cannot be assigned to an interface as a standard unicast address |
::1/128 | loopback | Valid only on the local machine |
2000::/3 | Common global unicast allocation range | May be globally routed depending on routing policies and configurations; not inherently reachable by default |
2001:db8::/32 | documentation | Reserved solely for illustrative examples in documentation; should not appear in public routing tables |
fc00::/7 | unique local | Should not be routed across the global Internet; actual local generation typically uses fd00::/8 |
fe80::/10 | link-local | Used only within a single link; routers do not forward these addresses |
ff00::/8 | multicast | Scope is determined by the scope field within the address |
ULA is not a complete synonym for IPv4 RFC 1918 addresses. RFC 4193-defined locally assigned ULA addresses typically begin with fd and use a randomly generated 40-bit Global ID to reduce collision risks when organizations merge; they may still be routed across subnets within the same organization.
Unicast, Multicast, and Anycast
IPv6 does not include the broadcast mechanisms found in IPv4. Instead, functions like neighbor discovery rely on multicast groups with well-defined scopes:
ff02::1: all-nodes multicast within link-local scope;ff02::2: all-routers multicast within link-local scope;- solicited-node multicast: NDP constructs this based on the lowest 24 bits of the target unicast address.
Multicast reduces the overhead of processing irrelevant protocol stacks that would otherwise occur with broadcast, but it does not mean that all multicast traffic remains harmless to other devices. Actual forwarding behavior is influenced by group membership management, switch MLD snooping configurations, and link-layer characteristics.
IPv6 anycast uses standard unicast address format: the same address is assigned to multiple nodes, and routing directs traffic to the instance selected by topology metrics. "Nearest" refers to the best path determined by routing policies, not necessarily the geographically closest node, nor does it guarantee that consecutive requests will reach the same instance.
/64 is a key convention, not a universal constant
Most typical LANs use /64, and SLAAC's primary operation model is built on a 64-bit interface identifier. Operators typically assign /64 to individual Layer 2 segments from a higher-level allocated /48, /56, or another prefix.
However, it's incorrect to claim that "every IPv6 host portion must always be 64 bits":
- Loopback addresses use
/128; - Routing entries and aggregated prefixes can employ various lengths;
- Point-to-point links may use
/127according to deployment specifications; - Special addresses and protocols may have their own structures.
The goal of subnet design is not to conserve individual addresses, but to maintain clear hierarchy, aggregation capabilities, and consistent operational models.
import ipaddress
from itertools import islice
site = ipaddress.IPv6Network("2001:db8:1200::/48")
first_four_lans = list(islice(site.subnets(new_prefix=64), 4))
assert [str(network) for network in first_four_lans] == [
"2001:db8:1200::/64",
"2001:db8:1200:1::/64",
"2001:db8:1200:2::/64",
"2001:db8:1200:3::/64",
]A /48 contains 2^(64-48) = 65,536 /64 subnets. Using islice consumes only four entries instead of constructing all 65,536 objects first. Abundant addresses do not require an equally abundant list.
Lesson Summary
IPv6's basic header is more structured, with fragmentation responsibility shifted to the source, and PMTUD relying on ICMPv6. The 128-bit address space introduces new norms around scope and coexistence of multiple addresses; /64 is the core agreement between LAN and SLAAC, but must be understood within the specific context of interfaces and protocols.
The next lesson will walk through the process of a host joining a link, exploring NDP, RA, SLAAC, DHCPv6, and address lifecycle.
Specification Entry Points
RFC 8200: IPv6 Specification;
RFC 4291: IPv6 Addressing Architecture;
RFC 5952: IPv6 Text Representation;
RFC 4193: Unique Local IPv6 Unicast Addresses;
RFC 8201: Path MTU Discovery for IPv6;
RFC 6164: Using 127-Bit IPv6 Prefixes on Inter-Router Links.
RFC 9844: Entering IPv6 Zone Identifiers in User Interfaces.