An address plan with variable-length subnet masks () gives each segment of a site a block of its own size instead of cutting the parent into equal pieces. VLSM: splitting a block into unequal subnets explains the principle; this article runs it to the last address on one block, 203.0.113.0/24, for an office local area network (), a guest , a management segment and two router-to-router links, under the Classless Inter-domain Routing () rules of (RFC) 4632. After reading, you can size and place the segments, fill every column of the table, account for what is left, number the links as /31 or /30 prefixes, recognise the order that makes a plan fail, and announce the site as one route.

The block and the requests

The parent is the third of the three blocks RFC 5737 sets aside for examples: "The blocks 192.0.2.0/24 (TEST--1), 198.51.100.0/24 (TEST-NET-2), and 203.0.113.0/24 (TEST-NET-3) are provided for use in documentation" (RFC 5737, section 3). The Internet Assigned Numbers Authority () lists it as Documentation (TEST-NET-3), with every reachability flag false (IANA, IPv4 Special-Purpose Address Space); such addresses should not appear on the public internet and operators should filter them (RFC 5737, section 4), so the plan will not route if copied into a live router.

A /24 holds 256 addresses, 203.0.113.0 to 203.0.113.255, under the mask 255.255.255.0: "the most significant 24 bits are ones and the least significant 8 bits are zeros" (RFC 4632, section 3.1); CIDR notation explained reads the slash. The requests, as they arrived:

RequestHosts
Link A, router to router2
Link B, router to router2
Management10
Office100
Guest Wi-Fi25

Step 1: size each segment

Under CIDR "prefixes may be defined to describe any power of two-sized block of between one and 2^32 end system addresses" (RFC 4632, section 3.1), so a segment gets the smallest power of two that holds its hosts plus two. The two are the addresses no host may take: the all-zeros host number, which names the network, and the all-ones host number, the directed broadcast (RFC 1812, section 4.2.2.11; RFC 1122, section 3.2.1.3). The sizes follow from RFC 1878's table for a /24 (RFC 1878, Table 1-2):

HostsNeededPrefixMaskAddressesUsable
100102/25255.255.255.128128126
2527/27255.255.255.2243230
1012/28255.255.255.2401614
24/30255.255.255.25242

A /26 holds only 62 hosts, hence the /25 for 100. Now add the blocks, not the hosts: 128 + 32 + 16 + 4 + 4 = 184 of 256. The host counts sum to 139, and a plan that compares 139 with 256 passes a check it should fail. The old habit of also discarding the first and last subnet of a block is gone: RFC 1878 calls it obsolete and RFC 1812 says the restriction "may be safely ignored" (RFC 1812, section 4.2.2.11), as subnetting basics recounts, so the first block may start at 203.0.113.0.

Step 2: largest first, and why

A prefix's network address has every host bit at zero, so a /27 can only start on an address whose last five bits are zero, a multiple of 32, and a /28 on a multiple of 16. Placed from the largest down, each block starts exactly where the previous one ended, because everything before it is a power of two at least as large, so the running total is a multiple of the next size. No RFC states the rule; it follows from RFC 1812's definition of a prefix as "a contiguous set of bits at the more significant end of the address" (RFC 1812, section 2.2.5.2). RFC 4632's own example shows the skip otherwise: a /20 that could not start at 10.24.8.0 jumped to 10.24.16.0 and left a hole (RFC 4632, section 6.1). The order here is Office (/25), Guest Wi-Fi (/27), Management (/28), Link A (/30), Link B (/30).

Step 3: the table

Each block starts at the first multiple of its own size at or after the end of the previous one; the first host is the network address plus one, the broadcast address is the block's last address, and the last host the one before it:

SegmentHostsBlockMaskFirst hostLast hostBroadcastUsable
Office100203.0.113.0/25255.255.255.128203.0.113.1203.0.113.126203.0.113.127126
Guest Wi-Fi25203.0.113.128/27255.255.255.224203.0.113.129203.0.113.158203.0.113.15930
Management10203.0.113.160/28255.255.255.240203.0.113.161203.0.113.174203.0.113.17514
Link A2203.0.113.176/30255.255.255.252203.0.113.177203.0.113.178203.0.113.1792
Link B2203.0.113.180/30255.255.255.252203.0.113.181203.0.113.182203.0.113.1832

Used 184, free 72, utilisation 71.9 percent (184 divided by 256 is 0.71875).

Step 4: check every boundary

Count each start as an offset from 203.0.113.0 and divide by the block size; then write the last octet in binary, where the host bits are the trailing zeros:

SegmentOffsetAs a multipleLast octet in binary
Office, /2500 × 12800000000
Guest Wi-Fi, /271284 × 3210000000
Management, /2816010 × 1610100000
Link A, /3017644 × 410110000
Link B, /3018045 × 410110100

Every /27 start ends in five zeros, every /28 start in four, every /30 start in two, which is what the host's own test on every packet checks, written in 1985 as pseudo-code (RFC 950, section 2.2):

IF bitwise_and(dg.ip_dest, my_ip_mask) = bitwise_and(my_ip_addr, my_ip_mask)
    THEN send_dg_locally(dg, dg.ip_dest)
    ELSE send_dg_locally(dg, gateway_to(bitwise_and(dg.ip_dest, my_ip_mask)))

A router runs the same comparison per interface (RFC 1812, section 5.2.4.2); an Office host with the mask 255.255.255.128 treats 203.0.113.1 to 203.0.113.126 as neighbours and sends everything else to its gateway.

Step 5: what is left

The free run is 203.0.113.184 to 203.0.113.255, 72 addresses. That is not a power of two, so it is never one block but two aligned ones:

Free blockAddressesFits
203.0.113.184/298up to 6 hosts
203.0.113.192/2664up to 62 hosts

8 + 64 = 72, so the whole parent is accounted for: 184 used plus 72 free. A later request for up to 62 hosts goes in the /26; a second 100-host segment fits nowhere, although 72 addresses are free, because a /25 needs 128 contiguous aligned addresses. Aligned blocks, not a count, make that visible in advance; subnet overlaps and gaps shows how to account for every address of any allocation.

The same two links as /31

A /30 between two routers wastes half its addresses: four per link, two of them the network and the broadcast, on a medium with exactly two endpoints and no broadcast to speak of (RFC 3021, section 1). RFC 3021 turns the two reserved addresses into hosts: "In a point-to-point link with a 31-bit subnet mask, the two addresses above MUST be interpreted as host addresses" (section 2.1); RFC 950 had already allowed a host field one bit wide (RFC 950, section 2.1).

Link A becomes 203.0.113.176/31, hosts 203.0.113.176 and 203.0.113.177, and Link B 203.0.113.178/31, hosts 203.0.113.178 and 203.0.113.179, both under the mask 255.255.255.254, neither with a broadcast address. Used falls from 184 to 180, free rises from 72 to 76, now 203.0.113.180/30, 203.0.113.184/29 and 203.0.113.192/26, and utilisation is 70.3 percent: "each point-to-point link in a large network would consume two addresses instead of four" (RFC 3021, section 1).

Three consequences follow. There is no directed broadcast to a /31, so "The limited broadcast MUST be used for all broadcast traffic on a point-to-point link with a 31-bit subnet mask assigned to it" (RFC 3021, section 2.2), which the RFC also counts as a small gain against denial of service (DoS) by directed-broadcast amplification (section 2.2.1). Routing protocols are indifferent, and among those tested (sections 2.3 and 4). And both ends must agree: "a point-to-point link in which only one end supports the use of 31-bit prefixes may not operate correctly" (section 5), and the rule is for two-ended links only, never a LAN segment (same section).

In the order the requests arrived

Place the same five blocks in the order the requests came in, each at the first aligned address after the last, and the plan breaks on the last request:

