All writing

Subnetting without memorising magic numbers

IPv4 subnetting does not require memorising a collection of disconnected masks and block sizes. Starting with capacity, powers of two and valid boundaries provides a repeatable method for designing CIDR allocations.

about 23 minutes min read

Subnetting is often taught as several collections of facts to memorise.

/24 means 256 addresses
/25 means 128
/26 means 64
/27 means 32
/28 means 16

Then another collection appears:

128
192
224
240
248
252
254
255

These are mask values.

A third collection follows:

128
64
32
16
8
4
2
1

These are block increments.

The numbers are related, but they are often presented as separate tables. The student is left trying to remember whether 224 belongs to /26, /27 or the part of the lesson that everyone else appeared to understand immediately.

Someone says:

172.20.44.173/20

and an experienced network engineer replies:

172.20.32.0 to 172.20.47.255

The answer can look like a parlour trick.

It is not.

The engineer recognised a small set of relationships:

  • IPv4 contains 32 bits
  • a prefix leaves a known number of host bits
  • host bits produce powers-of-two block sizes
  • each mask creates regularly spaced boundaries
  • an address belongs to the block beginning at the previous valid boundary

Subnetting does not require magic numbers. It requires one model applied repeatedly.

I still keep a reference table nearby. It is useful for speed, but it is no longer the source of the answer.

The same bits produce the prefix, mask and block size

Consider a /26.

It has:

26 network bits
6 host bits

The six host bits create:

2^6 = 64 addresses

The mask is:

11111111.11111111.11111111.11000000

The final mask octet is:

11000000

which is:

128 + 64 = 192

The block increment is:

256 - 192 = 64

The three apparently independent facts are therefore:

prefix:      /26
mask:        255.255.255.192
block size:  64

They all came from the same six host bits.

prefix
   │
   ▼
host bits
   │
   ├── address count
   ├── subnet mask
   └── boundary increment

Remembering one value can help derive the others. Remembering none of them is survivable too.

Begin with the requirement, not the prefix

A subnet should not begin with:

I think a /24 looks sensible.

It should begin with:

How many simultaneous address consumers
must this subnet support?

Suppose a subnet needs space for:

  • 70 application instances
  • 10 load-balancer or service interfaces
  • 20 addresses of deployment headroom
  • 15 addresses for expected growth

The planning requirement is:

70 + 10 + 20 + 15 = 115 addresses

CIDR blocks have power-of-two sizes. Find the smallest power of two that is at least 115:

64   too small
128  large enough

A block of 128 addresses uses seven host bits:

2^7 = 128

IPv4 contains 32 bits, so the prefix is:

32 - 7 = 25

The resulting block is:

/25

The design process is:

REQUIRED CAPACITY
        │
        ▼
NEXT POWER OF TWO
        │
        ▼
HOST BITS
        │
        ▼
PREFIX LENGTH

No /25 was memorised. It was derived from the requirement.

Round up, never down

Suppose a workload requires 300 address positions.

The nearby powers of two are:

256
512

A /24 provides 256 total addresses, so it is too small.

A /23 provides 512. It is the smallest block that satisfies the raw requirement.

required:        300
next power:      512
host bits:       9
prefix:          32 - 9
result:          /23

Address exhaustion does not award partial credit.

Required total addresses Next power of two Host bits Prefix
10 16 4 /28
25 32 5 /27
50 64 6 /26
100 128 7 /25
200 256 8 /24
700 1,024 10 /22
3,000 4,096 12 /20

Every row follows:

smallest 2^h >= requirement

prefix = 32 - h

The total requirement must include operating headroom. Platform-specific reservations are then applied before selecting the final prefix.

Apply platform rules after the binary arithmetic

The arithmetic is platform-neutral. Cloud platforms then decide which positions may be assigned and how services consume them.

For an AWS VPC IPv4 subnet, AWS reserves the first four addresses and the final address. AWS currently supports subnet prefixes from /28 to /16, and it canonicalises a supplied subnet CIDR to the actual network boundary.

For 10.0.0.0/24, AWS reserves:

  • 10.0.0.0 as the network address
  • 10.0.0.1 for the VPC router
  • 10.0.0.2 for DNS-related use
  • 10.0.0.3 for future use
  • 10.0.0.255 as the final address

The AWS planning equation is:

required assignable addresses
+ 5 AWS reservations
<= total CIDR addresses

Suppose I need 60 assignable addresses.

A /26 contains:

64 total
64 - 5 = 59 assignable

It is one address too small.

The next larger block is:

/25 = 128 total
128 - 5 = 123 assignable

