CIDR and Subnetting Explained, With Worked Examples

By , founder of Softaware Commerce · Published · Updated

Drafted with AI assistance. Every command and code example was run and its output checked before publication. How guides are made

CIDR notation writes an IPv4 network as an address, a slash and a prefix length, such as 192.168.10.0/24: the prefix is the number of leading bits that every address in the block shares, and the remaining 32 − prefix bits number the hosts. A /24 therefore holds 28 = 256 addresses, of which 254 are usable because the first (network) and last (broadcast) are reserved. To find the network an address belongs to, keep its first prefix bits and set the rest to 0; set them to 1 instead to get the broadcast address.

What does the number after the slash mean?

An IPv4 address is a 32-bit number, written as four 8-bit octets in decimal. In 172.16.45.200/20, the /20 says the first 20 bits identify the network and the last 12 identify a host within it. Classless Inter-Domain Routing was introduced to replace the old class A, B and C networks, which allowed only 8-, 16- and 24-bit boundaries; it is specified in RFC 4632. Any prefix from /0 (every IPv4 address) to /32 (one address) is valid.

Two rules follow directly:

  • A block of prefix n contains 232−n addresses. Each extra bit halves the block; each bit fewer doubles it.
  • A block always starts on a multiple of its own size. A /26 (64 addresses) can start at .0, .64, .128 or .192, never at .32.

How do I convert a subnet mask to a prefix length, and back?

A subnet mask is the prefix written as an address: the first n bits are 1 and the rest 0. /20 is 11111111.11111111.11110000.00000000, which is 255.255.240.0. To go the other way, count the 1 bits: every 255 is 8, and the last non-zero octet adds the number of leading ones in it.

Octet value128192224240248252254255
Binary1000000011000000111000001111000011111000111111001111111011111111
Bits added12345678

So 255.255.255.192 is 8 + 8 + 8 + 2 = /26. These eight are the only values a mask octet can take, and the ones must be contiguous: 255.0.255.0 is not a valid mask, and Python's ipaddress rejects it. The wildcard mask used in Cisco access lists and OSPF is the bitwise inverse: /20 becomes 0.0.15.255.

Worked example: calculating a subnet in binary

Take the host address 172.16.45.200/20. Write the address and mask in binary and line them up:

Address    172.16.45.200   10101100.00010000.0010|1101.11001000
Mask       255.255.240.0   11111111.11111111.1111|0000.00000000
                                                 ^ bit 20

The first two octets lie entirely inside the prefix, and the fourth entirely outside it, so only the third octet needs real work: 45 is 00101101.

  1. Network address: AND the address with the mask, which keeps the first 20 bits and zeroes the rest. In the third octet, 00101101 AND 11110000 = 00100000, which is 32. The fourth octet becomes 0. Network: 172.16.32.0.
  2. Broadcast address: set all 12 host bits to 1. In the third octet, 0010 followed by 1111 is 00101111 = 47; the fourth octet becomes 255. Broadcast: 172.16.47.255.
  3. Block size: 212 = 4,096 addresses. As a shortcut, the block size in the "interesting" octet is 256 − 240 = 16, and the network is the largest multiple of 16 not above 45, which is 32.
  4. Usable hosts: 4,096 − 2 = 4,094, from 172.16.32.1 to 172.16.47.254.

The same result in Python's ipaddress module:

import ipaddress

net = ipaddress.ip_network("172.16.45.200/20", strict=False)
net                      # IPv4Network('172.16.32.0/20')
net.network_address      # IPv4Address('172.16.32.0')
net.broadcast_address    # IPv4Address('172.16.47.255')
net.netmask              # IPv4Address('255.255.240.0')
net.num_addresses        # 4096

Without strict=False, Python raises ValueError: 172.16.45.200/20 has host bits set, because a network must be given by its network address. In JavaScript the same arithmetic needs >>> 0 to keep results unsigned, because bitwise operators work on signed 32-bit integers:

const toInt = ip => ip.split(".").reduce((n, o) => n * 256 + Number(o), 0);
const toIp = n => [24, 16, 8, 0].map(s => (n >>> s) & 255).join(".");

