Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Computer Networks  Module 7 – IPv4 addressing, subnetting and NAT

VLSM and route summarisation

Plan variable-length subnets largest first without overlaps, summarise routes into the shortest covering prefix and turn address ranges into CIDR blocks.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free: 30 minutes

What you will learn

  • Plan variable-length subnets largest first without overlaps or wasted gaps
  • Summarise contiguous prefixes into the shortest covering route and spot over-summarisation
  • Convert address ranges into the fewest CIDR blocks

Before you start

What you’ll learn · Before you start

What you will learn

  • Plan variable-length subnets largest first without overlaps or wasted gaps
  • Summarise contiguous prefixes into the shortest covering route and spot over-summarisation
  • Convert address ranges into the fewest CIDR blocks

Before you start

On this page

Variable-length subnet masking (VLSM) gives each subnet of a network a prefix length of its own, so a 100-host lab, a 12-camera network and a two-address link between routers each get a block that fits, instead of one size for all. Route summarisation works in the other direction: it replaces several routes with one shorter prefix that covers them all, so that other routers carry fewer routes. A summary that is shorter than the old classful network is also called a supernet. Both rest on one rule of CIDR: a block of 2^k addresses starts at a multiple of 2^k. This lesson plans a college branch with VLSM, places the blocks largest first, shows what goes wrong in other orders, summarises routes and catches summaries that cover too much, and turns any address range into the fewest CIDR blocks.

Why one size for every subnet wastes addresses

A college branch has 192.168.40.0/24 and needs seven subnets: labs with 100 computers, hostel Wi-Fi for 50 devices, 25 staff machines, 12 cameras, 5 printers and two links to other routers, one to the main campus and one to the ISP. Equal subnetting cannot do it. Seven subnets need 3 borrowed bits, which makes /27s of 30 hosts, too small for the labs. A subnet large enough for the labs is a /25, and a /24 holds only two of those.

Equal subnets are as large as the largest need. VLSM sizes each subnet on its own, and the same /24 then holds all seven with addresses to spare. The price is planning: blocks of different sizes must be placed so that none overlaps another.

Sizing each subnet

The size of a block follows from what it must hold:

  • A LAN: the hosts plus 2 (the network and broadcast addresses), rounded up to the next power of two. 100 hosts need 102 addresses, so the block is 128, a /25.
  • A point-to-point link between two routers: a /31 of two addresses, which RFC 3021 allows on such links because they need no broadcast address. Both routers must read the two addresses as hosts, as RFC 3021 requires; if either cannot, the link needs a /30 instead.
  • A single address, such as a router’s loopback: a /32.
Sizing the seven subnets of the branch Python · sizing.py
# Sizing each subnet of a college branch for VLSM: the hosts plus 2, rounded up to a power of two, or a /31 for a
# point-to-point link between two routers (RFC 3021).

NEEDS = [("Labs", 100), ("Hostel Wi-Fi", 50), ("Staff", 25), ("Cameras", 12), ("Printers", 5),
         ("Link to campus", "p2p"), ("Link to ISP", "p2p")]


def block_for(need):
    if need == "p2p":
        return 2
    size = 4
    while size - 2 < need:
        size *= 2
    return size


total = 0
for name, need in NEEDS:
    size = block_for(need)
    total += size
    prefix = 32 - (size.bit_length() - 1)
    usable = 2 if need == "p2p" else size - 2
    print(f"{name:<15}{need!s:>4} -> {size:>3}  /{prefix}  {usable} usable")
print(f"total {total} of the 256 addresses in a /24")

Output

Labs            100 -> 128  /25  126 usable
Hostel Wi-Fi     50 ->  64  /26  62 usable
Staff            25 ->  32  /27  30 usable
Cameras          12 ->  16  /28  14 usable
Printers          5 ->   8  /29  6 usable
Link to campus  p2p ->   2  /31  2 usable
Link to ISP     p2p ->   2  /31  2 usable
total 252 of the 256 addresses in a /24

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 sizing.py

