Lesson 17 / 17
Address and Naming Plan
On the same topology, a summarizable plan holds the table at 73 rows as the subnet count climbs from nine to thirty-six, while a plan distributed by creation order climbs from 90 rows to 335 on the same path; a single moved network leaves a summary announcing an address it no longer owns, and two packets fall into a black hole.
Contents
The previous three lessons measured topology as a graph, and table row count appeared as a column in every measurement: 272 in the three-layer design, 468 in the four-spine design. Every time, what determined the row count was the topology.
There is a second thing that determines row count, and it has nothing to do with topology: how destinations are named. On the same devices, with the same links, with the same number of subnets, two different address plans fill the same table with wildly different row counts. This lesson’s question is what the plan does to the table.
The Plan’s One Condition
A routing table can summarize neighboring addresses in a single row. This is called route summarization, and it has a single condition: every address in the summarized range must be reachable through the same next hop. The range must be aligned, and no address heading in another direction may fall inside it.
The netmask, alignment, and block-stride arithmetic were established in the Subnetting and Variable-Length Subnetting lessons and are not repeated here. What is measured is not the arithmetic itself, but its effect on table rows.
A plan either satisfies this condition or it does not. A plan that satisfies it divides the address space the same way the topology is divided: an aligned range for each block, an aligned sub-range for each leaf within that range, and growth room in both. A plan that does not satisfy it hands out addresses from a single pool in creation order.
# taught transcript, not run aligned plan — 64-slot space, four blocks, three in use block 0 slots 0-15 y1: 0-3 y2: 4-7 y3: 8-11 12-15 growth room block 1 slots 16-31 block 2 slots 32-47 block 3 48-63 reserved c1's table: 0-15 -> d1 16-31 -> d3 32-47 -> d5 creation-order plan — single pool, creation order slot 0 -> y1 slot 1 -> y2 slot 2 -> y3 slot 3 -> y4 ... two consecutive slots fall into separate blocks; no summarizable range forms
The assumptions the measurement rests on:
- TD27 — The topology is the first lesson’s three-layer design: nine leaves, three blocks, six distribution and two core nodes. The topology is the same in both plans; the only thing that changes is the plan.
- TD28 — The address space is 64 slots, and a slot represents one subnet. In the aligned
plan, each block gets 16 slots and each leaf gets 4;
kslots are used per leaf, and the rest is growth room. - TD29 — Row count is counted as the fewest aligned prefixes that cover a node’s table. An empty slot may fall inside a prefix; a slot heading in another direction may not.
- TD30 — The oracle is known because we built the topology ourselves, and it is, for every node, the first hop of the shortest path to every leaf. The packet is run with longest-prefix match.
- TD31 — The count of name zones is the fewest ranges countable without changing block when names are laid out in the plan’s order. Name resolution itself is the subject of The Domain Name System lesson and is not repeated here.
- TD32 — In a set of forty packets, the smallest measurable difference is 1/40 = 0.025.
The Measurement
"""Address and naming plan: the plan's effect on table row count. Part 1 - aligned plan vs. creation-order plan, 1-4 subnets per leaf. Part 2 - a summary announcing an address it no longer owns. """ SEED = 20260810 SLOT = 64 LEAF = [f"y{i}" for i in range(1, 10)] BLOCK = {0: LEAF[0:3], 1: LEAF[3:6], 2: LEAF[6:9]} DISTRIBUTION = {"d1": 0, "d2": 0, "d3": 1, "d4": 1, "d5": 2, "d6": 2} NODES = LEAF + sorted(DISTRIBUTION) + ["c1", "c2"] LINKS = ([(y, d) for d, b in DISTRIBUTION.items() for y in BLOCK[b]] + [(d, c) for d in sorted(DISTRIBUTION) for c in ("c1", "c2")] + [("c1", "c2")]) def make_rng(seed): state = seed % 2147483646 + 1 def rand(n): nonlocal state state = (state * 48271) % 2147483647 return state % n return rand def neighbors(): k = {u: set() for u in NODES} for x, y in LINKS: k[x].add(y) k[y].add(x) return k def oracle(): """The first hop of the shortest path to every destination, for every node.""" k, table = neighbors(), {} for source in NODES: prev, front = {}, [source] while front: new = [] for u in front: for v in sorted(k[u]): if v != source and v not in prev: prev[v] = u new.append(v) front = new for h in prev: step = h while prev[step] != source: step = prev[step] table[(source, h)] = step return table def aligned(k): """Each block gets 16 slots, each leaf 4; k of them are filled, the rest is growth room.""" return {16 * b + 4 * j + i: y for b, leaves in BLOCK.items() for j, y in enumerate(leaves) for i in range(k)} def creation_order(k): """Subnets are handed out from a single pool, in creation order.""" return {n: LEAF[n % 9] for n in range(9 * k)} def prefixes(u, plan, start=0, size=SLOT): """The fewest aligned prefixes that cover u's table.""" inside = {("local" if y == u else ORACLE[(u, y)]) for slot, y in plan.items() if start <= slot < start + size} if len(inside) < 2: return [(start, size, inside.pop())] if inside else [] return (prefixes(u, plan, start, size // 2) + prefixes(u, plan, start + size // 2, size // 2)) def forward(source, slot, prefix, neigh, truth): """Runs with longest-prefix match; arrival is checked against actual ownership.""" u, hops = source, 0 while hops < 12: candidates = [p for p in prefix[u] if p[0] <= slot < p[0] + p[1]] if not candidates: return "black hole" v = min(candidates, key=lambda p: p[1])[2] if v == "local": return "reached" if truth.get(slot) == u else "black hole" if v not in neigh[u]: return "black hole" u, hops = v, hops + 1 return "loop" def pairs(count=40, seed=SEED): rand, out = make_rng(seed), [] while len(out) < count: x, y = LEAF[rand(9)], LEAF[rand(9)] if x != y: out.append((x, y)) return out def zones(plan): """The fewest regions countable in the name sequence without changing block.""" prev, count = None, 0 for _, y in sorted(plan.items()): b = next(i for i, ys in BLOCK.items() if y in ys) if b != prev: count, prev = count + 1, b return count def measure(plan, dest=None, truth=None): """Rows come from the plan, destinations from the address plan, arrival from ground truth.""" dest, truth = dest or plan, truth or plan neigh = neighbors() prefix = {u: prefixes(u, plan) for u in NODES} first, counts = {}, {"reached": 0, "loop": 0, "black hole": 0} for slot, y in sorted(dest.items()): first.setdefault(y, slot) for x, y in pairs(): counts[forward(x, first[y], prefix, neigh, truth)] += 1 return sum(len(p) for p in prefix.values()), len(prefix["c1"]), counts ORACLE = oracle() print(f"{'plan':<16s} {'per leaf':>8s} {'subnets':>7s} " f"{'total rows':>10s} {'c1':>3s} {'name zones':>10s} {'reached':>7s}") for name, build in (("aligned", aligned), ("creation order", creation_order)): for k in (1, 2, 3, 4): plan = build(k) rows, c1, s = measure(plan) print(f"{name:<16s} {k:8d} {len(plan):7d} {rows:10d} {c1:3d} " f"{zones(plan):10d} {s['reached']:7d}") print() home = aligned(4) moved = {slot: ("y1" if y == "y9" else y) for slot, y in home.items()} print(f"{'state':<32s} {'total rows':>10s} {'c1':>3s} {'reached':>7s} " f"{'black hole':>10s}") for name, plan, truth in (("plan in place", home, None), ("moved, summary not updated", home, moved), ("moved, separate row added", moved, moved)): rows, c1, s = measure(plan, home, truth) print(f"{name:<32s} {rows:10d} {c1:3d} {s['reached']:7d} " f"{s['black hole']:10d}")
plan per leaf subnets total rows c1 name zones reached aligned 1 9 73 3 3 40 aligned 2 18 73 3 3 40 aligned 3 27 73 3 3 40 aligned 4 36 73 3 3 40 creation order 1 9 90 6 3 40 creation order 2 18 171 12 6 40 creation order 3 27 249 17 9 40 creation order 4 36 335 24 12 40 state total rows c1 reached black hole plan in place 73 3 40 0 moved, summary not updated 73 3 38 2 moved, separate row added 76 4 40 0
Row Count Can Be Independent of Subnet Count
The first four rows of the top table are the whole lesson. In the aligned plan, as subnet count climbs from 9 to 36, total table rows stay at 73. A network that quadruples in size adds not a single row to its table. The core’s table holds at 3 rows: one prefix per block.
The bottom four rows show the same topology with addresses distributed by creation order. Total rows climb 90, 171, 249, 335 — linear with subnet count. At thirty-six subnets, the gap is 73 against 335, a factor of 4.6. The core’s table holds 24 rows instead of 3.
The source of the gap is a single condition. In the aligned plan, every address in a block is reachable through the same next hop, so a single prefix covers all of them. In the creation-order plan, two consecutive addresses fall into separate blocks; no coverable range remains, and the table drops to one row per address.
The name zones column repeats the same accounting for names. In the aligned plan, when names
are laid out in the plan’s order, 3 ranges result — one zone per block. In names laid out by
creation order, the count grows 3, 6, 9, 12. A naming plan is not a separate design; it is
the same question as the address plan, and it is measured with the same arithmetic.
One thing does not change: the reached column reads 40 in all eight rows. The plan does not
lose packets, it only grows the table. The plan’s cost is not in latency, it is in the state
carried.
The Address the Summary Does Not Own
The bottom table measures the summary’s single weak point. If the networks attached to y9 are
moved to a different leaf and their addresses stay the same, the tables do not change at all —
total rows are still 73, the core still 3. But 2 of the forty packets fall into a
black hole.
The reason is this: the core’s 32-47 -> d5 row now announces an address it no longer owns. A
summary says that every address it covers lies in that direction; the moved network does not lie
in that direction. The summary is not wrong, it is over-broad — and a truth that over-covers
is a falsehood.
The fix is in the last row. If a separate, narrower row is added for the moved network, all forty of the forty packets reach; the cost is rows climbing from 73 to 76 in total, and from 3 to 4 at the core. Three rows look small, but the rule is plain: every exception is a row, and exceptions accumulate. The plan is the only thing protecting the table from growth; the way to keep protecting it is to renumber the moved network.
Summary
- Route summarization has a single condition: every address in the summarized range must be reachable through the same next hop; a plan either satisfies this condition or it does not.
- In the aligned plan, as subnet count climbs from 9 to 36, total rows stay at 73 and the core’s table stays at 3.
- In the plan distributed by creation order, the same topology holds 90, 171, 249, 335 rows; at thirty-six subnets the gap is a factor of 4.6.
- A naming plan is not a separate design: the name zone count stays at 3 in the aligned plan, and climbs from 3 to 12 for names laid out by creation order.
- A single moved network leaves the summary announcing an address it no longer owns, and 2 packets fall into a black hole; adding a separate row fixes it but raises the row count from 73 to 76.
Course Wrap-Up
The course opened with a single question: if the decision is read not from what is written in the packet but from the device’s own table, and that table is a copy of a shared truth, what happens to the packet for as long as the copies disagree? Seventeen lessons asked this question with seventeen separate disagreements, and every one counted the same three fates.
| lesson | disagreement measured | reached | loop or black hole |
|---|---|---|---|
| Repeater, Hub, and Switch | the absence of any table | 40 frames, 280 deliveries | none; 240 unnecessary copies, 34 collisions |
| MAC Address Tables | the entry’s age | 110 deliveries, 278 once lifetime is shortened | 3 black holes, 0 once lifetime is shortened |
| VLANs | the segment’s boundary against the table’s scope | flooding delivery 280, 51, 8 | black holes 0, 23, 29, 32 |
| Spanning Tree Protocol | the tree was renewed, tables are stale | 40/40 on the tree, 106 and 129 hops | 19 and 20 black holes; 10 loops once two switches refresh |
| Link Aggregation | leg mapping against the leg’s state | 8 flows distributed without splitting | 2 black holes in a five-frame window |
| Routing Decision | the copy’s age and the reading rule | converged 40/40, 83 and 99 hops | 14 black holes at the moment of the break |
| Static and Dynamic Routing | the static table never hears about the break | 40 in two rounds under dynamic | 14 black holes under static, fixed for six rounds; 6 loops once two nodes hear |
| Distance Vector Protocols | the age of the neighbor’s decision | 0, 9, 20, 32, 40 — four rounds | sixty of sixty packets loop at an unreachable destination; split horizon brings it down to 5 |
| Link State Protocols | the database’s missing entry | 9, 20, 32, 40 — three rounds | no loop; a wrong table comes only from the missing entry |
| Border Gateway Protocol | policy against the shortest path | 40/40 under the transit ban, 92 hops | 14 black holes once the advertisement closes; 7 packets outside the contract in the leak |
| Routing Instances | the same destination’s two decisions across two instances | 40/40 across three instances, 83, 99, 91 hops | 14 black holes once reduced to a single table |
| MPLS and Label Switching | the label path against the underlying link’s state | 40 full-view and 43 label-view hops | 14 black holes when the chord breaks and the path is not renewed |
| Overlay Networks | the overlay’s table against the underlay’s table | 40/40 with both layers converged, overlay 74 hops | 21 tunnel black holes while the underlay is stale; 12 overlay loops once the tunnel drops and both ends hear |
| Layered Design | cold start and the busiest link breaking | 40/40 across three designs; 121, 80, 138 hops | 21 permanent black holes in the flat chain |
| Spine–Leaf Design | the loss of a leaf-spine link | 40/40, 80 hops, every path 2 hops | 14 permanent black holes with a single spine, 0 from two onward |
| Redundancy and Failover | who holds the virtual address | 40/40 with failover | 40 black holes when nobody has heard; 40 loops when both believe the peer active |
| Address and Naming Plan | what the summary covers against what it owns | 40/40 with 73 rows | 2 black holes in the moved network |
The table repeats three things over and over. Partial information produces a more expensive failure than no information: a break nobody hears about gives a black hole, and the failure is unmistakable; a break a few nodes hear about gives a loop, and it looks like congestion. No single device can put a packet into a loop by itself: a loop is a disagreement between at least two tables, and a packet leaving a node whose own table is correct can still die. And convergence is not a speed, it is a round count: how many rounds it takes depends on how far the information has to travel.
All of these measurements shared one silent assumption. A link either exists or it does not; a neighbor either hears or it does not; a frame either gets forwarded or it does not. If a cable exists between two devices, what that cable carries reaches the other side — throughout the course, the opposite was never considered, except in the case of a break. The next course lifts this assumption: on a wireless link, whether a transmitted frame arrives is not a certainty but a probability, the medium is shared, and who is listening is unknown. Everything the wired link took as given will be asked again there.
To keep your progress and take notes, Log in
My notes
Log in to take notes.