I understand why CIDR works in binary.
An IPv4 address contains 32 bits.
The prefix fixes the network bits.
The remaining bits identify positions inside the block.
That model is essential.
I do not, however, want to write this every time I inspect a subnet:
10101100.00010000.00100000.00000000
11111111.11111111.11110000.00000000
Binary is the explanation beneath the arithmetic.
It is not always the quickest working notation.
For ordinary IPv4 planning, I use a smaller toolkit:
host bits
powers of two
prefix differences
mask increments
valid boundaries
next block minus one
These calculations answer most of the questions I meet while designing VPCs, subnets and address pools.
The aim is not to perform subnetting theatrically. It is to recognise the boundary quickly enough to make a sound architectural decision.
Start with the host bits
The first calculation is always:
host bits = 32 - prefix length
For a /20:
32 - 20 = 12 host bits
For a /26:
32 - 26 = 6 host bits
The number of addresses is:
2 ^ host bits
Therefore:
/20 = 2^12 = 4,096 addresses
/26 = 2^6 = 64 addresses
CIDR uses a 32-bit IPv4 address and a prefix length identifying the significant leading bits. RFC 4632 provides the corresponding address counts.
This formula tells me the block size, containment possibilities and capacity lost when the prefix grows.
Use the doubling and halving ladder
I do not recalculate every power of two from the beginning.
I keep a short ladder in mind:
| Prefix | Addresses |
|---|---|
/16 |
65,536 |
/17 |
32,768 |
/18 |
16,384 |
/19 |
8,192 |
/20 |
4,096 |
/21 |
2,048 |
/22 |
1,024 |
/23 |
512 |
/24 |
256 |
/25 |
128 |
/26 |
64 |
/27 |
32 |
/28 |
16 |
/29 |
8 |
/30 |
4 |
/31 |
2 |
/32 |
1 |
Increasing the prefix by one halves the block:
/24 = 256
/25 = 128
/26 = 64
Decreasing it by one doubles the block:
/24 = 256
/23 = 512
/22 = 1,024
For example:
/24 → /23 → /22 → /21
256 × 2 × 2 × 2 = 2,048
The ladder is the host-bit formula moving one bit at a time.
Prefix difference tells me how many subnets fit
Suppose I have:
10.64.0.0/16
and want to divide it into /20 allocations.
The prefix difference is:
20 - 16 = 4 bits
Four additional network bits can represent:
2^4 = 16 subnets
Therefore:
one /16 contains sixteen /20s
The compact formula is:
number of equal child subnets
= 2 ^ (child prefix - parent prefix)
For /24 children inside a /20:
2 ^ (24 - 20)
= 2^4
= 16
This is useful for hierarchical pools because every prefix change spends bits to create more boundaries.
Find the canonical block
Prefixes ending in /8, /16 or /24 are visually simple.
For other prefixes, one octet contains a mixture of network and host bits.
That is the interesting octet.
For example:
/20 mask = 255.255.240.0
The interesting octet is the third one.
For:
/26 mask = 255.255.255.192
it is the fourth one.
The mask values I use most frequently are:
| Network bits in octet | Mask value | Increment | Meaning |
|---|---|---|---|
| 0 | 0 | 256 | one whole octet |
| 1 | 128 | 128 | two blocks |
| 2 | 192 | 64 | four blocks |
| 3 | 224 | 32 | eight blocks |
| 4 | 240 | 16 | sixteen blocks |
| 5 | 248 | 8 | thirty-two blocks |
| 6 | 252 | 4 | sixty-four blocks |
| 7 | 254 | 2 | 128 blocks |
| 8 | 255 | 1 | every value |
The block increment is:
256 - mask value in the interesting octet
A /20 produces an increment of 16 in the third octet. A /26 produces an increment of 64 in the fourth:
/20: 0, 16, 32, 48, ... 240
/26: 0, 64, 128, 192
The increment tells me where every valid block begins.
Round down to the previous boundary
Consider:
10.42.77.19/20
A /20 has an increment of 16 in the third octet.
The third octet is 77.
The surrounding boundaries are:
64
80
The address belongs to the block beginning at the lower boundary:
10.42.64.0/20
I ask:
Which multiple of 16
comes immediately before 77?
The answer is 64.
Every octet after the interesting octet is then set to zero.
That final step matters.
For example:
10.64.20.5/22
has an aligned third octet because:
20 mod 4 = 0
but it is not the canonical network address because the fourth octet contains host bits.
The canonical block is:
10.64.20.0/22
A CIDR is aligned when:
1. the interesting octet is a multiple
of the increment;
2. every following octet is zero.
AWS similarly converts non-canonical subnet CIDR input to the actual aligned network form. The Amazon VPC subnet sizing documentation gives examples of this canonicalisation.
Find the next block
Once I know the current boundary, I add the increment to find the next network.
For:
192.0.2.128/26
the next block begins at:
192.0.2.192
When the addition reaches 256, I reset that octet to zero and carry one into the octet on its left.
For example:
192.0.2.192/26
is followed by:
192.0.3.0/26
not:
192.0.2.256
Likewise:
10.42.240.0/20
is followed by:
10.43.0.0/20
Step back once to find the end
The final address is:
next network address - 1
For:
192.0.2.128/26
the next block is:
192.0.2.192
Therefore the current block ends at:
192.0.2.191
The complete range is:
192.0.2.128 - 192.0.2.191
For:
10.42.64.0/20
the next block is:
10.42.80.0
The final address is:
10.42.79.255
Find the start.
Find the next start.
Step back once.
My practical worksheet
Given:
10.72.37.140/21
I work through it like this.
1. Host bits
32 - 21 = 11
2. Total addresses
2^11 = 2,048
3. Mask and increment
A /21 is:
255.255.248.0
Therefore:
256 - 248 = 8
The third octet changes in blocks of eight.
4. Previous boundary
The third octet is 37.
Nearby multiples of eight are:
32
40
The network begins at 32.
Every following octet becomes zero:
10.72.32.0/21
5. Next block
10.72.40.0/21
6. Final address and range
One address before the next block:
10.72.39.255
Therefore:
10.72.32.0 - 10.72.39.255
7. Ordinary AWS assignable count
2,048 - 5 = 2,043
The entire calculation needs no 32-bit expansion.
Binary remains underneath every step.
The increment is simply the host-bit combinations expressed in the interesting octet.
Check containment and overlap with ranges
Suppose I need to know whether:
10.64.80.0/22
fits inside:
10.64.64.0/18
The parent /18 advances by 64 in the third octet.
Its range is:
10.64.64.0 - 10.64.127.255
The proposed /22 advances by four and covers:
10.64.80.0 - 10.64.83.255
Both ends sit inside the parent range.
It fits.
Because the ranges are inclusive, two CIDRs overlap when:
A.start <= B.end
and
B.start <= A.end
In words:
Each range starts on or before the other range ends.
That includes equal starts, equal ends and complete containment.
Aggregation needs size, contiguity and alignment
Suppose I have four /20 blocks:
10.64.0.0/20
10.64.16.0/20
10.64.32.0/20
10.64.48.0/20
Four equal blocks require two fewer prefix bits:
four blocks = 2^2 blocks
/20 - 2 = /18
The candidate summary is:
10.64.0.0/18
A valid summary requires:
- equal-sized source blocks;
- a power-of-two number of blocks;
- contiguous address space;
- alignment on the resulting shorter prefix.
These four blocks are contiguous:
10.64.0.0 - 10.64.63.255
They also begin on a valid /18 boundary.
Therefore the summary is valid.
These blocks are also contiguous:
10.64.16.0/20
10.64.32.0/20
10.64.48.0/20
10.64.64.0/20
But they do not begin on a /18 boundary.
A /18 starting at zero would include an unlisted block.
A /18 starting at 64 would miss the first three.
CIDR aggregation therefore needs both the right quantity of addresses and the right binary alignment.
Traditional hosts and AWS capacity differ
For a conventional IPv4 subnet, the familiar host calculation is:
total addresses - 2
This removes:
- the network address;
- the directed broadcast address.
For a /26:
64 - 2 = 62 traditional host addresses
There are exceptions.
RFC 3021 allows the two addresses in a /31 to act as endpoint addresses on point-to-point links whose endpoints support that behaviour. A /32 identifies one address.
That /31 rule is a point-to-point exception, not the ordinary usable-host calculation, and /31 is not a supported AWS VPC subnet size.
For ordinary AWS VPC IPv4 subnet CIDRs, AWS reserves:
- the first four IPv4 addresses;
- the final IPv4 address.
AWS supports IPv4 subnet sizes from /28 to /16.
I therefore begin with:
ordinary AWS assignable addresses
= total addresses - 5
Examples:
| Prefix | Total | Ordinary AWS assignable |
|---|---|---|
/24 |
256 | 251 |
/25 |
128 | 123 |
/26 |
64 | 59 |
/27 |
32 | 27 |
/28 |
16 | 11 |
BYOIP is an exception. AWS documents that when an IPv4 range is brought into AWS using BYOIP, all addresses in the range can be used, including the first and final addresses.
The normal five-address reservation should therefore not be applied blindly to BYOIP ranges.
I also distinguish three capacity numbers:
TOTAL ADDRESSES
mathematical CIDR size
AWS ASSIGNABLE ADDRESSES
total minus applicable AWS reservations
CURRENTLY AVAILABLE ADDRESSES
assignable addresses minus
addresses already consumed
Consumers include network interfaces, load balancers, NAT gateways, interface endpoints, EKS nodes and Pods, managed databases and failover interfaces.
A /28 has eleven assignable addresses in an ordinary AWS subnet.
That is mathematically valid and architecturally tiny.
I size for the consumer, not the diagram
A neat design might allocate one /24 to every subnet.
public-a /24
application-a /24
data-a /24
The symmetry is pleasant.
The consumers may be very different.
A public subnet may contain only a load balancer, NAT gateway and a few interfaces. An EKS subnet may need addresses for nodes, Pods, rolling deployments, autoscaling, replacement capacity, load balancers and interface endpoints.
The question is not:
Which prefix makes the table look tidy?
It is:
How many simultaneous address consumers
can this subnet contain during normal,
scaling and failure conditions?
I calculate the smallest prefix that satisfies the estimate.
Then I add deliberate growth space.
AWS Well-Architected guidance recommends sizing subnets for growth, Availability Zone distribution and transient capacity rather than allocating only enough space for the first deployment.
Amazon VPC IPAM can allocate CIDRs and monitor utilisation. Automation can enforce the allocation, but it cannot decide how much future bfstore should fit inside it.
The arithmetic I keep beside me
IPv4 bits:
32
Host bits:
32 - prefix
Addresses:
2 ^ host bits
Equal child subnets:
2 ^ (child prefix - parent prefix)
Mask increment:
256 - interesting mask octet
Canonical network:
previous multiple of increment,
with every following octet set to zero
Next network:
current boundary + increment,
carrying left when the result reaches 256
Final address:
next network - 1
Ordinary AWS assignable addresses:
total addresses - 5
And the mask ladder:
128 → increment 128
192 → increment 64
224 → increment 32
240 → increment 16
248 → increment 8
252 → increment 4
254 → increment 2
255 → increment 1
That is most of the arithmetic I actually use.
Questions I now ask
Size
How many host bits remain, and how many addresses do they produce?
Increment
Which octet contains the prefix split, and how far apart are valid starts?
Alignment
Is the interesting octet on a valid boundary, with every following octet set to zero?
Range
Where does the next block begin, including any carry into the previous octet?
Containment
Do both ends of the child range sit inside the parent?
Aggregation
Are the blocks equal, a power-of-two quantity, contiguous and correctly aligned?
AWS capacity
Which reservation rule applies, and how many addresses are currently available?
Growth
Which resources consume the subnet during normal, scaling and failure conditions?
These questions turn CIDR notation into an address plan.
The mental model I am keeping
My full model remains:
32-bit address
│
▼
network bits | host bits
My working model is:
CIDR
│
┌───────────┴───────────┐
│ │
▼ ▼
PREFIX LENGTH IP ADDRESS
│ │
▼ ▼
HOST BITS INTERESTING OCTET
│ │
▼ ▼
ADDRESS COUNT INCREMENT
│ │
└───────────┬───────────┘
▼
NETWORK BOUNDARY
│
▼
BLOCK RANGE
│
┌──────────┴──────────┐
│ │
▼ ▼
CAPACITY ALLOCATION
The prefix tells me how many bits remain.
The remaining bits tell me the block size.
The mask tells me the increment.
The increment tells me the valid boundaries.
The trailing zeroes make the network canonical.
The next boundary tells me where the current range ends.
I use binary to understand CIDR, but I use boundaries to work with it.
When a result looks strange, I can still return to the bits.
Most of the time, I do not need to.
I count the host bits.
I find the increment.
I round down to the valid boundary.
I clear the remaining host octets.
I step forward to the next block.
Then I let a subnet calculator check my answer, rather than asking it what I believe.
References and further reading
-
RFC 4632: Classless Inter-Domain Routing Defines CIDR prefixes, address counts and route aggregation.
-
RFC 3021: Using 31-Bit Prefixes on IPv4 Point-to-Point Links Defines the special use of
/31blocks for point-to-point links. -
Amazon VPC subnet CIDR blocks Documents canonical CIDR handling, supported IPv4 subnet sizes, AWS’s five reserved addresses and the BYOIP exception.
-
AWS Well-Architected: Ensure IP subnet allocation accounts for expansion and availability Covers sizing VPCs and subnets for workload growth and multi-Availability-Zone operation.
-
Monitor CIDR usage with Amazon VPC IPAM Covers tracking allocation compliance and IPv4 subnet utilisation.