Loading learning content...
One of the most significant architectural changes from IPv4 to IPv6 is the handling of packet fragmentation. In IPv4, any router along the path can fragment a packet that's too large for the next link's Maximum Transmission Unit (MTU). This seems convenient but creates serious performance problems: fragmentation in the middle of the network is costly, fragments may take different paths causing reassembly delays, and critical header information may be lost in fragments.
IPv6 takes a radically different approach: only the source can fragment.
Intermediate routers never fragment IPv6 packets. If a packet is too large for a link, the router drops it and sends an ICMPv6 "Packet Too Big" message back to the source. The source then fragments the packet appropriately and retransmits. This mechanism—Path MTU Discovery (PMTUD)—ensures fragmentation decisions are made where they can be optimally managed.
The Fragment Header exists to carry fragmentation information when the source chooses to fragment. It's an extension header dedicated solely to this purpose, appearing only in fragmented packets.
By the end of this page, you will understand: (1) Why IPv6 prohibits router fragmentation and the benefits of source-only fragmentation, (2) Path MTU Discovery mechanics and the ICMPv6 Packet Too Big message, (3) The complete binary structure of the Fragment Header, (4) Fragment identification, offset calculation, and M flag usage, (5) The reassembly process at the destination, (6) Fragment overlap attacks and security considerations, and (7) Atomic fragments and minimum MTU requirements.
To appreciate IPv6's fragmentation architecture, we must first understand the problems with IPv4's approach. IPv4 allows any router to fragment packets, which creates cascading inefficiencies.
IPv4 Router Fragmentation Issues:
| Problem | Technical Cause | Impact |
|---|---|---|
| Router processing overhead | Routers must buffer entire packet, compute fragment boundaries, create multiple packets | Increased latency, reduced throughput |
| Fragment path divergence | Fragments may take different routes through the network | Destination must buffer out-of-order fragments, increasing memory usage |
| Reassembly timeout waste | If any fragment is lost, all fragments wasted; entire original packet must be retransmitted | Bandwidth waste, especially for large packets |
| Header duplication | Each fragment needs its own IP header, increasing per-packet overhead | Reduced effective payload ratio |
| Transport header loss | Only first fragment contains TCP/UDP header; subsequent fragments lack port info | Firewalls cannot filter fragments properly; security vulnerabilities |
| TTL asymmetry | Each fragment decrements TTL independently; fragments may expire at different points | Partial delivery possible, complicating error handling |
The Fragment Attack Threat:
The lack of transport-layer information in non-initial IPv4 fragments created serious security problems. Attackers could:
This "fragment overlap attack" and related "tiny fragment attack" forced firewalls to either:
IPv6's Solution:
IPv6 eliminates router fragmentation entirely. The source is the only entity that can fragment, and it does so using the Fragment Header extension. This ensures:
Even in IPv4, modern implementations prefer Path MTU Discovery over router fragmentation. IPv6 simply mandated what had become best practice, removing the legacy option of router fragmentation entirely.
Path MTU Discovery is the mechanism by which IPv6 sources learn the maximum packet size that can traverse the complete path to a destination without requiring fragmentation. This information allows sources to generate appropriately-sized packets from the start.
PMTUD Mechanics:
Path MTU Discovery Process═══════════════════════════════════════════════════════════════════════════ Scenario: Source wants to send to Destination across heterogeneous path Path structure:Source ─── Link1 ─── R1 ─── Link2 ─── R2 ─── Link3 ─── Destination MTU:1500 MTU:1400 MTU:1280 Step 1: Initial Transmission────────────────────────────────────────────────────────────────────────────Source sends packet with size 1500 bytes (assuming local Ethernet MTU)Packet reaches R1 successfully (Link1 MTU = 1500) Step 2: MTU Violation Detected────────────────────────────────────────────────────────────────────────────R1 tries to forward 1500-byte packet over Link2 (MTU = 1400)Packet is TOO LARGE - R1 cannot forwardR1 DROPS the packet (does NOT fragment)R1 sends ICMPv6 Packet Too Big to Source: Type: 2 Code: 0 MTU: 1400 (the limiting MTU) Original packet (as much as fits) Step 3: Source Adjusts────────────────────────────────────────────────────────────────────────────Source receives ICMPv6 Packet Too Big with MTU=1400Source updates Path MTU cache for this destinationSource retransmits with packet size ≤ 1400 bytes If fragmenting data that was already partially sent: Source creates Fragment Headers for remaining data Step 4: Repeat Until Success────────────────────────────────────────────────────────────────────────────If Link3 has even smaller MTU, process repeatsEventually source learns true Path MTU (1280 in this example)Subsequent packets use Path MTU directly ICMPv6 Packet Too Big Message Format:════════════════════════════════════════════════════════════════════════════ 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+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Type=2 | Code=0 | Checksum |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| MTU |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| As much of invoking packet || as possible without exceeding || the minimum IPv6 MTU (1280 bytes) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+PMTUD State Management:
Sources maintain a Path MTU cache—a table mapping destinations to discovered MTU values:
| Destination | Path MTU | Discovery Time | Expiry |
|---|---|---|---|
| 2001:db8::1 | 1280 | 10:00:00 | 10:10:00 |
| 2001:db8::2 | 1400 | 10:05:00 | 10:15:00 |
| 2001:db8::3 | 1500 | (assumed) | N/A |
If ICMPv6 Packet Too Big messages are blocked by firewalls, PMTUD fails silently. The source never learns the true Path MTU, packets are dropped, and connections hang or fail. This "PMTUD black hole" is a common operational problem. RFC 4821 (Packetization Layer Path MTU Discovery) provides an alternative using transport-layer feedback for environments where ICMP is filtered.
The Fragment Header is unique among extension headers: it has a fixed 8-byte size and does not contain a Header Extension Length field (since its length is constant). Its structure is optimized for the specific needs of fragmentation identification and reassembly.
Binary Format:
IPv6 Fragment Header Format (Fixed 8 bytes)═══════════════════════════════════════════════════════════════════════════ 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+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Next Header | Reserved | Fragment Offset |Res|M|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Identification |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Field Definitions:═══════════════════════════════════════════════════════════════════════════ Next Header (8 bits): - Identifies the type of the initial header of the Fragmentable Part - Same values as IPv6 Next Header field - Examples: TCP (6), UDP (17), ICMPv6 (58) - NOTE: This is the type of what's being fragmented, not what follows the Fragment Header in THIS fragment Reserved (8 bits): - First reserved field, initialized to zero - Ignored on reception, must be zero on transmission Fragment Offset (13 bits): - Offset of the data following this header in 8-octet units - Relative to the start of the Fragmentable Part - Valid range: 0 to 8191 (allowing fragments up to 65,528 bytes into packet) Calculation: Actual byte offset = Fragment Offset × 8 Examples: Fragment Offset = 0 → byte offset 0 (first fragment) Fragment Offset = 185 → byte offset 1480 (typical second fragment) Fragment Offset = 370 → byte offset 2960 (typical third fragment) Res (2 bits): - Second reserved field, initialized to zero - Must be ignored on reception, must be zero on transmission M Flag (1 bit): - More Fragments flag - 1 = More fragments follow this one - 0 = This is the last fragment (no more fragments) Identification (32 bits): - Unique identifier for this fragmented packet - Same value in all fragments of the original packet - Combined with Source Address to uniquely identify fragment group - MUST be different for each packet fragmented by the sourceComparison with IPv4 Fragmentation Fields:
| Aspect | IPv4 | IPv6 |
|---|---|---|
| Location | In main IP header (always present) | Separate Fragment Header (only in fragments) |
| Identification size | 16 bits | 32 bits (prevents ID exhaustion) |
| Offset unit | 8 bytes | 8 bytes (same) |
| Offset field size | 13 bits | 13 bits (same) |
| More Fragments flag | In flags field | Dedicated M bit |
| Don't Fragment flag | In flags field (DF) | Not needed (source-only fragmentation is mandatory) |
| Header overhead | 0 bytes (built-in) | 8 bytes (extension header) |
IPv6's 32-bit Identification field (vs IPv4's 16-bit) solves a significant problem: high-speed sources can exhaust a 16-bit ID space in seconds, causing fragments from different packets to be misassembled. With 32 bits, a source sending at 1 Gbps with 1500-byte packets would take over 25 hours to wrap around—effectively eliminating ID collision concerns.
IPv6 fragmentation follows strict rules that ensure fragments can be reliably reassembled and that extension headers are preserved appropriately.
Unfragmentable vs Fragmentable Parts:
Every IPv6 packet, when fragmented, is divided into two conceptual parts:
IPv6 Packet Structure for Fragmentation═══════════════════════════════════════════════════════════════════════════ Original Packet:┌─────────────────────────────────────────────────────────────────────────┐│ UNFRAGMENTABLE PART ││ ┌───────────────┬───────────────┬───────────────┬───────────────┐ ││ │ IPv6 Header │ Hop-by-Hop* │ Destination* │ Routing* │ ││ │ (40 bytes) │ Options │ Options │ Header │ ││ └───────────────┴───────────────┴───────────────┴───────────────┘ ││ * if present │├─────────────────────────────────────────────────────────────────────────┤│ FRAGMENTABLE PART ││ ┌───────────────┬───────────────┬───────────────────────────────┐ ││ │ Destination* │ Upper Layer │ │ ││ │ Options │ Header │ Payload │ ││ │ (if not for │ (TCP/UDP) │ │ ││ │ routing) │ │ │ ││ └───────────────┴───────────────┴───────────────────────────────┘ │└─────────────────────────────────────────────────────────────────────────┘ After Fragmentation:════════════════════════════════════════════════════════════════════════════ Fragment 1 (First Fragment):┌─────────────────────────────────────────────────────────────────────────┐│ Unfragmentable Part │ Fragment │ First chunk of Fragmentable Part ││ (headers) │ Header │ (includes upper-layer header) │└─────────────────────────────────────────────────────────────────────────┘ Fragment 2 (Middle Fragment):┌─────────────────────────────────────────────────────────────────────────┐│ Unfragmentable Part │ Fragment │ Middle chunk of Fragmentable Part ││ (headers) │ Header │ (payload only, no upper-layer header) │└─────────────────────────────────────────────────────────────────────────┘ Fragment N (Last Fragment):┌─────────────────────────────────────────────────────────────────────────┐│ Unfragmentable Part │ Fragment │ Final chunk of Fragmentable Part ││ (headers) │ Header │ (M flag = 0) │└─────────────────────────────────────────────────────────────────────────┘ Key Rules:════════════════════════════════════════════════════════════════════════════1. Unfragmentable Part appears in EVERY fragment (copied identically)2. Fragment Header is inserted between Unfragmentable and Fragmentable3. The original packet's extension headers that affect routing (Hop-by-Hop, Routing, first Destination Options before Routing) are part of the Unfragmentable Part4. The last header in Unfragmentable Part has its Next Header changed to 44 (Fragment Header)5. Fragment Header's Next Header indicates original next header typeFragment Size Constraints:
The IPv6 minimum MTU of 1280 bytes is a crucial guarantee. Sources that cannot perform PMTUD (or choose not to) can always send 1280-byte packets, assured they won't require fragmentation anywhere on the path. This is significantly larger than IPv4's 576-byte minimum reassembly buffer, improving efficiency for applications that avoid PMTUD.
Let's trace through a complete fragmentation example to solidify understanding of the mechanics.
Complete Fragmentation Example═══════════════════════════════════════════════════════════════════════════ Scenario: - Original packet size: 4000 bytes total - Path MTU: 1500 bytes - IPv6 header: 40 bytes - No extension headers in original packet - Upper layer: TCP (20-byte header) + 3940 bytes data - Fragment header adds 8 bytes per fragment Original Packet Structure:────────────────────────────────────────────────────────────────────────────┌────────────────────────────────────────────────────────────────────────┐│ IPv6 Header (40) │ TCP Header (20) │ TCP Data (3940) ││ Next Header: 6 │ │ ││ Payload Len: 3960 │ │ │└────────────────────────────────────────────────────────────────────────┘Total: 40 + 3960 = 4000 bytes Unfragmentable Part: IPv6 Header (40 bytes)Fragmentable Part: TCP Header + TCP Data = 3960 bytes Calculating Fragment Sizes:────────────────────────────────────────────────────────────────────────────Maximum fragment size: 1500 bytes (Path MTU)Per-fragment overhead: 40 (IPv6) + 8 (Fragment Header) = 48 bytesMaximum fragmentable data per fragment: 1500 - 48 = 1452 bytesRounded to 8-byte multiple: 1448 bytes per fragment (except last) Fragments needed: ceil(3960 / 1448) = 3 fragments Fragment 1 (First Fragment):────────────────────────────────────────────────────────────────────────────┌─────────────────────────────────────────────────────────────────────────┐│ IPv6 Header │ Fragment Header │ TCP Hdr │ TCP Data (1428 bytes) ││ (40 bytes) │ (8 bytes) │ (20) │ ││ Next Hdr: 44 │ Next Hdr: 6 │ │ ││ Payload: 1456 │ Offset: 0 │ │ ││ │ M: 1 │ │ ││ │ ID: 0x12345678 │ │ │└─────────────────────────────────────────────────────────────────────────┘Total: 40 + 8 + 20 + 1428 = 1496 bytesFragmentable data: 1448 bytes (TCP header + 1428 data)Fragment Offset: 0 (first fragment)M Flag: 1 (more fragments follow) Fragment 2 (Middle Fragment):────────────────────────────────────────────────────────────────────────────┌─────────────────────────────────────────────────────────────────────────┐│ IPv6 Header │ Fragment Header │ TCP Data (1448 bytes) ││ (40 bytes) │ (8 bytes) │ ││ Next Hdr: 44 │ Next Hdr: 6 │ ││ Payload: 1456 │ Offset: 181 │ (byte offset 1448) ││ │ M: 1 │ ││ │ ID: 0x12345678 │ │└─────────────────────────────────────────────────────────────────────────┘Total: 40 + 8 + 1448 = 1496 bytesFragment Offset: 181 (= 1448 ÷ 8 = 181 × 8 = 1448 bytes)M Flag: 1 (more fragments follow) Fragment 3 (Last Fragment):────────────────────────────────────────────────────────────────────────────┌─────────────────────────────────────────────────────────────────────────┐│ IPv6 Header │ Fragment Header │ TCP Data (1064 bytes) ││ (40 bytes) │ (8 bytes) │ ││ Next Hdr: 44 │ Next Hdr: 6 │ ││ Payload: 1072 │ Offset: 362 │ (byte offset 2896) ││ │ M: 0 │ (remaining data: 3960-2896=1064) ││ │ ID: 0x12345678 │ │└─────────────────────────────────────────────────────────────────────────┘Total: 40 + 8 + 1064 = 1112 bytesFragment Offset: 362 (= 2896 ÷ 8 = 362 × 8 = 2896 bytes)M Flag: 0 (this is the last fragment) Verification:────────────────────────────────────────────────────────────────────────────Fragment 1 data: 1448 bytes (offset 0)Fragment 2 data: 1448 bytes (offset 1448)Fragment 3 data: 1064 bytes (offset 2896)Total: 1448 + 1448 + 1064 = 3960 bytes ✓ (matches original fragmentable part)The Identification field (0x12345678 in the example) must be unique for each fragmented packet from the same source to the same destination. Combined with the source address, it uniquely identifies which fragment group a fragment belongs to—critical when multiple fragmented packets are in flight simultaneously.
Fragment reassembly at the destination is a critical process that must handle out-of-order arrival, missing fragments, and potential attacks. Understanding the reassembly algorithm reveals requirements and vulnerabilities.
Reassembly Algorithm:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
IPv6 Fragment Reassembly Algorithm═══════════════════════════════════════════════════════════════════════════ function receive_fragment(fragment): // Extract identification tuple src_addr = fragment.ipv6_header.source_address dst_addr = fragment.ipv6_header.destination_address identification = fragment.fragment_header.identification key = (src_addr, dst_addr, identification) // Check if reassembly already in progress for this packet if key not in reassembly_buffer: // Start new reassembly reassembly_buffer[key] = { fragments: [], received_bytes: bitmap(65536), // Track which byte ranges received first_fragment_received: false, last_fragment_received: false, total_length: unknown, timeout: current_time + 60 seconds } entry = reassembly_buffer[key] // Calculate byte range for this fragment offset_bytes = fragment.fragment_header.offset * 8 fragment_data = fragment.fragmentable_part end_bytes = offset_bytes + length(fragment_data) // Check for overlap with existing fragments (security check!) if entry.received_bytes.overlaps(offset_bytes, end_bytes): // Fragment overlaps existing data - potential attack // RFC 5722: MUST drop entire reassembly for this identification delete reassembly_buffer[key] return // Store fragment entry.fragments.append((offset_bytes, fragment_data)) entry.received_bytes.mark(offset_bytes, end_bytes) // Track first fragment (offset = 0) if fragment.fragment_header.offset == 0: entry.first_fragment_received = true entry.unfragmentable_part = fragment.unfragmentable_part // Track last fragment (M = 0) if fragment.fragment_header.m_flag == 0: entry.last_fragment_received = true entry.total_length = end_bytes // Check if complete if entry.first_fragment_received and entry.last_fragment_received and entry.received_bytes.complete(0, entry.total_length): // Reassemble packet reassembled = reassemble(entry) delete reassembly_buffer[key] deliver_to_upper_layer(reassembled) function reassembly_timeout_handler(): for key, entry in reassembly_buffer: if current_time > entry.timeout: // Incomplete reassembly - send ICMPv6 Time Exceeded if entry.first_fragment_received: send_icmpv6_time_exceeded( code=1, // Fragment reassembly time exceeded invoking_packet=entry.fragments[0] ) delete reassembly_buffer[key]Critical Reassembly Considerations:
| Aspect | Requirement | Rationale |
|---|---|---|
| Minimum reassembly buffer | 1500 bytes | Must handle minimum MTU packets |
| Recommended buffer | Configurable, typically 16KB-64KB | Balance memory usage vs large packet support |
| Reassembly timeout | 60-120 seconds recommended | Prevent memory exhaustion from incomplete reassemblies |
| Fragment overlap handling | Drop entire reassembly (RFC 5722) | Prevent fragment overlap attacks |
| Maximum fragments | Implementation-specific | Prevent resource exhaustion from many small fragments |
Attackers can target reassembly buffers by sending many first-fragments (starting reassemblies) without completing them. This exhausts memory and may cause legitimate reassemblies to fail. Rate-limiting fragment processing and limiting concurrent reassemblies per source are common mitigations.
Fragment handling has historically been a rich source of security vulnerabilities. IPv6's architecture addresses many IPv4 issues, but introduces its own considerations that operators must understand.
Fragment Overlap Attacks:
Fragment Overlap Attack Scenario═══════════════════════════════════════════════════════════════════════════ Attack Vector:Attacker sends fragments that deliberately overlap, with conflicting datain the overlapping region. Fragment 1: Offset 0, Data "SAFE_HEADER" + partial payloadFragment 2: Offset 0, Data "EVIL_HEADER" + different partial payload If destination uses second fragment's data for overlap: - Firewall may have inspected Fragment 1's "SAFE_HEADER" - Reassembled packet contains "EVIL_HEADER" - Attack payload bypasses security inspection RFC 5722 Mitigation (Mandatory in IPv6):────────────────────────────────────────────────────────────────────────────"If any of the fragments being combined overlap with any other fragments being combined for the same packet, the entire set of fragments MUST be silently discarded." Implementations MUST:- Track byte ranges received per reassembly- Detect any overlap between incoming fragment and existing data- Drop ALL fragments for that Identification if overlap detected- Do NOT try to "resolve" overlaps by preferring one or the otherAtomic Fragments:
An "atomic fragment" is a packet with a Fragment Header but no actual fragmentation (offset=0, M=0). These were sometimes generated by intermediate security devices but created vulnerabilities:
Additional Security Recommendations:
| Practice | Implementation | Benefit |
|---|---|---|
| Rate limit fragments | Maximum fragments per second per source | Prevent reassembly buffer exhaustion |
| Limit concurrent reassemblies | Maximum active reassemblies per source | Prevent memory exhaustion |
| Short timeout | 30-60 seconds vs 120 | Faster cleanup of attack traffic |
| Minimum fragment size | Require reasonable minimum (e.g., 400 bytes) | Prevent tiny fragment attacks |
| First fragment first | Require offset=0 to start reassembly | Prevent blind reassembly cache poisoning |
Due to the complexity and security risks of fragmentation, modern best practice increasingly favors avoiding fragmentation entirely. Application protocols are designed for Path MTU Discovery, and many enterprise networks drop fragments at security boundaries. IPv6's guarantee of 1280-byte MTU support makes fragment-free operation more practical than in IPv4.
We've completed a comprehensive examination of IPv6 fragmentation—from the architectural decision to prohibit router fragmentation through the detailed mechanics of the Fragment Header and reassembly. Let's consolidate the essential knowledge:
What's Next:
The final page in this module examines Header Chaining—how multiple extension headers combine into coherent processing pipelines, the ordering requirements, and how destinations parse extension header chains to reach upper-layer payloads.
You now possess comprehensive understanding of IPv6 fragmentation—from the architectural philosophy that prohibits router fragmentation through the binary structure of the Fragment Header to the security considerations of reassembly. This knowledge is essential for understanding IPv6's efficiency advantages and security posture.