The five reservations are only the first adjustment. The estimate may also need to include:

  • EC2 network interfaces
  • load balancers
  • NAT gateways
  • interface VPC endpoints
  • managed databases
  • EKS nodes and Pods
  • replacement resources during deployments
  • failover and scaling headroom

AWS Well-Architected guidance recommends planning for multiple Availability Zones, future expansion and transient capacity. A mathematically fitting subnet can still be operationally undersized.

Count host bits instead of memorising prefixes

The useful powers of two are easy to reconstruct:

2^0  = 1
2^1  = 2
2^2  = 4
2^3  = 8
2^4  = 16
2^5  = 32
2^6  = 64
2^7  = 128
2^8  = 256
2^9  = 512
2^10 = 1,024
2^11 = 2,048
2^12 = 4,096
2^13 = 8,192
2^14 = 16,384
2^15 = 32,768
2^16 = 65,536

If I know the capacity, I can identify the host bits. The prefix is then:

32 - host bits

For 2,048 addresses:

2^11 = 2,048
32 - 11 = 21
prefix = /21

For 32 addresses:

2^5 = 32
32 - 5 = 27
prefix = /27

A /18 is no longer a mysterious large block:

32 - 18 = 14 host bits
2^14 = 16,384 addresses

Increasing a prefix by one halves the block size. Decreasing it by one doubles the block size.

Derive the mask from the partial octet

A prefix can end at an octet boundary:

/8   = 255.0.0.0
/16  = 255.255.0.0
/24  = 255.255.255.0
/32  = 255.255.255.255

For other prefixes, one octet contains both network and host bits. I need only derive that partial octet.

For /20, the first 16 bits consume two complete octets. Four more network bits enter the third:

11110000

Add their values:

128 + 64 + 32 + 16 = 240

The mask is:

255.255.240.0

For /27, three network bits enter the fourth octet:

11100000

128 + 64 + 32 = 224

The mask is:

255.255.255.224

The partial-octet values are running totals of binary place values:

Network bits in partial octet Binary Decimal
1 10000000 128
2 11000000 192
3 11100000 224
4 11110000 240
5 11111000 248
6 11111100 252
7 11111110 254
8 11111111 255

The values are cumulative binary addition, not magic numbers.

The increment is the remaining space in the partial octet

Once I have the partial mask value, the boundary increment is:

256 - partial mask value

For /20:

256 - 240 = 16

For /27:

256 - 224 = 32

For /22:

mask = 255.255.252.0
256 - 252 = 4
Network bits in partial octet Mask value Increment
1 128 128
2 192 64
3 224 32
4 240 16
5 248 8
6 252 4
7 254 2
8 255 1

For the partial octet:

partial mask value + increment = 256

This is why 255.255.255.192 creates boundaries every 64 addresses and 255.255.240.0 creates boundaries every 16 values in the third octet.

Find the block by rounding down

Consider:

172.20.44.173/20

The mask is:

/20 = 255.255.240.0

The interesting octet is the third. Its increment is:

256 - 240 = 16

Valid third-octet boundaries include:

0
16
32
48
64
...
240

The address has third octet 44.

The previous boundary is 32. The next boundary is 48.

Therefore:

network:       172.20.32.0/20
next network:  172.20.48.0/20
final address: 172.20.47.255

The complete range is:

172.20.32.0 - 172.20.47.255

The formal calculation is:

floor(44 / 16) × 16 = 32

The mental version is:

Which multiple of 16
comes immediately before 44?

A valid CIDR starts on its boundary

Suppose someone proposes:

10.64.22.0/22

A /22 mask is:

255.255.252.0

The third-octet increment is:

256 - 252 = 4

Valid boundaries include:

0
4
8
12
16
20
24
28

22 is not one of them. It falls inside the block beginning at 20.

The canonical network is:

10.64.20.0/22

Its range is:

10.64.20.0 - 10.64.23.255

A compact check is:

proposed octet mod increment

For 20:

20 mod 4 = 0

Aligned.

For 22:

22 mod 4 = 2

Not aligned.

The network identifier has every host bit set to zero. A proposed CIDR containing non-zero host bits identifies an address inside the block, not its canonical start.

Divide a parent block without listing every address

Suppose a fictional organisation receives:

10.64.0.0/16

I want /20 environment allocations.

The prefix difference is:

20 - 16 = 4

Four additional network bits create:

2^4 = 16 child blocks

Each /20 contains:

2^(32 - 20) = 4,096 addresses

A /20 moves in increments of 16 in the third octet:

10.64.0.0/20
10.64.16.0/20
10.64.32.0/20
10.64.48.0/20
...
10.64.240.0/20

The formula is:

number of equal children
= 2^(child prefix - parent prefix)

The formula proves there are 16 children. The increment identifies where each one begins.

Unequal requirements need VLSM

