Why subnet at all

A subnet (subnetwork) is a range of Internet Protocol (IP) addresses that share the same network prefix and sit together on one layer 2 segment, such as one virtual local area network (VLAN). Hosts in the same subnet reach each other directly; traffic to any other subnet goes through a router. Subnetting is the act of cutting a larger address block into several of these smaller ranges. It builds on the address and mask basics from IPv4 Addressing.

Organizations subnet for four practical reasons:

  • Right-sized networks. A /16 holds 65,534 hosts. No single office segment needs that; a printer VLAN may need ten addresses and a point-to-point link between two routers only two.
  • Smaller broadcast domains. Every broadcast (for example an Address Resolution Protocol (ARP) request) reaches every host in the subnet. Fewer hosts per subnet means less broadcast traffic and a smaller blast radius when something misbehaves.
  • Security and control. Traffic between subnets passes a router or firewall, where access control lists can filter it. Putting servers, staff, guests and management interfaces in separate subnets is the basis of network segmentation (see Network Security Basics).
  • Tidy routing. Subnets carved from one block can be advertised to the rest of the network as a single summary route, which keeps routing tables small (see route summarization below).

Borrowing host bits

An IPv4 address has 32 bits. The prefix length — the number after the slash, as in /26 — says how many of those bits, counted from the left, form the network part. The remaining bits are the host bits: they number the individual addresses inside the subnet. With a /26 there are 26 network bits and 32 − 26 = 6 host bits.

To subnet, you borrow bits from the host part and make them network bits. Start with 192.168.10.0/24 and borrow two bits: the prefix becomes /26. Those two borrowed bits can take four values (00, 01, 10, 11), so the /24 turns into four /26 subnets. Each has six host bits left, so 64 addresses.

The address 192.168.10.0 with prefix /26: 24 network bits in the first three octets, 2 borrowed subnet bits and 6 host bits in the last octet, giving mask 255.255.255.192. network bits from the original /24 borrowed host bits 192 168 10 s s h h h h h h 128 64 32 16 8 4 2 1 prefix /26 = 24 + 2 network bits mask 255.255.255.192 (128 + 64) 6 host bits 2⁶ = 64 addresses
Borrowing two host bits turns 192.168.10.0/24 into four /26 subnets. The mask has a 1 for every network bit, so the last octet becomes 128 + 64 = 192.

Try it: subnet mask and prefix length

Convert a dotted-decimal mask to its prefix length or back, with the bits, the wildcard mask and the number of hosts.

Convert

A mask such as 255.255.255.192, or a prefix length from 0 to 32 such as 26 or /26.

The formulas

Two formulas cover almost every subnetting question:

Question Formula Example: /24 → /26
How many subnets? 2borrowed bits 22 = 4 subnets
How many addresses per subnet? 2host bits 26 = 64
How many usable hosts per subnet? 2host bits − 2 64 − 2 = 62

Why minus two

Two addresses in every ordinary subnet cannot be given to a host:

  • The network address is the first address of the subnet, with all host bits set to 0. It is the name of the subnet itself — the value that appears in routing tables, such as 192.168.10.64/26.
  • The broadcast address is the last address, with all host bits set to 1. A packet sent to it is delivered to every host in the subnet (a directed broadcast), such as 192.168.10.127 for 192.168.10.64/26.

Everything in between is usable: the first usable host is the network address + 1, the last usable host is the broadcast address − 1. By convention many networks give the default gateway the first (or the last) usable address, but that is a local habit, not a rule.

The exceptions: /31 and /32

The formula would give a /31 (one host bit) 2 − 2 = 0 hosts, which would make it useless. Request for Comments (RFC) 3021 changed that for point-to-point links: on a link with exactly two ends there is nobody else to broadcast to, so both addresses of a /31 may be used as host addresses. This saves half the addresses compared with the traditional /30 for router-to-router links. A /32 has no host bits at all and identifies exactly one address; it is used for loopback interfaces and host routes.

import ipaddress

for prefix in (30, 31, 32):
    net = ipaddress.ip_network(f"10.0.0.0/{prefix}")
    print(f"/{prefix}: {net.num_addresses} address(es), mask {net.netmask}")

link = ipaddress.ip_network("10.0.0.0/31")
print("usable on a /31:", [str(host) for host in link.hosts()])
/30: 4 address(es), mask 255.255.255.252
/31: 2 address(es), mask 255.255.255.254
/32: 1 address(es), mask 255.255.255.255
usable on a /31: ['10.0.0.0', '10.0.0.1']

