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.
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 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
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
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:
# 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
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
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.
# 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
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
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.
- 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.
- 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.
- 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.
# 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
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
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.
# 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
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
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.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
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.
References
- RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan (RFC Editor (IETF))
- RFC 1338: Supernetting: an Address Assignment and Aggregation Strategy (RFC Editor (IETF))
- RFC 1812: Requirements for IP Version 4 Routers (RFC Editor (IETF))
- RFC 3021: Using 31-Bit Prefixes on IPv4 Point-to-Point Links (RFC Editor (IETF))
- RFC 1878: Variable Length Subnet Table For IPv4 (RFC Editor (IETF))
- ipaddress: IPv4/IPv6 manipulation library (collapse_addresses() and summarize_address_range()) (Python Software Foundation)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress