All writing

IPv4 from binary to CIDR

IPv4 subnetting becomes easier to reason about when addresses, masks and prefixes are understood as 32-bit binary values. This article builds from binary place values to CIDR ranges, subnet allocation, route aggregation and AWS VPC sizing.

about 25 minutes min read

I can enter an IPv4 address and prefix into a subnet calculator.

It will immediately tell me:

  • the subnet mask
  • the network address
  • the final address
  • the traditional host range
  • the number of addresses

That is useful.

It is also easy to mistake the output for understanding.

Input:

192.0.2.130/26


Output:

Network:      192.0.2.128
Final:        192.0.2.191
Host range:   192.0.2.129 - 192.0.2.190
Mask:         255.255.255.192

The calculator has answered the immediate question.

It has not explained why the network begins at .128, why the block ends at .191, or why the next block begins at .192.

Without that model, CIDR becomes a collection of remembered fragments:

/24 means 256 addresses

/26 means 64 addresses

/28 means 16 addresses

That works until I meet:

10.42.77.19/20

or need to divide:

10.64.0.0/16

across environments, Availability Zones and subnet purposes.

Then the memorised table starts shedding screws.

The underlying model is much smaller than the collection of shortcuts.

An IPv4 address is a 32-bit value.

A prefix length says how many leading bits remain fixed as the network boundary.

The remaining bits vary through positions inside that block.

Subnetting is not primarily decimal arithmetic. It is binary boundary management displayed in decimal clothing.

Once the binary structure is visible, the decimal ranges stop looking arbitrary.

IPv4 is one 32-bit value

An IPv4 address contains 32 binary digits.

Each digit is either:

0

or:

1

The bits are normally displayed as four groups of eight.

Each group is an octet.

8 bits      8 bits      8 bits      8 bits

xxxxxxxx . xxxxxxxx . xxxxxxxx . xxxxxxxx

The familiar address:

192.0.2.130

is the dotted-decimal display of:

11000000.00000000.00000010.10000010

The dots improve readability.

They are not extra information carried in the address.

A 32-bit address space contains:

2^32 = 4,294,967,296

possible bit patterns.

Not every pattern is available as an ordinary public host address. Some blocks are private, loopback, link-local, multicast, documentation or otherwise special purpose.

For the arithmetic, the starting point is:

IPv4 address = 32 bits

Each octet ranges from 0 to 255

An octet has eight bit positions.

place value:  128   64   32   16    8    4    2    1

These are powers of two:

2^7  2^6  2^5  2^4  2^3  2^2  2^1  2^0

A 1 contributes its place value.

A 0 contributes nothing.

11000000

128 + 64 = 192
10000010

128 + 2 = 130

Therefore:

192 = 11000000

  0 = 00000000

  2 = 00000010

130 = 10000010

The largest octet is:

11111111

128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= 255

The smallest is:

00000000 = 0

That is why each dotted-decimal component ranges from 0 to 255.

It is not an IPv4 convention selected from a hat.

It is the complete numeric range of eight bits.

Converting decimal to binary

To convert a decimal octet, subtract the largest place value that fits and continue to the right.

Convert:

172
172 - 128 = 44

64 does not fit

44 - 32 = 12

16 does not fit

12 - 8 = 4

4 - 4 = 0

Lay the result over the positions:

place value:  128   64   32   16    8    4    2    1
bit:            1    0    1    0    1    1    0    0

Therefore:

172 = 10101100

For 19:

16 + 2 + 1 = 19

19 = 00010011

The leading zeros matter.

An octet is always eight bits:

2 = 00000010

The fixed width preserves its position inside the complete address.

The prefix draws the boundary

An address by itself does not identify its surrounding network.

10.42.77.19

could belong to:

10.0.0.0/8
10.42.0.0/16
10.42.64.0/18
10.42.77.0/24
10.42.77.16/28

The address has not changed.

The boundary has.

A prefix length says how many of the 32 leading bits describe the network.

network bits + variable bits = 32

For /24:

24 fixed network bits
8 variable bits