Python's hosts() follows RFC 3021 and returns both addresses of a /31. The examples on this page use the standard library module ipaddress; see The Standard Library if the module itself is new to you.

The block size method

Converting every address to binary works, but it is slow. The block size method (also called the magic number method) gives the same answer with only subtraction and multiplication. It works because subnets of the same size always start at a multiple of their size.

  1. Write the mask in dotted decimal and find the interesting octet: the one that is neither 255 nor 0. (If the mask is on an octet boundary, such as /16 or /24, the interesting octet is the one after the last 255, and the block size is 256.)
  2. Block size = 256 − the mask value in that octet. For 255.255.255.192 the block size is 256 − 192 = 64.
  3. List the multiples of the block size in the interesting octet: 0, 64, 128, 192. Each one is the start of a subnet.
  4. Find the subnet: the network address is the largest multiple that is not greater than the address's value in that octet. All octets to the right become 0.
  5. Broadcast address = the next subnet's start − 1 in the interesting octet, with all octets to the right set to 255.
  6. Usable range: network + 1 to broadcast − 1.

The mask values themselves follow a fixed pattern you will soon know by heart: 128, 192, 224, 240, 248, 252, 254, 255 (each adds the next bit: 128, +64, +32, +16, +8, +4, +2, +1).

Worked examples

Each example is worked out by hand first, then verified with Python. The Python code prints exactly the values in the table, so you can change the addresses and practice on your own.

Example 1: 192.168.10.0/24 into four subnets

Task: split 192.168.10.0/24 into four equal subnets.

  1. Four subnets need 2 borrowed bits (22 = 4). New prefix: /24 + 2 = /26.
  2. Mask: 255.255.255.192. Interesting octet: the fourth. Block size: 256 − 192 = 64.
  3. Subnets start at .0, .64, .128 and .192. Host bits: 32 − 26 = 6, so 26 − 2 = 62 usable hosts each.
Subnet Network First usable Last usable Broadcast
1 192.168.10.0/26 192.168.10.1 192.168.10.62 192.168.10.63
2 192.168.10.64/26 192.168.10.65 192.168.10.126 192.168.10.127
3 192.168.10.128/26 192.168.10.129 192.168.10.190 192.168.10.191
4 192.168.10.192/26 192.168.10.193 192.168.10.254 192.168.10.255
import ipaddress

block = ipaddress.ip_network("192.168.10.0/24")
for subnet in block.subnets(prefixlen_diff=2):   # borrow 2 bits
    first = subnet.network_address + 1
    last = subnet.broadcast_address - 1
    print(subnet, first, last, subnet.broadcast_address)
print("usable hosts per subnet:", subnet.num_addresses - 2)
192.168.10.0/26 192.168.10.1 192.168.10.62 192.168.10.63
192.168.10.64/26 192.168.10.65 192.168.10.126 192.168.10.127
192.168.10.128/26 192.168.10.129 192.168.10.190 192.168.10.191
192.168.10.192/26 192.168.10.193 192.168.10.254 192.168.10.255
usable hosts per subnet: 62

Example 2: which subnet is 172.16.45.130/20 in?

Task: a monitoring alert names host 172.16.45.130/20. Which subnet is it in, and what is its range?

  1. /20 = 8 + 8 + 4 network bits: mask 255.255.240.0. The interesting octet is the third (240), not the fourth.
  2. Block size: 256 − 240 = 16.
  3. Multiples of 16 in the third octet: 0, 16, 32, 48 … The address has 45 there; the largest multiple not above 45 is 32.
  4. Network address: 172.16.32.0 (the fourth octet becomes 0). The next subnet starts at 172.16.48.0, so the broadcast address is 172.16.47.255.
  5. Host bits: 32 − 20 = 12, so 212 − 2 = 4,094 usable hosts.
Network First usable Last usable Broadcast Usable hosts
172.16.32.0/20 172.16.32.1 172.16.47.254 172.16.47.255 4,094
import ipaddress

host = ipaddress.ip_interface("172.16.45.130/20")
net = host.network
print("mask:     ", net.netmask)
print("network:  ", net)
print("first:    ", net.network_address + 1)
print("last:     ", net.broadcast_address - 1)
print("broadcast:", net.broadcast_address)
print("usable:   ", net.num_addresses - 2)
mask:      255.255.240.0
network:   172.16.32.0/20
first:     172.16.32.1
last:      172.16.47.254
broadcast: 172.16.47.255
usable:    4094

