IP Addressing, Subnets, and Routing

Topics Covered

Prefixes and the Arithmetic of a Subnet

Reading a prefix without a calculator

Splitting and joining

The ranges that are not yours to use

Clouds take addresses you expected to keep

Masks, wildcards and the three notations you will meet

The arithmetic that turns up in interviews

An IPv4 address is 32 bits, and a prefix is an address plus a count of how many leading bits of it are fixed. Everything written about subnetting is a consequence of that one idea, and the arithmetic is worth being able to do in your head because it appears in every firewall rule, route table, VPC plan and incident where two networks turned out to overlap.

Reading a prefix without a calculator

10.4.56.0/22 fixes the first 22 bits and leaves 10 bits free, so the block holds

210=10242^{10} = 1024
addresses. The general forms are worth memorising rather than deriving each time:

addresses=232−nusable hosts=232−n−2(n≤30)\text{addresses} = 2^{32-n} \qquad \text{usable hosts} = 2^{32-n} - 2 \quad (n \le 30)

The subtraction of two is the network address, all host bits zero, and the broadcast address, all host bits one. A /24 therefore holds 256 addresses and 254 hosts, a /22 holds 1,024 and 1,022, a /26 holds 64 and 62.

The boundary of the block matters as much as its size. Since the prefix fixes leading bits, a block always starts at a multiple of its own size: a /22 can begin at 10.4.0.0, 10.4.4.0, 10.4.8.0 and so on, in steps of four in the third octet, and 10.4.56.0/22 is valid while 10.4.57.0/22 is not, because 57 is not a multiple of 4. The fast mental method is to find the block size in the octet where the prefix falls. A /22 leaves 2 bits in the third octet, so the step is

28−6=42^{8-6} = 4
. A /27 leaves 5 bits in the fourth octet, step 32, so valid /27 blocks start at .0, .32, .64 and upward.

The prefix length fixes leading bits, so block size and legal start address are the same fact. A /22 steps by 4 in the third octet, a /27 by 32 in the fourth.

Splitting and joining

Splitting a block means borrowing host bits. One /24 splits into two /25s, four /26s, eight /27s, and the count doubles for every bit borrowed. Joining is only legal between adjacent blocks of the same size whose combined range is itself aligned, which is why 10.0.0.0/25 and 10.0.0.128/25 join into 10.0.0.0/24 while 10.0.0.128/25 and 10.0.1.0/25 do not join into anything, despite being adjacent. That rule is the reason address plans are drawn as a binary tree and the reason a plan that allocates greedily from the front cannot be consolidated later.

Two prefix lengths are special and both are used constantly. A /32 fixes every bit and names one address, which is how host routes, firewall rules for a single server and loopback addresses on routers are written. A /31 leaves one bit and would, by the arithmetic above, have zero usable hosts, which is why RFC 3021 explicitly permits it on point-to-point links where there is no need for a broadcast address: both addresses are usable and a link consumes two addresses instead of four.

The ranges that are not yours to use

A surprising amount of debugging time is spent discovering that an address was special. The ones that matter in practice: 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 are private, from RFC 1918, and are the only blocks safe to use internally. 100.64.0.0/10 is carrier-grade NAT space from RFC 6598, which both makes it unusable for your own network if your users sit behind a provider that uses it, and makes it the conventional choice for overlay and service networks precisely because so little else uses it. 169.254.0.0/16 is link-local, assigned by a host that failed to get a DHCP lease, which is why a machine with a 169.254 address has a DHCP problem rather than a routing problem, and 169.254.169.254 inside that range is the instance metadata address on essentially every cloud. 127.0.0.0/8 is loopback, all 16 million of it, so 127.0.0.2 is as local as 127.0.0.1. 224.0.0.0/4 is multicast and 240.0.0.0/4 is reserved. And 192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24 exist for documentation, which is what you should use in examples and runbooks instead of inventing addresses that belong to someone.

Clouds take addresses you expected to keep

A subnet in a cloud VPC does not give you the host count the arithmetic predicts, because the platform reserves addresses inside it. AWS reserves five per subnet: the network address, the .1 address for the implicit router, .2 for the DNS resolver, .3 for future use, and the broadcast address. Azure reserves the same count. Google Cloud reserves four.

So an AWS /28 has 16 addresses and 11 usable, not 14, and a /24 has 251. That matters because the smallest allowed AWS subnet is a /28 and several managed services place multiple interfaces per subnet, so a /28 intended for a small internal service can fill with three load balancer interfaces and a handful of pods. The practical rule is to never size a cloud subnet from the host arithmetic alone, to add the platform's reservation, and then to add a factor for the services that quietly consume interfaces: load balancers, NAT gateways, VPC endpoints, managed database instances and anything using a container network interface that assigns real VPC addresses to pods, which is the arrangement where a cluster of 40 nodes can need thousands of addresses.

Common Pitfall

Sizing a subnet exactly to today's host count is the most expensive mistake in address planning, because a subnet cannot be resized in place on any major cloud. Growing a /27 that filled means creating a new subnet, moving every resource and updating every rule that named the old range. Allocate generously from a plan with room above each block, since IPv4 private space holds about 17.9 million addresses and almost no organisation is actually short of it, only short of a plan.

Masks, wildcards and the three notations you will meet

The same prefix gets written three ways and all three appear in configuration you will have to read. CIDR notation, 10.4.56.0/22, is the modern form. A dotted-decimal mask, 255.255.252.0, is the same 22 bits written as an address, which older equipment, DHCP configuration and some operating system dialogues still require; converting is counting bits, since 252 is 11111100. And a wildcard mask, 0.0.3.255, is the bitwise inverse, used by Cisco access lists and a few other systems, where a one means ignore this bit rather than match it.

Two habits prevent the errors these notations cause. Always convert to CIDR mentally before reasoning, because prefix length is the only form in which longest-prefix comparisons are obvious. And be suspicious of a mask that is not a contiguous run of ones: a discontiguous mask such as 255.255.0.255 is syntactically expressible in the dotted form and meaningless as a prefix, and the only system that ever accepted it in anger was an old access list where it was almost always a typo for something else.

The third notation worth recognising is the range form used by cloud consoles and some security tools, 10.4.56.0-10.4.59.255, which is a prefix expressed by its endpoints. A range that does not correspond to a single prefix, for example 10.4.56.0-10.4.60.0, has to be decomposed into several prefixes, and the decomposition is the same binary-tree reasoning as joining: greedily take the largest aligned block that fits at the current start, then repeat. This matters because a rule written as a range may expand into a dozen prefixes in the device that enforces it, consuming a dozen entries in a table with a fixed size.

The arithmetic that turns up in interviews

Three questions recur, and all three are the same question. Given 10.60.14.37/20, what is the network address: the prefix leaves 12 bits, so the third octet steps by 16, and 14 falls in the block starting at 0, giving 10.60.0.0/20 with a broadcast of 10.60.15.255. How many /26 subnets fit in a /22: the difference is 4 bits, so 16. Do 172.20.4.0/23 and 172.20.5.0/24 overlap: yes, because the /23 spans 172.20.4.0 through 172.20.5.255 and fully contains the /24, which is exactly the situation that makes a firewall rule or a route both valid and surprising.

The containment test is the one worth doing mechanically rather than by eye. Mask both addresses with the shorter prefix and compare: if address_a & mask_short == address_b & mask_short, the longer prefix is inside the shorter one. That single operation is the core of the CIDR containment problem later in this course, and it is also exactly what a router does millions of times a second, which is the subject of the next section.

Loading problem...