Skip to content
Back to Blog
Tutorials

CIDR Notation Explained: Subnet Masks from /8 to /32

A /26 leaves 62 usable hosts, not 64, and on a /31 the minus-two rule breaks. Read any CIDR prefix, do the mask in your head, check it in the calculator.

15 min read

CIDR Notation and Subnet Masks: How to Read /8 Through /32

The number after the slash in 192.168.1.0/24 counts bits, not addresses. It says how many of the 32 bits in an IPv4 address belong to the network; whatever is left over belongs to the hosts. That one sentence is most of what CIDR notation is.

A /24 leaves 8 host bits, so the block holds 2⁸ = 256 addresses. A /26 leaves 6, so it holds 64. Every bit you hand back to the host side doubles the block; every bit you take doubles the number of blocks. The count you can actually assign to devices is normally two lower than the total, because the first address names the network and the last one is the broadcast. A /26 gives you 62 usable hosts, not 64.

Two prefixes break that minus-two rule on purpose, and a wildcard mask is not a subnet mask even though the two get pasted into each other’s fields all the time. If you only want the answer for one block, the subnet calculator prints it; this article is about getting there without one.

What CIDR notation says

A subnet mask is itself a 32-bit number, written the way an address is written. Its bits are a run of 1s followed by a run of 0s. The 1s mark network bits, the 0s mark host bits. Spell a /26 out in full and you get:

11111111.11111111.11111111.11000000
    255  .   255  .   255  .   192

Convert each octet back to decimal and that is 255.255.255.192. CIDR notation counts the leading 1s instead of writing all thirty-two of them out. 192.168.1.0/26 and 192.168.1.0 255.255.255.192 are the same statement in two syntaxes, and which one a device wants depends entirely on the command you are typing.

/8, /16 and /24 land on octet boundaries, so they look tidy in decimal: 255.0.0.0, 255.255.0.0, 255.255.255.0. Nothing about the notation requires that. /22 and /27 are just as valid. They cut through the middle of an octet and produce masks like 255.255.252.0 that look arbitrary right up until you write them in binary.

Before 1993 the leading bits of an address decided its size: class A took a /8, class B a /16, class C a /24, and there was nothing in between. An organisation with 300 hosts had to claim a class B and waste more than 65,000 addresses, or take two class C blocks and carry two routes. CIDR (RFC 1519, later revised as RFC 4632) broke that coupling. The prefix travels with the address, so a block can be any power of two. Classes still turn up in certification exams and in old documentation, but classful routing has been obsolete since CIDR arrived in 1993. The mask decides where a network ends, not the first octet.

The subnet mask cheat sheet, /8 to /32

The last column of this CIDR to subnet mask chart is deliberate: it shows what the generic 2ⁿ − 2 formula produces, which matches the real usable count everywhere except the bottom two rows.

PrefixSubnet maskWildcard maskTotal addressesUsable hostsNaive 2ⁿ − 2 gives
/8255.0.0.00.255.255.255167772161677721416777214
/9255.128.0.00.127.255.255838860883886068388606
/10255.192.0.00.63.255.255419430441943024194302
/11255.224.0.00.31.255.255209715220971502097150
/12255.240.0.00.15.255.255104857610485741048574
/13255.248.0.00.7.255.255524288524286524286
/14255.252.0.00.3.255.255262144262142262142
/15255.254.0.00.1.255.255131072131070131070
/16255.255.0.00.0.255.255655366553465534
/17255.255.128.00.0.127.255327683276632766
/18255.255.192.00.0.63.255163841638216382
/19255.255.224.00.0.31.255819281908190
/20255.255.240.00.0.15.255409640944094
/21255.255.248.00.0.7.255204820462046
/22255.255.252.00.0.3.255102410221022
/23255.255.254.00.0.1.255512510510
/24255.255.255.00.0.0.255256254254
/25255.255.255.1280.0.0.127128126126
/26255.255.255.1920.0.0.63646262
/27255.255.255.2240.0.0.31323030
/28255.255.255.2400.0.0.15161414
/29255.255.255.2480.0.0.7866
/30255.255.255.2520.0.0.3422
/31255.255.255.2540.0.0.1220
/32255.255.255.2550.0.0.011−1