ip_interface accepts an address with host bits set (a host and its prefix, as configured on an interface); .network gives the subnet it belongs to.

Try it: is an address in this subnet?

Enter an address and a subnet to see whether the address belongs to it: both are ANDed with the mask and the network bits compared.

For example 172.16.47.200.

With a prefix length or a mask: 172.16.32.0/20 or 172.16.32.0 255.255.240.0.

Example 3: network, broadcast and range of 10.20.30.40/27

Task: a ticket says a new server got 10.20.30.40/27. Which addresses share its subnet?

  1. /27: mask 255.255.255.224, interesting octet the fourth.
  2. Block size: 256 − 224 = 32. Multiples: 0, 32, 64, 96 …
  3. 40 lies between 32 and 64, so the network address is 10.20.30.32 and the broadcast address is 64 − 1 = 10.20.30.63.
  4. Usable: 10.20.30.33 to 10.20.30.62, which is 25 − 2 = 30 hosts.
Network Mask First usable Last usable Broadcast
10.20.30.32/27 255.255.255.224 10.20.30.33 10.20.30.62 10.20.30.63
import ipaddress

net = ipaddress.ip_interface("10.20.30.40/27").network
hosts = list(net.hosts())
print(net, net.netmask)
print("first:", hosts[0], " last:", hosts[-1], " count:", len(hosts))
print("broadcast:", net.broadcast_address)
print("10.20.30.64 in this subnet?", ipaddress.ip_address("10.20.30.64") in net)
10.20.30.32/27 255.255.255.224
first: 10.20.30.33  last: 10.20.30.62  count: 30
broadcast: 10.20.30.63
10.20.30.64 in this subnet? False

Example 4: VLSM for a small office

Giving every subnet the same size wastes addresses: a router-to-router link needs 2, not 62. Variable Length Subnet Masking (VLSM) means using different prefix lengths for different subnets carved out of the same block, so each subnet gets only the size it needs.

Task: from 192.168.50.0/24, create subnets for staff (60 hosts), guests (28), servers (12) and a wide area network (WAN) link between two routers (2).

  1. Sort the needs from largest to smallest. Big blocks have the strictest alignment (a /26 must start at a multiple of 64); placing them first means each later, smaller block automatically starts on a valid boundary.
  2. For each need, find the smallest subnet that fits with 2h − 2 ≥ hosts: 60 → h = 6 (62) → /26; 28 → h = 5 (30) → /27; 12 → h = 4 (14) → /28; 2 → h = 2 (2) → /30.
  3. Allocate from the start of the block, each subnet beginning right after the previous broadcast address.
Need Hosts Subnet Usable range Broadcast
Staff 60 192.168.50.0/26 .1 – .62 192.168.50.63
Guests 28 192.168.50.64/27 .65 – .94 192.168.50.95
Servers 12 192.168.50.96/28 .97 – .110 192.168.50.111
WAN link 2 192.168.50.112/30 .113 – .114 192.168.50.115

Addresses 192.168.50.116 to 192.168.50.255 remain free for growth.

The block 192.168.50.0/24 drawn to scale: staff /26 from .0, guests /27 from .64, servers /28 from .96, WAN link /30 from .112, and free space from .116 to .255. .0 .64 .96 .255 Servers /28 Staff /26 Guests /27 free: .116 – .255 WAN link /30 (.112 – .115)
The VLSM plan drawn to scale. Largest first keeps every block on a multiple of its own size, with no gaps and no overlaps.
import ipaddress

block = ipaddress.ip_network("192.168.50.0/24")
needs = [("Staff", 60), ("Guests", 28), ("Servers", 12), ("WAN link", 2)]

next_free = block.network_address
for name, hosts in sorted(needs, key=lambda need: need[1], reverse=True):
    host_bits = 2
    while 2 ** host_bits - 2 < hosts:
        host_bits += 1
    # strict checking raises ValueError if the start is not aligned
    subnet = ipaddress.ip_network(f"{next_free}/{32 - host_bits}")
    first = subnet.network_address + 1
    last = subnet.broadcast_address - 1
    print(f"{name:9}{hosts:3}  {str(subnet):18} {first} - {last}")
    next_free = subnet.broadcast_address + 1

print("free from", next_free, "to", block.broadcast_address)
Staff     60  192.168.50.0/26    192.168.50.1 - 192.168.50.62
Guests    28  192.168.50.64/27   192.168.50.65 - 192.168.50.94
Servers   12  192.168.50.96/28   192.168.50.97 - 192.168.50.110
WAN link   2  192.168.50.112/30  192.168.50.113 - 192.168.50.114
free from 192.168.50.116 to 192.168.50.255