function cidr(input) {
  const [ip, len] = input.split("/");
  const prefix = Number(len);
  const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
  const network = (toInt(ip) & mask) >>> 0;
  const broadcast = (network | ~mask) >>> 0;
  return { network: toIp(network), broadcast: toIp(broadcast), mask: toIp(mask) };
}

cidr("172.16.45.200/20");
// { network: '172.16.32.0', broadcast: '172.16.47.255', mask: '255.255.240.0' }

The special case for /0 matters: JavaScript takes shift counts modulo 32, so 0xffffffff << 32 shifts by nothing. The CIDR / Subnet Calculator uses this same approach, adds input validation, and also shows the wildcard mask, first and last usable host and address counts. To see addresses and masks bit by bit, convert each octet in the Number Base Converter.

How do I split a /24 into four /26 subnets?

Borrow bits from the host part. Going from /24 to /26 borrows 2 bits, which gives 22 = 4 subnets, each with 26 = 64 addresses. The subnets start at every multiple of 64:

SubnetNetworkFirst hostLast hostBroadcastUsable
192.168.10.0/26192.168.10.0192.168.10.1192.168.10.62192.168.10.6362
192.168.10.64/26192.168.10.64192.168.10.65192.168.10.126192.168.10.12762
192.168.10.128/26192.168.10.128192.168.10.129192.168.10.190192.168.10.19162
192.168.10.192/26192.168.10.192192.168.10.193192.168.10.254192.168.10.25562

Splitting costs addresses: one /24 has 254 usable hosts, but four /26s have 4 × 62 = 248, because each subnet reserves its own network and broadcast address. Subnets do not all have to be the same size. You can split 192.168.10.0/24 into one /25 (.0–.127) and two /26s (.128 and .192), as long as each block starts on a multiple of its size. Allocate the largest blocks first to avoid gaps.

list(ipaddress.ip_network("192.168.10.0/24").subnets(new_prefix=26))
# [IPv4Network('192.168.10.0/26'), IPv4Network('192.168.10.64/26'),
#  IPv4Network('192.168.10.128/26'), IPv4Network('192.168.10.192/26')]

What is supernetting (route aggregation)?

Supernetting is the reverse: combining adjacent blocks into one shorter prefix, so that a routing table or firewall rule needs one entry instead of several. Four consecutive /24s starting on a multiple of four merge into a /22:

nets = [ipaddress.ip_network(n) for n in
        ["10.1.0.0/24", "10.1.1.0/24", "10.1.2.0/24", "10.1.3.0/24"]]
list(ipaddress.collapse_addresses(nets))
# [IPv4Network('10.1.0.0/22')]

Alignment is essential. 10.1.1.0/24 and 10.1.2.0/24 are adjacent but cannot form a /23, because a /23 must start at an even third octet; collapse_addresses returns them unchanged. Summarising them as 10.1.0.0/22 would also cover 10.1.0.0/24 and 10.1.3.0/24, which may belong to someone else.

Which ranges are private, and which are special?

BlockRangeAddressesPurpose
10.0.0.0/810.0.0.0 – 10.255.255.25516,777,216Private (RFC 1918)
172.16.0.0/12172.16.0.0 – 172.31.255.2551,048,576Private (RFC 1918)
192.168.0.0/16192.168.0.0 – 192.168.255.25565,536Private (RFC 1918)
100.64.0.0/10100.64.0.0 – 100.127.255.2554,194,304Carrier-grade NAT shared space (RFC 6598)
169.254.0.0/16169.254.0.0 – 169.254.255.25565,536Link-local, self-assigned (RFC 3927)
127.0.0.0/8127.0.0.0 – 127.255.255.25516,777,216Loopback
192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24–256 eachDocumentation examples (RFC 5737)

A frequent slip is assuming all of 172.x is private: only 172.16 to 172.31 are. 172.32.0.1 is a public address. The full list of special-purpose blocks is maintained in the IANA registry described by RFC 6890.

What about /31 and /32?

The "minus two" rule breaks down at the smallest sizes. A /30 has 4 addresses and 2 usable hosts, the traditional choice for a point-to-point link. RFC 3021 allows a /31 on point-to-point links: it has 2 addresses, no network or broadcast address, and both ends use one address each, which halves the address space spent on links. Not every device supports it, so check before relying on it. A /32 is a single address; it appears in host routes, firewall rules and cloud security groups to mean "exactly this machine". Python's hosts() follows the same rules: it yields both addresses of a /31 and the single address of a /32.