SegmentBlockOffsetSkipped before it
Link A203.0.113.0/300nothing
Link B203.0.113.4/304nothing
Management203.0.113.16/2816203.0.113.8 to 203.0.113.15 (8 is not a multiple of 16)
Office203.0.113.128/25128203.0.113.32 to 203.0.113.127 (32 is not a multiple of 128)
Guest Wi-Fidid not fit256a /27 would start at 203.0.114.0, beyond the parent

Used 152, free 104, utilisation 59.4 percent, and the free space is 203.0.113.8/29, 203.0.113.32/27 and 203.0.113.64/26. Room for the guest Wi-Fi exists twice over, in the /27 at .32 or inside the /26 at .64, but only by going back for it, and backtracking is where overlaps come from. Squeeze the /27 into the first free address, 203.0.113.8, and its real network address is 203.0.113.0, because 8 AND 224 is 0, so 203.0.113.0/27 covers 203.0.113.0 to 203.0.113.31 and swallows both links and the management block. Python refuses the attempt: "A ValueError is raised if address does not represent a valid IPv4 or IPv6 address, or if the network has host bits set" (Python 3.14 documentation, ipaddress).

The failure is often misnamed: this is not "smallest first". A true smallest-first order (the links, Management, Guest Wi-Fi, Office) also fits all five, each jump landing on a boundary the next block can use. What fails is an unsorted order, where a larger block follows a smaller one and must skip ahead. Largest first never skips.

One route for all of it

Because every block came out of one parent, the rest of the network reaches the site with a single route, 203.0.113.0/24, CIDR's reward for a contiguous block: "the site's routing information may be aggregated into a single prefix" (RFC 4632, section 4.1). The allocated blocks alone do not collapse that far: the two /30s merge to 203.0.113.176/29, but the /25, /27, /28 and /29 stay four prefixes, and only the covering /24, which also covers the 72 free addresses, is one route. Route summarisation and supernetting and route aggregation take the idea beyond one site.

Inside the site, the subnets win over the summary by length: "Routers must use the most specific matching route (the longest matching network prefix) when forwarding traffic" (RFC 1812, section 2.2.5.2), the forwarding algorithm keeping, of the matching routes, those with the largest length (section 5.2.4.3). A packet for 203.0.113.10 matches the /24 and the /25, and the /25 carries it to the Office; static routes, longest prefix match and administrative distance shows the choice in a routing table.

The route that leads nowhere

The router that announces the /24 also needs a route for it, one that drops packets: a router "must discard packets that match the aggregate route, but not any of the more-specific routes", so "the 'next hop' for the aggregate route should be the null destination" (RFC 4632, section 5.1), which "is necessary to prevent forwarding loops when some addresses covered by the aggregate are not reachable" (same section). A packet for 203.0.113.200, in the free /26, shows why: the /24 brings it to the site, no connected subnet matches it, and without the discard route the best match left is the site's default route, which points back out to a network that sends it in again, until its time to live () reaches zero and it is discarded (RFC 1812, section 5.3.1). In practice "this is implemented by installing a 'discard' or 'null' route for all aggregated prefixes that one network advertises to another" (RFC 4632, section 5.2). The loop in full, with the OSPF and forms, is in route summarisation; here it is one line of configuration.

Seeing it

The CIDR / Subnet Calculator has four modes, all computed in the browser. In VLSM mode, enter 203.0.113.0/24 as the parent block and the five requirements with their host counts: it sorts largest first itself, so any input order returns the table of Step 3 and 71.9 percent utilisation, with a Did not fit list. Two limits: a 2-host requirement always gets a /30, so each /31 is checked on its own in Subnet mode, where 203.0.113.176/31 returns two usable addresses and the last-address label notes the missing directed broadcast; and since the mode always sorts, it cannot show the arrival-order failure. Overlap mode, given the five blocks and 203.0.113.0/24 as the scope, reports no overlaps and the gaps 203.0.113.184/29 and 203.0.113.192/26; Supernet mode collapses the five to four prefixes and names 203.0.113.0/24 as the covering block, 72 addresses larger.

