Explained: CIDR

Codelooru cidr

You spin up a VPC in AWS and it asks for a CIDR block. You type 10.0.0.0/16 because that's what the tutorial said. Then you create a subnet and it wants another one, so you put 10.0.1.0/24. It works. You move on.

Six months later somebody asks why the subnet can only hold 251 usable addresses when you asked for 256, and whether 10.0.1.0/24 overlaps with the 10.0.0.0/22 block the networking team just allocated. You don't know. Nobody does. Everyone quietly opens a subnet calculator.

The slash number is not arbitrary syntax. It encodes exactly how the address space is carved up, and once you can read it directly you stop needing the calculator.


Before CIDR: the class system

An IPv4 address is 32 bits. Written as four decimal numbers separated by dots, each number represents one byte: 192.168.1.10 is really 11000000.10101000.00000001.00001010.

Some of those bits identify the network. The rest identify a specific host inside that network. Routers care only about the network portion, which is what lets them forward a packet toward the right general destination without knowing about every individual machine on the internet.

The question is where the boundary between the two sits. In 1981, the answer was baked into the address itself. This was classful addressing, defined in RFC 791, and it recognized three usable classes.

  • Class A: first bit is 0. The first byte is the network, the remaining three are hosts. 128 networks on paper, each holding roughly 16.7 million addresses. Range 0.0.0.0 to 127.255.255.255.
  • Class B: first two bits are 10. Two bytes network, two bytes host. 16,384 networks of 65,536 addresses. Range 128.0.0.0 to 191.255.255.255.
  • Class C: first three bits are 110. Three bytes network, one byte host. Roughly 2 million networks of 256 addresses. Range 192.0.0.0 to 223.255.255.255.

Two of those 128 Class A networks were never assignable. 0.0.0.0/8 was reserved to mean "this network" and 127.0.0.0/8 was reserved for loopback, which is why 127.0.0.1 resolves to your own machine. That left 126 usable Class A allocations for the entire world, and organizations that received one in the early 1980s (IBM, Ford, MIT, the US Postal Service) held blocks of 16.7 million addresses each.

Class D (224.0.0.0 onward) was reserved for multicast and Class E for experimental use. Neither was allocated to organizations.

The elegance was that a router could determine the network boundary by inspecting the leading bits of the address. No extra information needed to travel alongside it. In an era of expensive memory and slow processors, that mattered.

Classful addressing: fixed network/host boundaries CLASS A network (8 bits) host (24 bits) - 16.7M addresses CLASS B network (16 bits) host (16 bits) - 65,536 addresses CLASS C network (24 bits) host (8 bits) - 256 bit 0 bit 16 bit 31 Only three sizes available. Need 500 addresses? Class C is too small, Class B wastes 65,000. The leading bits of the address determined the class, so no extra routing information was needed.

Why the class system broke

The problem is visible the moment you write the three sizes next to each other. You could have 256 addresses, 65,536 addresses, or 16.7 million addresses. Nothing in between.

A university with 800 machines could not use a Class C. So it received a Class B and used a little over 1 percent of it. The other 64,700 addresses were allocated, unusable by anyone else, and permanently idle.

This was address exhaustion, and by 1992 the projections were alarming. Class B space was on track to run out within a couple of years. The internet had roughly 1.3 million connected hosts and was doubling annually.

A second problem was growing alongside it. Every Class C network needed its own entry in the global routing table, because there was no way to express "these 16 adjacent Class C networks all go the same direction." Backbone routers were accumulating tens of thousands of routes with no mechanism for compression. Router memory and lookup time were becoming the binding constraint on internet growth.

Two exhaustion problems, then: addresses running out, and routing tables growing faster than hardware could handle. Both traced back to the same cause, which was that the network/host boundary was fixed at three arbitrary positions.


The fix: move the boundary anywhere

CIDR, Classless Inter-Domain Routing, was specified in RFC 1518 and RFC 1519 in September 1993. The core idea is a single sentence: stop deriving the network boundary from the address, and carry it explicitly instead.