Try it: a VLSM plan

Enter a block and the hosts each subnet needs. The plan follows the steps above: largest first, the smallest subnet that fits, each one right after the previous.

A network address with prefix length, for example 192.168.50.0/24.

Subnets: name and number of hosts

Cheat sheet: /24 to /30

These prefixes cover most local area network (LAN) and link subnets you will meet. The block size equals the number of addresses, because all of these fall in the fourth octet.

Prefix Mask Block size Subnets in a /24 Usable hosts
/24 255.255.255.0 256 1 254
/25 255.255.255.128 128 2 126
/26 255.255.255.192 64 4 62
/27 255.255.255.224 32 8 30
/28 255.255.255.240 16 16 14
/29 255.255.255.248 8 32 6
/30 255.255.255.252 4 64 2

The same table, generated:

import ipaddress

for prefix in range(24, 31):
    net = ipaddress.ip_network(f"192.0.2.0/{prefix}")
    per_24 = 2 ** (prefix - 24)
    print(f"/{prefix}  {str(net.netmask):16} {net.num_addresses:4} {per_24:3} {net.num_addresses - 2:4}")
/24  255.255.255.0     256   1  254
/25  255.255.255.128   128   2  126
/26  255.255.255.192    64   4   62
/27  255.255.255.224    32   8   30
/28  255.255.255.240    16  16   14
/29  255.255.255.248     8  32    6
/30  255.255.255.252     4  64    2

Common mistakes

Python catches both errors for you. A network written with host bits set is refused, and overlaps() tests two plans against each other:

import ipaddress

staff = ipaddress.ip_network("192.168.50.0/26")
guests = ipaddress.ip_network("192.168.50.32/27")   # a typo: should be .64
print("overlap:", staff.overlaps(guests))
ipaddress.ip_network("10.20.30.40/27")              # host bits set
overlap: True
ValueError: 10.20.30.40/27 has host bits set

The last line fails on purpose: 10.20.30.40 is a host address, not the start of a /27. Pass strict=False (or use ip_interface) when you want Python to find the network for you.

Wildcard masks

Cisco access control lists (ACLs) and the Open Shortest Path First (OSPF) network command do not take a subnet mask but a wildcard mask: the inverse of the subnet mask. A 0 bit means "must match", a 1 bit means "don't care". You get it by subtracting each octet of the mask from 255: the wildcard for 255.255.255.192 (/26) is 0.0.0.63.

R1(config)# access-list 10 permit 192.168.10.0 0.0.0.63
R1(config)# router ospf 1
R1(config-router)# network 192.168.10.64 0.0.0.63 area 0
  • Line 1: a standard ACL (number 10) that matches every source in 192.168.10.0/26 (.0 to .63).
  • Line 2: starts OSPF process 1.
  • Line 3: enables OSPF, in area 0, on every interface whose address lies in 192.168.10.64/26. Exam-relevant.
import ipaddress

net = ipaddress.ip_network("192.168.10.0/26")
print("mask:    ", net.netmask)
print("wildcard:", net.hostmask)
mask:     255.255.255.192
wildcard: 0.0.0.63

Python calls the wildcard the hostmask: it has a 1 for every host bit. ACLs are explained on Network Security Basics, OSPF on Dynamic Routing and OSPF.

Route summarization: a preview

Subnetting borrows host bits to make smaller networks. Summarization (also called supernetting or route aggregation) does the reverse: it gives up network bits to describe several adjacent subnets with one shorter prefix. A branch office that owns 172.16.0.0/24 through 172.16.3.0/24 can be reached with a single route to 172.16.0.0/22, because the four networks differ only in the last two bits of the third octet.

import ipaddress

branch = [ipaddress.ip_network(f"172.16.{n}.0/24") for n in range(4)]
print(list(ipaddress.collapse_addresses(branch)))
[IPv4Network('172.16.0.0/22')]

Summaries work cleanly only when the subnets are contiguous and aligned — one more reason to plan subnets from one block, in order. How routers use these prefixes, including longest prefix match, is covered on Routing Basics.

Try it: summarize networks

Enter two or more networks to find the shortest prefix that covers them all, and whether that summary is exact or also covers addresses that are not yours.

Network addresses with a prefix length, such as 172.16.0.0/24; at least two.