The table is more useful as a set of relationships than as a list of answers. Each row down the table halves the block: /24 holds 256 addresses, /25 holds 128, /26 holds 64. The wildcard column is the subnet mask with every bit flipped, which is why 255.255.255.192 and 0.0.0.63 always appear on the same line. The two bold rows are where the standard formula stops describing reality.

Only the last octet values in the mask column need memorising, because they repeat: 128, 192, 224, 240, 248, 252, 254, 255. Those are the only eight non-trivial byte values a valid mask can end with. If you want to see why, the number base converter prints any of them in binary.

Reading the table backwards: from subnet mask to CIDR

Given a dotted-decimal mask, count the 1 bits. Every 255 contributes 8, and the one interesting octet contributes the rest:

Last mask octet128192224240248252254255
Bits it adds12345678

So 255.255.255.192 is 8 + 8 + 8 + 2 = /26. And 255.255.252.0 is 8 + 8 + 6 + 0 = /22, because 252 in binary is 11111100.

Two consequences follow. Any octet that is neither 255 nor 0 is the boundary octet, and a valid mask can only ever have one of them. The value of that octet also gives you the block size directly.

How to calculate a subnet mask and network by hand

The mechanical method has three steps and works for any prefix. The worked example below uses 192.168.1.130/26, but the point is the procedure, not this address.

Step 1: find the block size

Block size is 256 − the boundary mask octet.

For a /26 the mask is 255.255.255.192, so the block size is 256 − 192 = 64. Subnets of that size sit on multiples of 64 in the fourth octet: 0, 64, 128, 192. There are no other possible starting points.

Block size and address count are the same number, reached from the mask side instead of the bit-count side.

Step 2: find which block the address falls in

Divide the boundary octet of the address by the block size and round down.

The address is 192.168.1.130, the block size is 64, so 130 ÷ 64 = 2.03…, which rounds down to 2. Multiply back: 2 × 64 = 128. The address sits in the block that starts at 128.

Most errors happen here, always in the same direction: people assume the address they were handed is the start of its block, and it usually is not. 192.168.1.130 is a host address living in the third /26 of that /24.

Step 3: network, broadcast, first and last host

The block start is the network address. The broadcast is the block start plus the block size minus one. Everything strictly between them is assignable:

Network    192.168.1.128
Broadcast  192.168.1.191
Usable     192.168.1.129 - 192.168.1.190
Usable     62 (of 64 total)
Netmask    255.255.255.192
Wildcard   0.0.0.63

Broadcast is 128 + 64 − 1 = 191. First host is network + 1, last host is broadcast − 1, and the usable count is 64 − 2 = 62, which is what the /26 row of the cheat sheet says.

Compressed into something you can say to yourself: block size is 256 minus the mask octet; round the address down to a multiple of it; that is your network, and the next block start minus one is your broadcast.

The method is not specific to the fourth octet. For a /22 the mask is 255.255.252.0, so the boundary octet is the third and the block size there is 256 − 252 = 4. Blocks therefore start at 10.0.0.0, 10.0.4.0, 10.0.8.0, and the block 10.0.0.0/22 runs through broadcast 10.0.3.255 with usable addresses 10.0.0.1 to 10.0.3.254 — four consecutive /24s inside one broadcast domain. Same three steps, different octet.

If the binary-to-decimal side of this is where you slow down, the guide to number base conversion covers the conversion itself in more depth than a subnetting article should.

For checking your work in a script rather than in your head, Python’s standard library already knows all of this:

import ipaddress

net = ipaddress.ip_network("192.168.1.130/26", strict=False)

print(net)                     # 192.168.1.128/26
print(net.network_address)     # 192.168.1.128
print(net.broadcast_address)   # 192.168.1.191
print(net.netmask)             # 255.255.255.192
print(net.hostmask)            # 0.0.0.63
print(net.num_addresses)       # 64
print(len(list(net.hosts())))  # 62

strict=False is what lets you pass a host address instead of a network address; with the default strict=True the same call raises ValueError.

Where the minus-two rule stops being true