That explicit value is the prefix length, written after a slash. 192.168.1.0/24 means the first 24 bits are the network portion. 10.0.0.0/8 means the first 8 bits are. 203.0.113.64/26 means the first 26, which is a boundary that falls in the middle of the fourth byte and would have been unrepresentable under the class system.

The prefix length can be any value from 0 to 32. That gives 33 possible block sizes instead of 3, each one exactly half the size of the one before it.

Everything else follows mechanically. Host bits are whatever remains: 32 - prefix. The block size is 2^host_bits. A /26 has 6 host bits and therefore 64 addresses. A /30 has 2 host bits and 4 addresses.

CIDR: the boundary moves to wherever you need it 192.168.1.10 = 11000000 10101000 00000001 00001010 /16 network: 192.168 host: 16 bits = 65,536 addresses /24 network: 192.168.1 host: 8 bits = 256 /26 network: 26 bits (boundary inside the last byte) 64 bit 0 bit 31 Each additional prefix bit halves the block. 33 possible sizes instead of 3. The prefix length travels with the address because it can no longer be inferred from it.

Reading a block without a calculator

Three numbers describe any CIDR block, and all three come from the prefix length alone.

Total addresses is 2^(32-prefix). Usable addresses is that minus two, because the first address in the block is the network address (it names the network itself) and the last is the broadcast address (packets sent to it reach every host on the segment).

The subnet mask is the prefix written as a 32-bit number with all the network bits set to 1 and all the host bits set to 0. A /24 is 24 ones followed by 8 zeros, which in dotted decimal is 255.255.255.0.

PrefixMaskAddressesUsableTypical use
/8255.0.0.016,777,21616,777,214Entire private range 10.0.0.0/8
/16255.255.0.065,53665,534A whole VPC
/20255.255.240.04,0964,094Large subnet
/24255.255.255.0256254Standard subnet or office LAN
/26255.255.255.1926462Small subnet tier
/30255.255.255.25242Point-to-point link
/31255.255.255.25422Point-to-point (RFC 3021)
/32255.255.255.25511Single host, firewall rules

The /31 is a special case. A point-to-point link has exactly two endpoints and no need for a broadcast address, so RFC 3021 permits using both addresses in a /31 as hosts. Without it, every link between two routers would waste half a /30.

The /32 is the other useful extreme. It matches exactly one address, which makes it the standard way to express a single host in firewall rules and route tables. When you see 203.0.113.7/32 in a security group, it means that one machine and nothing else.


Where blocks can start

A CIDR block cannot begin at an arbitrary address. It must start on a boundary that is a multiple of its own size.

A /24 holds 256 addresses, so it must start at a multiple of 256 in the last byte: 10.0.0.0, 10.0.1.0, 10.0.2.0. A /26 holds 64, so within a single /24 the only valid starting points are .0, .64, .128, and .192.

Writing 192.168.1.100/26 is malformed. The block would run from .100 to .163, crossing the .128 boundary, and the prefix bits would no longer uniquely identify the network. Most tools will silently correct it to 192.168.1.64/26 or reject it outright.

The reason is that routing decisions are made with a bitwise AND. A router takes the destination address, ANDs it with the mask, and compares the result to the network address. That only works if the host bits in the network address are all zero, which is exactly what alignment guarantees.

Subdividing 192.168.1.0/24 into four /26 blocks 192.168.1.0/24 - 256 addresses (.0 through .255) 192.168.1.0/26 .0 - .63 192.168.1.64/26 .64 - .127 192.168.1.128/26 .128 - .191 192.168.1.192/26 .192 - .255 INVALID 192.168.1.100/26 would span .100 to .163, crossing the .128 boundary A block must start at a multiple of its own size Alignment guarantees all host bits in the network address are zero, which is what makes the router's bitwise AND against the mask produce a correct match.

Route aggregation

The other half of CIDR's value has nothing to do with allocation efficiency. It is about keeping the global routing table survivable.

