Subnetting & CIDR Basics
Subnetting & CIDR Basics
LinkedIn Hook
The question that separates developers who understand networking from those who just use it:
What does
/24mean at the end of an IP address?If your answer is "I've seen it in configs but I'm not sure" — this is the lesson for you.
CIDR notation (the
/24,/16,/8after an IP address) is everywhere:
- Your AWS VPC is
10.0.0.0/16- Your Docker network is
172.17.0.0/16- Your Kubernetes pod CIDR is
10.244.0.0/16- Your firewall rule is "allow
192.168.1.0/24"Once you understand what
/24means, all of these stop being magic strings and start making sense:
- The number after
/is the prefix length — the number of bits used for the network address/24means 24 bits network, 8 bits host — 254 usable addresses/16means 16 bits network, 16 bits host — 65,534 usable addresses- Subnetting lets you divide a large network into smaller isolated segments
This lesson shows you how to calculate subnets by hand, understand CIDR notation, and apply it to real cloud deployments.
Full lesson → [link]
#Networking #CIDR #Subnetting #CloudEngineering #BackendEngineering #InterviewPrep
What You'll Learn
- What subnetting is and why it matters — not just for network engineers but for developers
- How CIDR notation (the
/24suffix) encodes the subnet mask - How to calculate the number of hosts, network address, and broadcast address for any CIDR block
- Why cloud deployments (AWS VPC, Kubernetes, Docker) use subnetting heavily
- Practical subnet planning for a real-world three-tier application
The Analogy That Makes This Click
Think of your IP address block as a large office building your company just leased — say, an entire floor with 1,000 rooms numbered 1 to 1,000.
You do not want all 1,000 rooms connected to each other freely. Sales should not be able to walk into the server room. The reception area should not have access to executive offices. So you build internal walls and lock the connecting doors between sections.
Subnetting is building those internal walls. You divide one large address block into smaller segments — subnets. Each subnet is a contained neighborhood with its own range of addresses. Traffic between subnets must pass through a router (the building's security desk), where you can apply rules about what is allowed.
CIDR notation (/24, /16) is just the blueprint that says exactly where the walls go — how many rooms belong to each section.
What Is Subnetting?
Subnetting is the process of dividing a large IP network into smaller sub-networks (subnets). You take a block of IP addresses and split it into multiple smaller blocks — each one becomes its own independent network.
Why subnet?
-
Security isolation: Put your web servers, application servers, and databases in different subnets. Firewall rules between subnets control what can talk to what. A compromised web server cannot reach the database directly.
-
Performance: Broadcast traffic (DHCP, ARP) is contained within a subnet. A network with 65,000 devices all on one flat subnet would drown in broadcast noise. Smaller subnets mean smaller broadcast domains.
-
Organized IP management: Assign predictable ranges to different environments (dev, staging, prod) or teams (engineering, finance, HR).
-
Cloud resource control: AWS security groups and network ACLs operate at the subnet level. Kubernetes pod networking assigns CIDRs per node.
CIDR Notation — The Slash Number
CIDR stands for Classless Inter-Domain Routing. Introduced in 1993, it replaced the rigid class system (Class A/B/C) with flexible prefix lengths.
A CIDR block is written as:
<network address>/<prefix length>
The prefix length (the number after the slash) tells you how many bits of the 32-bit address are the network portion. The remaining bits are the host portion.
The Math
IPv4 address = 32 bits total
Network bits = prefix length (e.g., 24)
Host bits = 32 − prefix length (e.g., 32 − 24 = 8)
Total addresses = 2^(host bits)
Usable addresses = 2^(host bits) − 2
The −2 subtracts:
- The network address (all host bits = 0) — identifies the subnet itself
- The broadcast address (all host bits = 1) — used to address all hosts in the subnet simultaneously
CIDR Reference Table
| CIDR | Subnet Mask | Network Bits | Host Bits | Total Addresses | Usable Hosts |
|---|---|---|---|---|---|
| /8 | 255.0.0.0 | 8 | 24 | 16,777,216 | 16,777,214 |
| /16 | 255.255.0.0 | 16 | 16 | 65,536 | 65,534 |
| /24 | 255.255.255.0 | 24 | 8 | 256 | 254 |
| /25 | 255.255.255.128 | 25 | 7 | 128 | 126 |
| /26 | 255.255.255.192 | 26 | 6 | 64 | 62 |
| /27 | 255.255.255.224 | 27 | 5 | 32 | 30 |
| /28 | 255.255.255.240 | 28 | 4 | 16 | 14 |
| /29 | 255.255.255.248 | 29 | 3 | 8 | 6 |
| /30 | 255.255.255.252 | 30 | 2 | 4 | 2 |
| /31 | 255.255.255.254 | 31 | 1 | 2 | 0* |
| /32 | 255.255.255.255 | 32 | 0 | 1 | 1** |
*/31 is a special case for point-to-point links (RFC 3021) — no broadcast needed, both addresses usable.
**/32 addresses exactly one host — used in firewall rules, static routes, and load balancer health checks.
How to Calculate a Subnet — Step by Step
Given: 192.168.10.50/26
Step 1: Find the subnet mask
/26 means 26 network bits. The subnet mask in binary:
11111111.11111111.11111111.11000000 → 255.255.255.192
Step 2: Find the block size
Host bits = 32 − 26 = 6. Block size = 2⁶ = 64 addresses.
The subnet boundaries occur at multiples of 64 in the last octet: 0, 64, 128, 192.
Step 3: Find the network address
50 falls in the range 0–63 (the first /26 block). Network address: 192.168.10.0
IP: 192.168.10.50 → 11000000.10101000.00001010.00110010
Subnet mask: 255.255.255.192 → 11111111.11111111.11111111.11000000
─────────────────────────────────────
Network: 192.168.10.0 → 11000000.10101000.00001010.00000000
Step 4: Find the broadcast address
All host bits set to 1: 192.168.10.63
Step 5: Usable host range
192.168.10.1 to 192.168.10.62 — 62 usable hosts.
Summary for 192.168.10.50/26:
Network: 192.168.10.0
Broadcast: 192.168.10.63
First host: 192.168.10.1
Last host: 192.168.10.62
Usable: 62 hosts
Subnetting a Network — Dividing /16 into /24s
A common task: you are given a 10.0.0.0/16 block. How many /24 subnets can you create?
/16 has 16 bits for the host portion.
/24 uses 24 bits for the network — 8 bits for hosts.
Subnets = 2^(new network bits gained) = 2^(24 − 16) = 2^8 = 256 subnets
Each /24 subnet has 254 usable hosts.
The 256 /24 subnets within 10.0.0.0/16:
10.0.0.0/24 → hosts 10.0.0.1 – 10.0.0.254
10.0.1.0/24 → hosts 10.0.1.1 – 10.0.1.254
10.0.2.0/24 → hosts 10.0.2.1 – 10.0.2.254
...
10.0.255.0/24 → hosts 10.0.255.1 – 10.0.255.254
This is exactly how AWS VPC subnetting works: you get a VPC CIDR (e.g., 10.0.0.0/16) and create smaller subnets from it for different availability zones and tiers.
Subnetting in Cloud Deployments
AWS VPC Example
A typical three-tier web application in AWS:
VPC: 10.0.0.0/16 (65,534 usable addresses)
│
├── Public subnets (load balancers, NAT gateways)
│ ├── 10.0.0.0/24 — us-east-1a (254 hosts)
│ ├── 10.0.1.0/24 — us-east-1b (254 hosts)
│ └── 10.0.2.0/24 — us-east-1c (254 hosts)
│
├── Private subnets (application servers)
│ ├── 10.0.10.0/24 — us-east-1a (254 hosts)
│ ├── 10.0.11.0/24 — us-east-1b (254 hosts)
│ └── 10.0.12.0/24 — us-east-1c (254 hosts)
│
└── Database subnets (RDS, ElastiCache)
├── 10.0.20.0/24 — us-east-1a (254 hosts)
├── 10.0.21.0/24 — us-east-1b (254 hosts)
└── 10.0.22.0/24 — us-east-1c (254 hosts)
Security groups and network ACLs enforce that the public subnets can only reach the application subnets on specific ports, and application subnets can only reach database subnets on the database port.
Docker Networking
Docker creates a default bridge network at 172.17.0.0/16. Each container gets an IP from this range. When you create custom Docker networks, you specify the CIDR:
docker network create --subnet=10.10.0.0/24 my-app-network
Kubernetes Pod CIDR
Kubernetes assigns each node a slice of the pod CIDR. A cluster with 10.244.0.0/16 pod CIDR might give:
Node 1: 10.244.0.0/24 → pods on this node get .1 through .254
Node 2: 10.244.1.0/24
Node 3: 10.244.2.0/24
Code Example 1 — CIDR Calculator
// CIDR subnet calculator — given an IP and prefix, compute all subnet details
function cidrToSubnetMask(prefix) {
if (prefix < 0 || prefix > 32) throw new Error("Prefix must be 0–32");
const mask = prefix === 0
? 0
: (~0 << (32 - prefix)) >>> 0;
return [
(mask >>> 24) & 0xff,
(mask >>> 16) & 0xff,
(mask >>> 8) & 0xff,
mask & 0xff,
];
}
function ipToUint32(ip) {
const o = ip.split(".").map(Number);
return ((o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3]) >>> 0;
}
function uint32ToIp(n) {
return [
(n >>> 24) & 0xff,
(n >>> 16) & 0xff,
(n >>> 8) & 0xff,
n & 0xff,
].join(".");
}
function calculateSubnet(cidr) {
const [ipStr, prefixStr] = cidr.split("/");
const prefix = parseInt(prefixStr, 10);
const hostBits = 32 - prefix;
const ipInt = ipToUint32(ipStr);
const maskInt = ipToUint32(cidrToSubnetMask(prefix).join("."));
const networkInt = (ipInt & maskInt) >>> 0;
const broadcastInt = (networkInt | (~maskInt >>> 0)) >>> 0;
const firstHostInt = networkInt + 1;
const lastHostInt = broadcastInt - 1;
const totalAddresses = Math.pow(2, hostBits);
const usableHosts = Math.max(0, totalAddresses - 2);
return {
cidr,
ip: ipStr,
prefix,
subnetMask: cidrToSubnetMask(prefix).join("."),
network: uint32ToIp(networkInt),
broadcast: uint32ToIp(broadcastInt),
firstHost: usableHosts > 0 ? uint32ToIp(firstHostInt) : "N/A",
lastHost: usableHosts > 0 ? uint32ToIp(lastHostInt) : "N/A",
totalAddresses,
usableHosts,
};
}
function containsIP(cidr, testIP) {
const { network, prefix } = calculateSubnet(cidr);
const networkInt = ipToUint32(network);
const testInt = ipToUint32(testIP);
const maskInt = ipToUint32(cidrToSubnetMask(prefix).join("."));
return (testInt & maskInt) >>> 0 === networkInt;
}
// === Demo ===
const cidrs = [
"192.168.10.50/26",
"10.0.0.0/16",
"172.16.5.200/12",
"10.0.1.0/24",
"10.0.0.100/30",
];
for (const cidr of cidrs) {
const s = calculateSubnet(cidr);
console.log(`\n=== ${s.cidr} ===`);
console.log(` Subnet Mask: ${s.subnetMask}`);
console.log(` Network: ${s.network}`);
console.log(` Broadcast: ${s.broadcast}`);
console.log(` Host range: ${s.firstHost} – ${s.lastHost}`);
console.log(` Usable hosts: ${s.usableHosts.toLocaleString()}`);
}
// IP membership check
console.log("\n--- Membership checks ---");
console.log("10.0.1.5 in 10.0.0.0/16 ?", containsIP("10.0.0.0/16", "10.0.1.5")); // true
console.log("10.1.0.5 in 10.0.0.0/16 ?", containsIP("10.0.0.0/16", "10.1.0.5")); // false
console.log("192.168.1.100 in 192.168.1.0/24?", containsIP("192.168.1.0/24", "192.168.1.100")); // true
What this shows:
- CIDR prefix → subnet mask conversion is pure bit manipulation
- Network address = IP AND mask
- Broadcast address = network OR (inverted mask)
- Checking if an IP belongs to a CIDR: (IP AND mask) === network address
Code Example 2 — VPC Subnet Planner
This example simulates planning the subnets for a three-tier AWS VPC deployment.
// Simple VPC subnet planner
// Divides a parent CIDR into subnets of specified sizes
function getSubnets(parentCidr, subnetsConfig) {
const [baseIP, parentPrefix] = parentCidr.split("/");
let currentInt = ipToUint32(baseIP); // reuse ipToUint32 from previous example
// (inline for standalone use)
function ipToUint32(ip) {
const o = ip.split(".").map(Number);
return ((o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3]) >>> 0;
}
function uint32ToIp(n) {
return [(n>>>24)&0xff,(n>>>16)&0xff,(n>>>8)&0xff,n&0xff].join(".");
}
currentInt = ipToUint32(baseIP);
const results = [];
for (const { name, prefix } of subnetsConfig) {
const blockSize = Math.pow(2, 32 - prefix);
// Align to block size boundary
currentInt = Math.ceil(currentInt / blockSize) * blockSize >>> 0;
const networkInt = currentInt >>> 0;
const broadcastInt = (networkInt + blockSize - 1) >>> 0;
const usable = blockSize - 2;
results.push({
name,
cidr: `${uint32ToIp(networkInt)}/${prefix}`,
firstHost: uint32ToIp(networkInt + 1),
lastHost: uint32ToIp(broadcastInt - 1),
usable,
});
currentInt = (broadcastInt + 1) >>> 0;
}
return results;
}
// VPC: 10.0.0.0/16
// Three AZs × three tiers = 9 subnets
const vpcSubnets = getSubnets("10.0.0.0/16", [
// Public subnets (one per AZ)
{ name: "public-us-east-1a", prefix: 24 },
{ name: "public-us-east-1b", prefix: 24 },
{ name: "public-us-east-1c", prefix: 24 },
// Private app subnets
{ name: "private-app-1a", prefix: 24 },
{ name: "private-app-1b", prefix: 24 },
{ name: "private-app-1c", prefix: 24 },
// Private database subnets
{ name: "private-db-1a", prefix: 24 },
{ name: "private-db-1b", prefix: 24 },
{ name: "private-db-1c", prefix: 24 },
]);
console.log("VPC Subnet Plan — 10.0.0.0/16\n");
console.log(`${"Name".padEnd(25)} ${"CIDR".padEnd(18)} ${"First Host".padEnd(16)} ${"Last Host".padEnd(16)} Hosts`);
console.log("─".repeat(90));
for (const s of vpcSubnets) {
console.log(
`${s.name.padEnd(25)} ${s.cidr.padEnd(18)} ${s.firstHost.padEnd(16)} ${s.lastHost.padEnd(16)} ${s.usable}`
);
}
What this shows:
- Real VPC subnet planning starts with a parent CIDR and carves it into smaller blocks
- Subnet boundaries must align to their block size (a /24 always starts at a multiple of 256)
- Nine
/24subnets use 9 × 256 = 2,304 addresses from a /16's 65,536 — leaving room for future subnets
Common Mistakes
Mistake 1 — Counting total addresses instead of usable hosts
A /24 has 256 total addresses, but only 254 are usable for hosts. The first address (x.x.x.0) is the network address and the last (x.x.x.255) is the broadcast address — neither can be assigned to a device. Interviewers specifically ask "how many usable hosts" — always subtract 2. The exception: /31 (RFC 3021, point-to-point) and /32 (single host) have their own rules.
Mistake 2 — Thinking subnets can overlap
Subnets within the same routing domain cannot overlap — two subnets that share address space will cause routing ambiguity. A router receiving a packet for 10.0.1.5 needs exactly one matching route. If you define both 10.0.0.0/16 and 10.0.1.0/24 in a VPC, they do not overlap — the /24 is contained within the /16. But you cannot have both 10.0.1.0/24 and 10.0.1.128/25 in the same context unless they are explicitly non-overlapping (they are — /25 covers only half a /24).
Mistake 3 — Confusing the subnet mask with the host mask
The subnet mask (255.255.255.0 for /24) has 1s in the network portion and 0s in the host portion. The wildcard mask or host mask — used in ACLs and some firewall rules — is the inverse: 0s in the network portion and 1s in the host portion (0.0.0.255 for /24). Cisco ACLs use wildcard masks; subnet masks are used in routing and IP configuration. Confusing these will cause your firewall rules to match the wrong addresses.
Interview Questions
Q: What does /24 mean in 192.168.1.0/24?
It means the first 24 bits of the 32-bit address are the network portion, and the remaining 8 bits are the host portion. The subnet mask is 255.255.255.0. The network contains 2⁸ = 256 total addresses — from 192.168.1.0 (network) to 192.168.1.255 (broadcast) — with 254 usable host addresses.
Q: How many hosts can fit in a /28 subnet?
A /28 has 32 − 28 = 4 host bits. 2⁴ = 16 total addresses. Minus the network address and broadcast address = 14 usable hosts.
Q: Why do cloud VPCs use subnetting?
Cloud VPCs use subnetting for security isolation and traffic control. By placing public-facing resources (load balancers) in public subnets and backend resources (application servers, databases) in private subnets, you can apply network ACLs and security group rules at the subnet boundary. Only the public subnet is reachable from the internet — the private subnets route outbound traffic through a NAT gateway but are not directly reachable inbound. Subnets also map to availability zones, enabling high availability across multiple physical data center locations.
Q: Is 10.0.1.5 inside the 10.0.0.0/16 subnet?
Yes. 10.0.0.0/16 covers all addresses from 10.0.0.0 to 10.0.255.255. 10.0.1.5 falls within that range. To verify: apply the /16 mask (255.255.0.0) to 10.0.1.5:
10.0.1.5 AND 255.255.0.0 = 10.0.0.0 (matches the network address)
Yes, 10.0.1.5 is in 10.0.0.0/16.
Q: What is the difference between CIDR and classful addressing?
Classful addressing (pre-1993) assigned fixed subnet masks based on the first octet: Class A (/8), Class B (/16), Class C (/24). If a company needed 500 hosts, they had to take a full Class B (65,534 hosts) and waste 65,034 addresses. CIDR (Classless Inter-Domain Routing) removes these fixed class boundaries, allowing any prefix length from /0 to /32. A company needing 500 hosts can take a /23 (1,022 usable hosts) — much less waste. CIDR also enabled route aggregation (summarizing multiple small routes into one larger route), which drastically reduced the size of internet routing tables.
Quick Reference — Cheat Sheet
| /prefix | Subnet Mask | Hosts | Block Size |
|---|---|---|---|
| /8 | 255.0.0.0 | 16,777,214 | 16,777,216 |
| /16 | 255.255.0.0 | 65,534 | 65,536 |
| /24 | 255.255.255.0 | 254 | 256 |
| /25 | 255.255.255.128 | 126 | 128 |
| /26 | 255.255.255.192 | 62 | 64 |
| /27 | 255.255.255.224 | 30 | 32 |
| /28 | 255.255.255.240 | 14 | 16 |
| /29 | 255.255.255.248 | 6 | 8 |
| /30 | 255.255.255.252 | 2 | 4 |
| /32 | 255.255.255.255 | 1 (host route) | 1 |
Key formulas:
- Host bits = 32 − prefix
- Total addresses = 2^(host bits)
- Usable hosts = 2^(host bits) − 2
- Number of subnets from dividing /X into /Y = 2^(Y − X)
Common CIDR uses:
/8— large cloud provider blocks, ISP allocations/16— AWS VPC default, Docker bridge/24— typical office LAN, VPC subnet per AZ/28or/29— small subnet for load balancers, NAT gateways (few IPs needed)/32— single host (firewall rules, static routes, EIPs)
Previous: Lesson 3.3 — IPv4 vs IPv6 Comparison → Next: Lesson 4.1 — TCP — Reliable Communication →
This is Lesson 3.4 of the Networking Interview Prep Course — 8 chapters, 32 lessons.