The seven blocks add up to 252 addresses, which fits in 256. Leave room where you expect growth: a hostel that might add a floor deserves the next size up now, because enlarging a subnet later means renumbering its neighbours.

Placing the blocks: largest first

A block of 2^k addresses must start at a multiple of 2^k: a /26 (64 addresses) may start at .0, .64, .128 or .192, and nowhere else. The usual method sorts the blocks from largest to smallest and places each at the next free address that is a multiple of its size:

The branch plan, largest first Python · vlsm.py
# A VLSM plan for 192.168.40.0/24: blocks sorted largest first, each placed at the next free address that is a
# multiple of its size, then the space that is left as CIDR blocks.
import ipaddress

BASE = ipaddress.ip_network("192.168.40.0/24")
BLOCKS = [("Labs", 128), ("Hostel Wi-Fi", 64), ("Staff", 32), ("Cameras", 16), ("Printers", 8),
          ("Link to campus", 2), ("Link to ISP", 2)]


def last_octet(address):
    return str(address).rsplit(".", 1)[1]


end = int(BASE.broadcast_address)
next_free = int(BASE.network_address)
print(f"{BASE}, largest first:")
for name, size in sorted(BLOCKS, key=lambda b: -b[1]):  # sorted() keeps equal sizes in their order
    next_free = (next_free + size - 1) // size * size     # align up to a multiple of the size
    if next_free + size - 1 > end:
        raise SystemExit(f"{name} does not fit")
    net = ipaddress.ip_network((next_free, 33 - size.bit_length()))
    hosts = list(net.hosts())
    start = f".{last_octet(net.network_address)}/{net.prefixlen}"
    span = f".{last_octet(hosts[0])}-.{last_octet(hosts[-1])}"
    edge = f"broadcast .{last_octet(net.broadcast_address)}" if size > 2 else "link"
    print(f"{name:<16}{start:<9}{span:<11}{edge}")
    next_free += size

free = ipaddress.summarize_address_range(ipaddress.ip_address(next_free), BASE.broadcast_address)
print("free:", ", ".join(map(str, free)))

Output

192.168.40.0/24, largest first:
Labs            .0/25    .1-.126    broadcast .127
Hostel Wi-Fi    .128/26  .129-.190  broadcast .191
Staff           .192/27  .193-.222  broadcast .223
Cameras         .224/28  .225-.238  broadcast .239
Printers        .240/29  .241-.246  broadcast .247
Link to campus  .248/31  .248-.249  link
Link to ISP     .250/31  .250-.251  link
free: 192.168.40.252/30

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 vlsm.py

Every block landed immediately after the previous one. That is not luck: a larger power of two is always a multiple of a smaller one, so when a block ends, the next free address is already aligned for the next block in the sorted list. No gaps open between blocks, and all the space that is left stays together at the end, 192.168.40.252/30 here, ready for the next request.

The order matters as soon as blocks of different sizes are mixed. This program places the same four blocks in three orders: as the requests were listed, smallest first and largest first.

The same blocks in three orders Python · vlsm_order.py
# Why VLSM places the largest blocks first: the same four blocks for 192.168.40.0/24 (232 addresses in all)
# placed in three orders, each block at the next free address that is a multiple of its size.
REQUESTS = [("Printers", 8), ("Labs", 128), ("Staff", 32), ("Hostel Wi-Fi", 64)]  # as they were listed


def place(blocks):
    next_free = 0
    for name, size in blocks:
        start = (next_free + size - 1) // size * size  # the next multiple of the size
        if start > next_free:
            print(f"  {'hole':<14}{start - next_free} addresses")
        if start + size > 256:
            print(f"  {name:<14}does not fit ({size} addresses)")
            return
        print(f"  {name:<14}192.168.40.{start}/{33 - size.bit_length()}")
        next_free = start + size
    print(f"  {'free':<14}{256 - next_free} addresses at the end")


for title, order in [("as listed", REQUESTS), ("smallest first", sorted(REQUESTS, key=lambda r: r[1])),
                     ("largest first", sorted(REQUESTS, key=lambda r: -r[1]))]:
    print(title)
    place(order)