For /20:

20 fixed network bits
12 variable bits

For /28:

28 fixed network bits
4 variable bits

The variable bits identify every position inside the block.

This is the central arithmetic of CIDR.

The mask is the boundary written as bits

A subnet mask is another 32-bit value.

Network bits are 1.

Variable bits are 0.

For /24:

11111111.11111111.11111111.00000000

255.255.255.0

For /16:

11111111.11111111.00000000.00000000

255.255.0.0

For /26:

11111111.11111111.11111111.11000000

The final mask octet is:

128 + 64 = 192

Therefore:

/26 = 255.255.255.192

A normal CIDR mask contains one uninterrupted run of 1 bits followed by one uninterrupted run of 0 bits.

valid:

11111111.11111111.11110000.00000000
not a CIDR prefix mask:

11111111.11101111.11110000.00000000

The prefix length is simply the number of leading 1 bits.

255.255.240.0

11111111.11111111.11110000.00000000

Count them:

8 + 8 + 4 = 20

Therefore:

255.255.240.0 = /20

CIDR notation compresses the mask into one number.

CIDR replaced fixed class boundaries

Early IPv4 addressing used fixed classes.

The familiar historical associations were approximately:

Class A  /8

Class B  /16

Class C  /24

Those fixed sizes allocated address space in coarse chunks.

Classless Inter-Domain Routing allowed prefixes to be allocated and advertised at arbitrary bit boundaries. It improved address allocation and supported route aggregation.

Today:

10.20.0.0/17

is simply a /17 block.

Calling it a partial Class B network adds no useful architectural information.

Classful terminology still appears in old documentation and shorthand.

It should not be the basis of a new address plan.

The prefix is the boundary.

Prefix length determines raw block capacity

For prefix length p:

variable bits = 32 - p

The number of positions in the block is:

2^(32 - p)

For /24:

2^8 = 256

For /26:

2^6 = 64

For /20:

2^12 = 4,096

Increasing the prefix by one fixes one more bit.

The block halves.

/24 = 256
/25 = 128
/26 = 64
/27 = 32
/28 = 16
/29 = 8
/30 = 4
/31 = 2
/32 = 1

Decreasing the prefix by one doubles the block.

/24 = 256
/23 = 512
/22 = 1,024
/21 = 2,048
/20 = 4,096

A useful table is:

Prefix Mask Raw positions
/16 255.255.0.0 65,536
/20 255.255.240.0 4,096
/22 255.255.252.0 1,024
/24 255.255.255.0 256
/25 255.255.255.128 128
/26 255.255.255.192 64
/27 255.255.255.224 32
/28 255.255.255.240 16
/29 255.255.255.248 8
/30 255.255.255.252 4
/31 255.255.255.254 2
/32 255.255.255.255 1

The table is useful once the formula underneath it is understood.

Read one complete CIDR block

Consider:

192.0.2.130/26

The first three octets are entirely inside the fixed prefix.

The interesting work occurs in the final octet.

address:

130 = 10000010


mask:

192 = 11000000

Apply binary AND:

10000010
11000000
--------
10000000
10000000 = 128

The canonical network is:

192.0.2.128/26

The mask preserved the fixed bits and set every variable bit to zero.

Find the final address

A /26 has six variable bits.

The final position uses every variable bit as 1.

network bits | variable bits

10           | 111111

The final octet is:

10111111 = 191

Therefore the raw mathematical block is:

192.0.2.128 - 192.0.2.191

The all-zero variable pattern identifies the first aligned position.

The all-one pattern identifies the final position.

What those positions mean depends on the link and platform.

MATHEMATICAL CIDR BLOCK

192.0.2.128 - 192.0.2.191
64 positions


TRADITIONAL MULTI-ACCESS SUBNET

network:    192.0.2.128
broadcast:  192.0.2.191
hosts:      192.0.2.129 - 192.0.2.190


ORDINARY AWS VPC SUBNET MODEL

first four and final positions reserved
broadcast delivery not supported

The example uses a documentation block, not a proposed AWS subnet. The comparison shows why mathematical capacity and platform capacity must not be confused.

