Computer Networks

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

  1. Running Out
  2. The IPv4 Header
  3. IPv6 Addresses
  4. What IPv6 Changed
  5. Coexistence
  6. Why Adoption Took Decades
  7. 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 SUBNET
The /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

  1. Why does the IPv4 header checksum deliberately exclude the payload?
  2. Why is essentially every IPv6 subnet a /64, given that no LAN needs 18 quintillion addresses?
  3. 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