Output

as listed
  Printers      192.168.40.0/29
  hole          120 addresses
  Labs          192.168.40.128/25
  Staff         does not fit (32 addresses)
smallest first
  Printers      192.168.40.0/29
  hole          24 addresses
  Staff         192.168.40.32/27
  Hostel Wi-Fi  192.168.40.64/26
  Labs          192.168.40.128/25
  free          0 addresses at the end
largest first
  Labs          192.168.40.0/25
  Hostel Wi-Fi  192.168.40.128/26
  Staff         192.168.40.192/27
  Printers      192.168.40.224/29
  free          24 addresses at the end

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 vlsm_order.py

Three bars for 192.168.40.0/24: largest first fits with free space at the end, smallest first leaves a hole, as listed does not fit.Largest first: fits, free space at the endLabs /25Hostel /26StaffPfree.0.128.255Smallest first: fits, with a holePholeStaffHostel /26Labs /25.0.128.255As listed: Staff /27 no longer fitsPhole of 120Labs /25.0.128.255Staff is a /27 (32 addresses) and P the Printers /29 (8).Each block starts at a multiple of its own size.

The same four blocks placed in three orders

Text description of the diagram

The diagram draws 192.168.40.0/24 three times as a bar from .0 to .255, to scale, with four blocks placed in it: Labs /25 (128 addresses), Hostel /26 (64), Staff /27 (32) and Printers /29 (8), 232 addresses in all. Every block starts at a multiple of its own size.

  1. Largest first: Labs at .0, Hostel at .128, Staff at .192 and Printers at .224, one after another with no gap. The last 24 addresses, .232 to .255, are free at the end.
  2. Smallest first: Printers at .0, then a hole of 24 addresses (.8 to .31), because Staff must start at a multiple of 32; then Staff at .32, Hostel at .64 and Labs at .128. Everything fits, but the free space sits in the middle.
  3. As listed (Printers, Labs, Staff, Hostel): Printers at .0, then a hole of 120 addresses, because Labs must start at a multiple of 128, so Labs takes .128 to .255. Staff no longer fits anywhere after it, although the four blocks need only 232 of the 256 addresses.

Taken as listed, the printers’ /29 goes to .0, so the labs’ /25 has to wait for the next multiple of 128 and starts at .128. The 120 addresses in between are stranded, and the staff’s /27 no longer fits, although the four blocks need only 232 of 256 addresses. Smallest first fits, but it leaves a hole of 24 addresses in the middle of the plan. Largest first fits with the same 24 addresses free, all of them at the end.

VLSM Calculator Enter a network and the hosts each subnet needs to see the blocks placed largest first, with masks, ranges and the working for each subnet.

Route summarisation and supernets

Once the subnets exist, other routers need routes to them. A summary route, also called an aggregate, is one shorter prefix that covers several longer ones, and it is the longest prefix that all of them share. RFC 4632 made aggregation the point of CIDR: routes that are next to each other in the address space and reached the same way are announced as one, which keeps routing tables small.

To find a summary by hand, write the octet where the networks differ in binary and count the bits they share. Take 10.4.0.0/24, 10.4.1.0/24, 10.4.2.0/24 and 10.4.3.0/24. The third octets are 0, 1, 2 and 3, which is 000000 00, 000000 01, 000000 10 and 000000 11: the first six bits are the same. With the 16 bits of the first two octets, the shared prefix is 22 bits, so the summary is 10.4.0.0/22. It covers 10.4.0.0 to 10.4.3.255, exactly the four networks.

RFC 1338, the proposal that CIDR grew from, is titled “Supernetting”. A supernet is a block of class C networks announced as one route with a prefix shorter than the class allowed: the four networks from 192.168.0.0/24 to 192.168.3.0/24, for example, as one /22. Without classes, a supernet is simply a summary.

Exact routes and a single summary Python · summarise.py
# Route summarisation: the exact routes for a set of networks (collapse_addresses) and the one shortest prefix that
# covers them all, with the addresses that the summary covers but nobody listed.
import ipaddress