The final address has platform-specific meaning

The all-one variable pattern always identifies the final position in the block.

Its operational meaning varies.

TRADITIONAL LAN

final position is the
directed broadcast address


/31 POINT-TO-POINT LINK

both positions may identify
the two endpoints


/32

the network and final position
are the same address


AWS VPC SUBNET

broadcast delivery is unsupported
and the final position is reserved

Traditional host arithmetic often uses:

2^variable_bits - 2

For /26:

64 - 2 = 62

That is useful for conventional multi-access subnetting.

It is not a universal law for every prefix and platform.

The CIDR prefix range runs from /0 to /32. RFC 3021 separately defines the point-to-point use of /31, where both addresses may represent endpoints.

Use the faster block-increment method

Binary AND explains why the boundary exists.

The block increment is often faster in daily work.

A /26 mask is:

255.255.255.192

The partial mask octet is 192.

increment = 256 - 192 = 64

The boundaries in that octet are:

0
64
128
192

The value 130 lies between 128 and 192.

Therefore:

network:     192.0.2.128
next block:  192.0.2.192
final:       192.0.2.191

The method is:

increment = 256 - partial mask octet

Then find the largest boundary not greater than the address value.

Octet-aligned prefixes need no partial-octet calculation

Prefixes divisible by eight contain no partial mask octet.

For:

10.42.77.19/16

retain the two complete network octets:

10.42

Set every following octet to zero:

10.42.0.0/16

The general branch is:

IS PREFIX A MULTIPLE OF EIGHT?

yes
 │
 ▼
retain complete network octets
set remaining octets to zero


no
 │
 ▼
find partial mask octet
calculate increment
find preceding boundary

For /0, no address bits are fixed and the block is 0.0.0.0/0.

For /32, every bit is fixed and the network and final position are the supplied address.

Non-octet prefixes are where the model earns its keep

Consider:

10.42.77.19/20

The mask is:

11111111.11111111.11110000.00000000

255.255.240.0

The partial octet is the third.

increment = 256 - 240 = 16

The boundaries are:

0
16
32
48
64
80
96
112
128
144
160
176
192
208
224
240

The address has third octet:

77

It lies between:

64 and 80

Therefore:

network:     10.42.64.0/20
next block:  10.42.80.0/20
final:       10.42.79.255

The block contains:

2^(32 - 20)
= 2^12
= 4,096 positions

Binary AND reaches the same result.

77:

01001101


mask octet:

11110000


AND:

01001101
11110000
--------
01000000 = 64

The /20 is no longer a memorised number.

It is a visible binary division.

Subnetting increases the prefix length

Suppose an organisation receives:

10.64.0.0/16

The block contains:

2^16 = 65,536 positions

Divide it into /20 child blocks.

PARENT PREFIX

16 fixed bits
16 variable bits


CHILD PREFIX

20 fixed bits
12 variable bits


PROMOTED INTO CHILD PREFIX

4 bits

This is sometimes described as borrowing four host bits.

In classless terms, four of the parent block’s variable bits become fixed child-prefix bits.

The number of child blocks is:

2^(20 - 16)
= 2^4
= 16

The blocks are:

10.64.0.0/20
10.64.16.0/20
10.64.32.0/20
10.64.48.0/20
10.64.64.0/20
10.64.80.0/20
10.64.96.0/20
10.64.112.0/20
10.64.128.0/20
10.64.144.0/20
10.64.160.0/20
10.64.176.0/20
10.64.192.0/20
10.64.208.0/20
10.64.224.0/20
10.64.240.0/20

Subnetting does not create addresses.

It divides one existing block into more boundaries.

VLSM avoids equal boxes for unequal needs

Not every network needs the same capacity.

A platform may require:

  • large EKS application subnets
  • smaller ingress subnets
  • data subnets
  • interface-endpoint capacity
  • central network services
  • reserved growth space

Variable Length Subnet Masking allows differently sized child blocks to coexist inside one parent.

