Loading learning content...
When an IP datagram exceeds the Maximum Transmission Unit (MTU) of an outgoing link, the router must fragment it into smaller pieces. But this isn't arbitrary slicing—it's a carefully constrained mathematical operation governed by precise rules. A single byte miscalculation can render an entire datagram undeliverable.
Consider a 4,500-byte datagram encountering a link with a 1,500-byte MTU. How large should each fragment be? Why can't we simply split it into three 1,500-byte pieces? What happens if we fragment incorrectly? These questions have definitive answers rooted in the IPv4 header's Fragment Offset field and the fundamental requirement that fragments must be reassemblable at the destination.
Understanding fragment size calculations is essential for network administrators diagnosing MTU-related issues, security professionals analyzing packet captures, and anyone designing networks that span heterogeneous link technologies.
By the end of this page, you will understand: (1) The fundamental constraints governing fragment sizes, (2) Why fragment data must be a multiple of 8 bytes, (3) How to calculate the maximum fragment data size for any MTU, (4) The relationship between MTU, header size, and payload capacity, and (5) Real-world implications of fragment size decisions.
Before diving into calculations, let's establish the foundational concepts that govern IP fragmentation.
Why Fragmentation Exists:
Different network technologies support different maximum frame sizes. Ethernet typically supports 1,500 bytes of payload (MTU), while some WAN links support only 576 bytes, and jumbo frames can reach 9,000 bytes. When a datagram travels from a high-MTU network to a low-MTU network, it must be fragmented to fit.
The Fragmentation Process:
| Field | Size | Purpose in Fragmentation |
|---|---|---|
| Identification | 16 bits | Groups fragments belonging to same original datagram |
| Flags (DF) | 1 bit | Don't Fragment—if set, datagram cannot be fragmented |
| Flags (MF) | 1 bit | More Fragments—indicates additional fragments follow |
| Fragment Offset | 13 bits | Position of this fragment's data in original datagram |
| Total Length | 16 bits | Size of this fragment (header + data) |
| Header Length (IHL) | 4 bits | Size of IP header in 32-bit words |
IP fragmentation occurs at routers (or the source host), never at switches or Layer 2 devices. The destination host—never an intermediate router—performs reassembly. This asymmetry means fragments may take different paths and arrive out of order.
The most critical rule in fragment size calculation is the 8-byte alignment requirement. This constraint emerges directly from the IPv4 header's Fragment Offset field design.
Why 8 Bytes?
The Fragment Offset field is only 13 bits wide, but it must be able to address byte positions within datagrams up to 65,535 bytes long (the maximum Total Length). With 13 bits, we can represent values from 0 to 8,191. To cover 65,535 byte positions with only 8,192 possible offset values, IPv4 designers made the Fragment Offset represent 8-byte units, not individual bytes.
The Mathematics:
Maximum addressable offset = 8,191 × 8 = 65,528 bytes
Maximum datagram size = 65,528 + maximum fragment size ≈ 65,535 bytes ✓
This design choice has a critical implication: every fragment except the last must contain a data payload that is a multiple of 8 bytes.
All fragments EXCEPT the final fragment must have data payloads that are exact multiples of 8 bytes. Violating this constraint makes it impossible to express the next fragment's offset correctly, leading to reassembly failure.
Visual Example:
Consider fragmenting a 3,000-byte datagram payload:
CORRECT FRAGMENTATION (8-byte aligned):
┌─────────────────────────────────────────────────────────────────┐
│ Fragment 1: Data bytes 0-1471 (1472 bytes = 184 × 8) ✓ │
│ Fragment 2: Data bytes 1472-2943 (1472 bytes = 184 × 8) ✓ │
│ Fragment 3: Data bytes 2944-2999 (56 bytes - last, any size OK) │
└─────────────────────────────────────────────────────────────────┘
Offsets: 0, 184 (×8=1472), 368 (×8=2944)
INCORRECT FRAGMENTATION (not 8-byte aligned):
┌─────────────────────────────────────────────────────────────────┐
│ Fragment 1: Data bytes 0-1499 (1500 bytes = 187.5 × 8) ✗ │
│ Fragment 2: Data bytes 1500-???? (Cannot express offset!) │
└─────────────────────────────────────────────────────────────────┘
Offset for Fragment 2 = 1500/8 = 187.5 (not an integer!)
Given an MTU, how much data can each fragment carry? This fundamental calculation considers both the MTU constraint and the 8-byte alignment requirement.
The Basic Formula:
Maximum Fragment Data = floor((MTU - IP Header Size) / 8) × 8
Step-by-Step Derivation:
Standard Ethernet Example (MTU = 1500 bytes):
1234567891011121314151617181920
# Standard Ethernet MTU calculationMTU = 1500IP_HEADER_SIZE = 20 # Minimum IP header without options # Available space for dataavailable = MTU - IP_HEADER_SIZE # 1500 - 20 = 1480 bytes # Apply 8-byte alignmentmax_fragment_data = (available // 8) * 8 # (1480 // 8) * 8 = 1480 bytes print(f"MTU: {MTU} bytes")print(f"IP Header: {IP_HEADER_SIZE} bytes")print(f"Available for data: {available} bytes")print(f"Max fragment data (8-byte aligned): {max_fragment_data} bytes") # Output:# MTU: 1500 bytes# IP Header: 20 bytes# Available for data: 1480 bytes# Max fragment data (8-byte aligned): 1480 bytesIn this case, 1480 is already a multiple of 8 (1480 ÷ 8 = 185), so no adjustment is needed. Let's examine a case where alignment truncation occurs.
Non-Standard MTU Example (MTU = 1006 bytes):
123456789101112131415161718192021
# Non-standard MTU requiring alignment adjustmentMTU = 1006IP_HEADER_SIZE = 20 # Available space for dataavailable = MTU - IP_HEADER_SIZE # 1006 - 20 = 986 bytes # 986 ÷ 8 = 123.25 (not a whole number!)# We must round DOWN to 123, then multiply by 8max_fragment_data = (available // 8) * 8 # (986 // 8) * 8 = 123 * 8 = 984 bytes print(f"MTU: {MTU} bytes")print(f"Available for data: {available} bytes")print(f"Max fragment data: {max_fragment_data} bytes")print(f"Wasted bytes per fragment: {available - max_fragment_data}") # Output:# MTU: 1006 bytes# Available for data: 986 bytes# Max fragment data: 984 bytes# Wasted bytes per fragment: 2For common MTUs: Ethernet (1500) → 1480 bytes data, PPPoE (1492) → 1472 bytes data, Minimum IP (576) → 552 bytes data. Notice that 1480, 1472, and 552 are all divisible by 8. Network engineers designed these MTUs with fragmentation math in mind.
The standard 20-byte IP header assumption works for most traffic, but IP options complicate fragment size calculations. When options are present, the header grows (up to 60 bytes maximum), reducing available payload space.
Header Size Range:
Impact on Fragmentation:
| Header Size | IHL Value | Max Fragment Data | Data Reduction |
|---|---|---|---|
| 20 bytes | 5 | 1480 bytes | Baseline |
| 24 bytes | 6 | 1472 bytes | -8 bytes |
| 28 bytes | 7 | 1472 bytes | -8 bytes |
| 32 bytes | 8 | 1464 bytes | -16 bytes |
| 40 bytes | 10 | 1456 bytes | -24 bytes |
| 60 bytes | 15 | 1440 bytes | -40 bytes |
Critical Consideration: Option Handling During Fragmentation
Not all IP options are copied to every fragment. RFC 791 defines two categories:
Copied options: Must appear in every fragment
Non-copied options: Appear only in the first fragment
Practical Calculation with Options:
1234567891011121314151617181920212223
def calculate_fragment_data_size(mtu, header_size): """Calculate maximum fragment data size with arbitrary header.""" available = mtu - header_size return (available // 8) * 8 # Scenario: Record Route option adds 39 bytes to header# Header = 20 (base) + 39 (option) + 1 (padding) = 60 bytes# (Headers must be multiple of 4 bytes) MTU = 1500HEADER_WITH_OPTIONS = 60 # Maximum possible max_data = calculate_fragment_data_size(MTU, HEADER_WITH_OPTIONS)# (1500 - 60) // 8 * 8 = 1440 // 8 * 8 = 180 * 8 = 1440 bytes print(f"With 60-byte header: {max_data} bytes per fragment")print(f"Compared to no options: {calculate_fragment_data_size(MTU, 20)} bytes")print(f"Capacity reduction: {calculate_fragment_data_size(MTU, 20) - max_data} bytes") # Output:# With 60-byte header: 1440 bytes per fragment# Compared to no options: 1480 bytes# Capacity reduction: 40 bytesIP options are rarely used in modern networks—most firewalls and routers drop packets with options as a security precaution. However, understanding their impact on fragmentation remains important for comprehending the IPv4 specification and analyzing legacy or specialized systems.
While the maximum fragment data size is determined by MTU constraints, there are strategic considerations for choosing fragment sizes.
Strategy 1: Maximum Fragment Size (Most Common)
Use the largest possible 8-byte-aligned fragment data size for all fragments except the last. This minimizes the total number of fragments, reducing:
Strategy 2: Equal-Sized Fragments
Divide the datagram into approximately equal-sized fragments. This can balance:
However, equal sizing is rarely used in practice because it increases header overhead.
The Last Fragment:
The last fragment carries whatever data remains after filling previous fragments. Its size:
Calculation for Last Fragment:
Last fragment data = Original payload - (Sum of previous fragments' data)
Complete Example:
Original datagram: 4000 bytes data, 20-byte header (4020 bytes total)
MTU: 1500 bytes
Max fragment data: 1480 bytes
Fragment 1: 1480 bytes data, offset 0, MF=1
Fragment 2: 1480 bytes data, offset 185, MF=1
Fragment 3: 1040 bytes data, offset 370, MF=0 (last fragment)
Verification: 1480 + 1480 + 1040 = 4000 bytes ✓
Let's work through several realistic scenarios to build calculation fluency.
Scenario 1: Standard Ethernet
Datagram: 5000 bytes (20-byte header + 4980 bytes data) MTU: 1500 bytes
1234567891011121314151617181920212223242526272829303132333435363738
# Scenario 1: Standard Ethernet fragmentationoriginal_data = 4980mtu = 1500header_size = 20 # Maximum data per fragment (8-byte aligned)max_data = ((mtu - header_size) // 8) * 8print(f"Max data per fragment: {max_data} bytes") # 1480 bytes # Number of full fragmentsfull_fragments = original_data // max_dataprint(f"Full fragments: {full_fragments}") # 3 fragments # Remaining data for last fragmentremaining = original_data % max_dataprint(f"Last fragment data: {remaining} bytes") # 540 bytes # Total fragmentstotal = full_fragments + (1 if remaining > 0 else 0)print(f"Total fragments: {total}") # 4 fragments # Fragment breakdownfor i in range(total): if i < full_fragments: data = max_data mf = 1 else: data = remaining mf = 0 offset = i * max_data offset_field = offset // 8 print(f"Fragment {i+1}: {data} bytes data, offset={offset_field} ({offset} bytes), MF={mf}") # Output:# Fragment 1: 1480 bytes data, offset=0 (0 bytes), MF=1# Fragment 2: 1480 bytes data, offset=185 (1480 bytes), MF=1# Fragment 3: 1480 bytes data, offset=370 (2960 bytes), MF=1# Fragment 4: 540 bytes data, offset=555 (4440 bytes), MF=0Scenario 2: PPPoE Over Ethernet
PPPoE adds 8 bytes of overhead, reducing effective MTU from 1500 to 1492 bytes.
Datagram: 2900 bytes (20-byte header + 2880 bytes data) MTU: 1492 bytes
1234567891011121314151617181920212223242526272829
# Scenario 2: PPPoE fragmentationoriginal_data = 2880mtu = 1492header_size = 20 # Maximum data per fragmentmax_data = ((mtu - header_size) // 8) * 8 # (1472 // 8) * 8 = 1472print(f"Max data per fragment: {max_data} bytes") # Fragment calculationfull_fragments = original_data // max_data # 2880 // 1472 = 1remaining = original_data % max_data # 2880 % 1472 = 1408total = full_fragments + (1 if remaining > 0 else 0) # 2 fragments print(f"\nFragmentation Result:")print(f"Fragment 1: {max_data} bytes, offset=0, MF=1")print(f"Fragment 2: {remaining} bytes, offset={max_data // 8}, MF=0") # Verificationprint(f"\nVerification: {max_data} + {remaining} = {max_data + remaining} bytes ✓") # Output:# Max data per fragment: 1472 bytes# # Fragmentation Result:# Fragment 1: 1472 bytes, offset=0, MF=1# Fragment 2: 1408 bytes, offset=184, MF=0## Verification: 1472 + 1408 = 2880 bytes ✓Ethernet: 1500 (1480 data), PPPoE: 1492 (1472 data), GRE Tunnel: 1476 (1456 data), IPsec Tunnel: 1400-1438 (varies), IPv6-in-IPv4: 1480 (1460 data), Minimum IP MTU: 576 (552 data). Always verify actual path MTU using Path MTU Discovery.
Fragment size choices directly impact network performance, reliability, and security. Understanding these implications helps diagnose issues and design robust networks.
| MTU | Fragment Data | Fragments | Header Overhead | Overhead % |
|---|---|---|---|---|
| 1500 | 1480 | 7 | 140 bytes | 1.4% |
| 1000 | 976 | 11 | 220 bytes | 2.2% |
| 576 | 552 | 19 | 380 bytes | 3.8% |
| 296 | 272 | 37 | 740 bytes | 7.4% |
Path MTU Discovery (PMTUD):
Modern systems prefer avoiding fragmentation entirely using Path MTU Discovery:
This discovers the minimum MTU along the entire path, allowing sources to pre-fragment (or size datagrams appropriately) before transmission.
Why PMTUD Matters for Fragment Calculations:
While PMTUD exists, it's not always reliable—some firewalls block ICMP, causing "black holes" where oversized packets silently disappear. Understanding fragmentation calculations remains essential because:
We've established the mathematical foundation for IP fragment size calculations. Before moving to offset calculations, let's consolidate the key formulas and concepts.
12345678910111213141516171819202122
# Complete Fragment Size Calculation Reference def max_fragment_data(mtu, header_size=20): """Calculate maximum 8-byte aligned fragment data size.""" available = mtu - header_size return (available // 8) * 8 def fragment_count(original_data, max_data): """Calculate total number of fragments needed.""" full = original_data // max_data remaining = original_data % max_data return full + (1 if remaining > 0 else 0) def last_fragment_size(original_data, max_data): """Calculate size of the last fragment.""" remaining = original_data % max_data return remaining if remaining > 0 else max_data # Quick reference for common MTUsprint("Common MTU Fragment Data Sizes:")for mtu, name in [(1500, "Ethernet"), (1492, "PPPoE"), (1472, "GRE"), (576, "Minimum")]: print(f" {name} ({mtu}): {max_fragment_data(mtu)} bytes")What's Next:
With fragment size mastered, the next page covers offset calculations—how to compute the Fragment Offset field value for each fragment and verify correct positioning during reassembly. This is the complementary skill that, combined with size calculations, enables complete fragmentation analysis.
You now understand the mathematics governing fragment sizes—the 8-byte alignment constraint, MTU-based calculations, options impact, and performance implications. Next, we'll learn how fragments are positioned using offset calculations.