Equal-size subnetting is simple. Real systems rarely have equal requirements.

Suppose one VPC has these three-Availability-Zone requirements:

Purpose Subnets Required AWS-assignable addresses per subnet
EKS applications 3 900
Public entry 3 40
Data services 3 100

Add AWS’s five reservations to each subnet:

Purpose Calculation Next power of two Prefix
EKS applications 900 + 5 = 905 1,024 /22
Public entry 40 + 5 = 45 64 /26
Data services 100 + 5 = 105 128 /25

The design therefore needs:

3 × /22 application subnets
3 × /25 data subnets
3 × /26 public subnets

This is Variable Length Subnet Masking, or VLSM: unequal requirements receive different prefix lengths from the same parent allocation.

The useful principle is not the name. It is refusing to give every consumer the same box merely because equal boxes are easier to draw.

Allocate the largest blocks first

When fitting unequal subnets into a parent, allocate the largest first.

Suppose production receives the aligned parent:

10.64.128.0/18

It spans:

10.64.128.0 - 10.64.191.255

A possible allocation is:

application-a  10.64.128.0/22
application-b  10.64.132.0/22
application-c  10.64.136.0/22

data-a         10.64.140.0/25
data-b         10.64.140.128/25
data-c         10.64.141.0/25

public-a       10.64.141.128/26
public-b       10.64.141.192/26
public-c       10.64.142.0/26

A /22 moves by four in the third octet:

128
132
136
140

A /25 divides one /24 into two halves:

.0 - .127
.128 - .255

A /26 divides one /24 into four quarters:

.0 - .63
.64 - .127
.128 - .191
.192 - .255

Large-first allocation reduces the chance that small ranges will fragment the parent and leave no aligned location for a later large subnet.

Total free addresses are not contiguous free capacity

Suppose a parent allocation has 4,096 unallocated addresses in total.

Those addresses are spread across eight disconnected /23 gaps:

8 × 512 = 4,096

A new workload needs one /20:

1 × 4,096 = 4,096

The quantities match, but the allocation cannot be made. A /20 requires one contiguous, aligned block.

TOTAL FREE

4,096 addresses


ACTUAL SHAPE

/23  /23  /23  /23
/23  /23  /23  /23


REQUEST

one aligned /20

Address planning therefore needs to track:

  • total remaining capacity
  • the largest contiguous free block
  • alignment of the free ranges
  • whether related ranges can grow into adjacent space

Leaving deliberate gaps can be better than packing the first version tightly:

application-a  /22
reserved-a     /22

application-b  /22
reserved-b     /22

application-c  /22
reserved-c     /22

Each Availability Zone receives adjacent growth space. Planning space is consumed before resource addresses are, but future renumbering may be avoided.

Preserve architectural structure

A good address plan reveals the network architecture.

For example:

10.64.0.0/16
│
├── 10.64.0.0/18       development
├── 10.64.64.0/19      staging
├── 10.64.96.0/19      shared infrastructure
├── 10.64.128.0/18     production
└── 10.64.192.0/18     future use

Every prefix is aligned. Together, the allocations cover the /16 without overlap.

Within production:

10.64.128.0/18
│
├── Availability Zone A
├── Availability Zone B
├── Availability Zone C
└── reserved expansion

The useful hierarchy is:

ORGANISATION POOL
        │
        ▼
REGION
        │
        ▼
ENVIRONMENT OR VPC
        │
        ▼
AVAILABILITY ZONE
        │
        ▼
SUBNET PURPOSE

Amazon VPC IP Address Manager can organise address space into pools, allocate CIDRs and monitor utilisation, overlap and compliance.

IPAM can manage allocation. Architecture still decides why a particular /22 belongs in a particular place.

Summarisation is subnetting in reverse

Suppose these four prefixes have been allocated:

10.64.96.0/20
10.64.112.0/20
10.64.128.0/20
10.64.144.0/20

They are contiguous and contain:

4 × 4,096 = 16,384 addresses

That quantity corresponds to a /18.

However, a /18 advances by 64 in the third octet:

0
64
128
192

96 is not a valid /18 boundary. The four blocks cannot be represented by one /18 without including addresses outside the set.

Now consider:

10.64.128.0/20
10.64.144.0/20
10.64.160.0/20
10.64.176.0/20

These begin at 128, a valid /18 boundary, and cover:

10.64.128.0 - 10.64.191.255

They can be summarised as:

10.64.128.0/18

Size is not enough. Boundary alignment matters.

The traditional host formula has limits

The familiar formula is:

usable hosts = 2^host_bits - 2

It removes the all-zero host position used as the network identifier and the all-one position traditionally used as the directed broadcast address.

For a /26:

2^6 - 2 = 62

