All notes

The CIDR arithmetic I actually use

Most day-to-day IPv4 subnetting does not require writing all 32 bits. A small set of calculations covering host bits, address counts, block increments, alignment and AWS reservations is enough to reason confidently about CIDR ranges.

about 16 minutes min read

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