def covering(networks):
    low = min(int(n.network_address) for n in networks)
    high = max(int(n.broadcast_address) for n in networks)
    prefix = 32 - (low ^ high).bit_length()  # the bits that all addresses share
    return ipaddress.ip_network((low, prefix), strict=False)


def minus(summary, used):
    left = [summary]
    for u in used:
        left = [part for block in left
                for part in (block.address_exclude(u) if u.subnet_of(block) else [] if block.subnet_of(u) else [block])]
    return list(ipaddress.collapse_addresses(left))


for listed in [["10.4.0.0/24", "10.4.1.0/24", "10.4.2.0/24", "10.4.3.0/24"],
               ["10.4.1.0/24", "10.4.2.0/24", "10.4.3.0/24", "10.4.4.0/24"]]:
    nets = [ipaddress.ip_network(n) for n in listed]
    exact = list(ipaddress.collapse_addresses(nets))
    summary = covering(nets)
    extra = minus(summary, exact)
    print(f"{listed[0]} to {listed[-1]}")
    print("  exact routes:", ", ".join(map(str, exact)))
    print("  one summary: ", summary)
    print(f"  it covers {summary.num_addresses} addresses, {sum(n.num_addresses for n in exact)} of them listed")
    print("  extra:", ", ".join(map(str, extra)) or "nothing")

Output

10.4.0.0/24 to 10.4.3.0/24
  exact routes: 10.4.0.0/22
  one summary:  10.4.0.0/22
  it covers 1024 addresses, 1024 of them listed
  extra: nothing
10.4.1.0/24 to 10.4.4.0/24
  exact routes: 10.4.1.0/24, 10.4.2.0/23, 10.4.4.0/24
  one summary:  10.4.0.0/21
  it covers 2048 addresses, 1024 of them listed
  extra: 10.4.0.0/24, 10.4.5.0/24, 10.4.6.0/23

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 summarise.py

collapse_addresses() returns the exact routes: the fewest prefixes that cover precisely the listed networks. The covering() function in the program finds the one shortest prefix that covers them all, which may cover more.

When a summary covers too much

The second set of networks in the output starts at 10.4.1.0 instead of 10.4.0.0. Its exact routes are three prefixes, and the only single prefix that covers it is 10.4.0.0/21: 2,048 addresses, of which the branch has 1,024. Announcing that /21 claims 10.4.0.0/24 and 10.4.5.0 to 10.4.7.255, which belong to nobody here, or to somebody else.

Two rules of RFC 4632 decide what happens next:

  • Forwarding uses the longest match. A router picks the most specific route that contains the destination, the rule RFC 1812 calls longest match. With routes to 10.0.0.0/8, to the branch’s 10.4.0.0/21 and to another site’s 10.4.5.0/24, a packet for 10.4.5.9 matches all three and takes the /24. So if another site announces 10.4.5.0/24, its traffic still goes there, and the summary only attracts the addresses that nobody announces more precisely. The same rule means that a more specific route announced by mistake wins over a correct summary.
  • An aggregate needs a discard route. A router that announces a summary must drop packets that match the summary but none of its more specific routes; the usual way is a “null” or “discard” route for the summary. Without it, a packet for a missing part of the summary would follow a less specific route, often the default route back the way it came, and bounce between two routers until its time to live runs out.

So summarise only space you hold, announce exact routes when the networks do not fill a summary (three routes here), and when you plan addresses, give each site a block that is aligned on its own size so that one summary describes it exactly.

From an address range to CIDR blocks

Firewalls, cloud security groups and allow-lists take prefixes, but address lists often arrive as ranges. The conversion is greedy: from the first address, take the largest block that starts there (aligned on its own size) and does not run past the end of the range, then continue from the address after it.

For 192.168.1.10 to 192.168.1.20, the largest block that may start at .10 is a /31 (.10 and .11), because .10 is even but not a multiple of 4. From .12 a /30 fits (.12 to .15), from .16 another /30 (.16 to .19), and .20 is left alone as a /32: four blocks for eleven addresses.

