Topic Overview

IP Addressing (IPv4/IPv6)

Master IP addressing: IPv4 (32-bit) and IPv6 (128-bit) addresses, address classes, CIDR notation, and subnetting.

IP addressing is fundamental to networking. Every device on a network needs a unique IP address to communicate. IPv4 uses 32-bit addresses (4.3 billion addresses), while IPv6 uses 128-bit addresses (340 undecillion addresses) to solve IPv4 exhaustion.


IPv4 Addressing

Structure

IPv4 addresses are 32-bit numbers, typically written as four decimal numbers (0-255) separated by dots:

192.168.1.100

Binary representation:

192.168.1.100 = 11000000.10101000.00000001.01100100

Address Classes (Historical)

Originally, IPv4 addresses were divided into classes:

ClassRangeDefault Subnet MaskUse Case
A1.0.0.0 - 126.255.255.255255.0.0.0 (/8)Large networks
B128.0.0.0 - 191.255.255.255255.255.0.0 (/16)Medium networks
C192.0.0.0 - 223.255.255.255255.255.255.0 (/24)Small networks
D224.0.0.0 - 239.255.255.255N/AMulticast
E240.0.0.0 - 255.255.255.255N/AReserved

Note: Classful addressing is obsolete. Modern networks use CIDR (Classless Inter-Domain Routing).

CIDR Notation

CIDR (Classless Inter-Domain Routing) uses a slash notation to specify the network prefix:

192.168.1.0/24
  • 192.168.1.0: Network address
  • /24: Subnet mask (24 bits for network, 8 bits for hosts)
  • Subnet mask: 255.255.255.0 (in dotted decimal)

Special IPv4 Addresses

  • 0.0.0.0/0: Default route (all networks)
  • 127.0.0.1: Loopback (localhost)
  • 169.254.0.0/16: Link-local (APIPA, auto-assigned when DHCP fails)
  • 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16: Private addresses (RFC 1918)
  • 255.255.255.255: Broadcast address

IPv6 Addressing

Structure

IPv6 addresses are 128-bit numbers, written as eight groups of four hexadecimal digits:

2001:0db8:85a3:0000:0000:8a2e:0370:7334

Shortened form:

2001:db8:85a3::8a2e:370:7334  (:: replaces consecutive zeros)

IPv6 Address Types

  1. Unicast: Single interface address

    • Global Unicast: Public routable addresses (2000::/3)
    • Link-Local: FE80::/10 (similar to 169.254.x.x in IPv4)
    • Unique Local: FC00::/7 (similar to private addresses)
  2. Multicast: Multiple interfaces (FF00::/8)

  3. Anycast: Nearest interface with the address

IPv6 Benefits

  • Larger address space: 2^128 addresses vs 2^32
  • Simplified header: Fixed 40-byte header (vs variable IPv4)
  • Built-in security: IPSec support
  • Better multicast: Native multicast support
  • Stateless autoconfiguration: Devices can configure themselves

Subnetting

Subnetting divides a network into smaller subnetworks.

Calculating Subnets

Example: 192.168.1.0/24 → /26 (4 subnets)

Original: 192.168.1.0/24
  Network: 192.168.1.0
  Mask:    255.255.255.0
  Hosts:   256 (254 usable)

Subnet 1: 192.168.1.0/26
  Network: 192.168.1.0
  Broadcast: 192.168.1.63
  Hosts: 64 (62 usable)
  Range: 192.168.1.1 - 192.168.1.62

Subnet 2: 192.168.1.64/26
  Network: 192.168.1.64
  Broadcast: 192.168.1.127
  Hosts: 64 (62 usable)
  Range: 192.168.1.65 - 192.168.1.126

Subnet 3: 192.168.1.128/26
  Network: 192.168.1.128
  Broadcast: 192.168.1.191
  Hosts: 64 (62 usable)
  Range: 192.168.1.129 - 192.168.1.190

Subnet 4: 192.168.1.192/26
  Network: 192.168.1.192
  Broadcast: 192.168.1.255
  Hosts: 64 (62 usable)
  Range: 192.168.1.193 - 192.168.1.254

Subnet Calculation Formula

Number of subnets = 2^(subnet_bits - network_bits)
Hosts per subnet = 2^(32 - subnet_bits) - 2
  (-2 for network and broadcast addresses)

Examples

IPv4 Subnetting Example

def calculate_subnet(ip, cidr, new_cidr):
    """
    Calculate subnet details for 192.168.1.0/24 → /26
    """
    import ipaddress
    
    network = ipaddress.IPv4Network(f"{ip}/{cidr}", strict=False)
    subnets = list(network.subnets(new_prefix=new_cidr))
    
    for i, subnet in enumerate(subnets, 1):
        print(f"Subnet {i}:")
        print(f"  Network: {subnet.network_address}")
        print(f"  Broadcast: {subnet.broadcast_address}")
        print(f"  Hosts: {subnet.num_addresses} ({subnet.num_addresses - 2} usable)")
        print(f"  Range: {subnet.network_address + 1} - {subnet.broadcast_address - 1}")
        print()

# Usage
calculate_subnet("192.168.1.0", 24, 26)

Output:

Subnet 1:
  Network: 192.168.1.0
  Broadcast: 192.168.1.63
  Hosts: 64 (62 usable)
  Range: 192.168.1.1 - 192.168.1.62

Subnet 2:
  Network: 192.168.1.64
  Broadcast: 192.168.1.127
  Hosts: 64 (62 usable)
  Range: 192.168.1.65 - 192.168.1.126
...

IPv6 Address Configuration

import ipaddress

# IPv6 address parsing
addr = ipaddress.IPv6Address("2001:db8::1")
print(f"Compressed: {addr.compressed}")
print(f"Exploded: {addr.exploded}")

# IPv6 network
network = ipaddress.IPv6Network("2001:db8::/64")
print(f"Network: {network.network_address}")
print(f"Hosts: {network.num_addresses}")

# Subnetting IPv6
subnets = list(network.subnets(new_prefix=66))
print(f"Number of /66 subnets: {len(subnets)}")

Network Address Calculation

def get_network_info(ip_with_cidr):
    """Get network, broadcast, and host range"""
    import ipaddress
    
    network = ipaddress.IPv4Network(ip_with_cidr, strict=False)
    
    return {
        "network": str(network.network_address),
        "broadcast": str(network.broadcast_address),
        "netmask": str(network.netmask),
        "hosts": network.num_addresses - 2,
        "first_host": str(network.network_address + 1),
        "last_host": str(network.broadcast_address - 1)
    }

# Example
info = get_network_info("192.168.1.100/24")
print(info)
# {
#   "network": "192.168.1.0",
#   "broadcast": "192.168.1.255",
#   "netmask": "255.255.255.0",
#   "hosts": 254,
#   "first_host": "192.168.1.1",
#   "last_host": "192.168.1.254"
# }

Common Pitfalls

  • Confusing network vs host address: Network address has all host bits as 0, broadcast has all host bits as 1. Fix: Always calculate network and broadcast addresses
  • Forgetting to subtract 2: Network and broadcast addresses aren't usable hosts. Fix: Usable hosts = 2^n - 2
  • Mixing up CIDR notation: /24 means 24 network bits, not 24 host bits. Fix: Remember CIDR = network prefix length
  • IPv4 exhaustion: Running out of IPv4 addresses. Fix: Use NAT, IPv6, or proper subnetting
  • Private vs public addresses: Using private addresses on public internet. Fix: Understand RFC 1918 private ranges
  • Subnet mask calculation errors: Incorrect binary math. Fix: Use subnet calculators or libraries
  • IPv6 adoption: Not understanding IPv6 format and benefits. Fix: Learn hexadecimal and IPv6 address types

Interview Questions

Beginner

Q: What is the difference between IPv4 and IPv6? Explain the address format and size.

A:

IPv4:

  • Size: 32 bits (4 bytes)
  • Format: Dotted decimal (192.168.1.1)
  • Address space: 2^32 = 4.3 billion addresses
  • Header: Variable length (20-60 bytes)
  • Example: 192.168.1.100

IPv6:

  • Size: 128 bits (16 bytes)
  • Format: Hexadecimal groups (2001:db8::1)
  • Address space: 2^128 = 340 undecillion addresses
  • Header: Fixed 40 bytes
  • Example: 2001:0db8:85a3:0000:0000:8a2e:0370:7334 or 2001:db8:85a3::8a2e:370:7334

Key Differences:

  1. Address space: IPv6 has vastly more addresses
  2. Format: IPv4 uses decimal, IPv6 uses hexadecimal
  3. Header: IPv6 has simplified, fixed-length header
  4. Security: IPv6 has built-in IPSec support
  5. Configuration: IPv6 supports stateless autoconfiguration

Intermediate

Q: Given the network 192.168.1.0/24, how would you subnet it to create 8 subnets? What are the network addresses, broadcast addresses, and usable host ranges?

A:

Original Network: 192.168.1.0/24

  • Network bits: 24
  • Host bits: 8
  • Total addresses: 256
  • Usable hosts: 254

To create 8 subnets:

  • Need 3 additional bits (2^3 = 8 subnets)
  • New prefix: /27 (24 + 3)
  • Hosts per subnet: 2^(32-27) - 2 = 32 - 2 = 30 usable hosts

Subnet Breakdown:

SubnetNetworkBroadcastUsable Range
1192.168.1.0/27192.168.1.31192.168.1.1 - 192.168.1.30
2192.168.1.32/27192.168.1.63192.168.1.33 - 192.168.1.62
3192.168.1.64/27192.168.1.95192.168.1.65 - 192.168.1.94
4192.168.1.96/27192.168.1.127192.168.1.97 - 192.168.1.126
5192.168.1.128/27192.168.1.159192.168.1.129 - 192.168.1.158
6192.168.1.160/27192.168.1.191192.168.1.161 - 192.168.1.190
7192.168.1.192/27192.168.1.223192.168.1.193 - 192.168.1.222
8192.168.1.224/27192.168.1.255192.168.1.225 - 192.168.1.254

Calculation:

  • Subnet size = 256 / 8 = 32 addresses per subnet
  • First subnet: 192.168.1.0 - 192.168.1.31
  • Each subsequent subnet starts at +32

Senior

Q: Design an IP address allocation system for a cloud provider that needs to allocate subnets to customers efficiently. How do you handle IPv4 exhaustion, subnet allocation, and address tracking?

A:

class IPAllocationSystem {
  private ipv4Pool: IPv4Pool;
  private ipv6Pool: IPv6Pool;
  private allocations: Map<string, Allocation>;
  
  constructor() {
    // Reserve management networks
    this.ipv4Pool = new IPv4Pool("10.0.0.0/8");
    this.ipv6Pool = new IPv6Pool("2001:db8::/32");
    
    // Pre-allocate management subnets
    this.reserveManagementNetworks();
  }
  
  // 1. Efficient Subnet Allocation
  async allocateSubnet(customerId: string, size: number, version: 'v4' | 'v6'): Promise<Allocation> {
    const pool = version === 'v4' ? this.ipv4Pool : this.ipv6Pool;
    
    // Find smallest available subnet that fits
    const subnet = await pool.findSmallestFit(size);
    
    if (!subnet) {
      // IPv4 exhaustion: use NAT or IPv6
      if (version === 'v4') {
        return this.allocateWithNAT(customerId, size);
      }
      throw new Error("Address pool exhausted");
    }
    
    // Allocate and track
    const allocation = {
      customerId,
      subnet,
      version,
      allocatedAt: Date.now(),
      status: 'active'
    };
    
    this.allocations.set(customerId, allocation);
    pool.markAllocated(subnet);
    
    return allocation;
  }
  