This remains useful for ordinary IPv4 LAN reasoning, but it is not universal.

A /31 can use both addresses on supported point-to-point links. RFC 3021 defines this special use to avoid spending four addresses on a link that needs two endpoints. A /32 identifies one address.

AWS VPC subnets use their own five-address reservation rule and support IPv4 subnet prefixes only from /28 to /16.

Keep the calculations separate:

RAW CIDR CAPACITY

2^host_bits

and:

PLATFORM-ASSIGNABLE CAPACITY

raw capacity
minus platform reservations

The binary calculation stays stable while the platform applies its operating rules.

Tools should verify the model

I still use:

  • subnet calculators
  • Python’s ipaddress module
  • Terraform or OpenTofu functions
  • IPAM
  • cloud-platform validation
  • automated overlap checks

The difference is what I expect from them.

Weak workflow:

enter address
copy answer
hope the input represented
what I intended

Stronger workflow:

estimate answer
run tool
compare result
investigate disagreement

A small Python check is:

from ipaddress import IPv4Network

network = IPv4Network("172.20.44.173/20", strict=False)

print(f"Network: {network.network_address}")
print(f"Final:   {network.broadcast_address}")
print(f"Count:   {network.num_addresses}")
print(f"Prefix:  /{network.prefixlen}")

Expected output:

Network: 172.20.32.0
Final:   172.20.47.255
Count:   4096
Prefix:  /20

strict=False accepts an address with host bits and returns its canonical network. The tool confirms the reasoning rather than replacing it.

A repeatable method

When I need to choose and place a subnet:

1. Count workload demand

Include:

  • current resources
  • scaling and failover
  • rolling replacement
  • service interfaces
  • expected growth

2. Apply platform reservations

For an AWS VPC subnet:

required total
= required assignable + 5

3. Round up to the next power of two

smallest 2^h
that is not smaller
than the requirement

4. Convert host bits into a prefix

prefix = 32 - h

5. Find the mask and increment

Derive the partial mask octet from binary place values:

increment = 256 - partial mask value

6. Choose an aligned boundary

The interesting octet must be a multiple of the increment.

7. Find the range

Move forward by one increment to find the next boundary, then step back by one address to find the final position.

8. Check the architecture

Verify that the complete range:

  • fits inside its parent
  • does not overlap another allocation
  • leaves useful contiguous growth space
  • supports the required Availability Zones

9. Verify independently

Use a calculator, code, IPAM or platform validation and investigate any disagreement.

REQUIREMENT
    │
    ▼
PLATFORM RULES
    │
    ▼
POWER OF TWO
    │
    ▼
HOST BITS
    │
    ▼
PREFIX
    │
    ▼
ALIGNED RANGE
    │
    ▼
ARCHITECTURAL ALLOCATION

The design checklist

Area Question
Demand How many assignable addresses are required?
Platform Which positions does the target platform reserve?
Growth What is needed during scaling, failover and replacement?
Size What is the next power of two above the total requirement?
Boundary Where can a block of that size begin legally?
Parent Does the complete range fit inside its parent allocation?
Overlap Does it intersect any allocated or reserved range?
Fragmentation Does it preserve useful contiguous space?
Availability Does each Availability Zone receive independent capacity?
Summary Can related allocations form meaningful aggregate routes?
Verification Does an independent tool produce the same result?

These questions replace the subnetting recital with a design process.

The mental model

                     ADDRESS REQUIREMENT
                              │
                              ▼
                       PLATFORM RULES
                              │
                              ▼
                   ROUND TO POWER OF TWO
                              │
                              ▼
                         HOST BITS
                              │
                              ▼
                       PREFIX LENGTH
                              │
                 ┌────────────┴────────────┐
                 │                         │
                 ▼                         ▼
            SUBNET MASK               BLOCK SIZE
                 │                         │
                 ▼                         ▼
             INCREMENT               CAPACITY
                 │                         │
                 └────────────┬────────────┘
                              ▼
                     ALIGNED BOUNDARY
                              │
                              ▼
                         CIDR RANGE
                              │
                              ▼
                    NETWORK ARCHITECTURE

The familiar mask values still exist:

192
224
240
248
252

They are not magic. They are binary network bits accumulated from left to right.

The familiar prefixes still exist:

/24
/25
/26
/27
/28

They are eight, seven, six, five and four host bits producing 256, 128, 64, 32 and 16 positions.

Subnetting becomes easier when I stop asking which number I should remember and start asking which boundary the requirement creates.

Count the consumers.

Apply the platform rules.

Round up.

Find the host bits.

Subtract from 32.

Align the range.

Check the architecture.

Then verify the answer with a tool.

The result may still be /26.

This time, it arrived with its paperwork.

References and further reading