Ranges as the fewest CIDR blocks Python · range_to_cidr.py
# An address range as the fewest CIDR blocks: from the first address, take the largest block that starts there
# (aligned on its own size) and does not run past the end, then repeat.
import ipaddress


def range_to_cidr(first, last):
    start, end = int(ipaddress.ip_address(first)), int(ipaddress.ip_address(last))
    blocks = []
    while start <= end:
        size = start & -start if start else 2 ** 32  # the largest block that may start here
        while size > end - start + 1:                # shrink it until it fits in the range
            size //= 2
        blocks.append(f"{ipaddress.ip_address(start)}/{33 - size.bit_length()}")
        start += size
    return blocks


same = True
for first, last in [("192.168.1.10", "192.168.1.20"), ("10.0.0.0", "10.0.3.255"), ("172.16.5.1", "172.16.5.254")]:
    blocks = range_to_cidr(first, last)
    check = [str(n) for n in ipaddress.summarize_address_range(ipaddress.ip_address(first), ipaddress.ip_address(last))]
    same = same and blocks == check
    print(f"{first} - {last}: {len(blocks)} block{'s' if len(blocks) > 1 else ''}")
    for i in range(0, len(blocks), 3):
        print("  " + ", ".join(blocks[i:i + 3]))
print("same as ipaddress.summarize_address_range:", same)

Output

192.168.1.10 - 192.168.1.20: 4 blocks
  192.168.1.10/31, 192.168.1.12/30, 192.168.1.16/30
  192.168.1.20/32
10.0.0.0 - 10.0.3.255: 1 block
  10.0.0.0/22
172.16.5.1 - 172.16.5.254: 14 blocks
  172.16.5.1/32, 172.16.5.2/31, 172.16.5.4/30
  172.16.5.8/29, 172.16.5.16/28, 172.16.5.32/27
  172.16.5.64/26, 172.16.5.128/26, 172.16.5.192/27
  172.16.5.224/28, 172.16.5.240/29, 172.16.5.248/30
  172.16.5.252/31, 172.16.5.254/32
same as ipaddress.summarize_address_range: True

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 range_to_cidr.py

The third range shows why aligned ranges are cheap and others are not. 172.16.5.0 to 172.16.5.255 is one /24, but the same range without its first and last address, the usable hosts of that /24, needs 14 blocks. When you write firewall rules, a block that is slightly larger and aligned is often the better rule, as long as you hold every address it covers.

IP Range to CIDR Converter Paste ranges, single addresses or CIDR blocks to get the fewest prefixes, merge or subtract lists and export firewall rules.

Interview questions

What is VLSM, and why are the largest subnets allocated first?

Variable-length subnet masking (VLSM) lets the subnets of one network have different prefix lengths, so each gets only the addresses it needs: a 100-host lab gets a /25, a 12-host camera network a /28 and a router-to-router link a /31, instead of every subnet getting the size of the largest. Each block must start at a multiple of its own size. Sorting the requests largest first and placing each at the next free address satisfies that automatically, because a larger power of two is always a multiple of a smaller one: no gaps open between blocks and the unused space stays in one run at the end. Taking requests in the order they were written can strand space and even fail when the total would have fitted.

Key takeaways

  • VLSM gives each subnet its own size: hosts plus 2, rounded up to a power of two; /31 for point-to-point links and /32 for single addresses.
  • Every block starts at a multiple of its size. Placing blocks largest first keeps them back to back and the free space together at the end.
  • A summary is the longest prefix that all the networks share; it is exact only when the networks fill it.
  • Longest-match forwarding lets more specific routes override a summary, and a router that announces a summary needs a discard route for it.
  • Summarise only space you hold; otherwise announce the exact routes from collapse_addresses().
  • A range becomes CIDR blocks by taking, from each start, the largest aligned block that fits; unaligned ranges need many blocks.

Exercise

Exercise · Medium · Python

Plan subnets with VLSM and summarise routes

Write two functions in vlsm_plan.py.

**vlsm(base, requests)** plans variable-length subnets inside the IPv4 network base (a string such as "192.168.40.0/24"). requests is a dictionary from a name to what that subnet needs:

- a whole number of hosts, which gets the smallest power-of-two block that holds the hosts plus 2 (at least 4 addresses, a /30); - the string "p2p", a point-to-point link, which gets a /31.

Place the blocks largest first (blocks of equal size keep the order of requests), each at the next free address that is a multiple of its size. Return a pair: the list of (name, "network/prefix") tuples in the order they were placed, and the list of the free space after the last block as the fewest CIDR strings, in address order. Raise ValueError when a block does not fit.

**summarise(prefixes)** takes a list of network strings and returns a pair: the shortest single prefix that covers all of them, as a string, and how many addresses that prefix covers that none of the given networks contains. summarise(["10.4.1.0/24", "10.4.2.0/24", "10.4.3.0/24", "10.4.4.0/24"]) is ("10.4.0.0/21", 1024).

The sample tests import both functions from vlsm_plan.py.

Starter code · vlsm_plan.py

def vlsm(base, requests):
    """Place the requested subnets in base largest first; return (allocations, free space)."""
    # Replace this line with your code.
    return [], []


def summarise(prefixes):
    """Return the shortest prefix that covers all prefixes, and how many extra addresses it covers."""
    # Replace this line with your code.
    return "", 0
The sample tests · test_vlsm_plan.py
from vlsm_plan import summarise, vlsm


def refused(base, requests):
    """True when vlsm raises ValueError for this plan."""
    try:
        vlsm(base, requests)
    except ValueError:
        return True
    return False


def test_branch_plan():
    """places the lesson's seven subnets largest first"""
    allocations, free = vlsm("192.168.40.0/24", {
        "Printers": 5, "Labs": 100, "Link to ISP": "p2p", "Staff": 25,
        "Hostel Wi-Fi": 50, "Cameras": 12, "Link to campus": "p2p",
    })
    assert allocations == [
        ("Labs", "192.168.40.0/25"), ("Hostel Wi-Fi", "192.168.40.128/26"), ("Staff", "192.168.40.192/27"),
        ("Cameras", "192.168.40.224/28"), ("Printers", "192.168.40.240/29"),
        ("Link to ISP", "192.168.40.248/31"), ("Link to campus", "192.168.40.250/31"),
    ]
    assert free == ["192.168.40.252/30"]


def test_free_space_in_several_blocks():
    """returns the free space as the fewest CIDR blocks"""
    assert vlsm("10.0.0.0/24", {"Office": 60}) == ([("Office", "10.0.0.0/26")], ["10.0.0.64/26", "10.0.0.128/25"])
    assert vlsm("10.0.0.0/24", {"Tiny": 1}) == ([("Tiny", "10.0.0.0/30")], [
        "10.0.0.4/30", "10.0.0.8/29", "10.0.0.16/28", "10.0.0.32/27", "10.0.0.64/26", "10.0.0.128/25",
    ])


def test_sizes_at_the_edges():
    """rounds hosts plus 2 up to the next power of two"""
    allocations, free = vlsm("172.16.0.0/22", {"a": 126, "b": 127, "c": 254})
    assert allocations == [("b", "172.16.0.0/24"), ("c", "172.16.1.0/24"), ("a", "172.16.2.0/25")]
    assert free == ["172.16.2.128/25", "172.16.3.0/24"]


def test_exactly_full():
    """fills the network to its last address and leaves no free space"""
    assert vlsm("10.0.0.0/24", {"a": 126, "b": 126}) == ([("a", "10.0.0.0/25"), ("b", "10.0.0.128/25")], [])
    assert vlsm("192.0.2.0/30", {"link": "p2p", "other": "p2p"}) == ([("link", "192.0.2.0/31"), ("other", "192.0.2.2/31")], [])


def test_does_not_fit():
    """raises ValueError when the blocks do not fit"""
    assert refused("192.168.40.0/24", {"Labs": 200, "Staff": 60})
    assert refused("192.168.40.0/26", {"Labs": 100})