10.64.0.0/16
     │
     ├── 10.64.0.0/18
     ├── 10.64.64.0/20
     ├── 10.64.80.0/22
     ├── 10.64.84.0/24
     └── remaining space reserved

A practical allocation sequence is:

  1. estimate the largest requirement
  2. choose the smallest prefix with safe headroom
  3. place it on a valid boundary
  4. continue with the next-largest requirement
  5. preserve contiguous space for growth

If a tier needs approximately 700 positions:

/23 = 512

is too small.

/22 = 1,024

may fit.

The platform still needs headroom for service behaviour.

EKS Pods, load balancers, endpoints and managed services all consume addresses.

CIDR arithmetic gives the capacity.

Architecture decides the margin.

Alignment is mandatory

A block must begin on a boundary appropriate to its size.

A /22 has mask:

255.255.252.0

The third-octet increment is:

256 - 252 = 4

Valid third-octet boundaries include:

0
4
8
12
16
20
...
252

This is canonical:

10.64.20.0/22

because:

20 mod 4 = 0

This is not a canonical /22 network:

10.64.22.0/22

It belongs to:

10.64.20.0/22

because:

22 mod 4 = 2

The block spans:

10.64.20.0 - 10.64.23.255

When a VPC or subnet is created through the AWS API or CLI, AWS canonicalises a non-canonical CIDR to the actual network boundary.

Canonicalisation does not make an invalid plan safe.

If the canonical block overlaps an existing subnet, creation fails.

Aggregation reverses the direction

Subnetting divides a larger prefix.

Aggregation represents contiguous smaller prefixes with one larger summary.

Consider:

10.64.0.0/20
10.64.16.0/20
10.64.32.0/20
10.64.48.0/20

Together they cover:

10.64.0.0 - 10.64.63.255

They can be summarised as:

10.64.0.0/18

Four /20 blocks contain:

4 × 4,096 = 16,384 positions

A /18 also contains:

2^14 = 16,384 positions

The child blocks are contiguous, aligned and share the same leading 18 bits.

Aggregation works when allocations are:

  • contiguous
  • correctly aligned
  • exactly covered by the summary
  • intended to receive the same routing treatment

These blocks:

10.64.0.0/20
10.64.32.0/20

cannot safely be advertised as:

10.64.0.0/18

without also claiming the missing ranges.

A summary route that includes addresses owned elsewhere is not simplification.

It is an attractive lie in a routing table.

Private space is still real address space

RFC 1918 reserves:

10.0.0.0/8

172.16.0.0/12

192.168.0.0/16

The middle range is often misremembered as every 172.x.x.x address.

A /12 mask is:

255.240.0.0

The second-octet increment is:

256 - 240 = 16

The block begins at 16 and stops before the next boundary at 32.

Therefore the private range is:

172.16.0.0 - 172.31.255.255

These are not inside it:

172.15.10.20
172.32.10.20

Private addresses are reusable.

That creates overlap risk when independently designed networks later connect.

Private does not mean planning-free.

It means the address is not globally unique.

Special-purpose ranges are not spare capacity

Non-public-looking space is not automatically available for internal assignment.

Special-purpose examples include:

  • loopback
  • link-local
  • multicast
  • shared address space
  • documentation ranges
  • protocol reservations

IANA maintains the authoritative IPv4 Special-Purpose Address Registry, including whether each block is valid as a source or destination, forwardable or globally reachable.

For documentation, use:

192.0.2.0/24

198.51.100.0/24

203.0.113.0/24

An address that does not currently respond to a ping has not volunteered for architecture duty.

Apply the model to AWS VPC subnets

AWS permits standard IPv4 VPC subnet sizes from /16 through /28.

For an ordinary AWS VPC subnet, the first four positions and final position are reserved.

10.0.0.0     network position

10.0.0.1     VPC router

10.0.0.2     DNS-related reservation

10.0.0.3     future use

10.0.0.255   final position

AWS does not support broadcast delivery inside a VPC, but it reserves the final address.

The ordinary calculation is:

addresses available for assignment
to customer resources