The Python playground runs CPython 3.14 in the browser, where the ipaddress module does the whole plan: hosts() lists the usable addresses, both of them on a /31, address_exclude() yields the free blocks, subnet_of() tests containment and collapse_addresses() merges what merges (Python 3.14 documentation, ipaddress). Run in this session, output below the code:

from ipaddress import ip_network, collapse_addresses
parent = ip_network("203.0.113.0/24")
plan = [ip_network(p) for p in ("203.0.113.0/25", "203.0.113.128/27",
        "203.0.113.160/28", "203.0.113.176/30", "203.0.113.180/30")]
for n in plan:
    h = list(n.hosts())
    print(n, n.netmask, h[0], h[-1], n.broadcast_address, len(h))
free = [parent]
for n in plan:
    free = [g for f in free for g in (f.address_exclude(n) if n.subnet_of(f) else [f])]
print(sorted(free), sum(f.num_addresses for f in free))
print(list(collapse_addresses(plan)))
print(list(ip_network("203.0.113.176/31").hosts()))
203.0.113.0/25 255.255.255.128 203.0.113.1 203.0.113.126 203.0.113.127 126
203.0.113.128/27 255.255.255.224 203.0.113.129 203.0.113.158 203.0.113.159 30
203.0.113.160/28 255.255.255.240 203.0.113.161 203.0.113.174 203.0.113.175 14
203.0.113.176/30 255.255.255.252 203.0.113.177 203.0.113.178 203.0.113.179 2
203.0.113.180/30 255.255.255.252 203.0.113.181 203.0.113.182 203.0.113.183 2
[IPv4Network('203.0.113.184/29'), IPv4Network('203.0.113.192/26')] 72
[IPv4Network('203.0.113.0/25'), IPv4Network('203.0.113.128/27'), IPv4Network('203.0.113.160/28'), IPv4Network('203.0.113.176/29')]
[IPv4Address('203.0.113.176'), IPv4Address('203.0.113.177')]

On Linux the plan becomes addresses with prefix lengths and one discard route: ip-address(8) takes the address followed by a slash and the prefix length (ip-address(8), Linux manual page); in ip-route(8) a blackhole route discards silently and ip route get prints the route the kernel would use (ip-route(8), Linux manual page). Illustrative, on the site's router:

ip address add 203.0.113.1/25 dev eth0
ip address add 203.0.113.177/30 dev eth1
ip route add blackhole 203.0.113.0/24
ip route get 203.0.113.200

In FRRouting, ip address ADDRESS/PREFIX under an interface sets the address and prefix (FRRouting documentation, Zebra), and ip route NETWORK (Null0|blackhole|reject) installs the discard; its documented example, a high-distance blackhole, exists "to prevent traffic destined for a prefix to match less-specific routes (e.g. default) should the specified gateways not be reachable" (FRRouting documentation, STATIC). For the plan: ip route 203.0.113.0/24 Null0.

What to remember

  • Size by blocks, not hosts: hosts plus two, rounded up to a power of two; the blocks here sum to 184, the hosts to 139.
  • Largest first places each block where the last ended, on a multiple of its own size, so nothing overlaps or is skipped; the rule is arithmetic, not a requirement of any RFC.
  • Write the leftover as aligned blocks: 72 free addresses are a /29 and a /26, and a 100-host segment fits in neither.
  • A /31 on a two-ended link makes both addresses hosts, removes the directed broadcast and saves two addresses per link; both ends must support it (RFC 3021).
  • Arrival order skips space and can strand a request although room remains; a /27 forced onto 203.0.113.8 really starts at 203.0.113.0 and overlaps three blocks.
  • One parent, one route: 203.0.113.0/24 reaches the whole plan, and longest match lets the subnets win inside it.
  • The router that announces the summary carries a discard route for it, so a packet for a free address ends there instead of looping.

Sources