def test_summarise_exact():
    """summarises contiguous, aligned networks with nothing extra"""
    assert summarise(["10.4.0.0/24", "10.4.1.0/24", "10.4.2.0/24", "10.4.3.0/24"]) == ("10.4.0.0/22", 0)
    assert summarise(["192.168.0.0/25", "192.168.0.128/25"]) == ("192.168.0.0/24", 0)


def test_summarise_over_coverage():
    """counts the addresses a summary covers but nobody listed"""
    assert summarise(["10.4.1.0/24", "10.4.2.0/24", "10.4.3.0/24", "10.4.4.0/24"]) == ("10.4.0.0/21", 1024)
    assert summarise(["172.16.8.0/24", "172.16.11.0/24"]) == ("172.16.8.0/22", 512)


def test_summarise_overlaps_and_one_network():
    """counts overlapping networks once and summarises one network as itself"""
    assert summarise(["10.4.1.0/24", "10.4.1.0/25"]) == ("10.4.1.0/24", 0)
    assert summarise(["203.0.113.0/24"]) == ("203.0.113.0/24", 0)
A hint

For vlsm, turn each request into a block size first, then sort with sorted(..., key=...), which keeps equal sizes in their order. Rounding n up to a multiple of size is (n + size - 1) // size * size. For summarise, the covering prefix keeps the bits that the lowest and the highest address share: 32 - (low ^ high).bit_length() of them. ipaddress.collapse_addresses() merges the given networks, so overlaps are not counted twice.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Check yourself

6 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 6 With VLSM, which prefix length does a subnet for 60 hosts get? Type the number after the slash.

    Type a number.

    Show the answer to question 1

    Answer: 26

    60 hosts plus the network and broadcast addresses make 62, and the next power of two is 64, a block of 6 host bits: 32 − 6 = 26, so the subnet is a /26 with 62 usable addresses.

  2. Question 2 of 6 Which single route summarises exactly 172.16.8.0/24, 172.16.9.0/24, 172.16.10.0/24 and 172.16.11.0/24?

    Choose one answer.

    Show the answer to question 2

    Answer: 172.16.8.0/22

    In binary the third octets are 000010 00, 01, 10 and 11: the first 6 bits are the same, so 16 + 6 = 22 bits are shared. 172.16.8.0/22 covers 172.16.8.0 to 172.16.11.255, exactly the four networks.

  3. Question 3 of 6 Which of these networks lie inside 10.4.0.0/21?

    Choose every answer that is right.

    Show the answer to question 3

    Answer:

    • 10.4.6.0/23
    • 10.4.0.0/24
    • 10.4.7.128/25

    A /21 has a block size of 8 in the third octet, so 10.4.0.0/21 runs from 10.4.0.0 to 10.4.7.255. 10.4.8.0/24 starts the next /21, and 10.5.0.0/24 is in another /16 altogether.

  4. Question 4 of 6 Why does a router that announces a summary install a discard (null) route for it?

    Choose one answer.

    Show the answer to question 4

    Answer: So that packets for unreachable parts of the summary are dropped instead of looping along a default route

    RFC 4632 requires a router that generates an aggregate to discard packets that match the aggregate but none of its more specific routes. Without that, such packets would follow a less specific route, often the default route back towards the sender, and loop.

  5. Question 5 of 6 How many CIDR blocks are needed, at the fewest, to cover exactly 10.0.0.1 to 10.0.0.6?

    Type a number.

    Show the answer to question 5

    Answer: 4 blocks

    From 10.0.0.1 only a /32 fits, then 10.0.0.2/31 (.2 and .3), 10.0.0.4/31 (.4 and .5) and 10.0.0.6/32. A /30 at .4 would reach .7, past the end of the range.

  6. Question 6 of 6 What does placing VLSM blocks largest first guarantee?

    Choose one answer.

    Show the answer to question 6

    Answer: Each block starts right where the previous one ended, so no gaps open between blocks

    A larger power of two is always a multiple of a smaller one, so after a block ends the next free address is already aligned for the next, smaller block. The total used is the same in any order that fits; the gain is that nothing is stranded between blocks and the free space stays in one run at the end.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.