= raw positions - 5
Prefix Raw positions Standard AWS-assignable positions
/24 256 251
/26 64 59
/28 16 11

This is a platform rule, not a mathematical property of CIDR.

AWS documents a BYOIP exception in which all addresses in the brought range, including the first and final positions, may be usable.

Subnet CIDR reservations can reduce automatic assignment further, and existing resources may retain addresses even while stopped.

The useful capacity model is:

RAW CIDR POSITIONS

2^(32 - prefix)
        │
        ▼
PLATFORM RESERVATIONS

standard AWS reservation model
        │
        ▼
SERVICE CONSUMPTION

network interfaces
load balancers
NAT gateways
endpoints
EKS nodes and Pods
managed services
        │
        ▼
OPERATIONAL HEADROOM

The binary block size is raw capacity.

The platform and architecture determine how much remains useful.

AWS subnet boundaries are durable

An IPv4 subnet CIDR cannot be changed after the subnet is created.

Changing the boundary requires a replacement subnet and workload migration.

CIDR MATHEMATICS

determines capacity


SERVICE CONSUMPTION

determines headroom


SUBNET IMMUTABILITY

determines the cost
of getting it wrong

Leave growth space around important allocations rather than assuming a live subnet can later be enlarged in place.

A corrected bfstore allocation

Suppose bfstore reserves:

10.64.0.0/16

This is an educational plan rather than a final approved allocation.

A valid top-level division is:

Allocation Prefix Range Raw positions
Development 10.64.0.0/18 10.64.0.0–10.64.63.255 16,384
Staging 10.64.64.0/19 10.64.64.0–10.64.95.255 8,192
Shared infrastructure 10.64.96.0/19 10.64.96.0–10.64.127.255 8,192
Production 10.64.128.0/18 10.64.128.0–10.64.191.255 16,384
Reserved 10.64.192.0/18 10.64.192.0–10.64.255.255 16,384
Total     65,536

Every child is aligned.

The allocations are contiguous and non-overlapping.

A previous proposal such as:

10.64.96.0/18

would not be a valid /18 boundary. It canonicalises to:

10.64.64.0/18

which would overlap the staging range.

The corrected production block begins at the next valid /18 boundary:

10.64.128.0/18

Describe the allocation as a contract

allocation:
  name: bfstore-development
  cidr: 10.64.0.0/18
  owner: platform-networking

capacity:
  raw_positions: 16384
  aws_reserved_per_standard_subnet: 5

structure:
  availability_zones: 3
  subnet_classes:
    - ingress
    - application
    - data
    - endpoints

growth:
  contiguous_space_required: true
  review_trigger: 60_percent_allocated

routing:
  summary: 10.64.0.0/18

overlap:
  checked_against:
    - production
    - corporate-network
    - partner-networks
    - disaster-recovery

Development can then divide its /18 by Availability Zone and subnet purpose.

10.64.0.0/18
      │
      ├── Availability Zone A
      │     ├── ingress
      │     ├── application
      │     ├── data
      │     └── endpoints
      │
      ├── Availability Zone B
      │     ├── ingress
      │     ├── application
      │     ├── data
      │     └── endpoints
      │
      └── Availability Zone C
            ├── ingress
            ├── application
            ├── data
            └── endpoints

Application subnets serving EKS may need more space than ingress or data subnets.

Endpoint density may justify a separate class.

The plan should preserve summaries and contiguous growth where possible.

A CIDR block is not only capacity.

It is an ownership, routing, growth and failure boundary.

A general CIDR-reading procedure

Given:

address/prefix

use this process.

1. Count the variable bits

variable bits = 32 - prefix

2. Calculate raw positions

positions = 2^variable_bits

3. Write the mask

Use one 1 for each prefix bit and one 0 for each variable bit.

Convert each octet to decimal.

4. Check whether the prefix is octet-aligned

If the prefix is divisible by eight:

  • retain the complete network octets
  • set every following octet to zero
  • skip the partial-octet increment

Otherwise, continue with the partial mask octet.

5. Calculate the increment