The subtraction has a reason behind it. In an ordinary subnet the all-zeros host pattern names the network itself and the all-ones host pattern is the directed broadcast address. Neither can be configured on an interface, so a block of 2ⁿ addresses offers 2ⁿ − 2 to hosts. That is why a /24 gives 254 and a /26 gives 62.

The reason is also the limit: when a block is too small to contain those two reserved addresses, subtracting them stops making sense.

A /31 has two addresses and two usable hosts. RFC 3021 defines /31 for point-to-point links. Such a link has exactly two endpoints and no shared segment, so there is nothing for a broadcast address to do and nothing for a network address to identify. Both addresses go to the two ends. Applying 2ⁿ − 2 here returns 0, because the formula assumes a topology this link does not have. The condition attached is real: /31 is valid only on genuinely point-to-point interfaces. A multi-access LAN segment still needs /30 or shorter, and Windows will not accept a /31 on a NIC.

A /32 has one address and one usable host. It is a single host route: loopback interfaces, static routes, anycast addresses, single-address firewall rules. There is no broadcast address, so the formula’s − 2 would return −1.

Python agrees with both:

import ipaddress

p2p = ipaddress.ip_network("203.0.113.4/31")
print([str(h) for h in p2p.hosts()])  # ['203.0.113.4', '203.0.113.5']

host = ipaddress.ip_network("10.0.0.1/32")
print([str(h) for h in host.hosts()])  # ['10.0.0.1']

It is easier to remember this as one rule than as two exceptions: the subtraction removes two specific addresses, so check that they exist before you remove them. A /31 and a /32 have no broadcast address at all, so nothing is removed.

Total, usable, and number of subnets are three different numbers

These three get conflated constantly, and the confusion is understandable because they are all powers of two derived from the same prefix.

  • Total addresses in a /p is 2^(32 − p). A /26: 64.
  • Usable hosts is that minus 2, except for /31 and /32. A /26: 62.
  • Number of subnets you get by splitting a parent /p into children /q is 2^(q − p). Splitting a /24 into /26s borrows two bits, so 2² = 4 subnets.

The three answer different questions, so a sentence like “a /26 gives you 4” is only true if the question was about splitting a /24. Splitting also costs you addresses, because every child subnet reserves its own network and broadcast pair. Four /26s carved out of a /24 hold 4 × 62 = 248 usable addresses against the parent’s 254. Six addresses go to the split itself.

Wildcard mask vs subnet mask: which command wants which

A wildcard mask is the bitwise inverse of the subnet mask. Where the subnet mask has 1s, the wildcard has 0s. Take the /26 row of the cheat sheet: mask 255.255.255.192, wildcard 0.0.0.63. Flip every bit of one and you have the other, so they never appear apart.

The two are used in opposite senses, and that is where people trip. A subnet mask is applied with a bitwise AND, so a 1 bit means “this bit is part of the network”. A wildcard is a match filter, so a 0 bit means “this bit must match” and a 1 bit means “don’t care”. Same underlying operation, opposite polarity. If the bit-level mechanics are fuzzy, the guide to bitwise operations covers AND, OR and NOT in more general terms.

Which one a device wants is not a matter of preference. For the block 192.168.1.128/26:

! wants the subnet mask
ip address 192.168.1.129 255.255.255.192

! wants the wildcard mask
access-list 10 permit 192.168.1.128 0.0.0.63
network 192.168.1.128 0.0.0.63 area 0
! Cisco ASA — wants the subnet mask, unlike IOS ACLs
access-list OUT permit ip 192.168.1.128 255.255.255.192 any
# Linux iproute2 — takes the prefix directly
ip addr add 192.168.1.129/26 dev eth0

Cisco IOS ACLs and OSPF network statements take the wildcard mask; the ASA takes the subnet mask instead. That is one vendor with two conventions in the same product family, and it is the most common copy-paste failure in the area. Other platforms have their own conventions, so before pasting a value into an unfamiliar field, confirm which of the two that field expects.

Paste 255.255.255.192 into an IOS ACL and the router reads it as a wildcard: three octets of all-1s mean “don’t care”, so the first three octets stop being matched at all and the rule reaches far outside the block you had in mind. The router reports no syntax error and logs nothing; you are left with a permit statement that has the wrong scope. The reverse mistake at least has a chance of being caught, because 0.0.0.63 is not a valid subnet mask; it has no leading run of 1s. Whether a given platform rejects it or accepts it quietly is not something to discover in production.