Prefix reference table: /8 to /32

Every row was generated with Python's ipaddress module and matches the calculator's output. "Usable" is total minus 2, except for /31 and /32.

PrefixSubnet maskWildcardAddressesUsable hosts
/8255.0.0.00.255.255.25516,777,21616,777,214
/9255.128.0.00.127.255.2558,388,6088,388,606
/10255.192.0.00.63.255.2554,194,3044,194,302
/11255.224.0.00.31.255.2552,097,1522,097,150
/12255.240.0.00.15.255.2551,048,5761,048,574
/13255.248.0.00.7.255.255524,288524,286
/14255.252.0.00.3.255.255262,144262,142
/15255.254.0.00.1.255.255131,072131,070
/16255.255.0.00.0.255.25565,53665,534
/17255.255.128.00.0.127.25532,76832,766
/18255.255.192.00.0.63.25516,38416,382
/19255.255.224.00.0.31.2558,1928,190
/20255.255.240.00.0.15.2554,0964,094
/21255.255.248.00.0.7.2552,0482,046
/22255.255.252.00.0.3.2551,0241,022
/23255.255.254.00.0.1.255512510
/24255.255.255.00.0.0.255256254
/25255.255.255.1280.0.0.127128126
/26255.255.255.1920.0.0.636462
/27255.255.255.2240.0.0.313230
/28255.255.255.2400.0.0.151614
/29255.255.255.2480.0.0.786
/30255.255.255.2520.0.0.342
/31255.255.255.2540.0.0.122 (RFC 3021)
/32255.255.255.2550.0.0.011

Common subnetting mistakes

  • Host bits in a network definition. 192.168.10.77/26 is a host, not a network; the network is 192.168.10.64/26. Some tools silently mask it, others reject it.
  • Misaligned blocks. 10.0.0.32/26 is not a /26 network: 32 is not a multiple of 64. It masks to 10.0.0.0/26.
  • Counting total instead of usable addresses, or forgetting that every subnet loses two. Cloud providers reserve additional addresses in each subnet, so check your provider's documentation for the exact number.
  • Overlapping ranges. Two VPCs or sites with overlapping blocks cannot be peered or routed to each other cleanly. ipaddress.ip_network("10.0.0.0/16").overlaps(ipaddress.ip_network("10.0.128.0/17")) returns True.
  • Swapping mask and wildcard. In a Cisco ACL the wildcard for a /24 is 0.0.0.255; writing the subnet mask 255.255.255.0 there matches a completely different set of addresses.
  • Leading zeros. Some parsers, including C's inet_aton, read 010 as octal 8; write octets without leading zeros. The calculator rejects them.

Checklist

  • Addresses in a block: 232 − prefix; usable hosts: that minus 2 (except /31 and /32).
  • Network address: host bits all 0. Broadcast: host bits all 1.
  • Every block starts on a multiple of its size.
  • One more prefix bit halves the block; one fewer doubles it.
  • Private ranges: 10/8, 172.16/12, 192.168/16.
  • Check new ranges for overlap with every network you may need to reach.

Frequently asked questions

How many usable hosts are in a /24?

254. A /24 has 256 addresses; the first is the network address and the last the broadcast address, and neither can be assigned to a host on a normal LAN.

Is a smaller prefix number a bigger network?

Yes. The prefix counts fixed bits, so fewer fixed bits leave more host bits. A /16 holds 65,536 addresses; a /28 holds 16.

How do I check whether an IP address is inside a CIDR block?

Mask the address with the block's prefix and compare the result with the network address. In Python, ipaddress.ip_address("192.168.10.70") in ipaddress.ip_network("192.168.10.64/26") returns True. The CIDR calculator shows a block's first and last address so you can check by eye.

What does 0.0.0.0/0 mean?

Every IPv4 address: the prefix fixes no bits at all. In a routing table it is the default route; in a firewall rule it means "from or to anywhere", so treat inbound rules with it carefully.

Does CIDR work the same way for IPv6?

The notation and arithmetic are the same, but addresses are 128 bits and IPv6 has no broadcast address. Ordinary LAN subnets are /64, so host counts are rarely the constraint; the calculator on this site handles IPv4 only.

Tools for this guide