increment = 256 - partial mask octet

6. Find the preceding boundary

Find the largest multiple of the increment not greater than the address value in that octet.

7. Construct the canonical network

Set every variable bit to zero.

8. Find the final position

Set every variable bit to one.

For the ordinary partial-octet method, this is also one address before the next block.

9. Apply edge semantics

/0

complete IPv4 space


/31

two-position point-to-point use
where supported


/32

one exact address

10. Apply platform rules

Determine:

  • traditional broadcast semantics
  • AWS or other provider reservations
  • BYOIP or platform exceptions
  • subnet CIDR reservations
  • service-specific address consumption
  • boundary immutability

The arithmetic finds the block.

The platform determines how it may be used.

Questions I now ask

Representation

What is the complete
32-bit value?

Prefix

How many leading bits
remain fixed?

Capacity

How many positions
exist in the block?

Boundary

Where does the canonical
network begin?

Final position

Where does the aligned
block end?

Semantics

What do the first and final
positions mean on this platform?

Reservations

How many positions may
resources actually receive?

Alignment

Does the proposed child block
begin on a valid boundary?

Subdivision

How many child prefixes
fit inside the parent?

Aggregation

Can the children be summarised
without claiming another range?

Overlap

Will this allocation conflict
with a connected network?

Growth

Has contiguous space been left
for future expansion?

These questions turn an address into an architectural object.

The mental model I am keeping

My earlier model was:

192.0.2.130/26

four decimal numbers
plus a subnetting suffix

The stronger model is:

                    IPv4 ADDRESS
                         │
                         ▼
                       32 BITS
                         │
             ┌───────────┴───────────┐
             │                       │
             ▼                       ▼
        FIXED PREFIX            VARIABLE BITS
             │                       │
             ▼                       ▼
     CANONICAL NETWORK          RAW CAPACITY
             │                       │
             └───────────┬───────────┘
                         ▼
                    ALIGNED RANGE
                         │
             ┌───────────┼───────────┐
             │           │           │
             ▼           ▼           ▼
        SUBDIVISION   AGGREGATION   PLATFORM RULES
             │           │           │
             └───────────┼───────────┘
                         ▼
                  NETWORK ARCHITECTURE

Binary answers:

Which numeric value does
each bit pattern represent?

The prefix answers:

How many leading bits
remain fixed?

The network address answers:

What is the first position
in this aligned block?

The final address answers:

Where does the block stop
before the next one begins?

Subnetting answers:

How does a larger allocation
become smaller boundaries?

Aggregation answers:

How can related boundaries
be represented by one route?

Platform rules answer:

What do the positions mean,
and how many may be assigned?

CIDR notation is compact because the underlying idea is compact.

address/prefix

The address supplies 32 bits.

The prefix tells us where to draw the line.

To understand an IPv4 block, keep the leading prefix bits fixed and allow the remaining bits to vary through every possible combination.

The all-zero variable pattern gives the canonical network.

The all-one pattern gives the final position.

The number of variable bits gives the raw capacity.

Increasing the prefix creates more, smaller child blocks.

Decreasing it creates fewer, larger blocks.

That is subnetting.

The calculators remain useful.

I will continue using them.

But now they check the arithmetic rather than supply the model.

The /20 is no longer punctuation.

It is twenty fixed bits, twelve changing bits and 4,096 positions waiting to be designed carefully.

References and further reading

  1. RFC 4632: Classless Inter-Domain Routing
  2. RFC 950: Internet Standard Subnetting Procedure
  3. RFC 1878: Variable Length Subnet Table for IPv4
  4. RFC 1918: Address Allocation for Private Internets
  5. RFC 3021: Using 31-Bit Prefixes on IPv4 Point-to-Point Links
  6. RFC 5737: IPv4 Address Blocks Reserved for Documentation
  7. IANA IPv4 Special-Purpose Address Registry
  8. Amazon VPC: Subnet CIDR blocks
  9. Amazon EC2 API: CreateSubnet
  10. AWS Well-Architected: Plan subnet allocation for expansion