  // 2. IPv4 Exhaustion Handling
  async allocateWithNAT(customerId: string, size: number): Promise<Allocation> {
    // Option 1: Use private IPs with NAT
    const privateSubnet = await this.ipv4Pool.allocatePrivate(size);
    
    // Option 2: Allocate IPv6 instead
    const ipv6Subnet = await this.ipv6Pool.allocate(size);
    
    return {
      customerId,
      ipv4: privateSubnet, // Private IPs
      ipv6: ipv6Subnet,    // Public IPv6
      nat: true,
      version: 'dual-stack'
    };
  }
  
  // 3. Subnet Reclamation
  async deallocateSubnet(customerId: string): Promise<void> {
    const allocation = this.allocations.get(customerId);
    if (!allocation) return;
    
    // Mark as available after grace period
    const pool = allocation.version === 'v4' ? this.ipv4Pool : this.ipv6Pool;
    pool.markAvailable(allocation.subnet, { gracePeriod: 24 * 60 * 60 * 1000 }); // 24 hours
    
    this.allocations.delete(customerId);
  }
  
  // 4. Address Tracking
  class IPv4Pool {
    private available: Set<string>;
    private allocated: Map<string, AllocationInfo>;
    
    async findSmallestFit(size: number): Promise<Subnet | null> {
      // Use binary tree or trie for efficient search
      // Find smallest subnet that can accommodate 'size' hosts
      const requiredCIDR = this.calculateCIDR(size);
      
      // Search available subnets
      for (const subnet of this.available) {
        if (this.canFit(subnet, requiredCIDR)) {
          return this.splitSubnet(subnet, requiredCIDR);
        }
      }
      
      return null;
    }
    
    calculateCIDR(hosts: number): number {
      // Calculate CIDR needed for 'hosts' addresses
      // Add 2 for network and broadcast
      const bits = Math.ceil(Math.log2(hosts + 2));
      return 32 - bits;
    }
  }
  
  // 5. IPv6 Migration Strategy
  async migrateToIPv6(customerId: string): Promise<Allocation> {
    const existing = this.allocations.get(customerId);
    
    // Allocate IPv6 while keeping IPv4
    const ipv6Subnet = await this.ipv6Pool.allocate(existing.size);
    
    return {
      ...existing,
      ipv6: ipv6Subnet,
      version: 'dual-stack',
      migration: 'in-progress'
    };
  }
}

Features:

  1. Efficient allocation: Use data structures (trie, binary tree) for fast subnet search
  2. IPv4 exhaustion: NAT with private IPs, IPv6 allocation, dual-stack
  3. Subnet reclamation: Grace period before reusing addresses
  4. Address tracking: Database of all allocations with metadata
  5. CIDR calculation: Automatic CIDR calculation based on host requirements
  6. Monitoring: Track pool utilization, allocation rates, exhaustion predictions

Key Takeaways

  • IPv4: 32-bit addresses (4.3 billion), dotted decimal format, CIDR notation for subnetting
  • IPv6: 128-bit addresses (340 undecillion), hexadecimal format, built-in security and autoconfiguration
  • CIDR notation: /n specifies network prefix length (e.g., /24 = 24 network bits)
  • Subnetting: Divide networks into smaller subnets using additional network bits
  • Network vs broadcast: Network address (all host bits 0), broadcast (all host bits 1) are not usable
  • Usable hosts: 2^n - 2 (subtract network and broadcast addresses)
  • Private addresses: RFC 1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) for internal use
  • IPv4 exhaustion: Use NAT, IPv6, or efficient subnet allocation to manage limited addresses
  • Subnet calculation: Number of subnets = 2^(subnet_bits - network_bits), hosts = 2^(32 - subnet_bits) - 2

About the author

InterviewCrafted helps you master system design with patience. We believe in curiosity-led engineering, reflective writing, and designing systems that make future changes feel calm.