Why ACL wildcards may have gaps but subnet masks may not

A subnet mask must be one contiguous run of 1s followed by 0s. That requirement is what makes the AND operation split an address into exactly two parts. A value like 255.0.255.0 has a hole in it, describes no coherent boundary, and devices reject it. So does Python:

import ipaddress
ipaddress.ip_network("10.0.0.0/255.0.255.0")
# ValueError: '10.0.0.0/255.0.255.0' does not appear to be an IPv4 or IPv6 network

Only 33 masks are valid, /0 through /32. Anything else is a typo.

ACL wildcards are under no such constraint, because they are not splitting an address into a network and a host part. They are a per-bit match filter, so gaps are legal and occasionally useful. A single wildcard with a gap can match every odd-numbered address in a range, for instance. That difference is why the two values cannot be swapped: they are not the same kind of object, they just happen to look alike in dotted-decimal.

Private, CGNAT and other reserved ranges

A prefix tells you how big a block is. Which block it is tells you whether it is yours to use.

BlockRangeReserved by
10.0.0.0/810.0.0.0 – 10.255.255.255RFC 1918 private
172.16.0.0/12172.16.0.0 – 172.31.255.255RFC 1918 private
192.168.0.0/16192.168.0.0 – 192.168.255.255RFC 1918 private
100.64.0.0/10100.64.0.0 – 100.127.255.255RFC 6598 carrier-grade NAT
169.254.0.0/16169.254.0.0 – 169.254.255.255RFC 3927 link-local
255.255.255.255/32single addresslimited broadcast

The RFC 1918 ranges are never routed on the public internet, which is what makes them safe to allocate from. The other three show up for different reasons.

100.64.0.0/10 is carrier-grade NAT space. If your ISP hands you an address in it, you are behind their NAT and no inbound connection will reach you without a tunnel. It is not private space in the RFC 1918 sense and it is not yours to use in an internal plan, because your provider may already be using it on the other side of your router.

169.254.0.0/16 is link-local. A host assigns itself one of these when DHCP fails, so seeing a 169.254 address on an interface is a diagnosis rather than a configuration: nothing answered the DHCP request. Traffic to it never crosses a router.

For examples in documentation and runbooks, RFC 5737 reserves 192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24 precisely so that a copy-pasted example cannot point at a real host.

172.16.0.0/12 is sixteen /16s, not one

People get this reserved range wrong because of the prefix. A /12 borrows four bits from the second octet, so the block spans 172.16.0.0 through 172.31.255.255: sixteen consecutive /16s, not just 172.16.x.x.

The consequences run both ways. An address like 172.20.5.1 is private, sitting comfortably inside the range, even though it does not start with 172.16. And 172.15.x.x and 172.32.x.x are public addresses belonging to somebody else, so a firewall rule or a “trust the internal range” check written against 172.0.0.0/8 quietly trusts a large slice of the internet.

If you need to confirm a boundary like this, the cheat sheet gives you the arithmetic: a /12 has 2^(32−12) addresses, the second octet moves in steps of 256 − 240 = 16, and 16 + 16 = 32, so the block ends immediately before 172.32.0.0.

VLSM: splitting one block into unequal subnets

Equal-sized subnets are easy and usually wrong. A branch office given a single 192.168.1.0/24 might need four segments with nothing in common: a hundred workstations, fifty phones, a dozen servers, and a handful of management interfaces. Split the /24 into four equal /26s and the workstation segment overflows at 62 hosts, while the management segment sits on 62 addresses to serve ten devices.

Variable Length Subnet Masking means giving each segment the prefix it actually needs. The table below carves the same /24 into one /25, one /26 and two /28s.

Allocate from largest to smallest. Each block must start on a multiple of its own size, so the biggest block gets first pick:

