The Network Layer
IPv4, IPv6 and Address Exhaustion
Minus reserved ranges (Chapter 1), the usable
JrCodex·8 min read
Jr Codex Computer Networks Notes
Level: Intermediate Prerequisites: Chapter 1: IP Addressing and Subnetting Time to complete: ~20 minutes
Table of Contents
- Running Out
- The IPv4 Header
- IPv6 Addresses
- What IPv6 Changed
- Coexistence
- Why Adoption Took Decades
- Summary & Next Steps
1. Running Out
The Arithmetic
─────────────────────────────────────────
32 bits = 4,294,967,296 addresses.
Minus reserved ranges (Chapter 1), the usable
total is closer to 3.7 billion.
There are more than 8 billion people, and vastly
more devices — phones, laptops, servers, cameras,
sensors, cars.
The pool was always going to be too small. IANA
allocated its last blocks in 2011; the regional
registries exhausted theirs over the following
years.
─────────────────────────────────────────
Three Things Bought Time
─────────────────────────────────────────
CIDR (Chapter 1)
ended the enormous waste of classful
allocation.
PRIVATE ADDRESSES + NAT (Chapter 5)
an entire company behind one public address.
The biggest single saver, and the source of
most of the internet's architectural awkwardness.
RECLAMATION and a TRADING MARKET
unused blocks bought and sold — IPv4 addresses
now have a real market price.
All three are workarounds. IPv6 is the fix.
─────────────────────────────────────────
2. The IPv4 Header
20 Bytes, Minimum
─────────────────────────────────────────
0 4 8 16 31
┌────┬────┬────────┬─────────────────────────┐
│Ver │IHL │ TOS │ Total Length │
├────┴────┴────────┼─────┬───────────────────┤
│ Identification │Flags│ Fragment Offset │
├─────────┬────────┼─────┴───────────────────┤
│ TTL │Protocol│ Header Checksum │
├─────────┴────────┴─────────────────────────┤
│ Source IP Address │
├────────────────────────────────────────────┤
│ Destination IP Address │
├────────────────────────────────────────────┤
│ Options (optional, variable) │
└────────────────────────────────────────────┘
─────────────────────────────────────────
The Fields That Matter Most
─────────────────────────────────────────
TTL Time To Live. Decremented at EVERY
router; the packet is discarded at
zero, and ICMP Time Exceeded is sent
back.
── prevents infinite routing loops
(Module 2, Chapter 4) and makes
traceroute possible (Chapter 5)
PROTOCOL the demux field (Module 1, Chapter 3)
6=TCP, 17=UDP, 1=ICMP
TOTAL LEN header plus payload, so the receiver
knows where the packet ends
ID/FLAGS/ fragmentation (Module 1, Chapter 3)
OFFSET
CHECKSUM covers the HEADER ONLY, not the
payload. Recomputed at every hop,
because TTL changed.
─────────────────────────────────────────
Why the Checksum Covers Only the Header
─────────────────────────────────────────
The TTL changes at every hop, so the checksum
must be recomputed at every hop.
Checksumming the whole payload at every router
would be prohibitively expensive at line rate.
The payload's integrity is TCP's or UDP's
responsibility, end to end — Module 1, Chapter 1's
end-to-end principle again. IPv6 removed the
header checksum entirely for the same reason.
─────────────────────────────────────────
3. IPv6 Addresses
128 Bits
─────────────────────────────────────────
2001:0db8:85a3:0000:0000:8a2e:0370:7334
Eight groups of four hex digits, colon-separated.
340,282,366,920,938,463,463,374,607,431,768,211,456
addresses.
── roughly 10^28 per person. The number is
absurd deliberately: it makes address
conservation a non-issue forever, which is
what allows the simplifications in Section 4.
─────────────────────────────────────────
Two Shortening Rules
─────────────────────────────────────────
1. DROP LEADING ZEROS in each group
2001:0db8:0000:0000:0000:8a2e:0370:7334
2001:db8:0:0:0:8a2e:370:7334
2. REPLACE ONE run of all-zero groups with ::
2001:db8::8a2e:370:7334
:: may appear ONLY ONCE — otherwise the number of
zero groups it stands for would be ambiguous.
Familiar examples:
::1 loopback (IPv4's 127.0.0.1)
:: unspecified (IPv4's 0.0.0.0)
fe80::/10 link-local — ALWAYS present on
every IPv6 interface
2000::/3 global unicast — the routable
internet
ff00::/8 multicast
─────────────────────────────────────────
import ipaddress
a = ipaddress.ip_address("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
print(a.compressed) # 2001:db8:85a3::8a2e:370:7334
print(a.exploded) # 2001:0db8:85a3:0000:0000:8a2e:0370:7334
net = ipaddress.ip_network("2001:db8:85a3::/64")
print(net.num_addresses) # 18,446,744,073,709,551,616 — one /64 SUBNETThe /64 Convention
─────────────────────────────────────────
Essentially every IPv6 subnet is a /64 — half the
address space, per subnet.
That gives 18 quintillion host addresses on a LAN
with maybe fifty devices, which sounds
extravagant.
It is deliberate: a fixed 64-bit host portion
lets a device generate its own address from its
MAC or at random (Section 4), with no
coordination and no realistic chance of
collision.
Address abundance is being spent to buy
SIMPLICITY.
─────────────────────────────────────────
4. What IPv6 Changed
Beyond More Addresses
─────────────────────────────────────────
SIMPLER HEADER
Fixed 40 bytes, 8 fields, no checksum, no
options in the base header. Faster to process
at line rate.
NO FRAGMENTATION BY ROUTERS
Only the sender may fragment. Routers drop
oversized packets and return ICMPv6 Packet Too
Big — which makes path MTU discovery MANDATORY
(Module 1, Chapter 3).
SLAAC — Stateless Address Autoconfiguration
A host learns the network prefix from a router
advertisement and generates its own address.
No DHCP server required.
BUILT-IN MULTICAST, NO BROADCAST
Broadcast is gone entirely. Its jobs are done
by multicast to specific groups, so devices are
not interrupted by traffic irrelevant to them.
NDP replaces ARP
Neighbor Discovery does ARP's job (Module 2,
Chapter 4) over ICMPv6, with optional
cryptographic authentication — closing the ARP
spoofing hole.
─────────────────────────────────────────
The Header Comparison
─────────────────────────────────────────
IPv4 20-60 bytes, 13 fields, checksum,
variable length
IPv6 40 bytes fixed, 8 fields, NO checksum
IPv6's header is larger in bytes and far simpler
to process — no length calculation, no checksum
recomputation, no options parsing on the fast
path.
That trade favours routers, which is where the
work happens.
─────────────────────────────────────────
5. Coexistence
Three Strategies
─────────────────────────────────────────
DUAL STACK
Run both protocols on every device. Use IPv6
where possible, fall back to IPv4.
+ simple, no translation, everything works
- you still need an IPv4 address, so it does
not solve exhaustion
── the dominant approach
TUNNELLING
Encapsulate IPv6 packets inside IPv4 to cross
IPv4-only networks. 6to4, Teredo, 6in4.
+ connects IPv6 islands
- overhead, MTU problems, complexity
TRANSLATION
NAT64/DNS64 converts between the protocols so
IPv6-only clients can reach IPv4 servers.
+ genuinely IPv6-only clients
- breaks anything embedding literal IPv4
addresses
─────────────────────────────────────────
HAPPY EYEBALLS
─────────────────────────────────────────
A dual-stack client faces a real question: try
IPv6 first and wait for it to time out if the
path is broken?
Happy Eyeballs (RFC 8305) starts the IPv6
connection, waits a short interval (~250ms),
starts the IPv4 connection in parallel, and uses
whichever completes first.
This is why broken IPv6 paths rarely cause
visible problems any more — your browser is
quietly racing both and taking the winner.
─────────────────────────────────────────
6. Why Adoption Took Decades
The Reasons
─────────────────────────────────────────
NOT BACKWARD COMPATIBLE
An IPv4-only host cannot talk to an IPv6-only
host. There is no gradual path where a single
upgrade helps — this is the fundamental
problem.
NAT WORKED TOO WELL
NAT (Chapter 5) removed the urgency. The pain
that would have forced migration was absorbed.
THE CHICKEN AND EGG
Content providers saw no users; ISPs saw no
content. Neither side moved first for years.
COST WITHOUT VISIBLE BENEFIT
Upgrading equipment, retraining staff and
rewriting tooling delivers nothing a user
notices.
─────────────────────────────────────────
Where It Stands
─────────────────────────────────────────
Roughly 40-45% of traffic to major providers is
IPv6, and rising steadily. Mobile networks are
well ahead — many are IPv6-only internally with
NAT64 at the edge.
PRACTICAL ADVICE
- write code that is address-family agnostic:
use getaddrinfo, never assume 4 bytes
- store addresses in a field that fits IPv6
(45 characters, or a native INET type)
- test with IPv6 enabled; do not discover the
assumption in production
- a literal IPv4 address in a config file is a
future bug
─────────────────────────────────────────
import socket
# Address-family agnostic. Works with IPv4 and IPv6, today and later.
def connect(host, port):
for family, socktype, proto, _, addr in socket.getaddrinfo(
host, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
try:
s = socket.socket(family, socktype, proto)
s.settimeout(5)
s.connect(addr)
return s
except OSError:
continue # try the next address family
raise ConnectionError(f"could not reach {host}:{port}")7. Summary & Next Steps
Key Takeaways
- IPv4's 32-bit space was always too small; CIDR, NAT and address trading bought decades of time without fixing the underlying problem.
- The IPv4 header checksum covers only the header because TTL changes at every hop, and payload integrity is the transport layer's end-to-end responsibility.
- IPv6 spends its enormous address abundance on simplicity: a fixed header, no router fragmentation, self-generated addresses, and no broadcast at all.
- IPv6 is not backward compatible, which is the root reason adoption took decades — no single upgrade helps until both ends have moved.
Concept Check
- Why does the IPv4 header checksum deliberately exclude the payload?
- Why is essentially every IPv6 subnet a /64, given that no LAN needs 18 quintillion addresses?
- What problem does Happy Eyeballs solve, and how?
Next Chapter
→ Chapter 3: Routing Fundamentals
Jr Codex — 1-on-1 Personalized Coaching | Back to Module Index | Back to Computer Networks Index