Consider four adjacent networks: 203.0.112.0/24, 203.0.113.0/24, 203.0.114.0/24, and 203.0.115.0/24. Under classful routing these are four separate Class C networks and require four routing table entries, even if every packet for all four leaves through the same router.

With CIDR, if the four blocks are adjacent and aligned, they can be advertised as a single 203.0.112.0/22. One entry replaces four. This is route aggregation, sometimes called route summarization or supernetting.

The effect compounds. An ISP holding a /16 can hand out hundreds of customer subnets internally while advertising exactly one prefix to the rest of the internet. The outside world does not need to know or care how the space is divided inside.

This is why CIDR allocations follow geography and provider hierarchy rather than being handed out first-come-first-served. Aggregation only works when the blocks that belong together are numerically adjacent. Regional registries allocate contiguous ranges to providers specifically so those providers can summarize.

Four routes become one CUSTOMER NETWORKS 203.0.112.0/24 203.0.113.0/24 203.0.114.0/24 203.0.115.0/24 ISP edge router advertises 203.0.112.0/22 one entry in the global table Aggregation only works when blocks are numerically adjacent and aligned, which is why registries allocate contiguous ranges.

Longest prefix match

Aggregation creates an obvious question. If a router holds both 203.0.112.0/22 and a more specific 203.0.113.0/24, and a packet arrives for 203.0.113.50, both entries match. Which one wins?

The rule is longest prefix match: the entry with the most network bits takes priority. The /24 beats the /22 because 24 is more specific than 22.

This is the mechanism behind almost every routing behavior you encounter. The default route 0.0.0.0/0 matches every possible address with zero prefix bits, which makes it the least specific entry and therefore the last resort. Anything more specific overrides it.

It is also how traffic engineering works in practice. An organization advertising a /20 to two providers can advertise a more specific /24 out of that range to just one of them, and traffic for that /24 will prefer that path everywhere on the internet. Deaggregation for the sake of steering traffic is common, and it is also a significant contributor to routing table growth.


Where you meet CIDR

Cloud networking is the most common encounter. A VPC is defined by a CIDR block, usually a /16 from private space, and subnets carve it into smaller aligned pieces. Cloud providers reserve extra addresses inside each subnet: AWS takes five per subnet rather than two, which is why a /24 subnet gives you 251 usable addresses instead of 254.

Firewall and security group rules use CIDR notation for source and destination ranges. 0.0.0.0/0 means the entire internet, which is why seeing it on an SSH ingress rule is an incident. A single host is /32. An office range might be 198.51.100.0/24.

The private address ranges defined in RFC 1918 are themselves CIDR blocks: 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16. The middle one is a good demonstration of why classless allocation matters, since a /12 covers 172.16.x.x through 172.31.x.x and has no classful equivalent at all.

Kubernetes uses CIDR blocks for pod and service networks, and network policies express allowed traffic in CIDR terms. Container runtimes allocate per-node pod ranges by subdividing a cluster-wide block.

IPv6 uses the same notation with a 128-bit address space. Prefix lengths run from 0 to 128, a typical end-site allocation is a /48, and a single LAN segment is conventionally a /64. The classful era left no residue in IPv6; it was classless from the start.


Summary

CIDR's real contribution was not a new notation. It was recognizing that the network/host boundary is an allocation decision, not a property of the address, and that fixing it in the address format meant every allocation had to be rounded up to one of three sizes.

Making the boundary explicit solved both crises at once. Variable prefix lengths meant an organization needing 500 addresses could receive a /23 instead of wasting a Class B, which slowed address exhaustion enough to buy the roughly thirty years it has taken IPv6 to reach meaningful deployment. Hierarchical, aggregatable allocation meant routing table growth could be decoupled from the number of connected networks, which is the only reason backbone routers remained buildable as the internet scaled.

Once the slash number stops being a magic value and becomes what it actually is, a count of fixed leading bits, everything downstream follows: the block size, the valid starting addresses, the mask, and which route wins when several match.


Part of the Explained series: concepts in tech, clearly.



×