SegmentHosts neededPrefixNetworkUsable rangeBroadcastSubnet mask
Workstations100/25192.168.1.0192.168.1.1 – 192.168.1.126192.168.1.127255.255.255.128
Voice50/26192.168.1.128192.168.1.129 – 192.168.1.190192.168.1.191255.255.255.192
Servers12/28192.168.1.192192.168.1.193 – 192.168.1.206192.168.1.207255.255.255.240
Management10/28192.168.1.208192.168.1.209 – 192.168.1.222192.168.1.223255.255.255.240
unallocated/27192.168.1.224192.168.1.225 – 192.168.1.254192.168.1.255255.255.255.224

Walking it with the three-step method:

  1. The /25 has block size 256 − 128 = 128, so it starts at 0 and its broadcast is 0 + 128 − 1 = 127. Usable 1 to 126, which is 126 addresses, enough for 100 workstations with room left. The cheat sheet’s /25 row agrees: 128 total, 126 usable.
  2. The next free address is 128. The /26 has block size 64, and 128 is a multiple of 64, so it fits: network 192.168.1.128, broadcast 128 + 64 − 1 = 191, usable 129 to 190. That is 62 usable for 50 phones. Cheat sheet /26 row: 64 total, 62 usable.
  3. Next free is 192. The /28 has block size 16, and 192 = 16 × 12, so it fits: network 192.168.1.192, broadcast 207, usable 193 to 206, which is 14 addresses for 12 servers. Cheat sheet /28 row: 16 total, 14 usable.
  4. Next free is 208, and 208 = 16 × 13, so the second /28 lands at 192.168.1.208 with broadcast 223 and usable 209 to 222.

That accounts for 128 + 64 + 16 + 16 = 224 of the 256 addresses, leaving 192.168.1.224 through 192.168.1.255. Those 32 addresses happen to be exactly one aligned /27, which is where the point-to-point links would come from later: sixteen /31s fit inside it, one per router link.

Why largest first, and what it costs when you do not. Suppose you place the two /28s at the bottom instead: 192.168.1.0/28 and 192.168.1.16/28. The next free address is 192.168.1.32, and a /25 must start on a multiple of 128, so it cannot start there. It has to skip forward to 192.168.1.128. The addresses from 32 to 127 are not lost, but they are only usable as smaller aligned pieces (a /27 at 192.168.1.32 and a /26 at 192.168.1.64), so the leftover space ends up scattered instead of sitting in one contiguous block at the top. Add one more segment to the request and the same manoeuvre stops fitting at all.

Ordering by size avoids that. After you place a block, the next free address is a multiple of that block’s size, and a multiple of a larger power of two is automatically a multiple of every smaller one, so every subsequent, smaller block is aligned wherever the previous one ended. You never have to skip. Before committing a plan like this to a switch, running it through the subnet calculator division table is faster than checking the alignment of every segment by hand.

Five mistakes that survive into production

1. Treating the address you typed as the network address

Symptom: a firewall rule matches nothing, or a route covers the wrong half of a segment. Cause: 192.168.1.130/26 was read as network 192.168.1.0, broadcast 192.168.1.255: the /24 boundary, because that is the one people see in decimal. Fix: apply step 2. Block size 64, 130 ÷ 64 rounds down to 2, so the network is 2 × 64 = 128. The block is 192.168.1.128 to 192.168.1.191, and 192.168.1.0 is a different subnet entirely. Any time a prefix is longer than /24, assume the address you were given is a host address until you have masked it.

2. Applying 2ⁿ − 2 to a /31

Symptom: an IPAM tool or a spreadsheet reports 0 usable hosts for a point-to-point link that is up and passing traffic. Cause: the minus-two rule assumes a network and a broadcast address exist to be subtracted. On a /31 they do not. Fix: treat /31 and /32 as the boundary conditions of the formula rather than as anomalies. RFC 3021 makes both addresses of a /31 assignable, and a /32 is a single host route with one address. Anything that reports 0 or −1 has applied the formula outside its domain. Check /31 support on the specific interface first, since the exception only holds on genuinely point-to-point links.

3. Treating 172.16.0.0/12 as 172.16.x.x only

