Subnetting, from first principles to fluent.
No memorized tables. By the end you'll look at 172.16.77.200/26 and read off the network, the broadcast, the host range and the host count in under ten seconds — in your head.
00Why subnetting exists
An IPv4 address is just a 32-bit number — about 4.3 billion of them. Early on, addresses were handed out in three rigid sizes (the old "classes"): a Class A block held ~16 million addresses, a Class B held ~65 thousand, a Class C held 254. If you needed 300 machines, a Class C was too small and a Class B wasted 65,000 addresses. That waste, multiplied across the planet, was burning the address space alive.
Subnetting is the act of slicing one block into right-sized pieces by moving the boundary between "which network" and "which host" wherever you want it — not just at the three legacy sizes. The same mechanism also lets routers aggregate many small networks back into one line in a routing table (summarization). Slice down, summarize up: it's the same knob turned in two directions.
01Anatomy of an IPv4 address
32 bits, written as four 8-bit groups (octets) in decimal, separated by dots. Each octet ranges 0–255, because 8 bits can represent 256 values.
The grid above is 172.16.45.1. Read each octet by adding the place-values under the 1s: 128+32+8+4 = 172, then 16, then 32+8+4+1 = 45, then 1. The first three octets are coloured as network here, the last as host — but where that colour boundary sits is exactly what the mask decides, which is the rest of this guide.
02The binary you must own
You don't need to convert big numbers in binary all day. You need two small skills cold: the eight place-values of an octet, and the eight "mask values". Burn these in.
The eight bit place-values
| bit position | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| place-value | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
| power of 2 | 2⁷ | 2⁶ | 2⁵ | 2⁴ | 2³ | 2² | 2¹ | 2⁰ |
To turn an octet into decimal, add the place-values wherever there's a 1. 11000000 = 128+64 = 192. To go the other way, greedily subtract from 128 down: 200 → 128 (leaves 72) → 64 (leaves 8) → 8 (leaves 0) so 200 = 11001000.
The eight mask values (memorize this row)
A mask octet is always a run of 1s from the left, then 0s — never mixed. So only nine values are legal per octet. These are the only ones you'll ever see:
| # of 1-bits | binary | decimal | block size (256−dec) |
|---|---|---|---|
| 0 | 00000000 | 0 | 256 |
| 1 | 10000000 | 128 | 128 |
| 2 | 11000000 | 192 | 64 |
| 3 | 11100000 | 224 | 32 |
| 4 | 11110000 | 240 | 16 |
| 5 | 11111000 | 248 | 8 |
| 6 | 11111100 | 252 | 4 |
| 7 | 11111110 | 254 | 2 |
| 8 | 11111111 | 255 | 1 |
256 − mask value. The 192 mask has block size 64. The 224 mask has block size 32. This "block size" (a.k.a. the magic number) is what makes the whole thing doable in your head. We'll use it constantly from §07 on.03Network vs host: the only split that matters
Take the 32 bits and draw one vertical line through them. Everything left of the line is the network ID — shared by every device on that wire. Everything right of the line is the host ID — unique to each device. Move the line right, you get more host bits (bigger subnet, fewer subnets). Move it left, fewer host bits (smaller subnets, more of them).
Above the line sits after 18 network bits — a /18. There are 14 host bits left, so this subnet holds 2¹⁴ = 16384 addresses. Two of those are reserved (next section), leaving 16382 usable hosts.
2ⁿ − 2, where n = host bits.04The subnet mask is just where the line is
The mask is a second 32-bit number whose 1s mark the network portion and 0s mark the host portion. A /24 means 24 ones then 8 zeros:
Three octets of all-ones (255) and one of all-zeros (0) → 255.255.255.0. The router computes the network ID by a bitwise AND of the address and the mask: wherever the mask is 1 the address bit passes through; wherever the mask is 0 the result is forced to 0. That AND is the only arithmetic a router actually does here — everything in this guide is just doing it faster than the long way.
05CIDR & the master table
CIDR (Classless Inter-Domain Routing) is just the /n shorthand: n = number of network bits. 10.0.0.0/8, 192.168.1.0/24, 172.16.4.0/30. It killed the rigid classes for good. This is the one table worth half-memorizing — but really you only need the pattern, because §07 lets you regenerate any row on demand.
| CIDR | mask | host bits | total addrs | usable hosts | block size* |
|---|---|---|---|---|---|
| /8 | 255.0.0.0 | 24 | 16,777,216 | 16,777,214 | 1 (oct 1) |
| /16 | 255.255.0.0 | 16 | 65,536 | 65,534 | 1 (oct 2) |
| /20 | 255.255.240.0 | 12 | 4,096 | 4,094 | 16 (oct 3) |
| /22 | 255.255.252.0 | 10 | 1,024 | 1,022 | 4 (oct 3) |
| /23 | 255.255.254.0 | 9 | 512 | 510 | 2 (oct 3) |
| /24 | 255.255.255.0 | 8 | 256 | 254 | 1 (oct 4) |
| /25 | 255.255.255.128 | 7 | 128 | 126 | 128 (oct 4) |
| /26 | 255.255.255.192 | 6 | 64 | 62 | 64 (oct 4) |
| /27 | 255.255.255.224 | 5 | 32 | 30 | 32 (oct 4) |
| /28 | 255.255.255.240 | 4 | 16 | 14 | 16 (oct 4) |
| /29 | 255.255.255.248 | 3 | 8 | 6 | 8 (oct 4) |
| /30 | 255.255.255.252 | 2 | 4 | 2 | 4 (oct 4) |
| /31 | 255.255.255.254 | 1 | 2 | 2† | 2 (oct 4) |
| /32 | 255.255.255.255 | 0 | 1 | 1† | 1 (oct 4) |
* "block size" = how much the network address jumps each step, in the octet where the mask isn't 0 or 255. † /31 and /32 are special-cased — see §12.
/26→/25 doubles 62→126 usable. That doubling is the entire table.06The four numbers you compute for any subnet
Given any address with a prefix, you describe its subnet with four facts. Everything else is derived from these.
| # | name | what it is | how to get it |
|---|---|---|---|
| 1 | Network address | name of the wire; host bits all 0 | round the address down to a block-size multiple |
| 2 | Broadcast address | reaches everyone; host bits all 1 | next network − 1 |
| 3 | First usable host | first assignable IP | network + 1 |
| 4 | Last usable host | last assignable IP | broadcast − 1 |
Host count = 2^(host bits) − 2. Once you can place the network and broadcast, the two host ends are just ±1 from them. So the real skill is step 1 — and that's what the magic-number method gives you instantly.
07The magic-number method (the expert shortcut)
This is the technique that lets people answer subnet questions out loud. Four steps, no binary.
- 1. Find the interesting octet. Write the mask. The "interesting" octet is the one that's neither
255nor0. (For a/26, mask255.255.255.192→ 4th octet.) - 2. Block size = 256 − that octet's mask value. (
256 − 192 = 64.) - 3. Network = round the address's interesting-octet down to a multiple of the block size. The multiples are your subnet boundaries: 0, block, 2×block, …
- 4. Broadcast = network's interesting octet + block size − 1. Host range sits between, ±1.
/26 is block-64 in the last octet; 200 rounds down to 192; so .192 network, .255 broadcast, .193–.254 hosts, 62 of them." That sentence is fluency. Drill it until it's reflex.08Worked examples (watch the octet move)
Example A — boundary in the 3rd octet
When the boundary is in the 3rd octet, the host portion spills across octets 3 and 4. The broadcast's 3rd octet is one below the next block (31), and the 4th octet goes all the way to 255. Everything to the right of the boundary is host space.
Example B — the trap of a non-zero 3rd octet
Notice the 4th octet (200) was a distraction: the boundary is in octet 3, so octet 4 is pure host and doesn't affect the network ID at all. Always round in the interesting octet, and zero everything to its right.
Example C — a point-to-point link
09Borrowing bits: turning one network into many
"Subnetting" in the verb sense means: take a block, steal some host bits to act as a subnet number, and split it into equal pieces. Each borrowed bit doubles the count of subnets and halves the hosts each.
- Subnets created =
2^(bits borrowed) - Hosts per subnet =
2^(host bits remaining) − 2
Borrow 3 bits from a /24 (→ /27). The grid: 24 fixed network bits, 3 purple borrowed bits, 5 host bits.
3 borrowed → 2³ = 8 subnets. 5 host bits → 2⁵ − 2 = 30 hosts each. Block size in the last octet = 256 − 224 = 32, so the eight subnets of 192.168.1.0/24 are:
| subnet | network | first host | last host | broadcast |
|---|---|---|---|---|
| 0 | 192.168.1.0 | .1 | .30 | .31 |
| 1 | 192.168.1.32 | .33 | .62 | .63 |
| 2 | 192.168.1.64 | .65 | .94 | .95 |
| 3 | 192.168.1.96 | .97 | .126 | .127 |
| 4 | 192.168.1.128 | .129 | .158 | .159 |
| 5 | 192.168.1.160 | .161 | .190 | .191 |
| 6 | 192.168.1.192 | .193 | .222 | .223 |
| 7 | 192.168.1.224 | .225 | .254 | .255 |
See the rhythm: each network jumps by the block size (32), and each broadcast is one below the next network. That's the entire table generated from one number.
10VLSM — sizing each subnet to its real need
Fixed-size subnetting wastes space when your segments differ wildly in size. Variable Length Subnet Masking lets each subnet pick its own prefix. The discipline: allocate largest-first, always carving the next block immediately after the previous one.
Brief: split 192.168.10.0/24 for segments needing 100, 50, 25, and 2 hosts (two point-to-point links).
Each block starts exactly where the last one ended, and no two overlap. The leftover .232–.255 is real, reclaimable space — the payoff of VLSM over fixed sizing.
11Summarization — the same knob, turned up
Routers don't want 50 routes when one will do. Summarization (supernetting) collapses several adjacent networks into one advertisement by moving the boundary left until a single prefix covers them all. The trick: find the longest prefix where all the networks share identical bits.
Collapse these four:
The four /24s (4,5,6,7) differ only in their lowest two bits, so a /22 covers all of them and nothing extra. One route instead of four. This only works on a properly aligned, contiguous block — 4,5,6,7 summarize cleanly; 5,6,7,8 do not, because they straddle a boundary.
12Private & special-case ranges
RFC 1918 private space (memorize)
| range | CIDR | size | typical use |
|---|---|---|---|
| 10.0.0.0 – 10.255.255.255 | 10.0.0.0/8 | ~16.7M | big cloud VNets, k8s |
| 172.16.0.0 – 172.31.255.255 | 172.16.0.0/12 | ~1M | mid-size estates |
| 192.168.0.0 – 192.168.255.255 | 192.168.0.0/16 | 65K | homes, small labs |
172.16.0.0/12, not /16. It spans 172.16.x.x through 172.31.x.x — sixteen Class-B-sized blocks. People misread this constantly.Other ranges worth knowing
127.0.0.0/8— loopback (127.0.0.1= localhost).169.254.0.0/16— link-local / APIPA. If a host shows this, DHCP failed.100.64.0.0/10— carrier-grade NAT (and Tailscale's default range).224.0.0.0/4— multicast.
The /31 and /32 exceptions
By the 2ⁿ−2 rule a /31 would have zero usable hosts. RFC 3021 special-cases it: on a point-to-point link a /31 gives you both addresses as usable hosts (no network/broadcast waste). A /32 is a single host — used for loopbacks, host routes, and matching one exact IP in a firewall or route table.
13Where this actually bites you in prod
This isn't an exam topic for you — it's the thing behind half your incidents. A few translations into your world:
- VNet / subnet sizing. A VNet is just a CIDR (say
10.20.0.0/16); each subnet carves a slice. Size a subnet too tight and you run out of IPs mid-scale-out — the node pool can't get addresses and pods goPending. - AKS / pod CIDRs. In Azure CNI every pod consumes a real subnet IP, so a
/24node subnet (254 usable) can be exhausted by a couple of busy nodes. The "careful IP planning" you did during the AGIC pod-IP-update incident is exactly §10 VLSM thinking — carving non-overlapping subnets sized to real pod density. - App Gateway subnets. AGIC wants headroom in its dedicated subnet; an undersized one is why pod-IP updates stall. Knowing block size at a glance tells you instantly whether a
/27can survive a scale event. - Route tables & NSGs. A rule scoped to
10.20.0.0/22covers four/24s — that's §11 summarization. Get the prefix wrong and you either leak access or black-hole traffic. - Peering overlap. Two VNets that both use
10.0.0.0/16can't peer. Disciplined allocation from one parent block is what prevents the collision.
14Graded drills
Do these on paper, out loud, then reveal. The goal isn't the answer — it's the sentence you say to get there. If you can't narrate the block-size step, you're not fluent yet.
EASYFor 192.168.4.77/26: network, broadcast, host range, usable count?
Mask …255.192 → block 64 in oct 4. Multiples 0/64/128/192; 77 rounds down to 64.
Broadcast = 64 + 64 − 1 = 127.
EASYHow many usable hosts in a /29? And what's its mask?
32 − 29 = 3 host bits → 2³ − 2 = 6. Mask: 5 ones in the last octet = 248.
MEDIUMFor 10.34.150.200/21: network & broadcast?
Mask 255.255.248.0 → interesting octet 3, block 256 − 248 = 8. Multiples in oct 3: 0,8,…,144,152; 150 rounds down to 144 (next is 152).
Broadcast oct 3 = 144 + 8 − 1 = 151, oct 4 = 255.
MEDIUMIs 172.16.93.40/26 in the same subnet as 172.16.93.70/26?
Block 64 in oct 4. 40 rounds to 0 (range .0–.63). 70 rounds to 64 (range .64–.127). Different blocks.
HARDVLSM: carve 10.10.0.0/24 for needs of 60, 30, 12, and 2 hosts.
Round each up: 60→/26 (62), 30→/27 (30), 12→/28 (14), 2→/30 (2). Allocate largest-first, contiguously:
HARDSummarize 10.8.16.0/24, 10.8.17.0/24, 10.8.18.0/24, 10.8.19.0/24 into one route.
Octet 3 values 16–19 in binary: 00010000 / 00010001 / 00010010 / 00010011. First 6 bits identical, last 2 vary → drop 2 bits from /24.
HARDTrap check: can you summarize 10.8.17.0/24 … 10.8.20.0/24 (17,18,19,20) into one clean route?
No. 17–20 straddle the /22 boundary: 16–19 form one aligned /22, but 20 starts the next. A single prefix that covers 17–20 (a /21 = 16–23) would also pull in 16, 21, 22, 23 — addresses you didn't intend. Summarization needs a power-of-two-aligned, contiguous set.
15Live calculator — check your own work
Use this after you've worked a problem by hand, never before. The point is to verify the sentence in your head, not replace it.
16Cheat sheet — the whole thing on one card
| you want… | do this |
|---|---|
| usable hosts | 2^(32 − prefix) − 2 |
| host bits | 32 − prefix |
| block size (magic number) | 256 − (mask value of interesting octet) |
| network address | round interesting octet DOWN to a block multiple; zero everything right |
| broadcast | network's interesting octet + block − 1; 255 everything right |
| first / last host | network + 1 / broadcast − 1 |
| # subnets when borrowing b bits | 2^b |
| VLSM rule | sort needs descending, round up to powers of 2, allocate contiguously |
| summarization | find longest prefix where all networks share identical bits |
| mask octet values | 128·192·224·240·248·252·254·255 |
block size = 256 − mask, and the network address is the multiple of the block size at or below your octet. Everything else falls out of that.Now go drill §14 until the sentences come without effort, then test yourself against §15. That's the path from "I can derive it slowly" to "I just know."