Symptom: an internal service is unreachable from one office, or a “block all private ranges” rule leaks. Cause: the /12 was read as if it were a /16. Fix: the range is 172.16.0.0 to 172.31.255.255. Write ACLs and allowlists against the prefix 172.16.0.0/12 rather than against an octet pattern, and remember that 172.15.x.x and 172.32.x.x sit outside it on the public internet. If you are matching by hand, the second octet is the boundary octet and it steps by 16.

4. Pasting a wildcard into a field that wants a subnet mask

Symptom: an ACL permits far more, or far less, than intended, and nothing in the config looks wrong. Cause: IOS ACLs and OSPF network statements take the wildcard while the ASA takes the subnet mask, and 0.0.0.63 and 255.255.255.192 are visually interchangeable at a glance. Fix: check the field before pasting, not after. A useful tell: for any prefix of /8 or longer, a subnet mask begins with 255 and a wildcard begins with 0. If a value sitting in an ACL or an OSPF network statement begins with 255, it is a subnet mask in a wildcard field.

5. Writing a non-contiguous mask, or generating one by accident

Symptom: a device rejects a configuration line, or a home-grown script produces masks that look plausible and are wrong. Cause: a value like 255.0.255.0 is not a valid subnet mask — it has a hole. The scripted version is subtler: in JavaScript, shift operators take their right operand modulo 32, so an out-of-range prefix silently produces a plausible-looking wrong mask (33 becomes /1, −1 becomes /31) instead of throwing. Fix: validate the prefix range before shifting, and reject any mask that is not a solid run of 1s followed by 0s. A library that raises on bad input is worth more here than one that guesses, because both failure modes are silent.

FAQ

What is the difference between a subnet and a VLAN?

A VLAN is a layer 2 broadcast domain configured on switches; a subnet is a layer 3 range of addresses. They are usually mapped one to one, but nothing enforces that: you can put two subnets on one VLAN, or trunk one VLAN across sites. Renumber the subnet and the VLAN ID does not change.

How many subnets do I get if I split a /24 into /26s?

Four. The count is 2 raised to the number of borrowed bits, and /26 is two bits longer than /24, so 2² = 4 subnets of 64 addresses each. Each child reserves its own network and broadcast address, so the four /26s hold 248 usable addresses against the parent /24’s 254.

Does CIDR notation work the same way in IPv6?

The slash still counts leading network bits, so /64 means 64 network bits out of 128. What does not carry over is the minus-two rule: IPv6 has no broadcast address, so nothing is subtracted from the total. The cheat sheet above and the calculator behind it are IPv4 only.

What does 0.0.0.0/0 mean?

Zero network bits, so it matches every IPv4 address. In a routing table it is the default route, used when no more specific prefix matches. As a bind address it means “all interfaces”, which is why a service listening on 0.0.0.0 is reachable from every network the machine is attached to.

What happens if two subnets on the same network overlap?

Routers pick the more specific route, since forwarding always prefers the longest matching prefix, while hosts inside the overlap disagree about which destinations are local. The symptom is partial: some destinations work and some do not, and which ones changes depending on where you test from.

Why were Class A, B and C addresses replaced by CIDR?

Because the classes only offered three sizes: /8, /16 and /24. An organisation needing 300 addresses had to take a class B and waste most of it or run two class C routes. CIDR let a prefix be any length, which slowed address exhaustion and let providers summarise many customer blocks into one route.

Can I subnet a private range like 192.168.0.0/16 however I want?

Yes. RFC 1918 space is yours to divide at any prefix length and nobody outside your network sees it. The constraint is internal: overlapping with a partner network or a cloud VPC you later peer with is expensive to unwind, which is why plans tend to avoid the blocks every home router already uses.

What to carry away. The prefix counts network bits, and block size is 256 − the boundary mask octet. Round the address down to a multiple of the block size for the network, and add block size minus one for the broadcast. Subtract two for the reserved pair, but only when a /31 or /32 has not already removed the reason to subtract. Keep the wildcard and the subnet mask straight by their shape. Allocate large blocks before small ones.

None of it needs a tool once the arithmetic is in your head, which is the reason to work through it by hand at least once. For checking a plan before it reaches a router, or for reading a block’s binary boundary at a glance, the subnet calculator runs locally in your browser.

Tags: networking subnetting cidr ip-address cheat-sheet

Related Articles

View all articles