Lesson 13 / 17
Overlay Networks
A logical topology built with tunnels keeps its own table and never sees the table beneath it: when the underlay breaks, not a single row of the overlay's table changes, but the underlay's hops climb from 188 to 211; when the underlay's tables go stale, 21 packets die even though the overlay's table is correct; and the overlay tables' partial information puts 12 packets into a loop with not a single wrong decision in the underlay.
Contents
The previous lesson moved the decision to the edge, but the path still ran over the
network’s own links: a labeled packet going from b to c genuinely used the b–c
link. The label named the path, and the path it named was physical.
This lesson’s question is: what would happen if the link between two nodes were not a physical link but a logical one, built over another network? Then there would not be one table but two tables, the two would converge separately, and the packet’s fate would be tied to both of them agreeing. This is the most extreme form of the course’s axis of measurement.
Overlay and Underlay
An overlay network is a logical topology built with tunnels. A link in the overlay
does not mean there is a direct cable between two nodes; it means those two nodes
count each other as neighbors. The real set of links the overlay stands on is called
the underlay. (Subnet on its own is reserved for the concept that divides an
address block; the concept here is named the underlay, and the two are not to be
confused.)
The Containers course built container networks’ overlay; that procedure is not repeated here. Here, the overlay is measured as a logical topology: it has its own table, its own neighborhood, its own convergence, and its own hop counter.
# taught transcript, not run overlay link path in the underlay meaning a-c a-b-c a and c are neighbors in the overlay a-e a-b-f-e a and e are neighbors in the overlay c-f c-b-f c and f are neighbors in the overlay tunneled packet outer header source a dest c <- only the underlay reads this inner header source a dest g <- only the overlay reads this payload ... node a's two tables overlay table underlay table dest next hop dest next hop g e c b d d e b
The two tables on the right are the whole lesson. Node a’s overlay points to e for
destination g; e is a neighbor in the overlay but three hops away in the underlay.
As the packet leaves a, it goes to b according to the underlay table, and the
overlay never sees this at all. The two tables are inside the same device, and
neither reads the other.
This has a direct consequence: one overlay hop is several hops in the underlay. The two layers’ counters are separate, and they have to be counted separately.
The measurement’s assumptions:
- RT81 — The underlay is the same throughout the course: eight nodes, the
a–b–c–d–e–f–g–h–aring, and theb–fchord that cuts the ring. - RT82 — The overlay is built from nine tunnels, and none of the tunnels is the same as an underlay link; every tunnel corresponds to a path of between two and four hops in the underlay.
- RT83 — The two layers’ tables are computed separately and do not see each other. The rule is the same in both: the first hop of the shortest path to every destination. The oracle is not changed.
- RT84 — Every layer has its own hop counter, and the limit for both is 12. Underlay hops spent inside one overlay hop are not added to the overlay counter.
- RT85 — An overlay hop is counted as taken only if the tunnel was delivered in the underlay; if the tunnel cannot be delivered, the packet’s fate is the tunnel’s fate.
- RT86 — In the last two regimes, the overlay link that drops is the
a–ctunnel. In the fourth, onlyaandchear about the drop; the other seven nodes keep their old overlay table. - RT87 — In the last two regimes, the underlay’s table is the oracle itself: there is not a single wrong decision in the underlay, and not a single tunnel is undeliverable.
- RT88 — The forty source–destination pairs come from the course’s core generator,
each occurrence is a separate packet, and the set’s resolution is
1/40 = 0.025.
Measurement
"""Overlay network: when the overlay's table and the underlay's table disagree.""" SEED = 20260810 NODES = "abcdefgh" LINKS = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("f", "g"), ("g", "h"), ("h", "a"), ("b", "f")] BROKEN = [b for b in LINKS if b != ("b", "f")] OVERLAY = [("a", "c"), ("a", "d"), ("a", "e"), ("b", "d"), ("b", "g"), ("c", "f"), ("d", "h"), ("e", "g"), ("f", "h")] HOP_LIMIT = 12 def generator(seed): d = seed % 2147483646 + 1 def r(n): nonlocal d d = (d * 48271) % 2147483647 return d % n return r def pairs(count=40): r, result = generator(SEED), [] while len(result) < count: x, y = NODES[r(8)], NODES[r(8)] if x != y: result.append((x, y)) return result def neighbors(links): k = {u: set() for u in NODES} for x, y in links: k[x].add(y) k[y].add(x) return k def oracle(links): """The first hop of the shortest path for every node to every destination.""" kom, t = neighbors(links), {} for source in NODES: prev, frontier, seen = {}, [source], {source} while frontier: nxt = [] for u in frontier: for v in sorted(kom[u]): if v not in seen: seen.add(v) prev[v] = u nxt.append(v) frontier = nxt for dest in NODES: if dest == source or dest not in prev: continue step = dest while prev[step] != source: step = prev[step] t[(source, dest)] = step return t def forward(source, dest, t, links): """Runs a single layer; returns the fate and the hops it took.""" kom, u, crossed, hop = neighbors(links), source, [], 0 while u != dest: if hop >= HOP_LIMIT: return "loop", hop s = t.get((u, dest)) if s is None or s not in kom[u]: return "black hole", hop if (u, s) in crossed: return "loop", hop crossed.append((u, s)) u, hop = s, hop + 1 return "reached", hop def overlay_forward(source, dest, over, over_links, under, under_links): """Every overlay hop is a tunnel, and it is also run in the underlay.""" kom, u, crossed, over_hop, under_hop = neighbors(over_links), source, [], 0, 0 while u != dest: if over_hop >= HOP_LIMIT: return "overlay loop", over_hop, under_hop s = over.get((u, dest)) if s is None or s not in kom[u]: return "overlay black hole", over_hop, under_hop if (u, s) in crossed: return "overlay loop", over_hop, under_hop fate, a = forward(u, s, under, under_links) under_hop += a if fate != "reached": return "tunnel " + fate, over_hop, under_hop crossed.append((u, s)) u, over_hop = s, over_hop + 1 return "reached", over_hop, under_hop def partial(old, new, informed): """Only the informed set has heard that the overlay link came down.""" return {(u, h): (new if u in informed else old)[(u, h)] for (u, h) in old if (u, h) in new} def measure(over, over_links, under, under_links): tally = {"reached": 0, "overlay loop": 0, "overlay black hole": 0, "tunnel black hole": 0, "tunnel loop": 0} oa = ua = 0 for x, y in pairs(): fate, o_, a_ = overlay_forward(x, y, over, over_links, under, under_links) tally[fate] += 1 oa += o_ ua += a_ return tally, oa, ua UP, DOWN, DOWN_NEW = oracle(OVERLAY), oracle(LINKS), oracle(BROKEN) MISSING = [b for b in OVERLAY if b != ("a", "c")] UP_MISSING = oracle(MISSING) REGIME = (("both layers converged", UP, OVERLAY, DOWN, LINKS), ("underlay broke, converged", UP, OVERLAY, DOWN_NEW, BROKEN), ("underlay broke, table stale", UP, OVERLAY, DOWN, BROKEN), ("tunnel dropped, two ends heard", partial(UP, UP_MISSING, {"a", "c"}), MISSING, DOWN, LINKS), ("tunnel dropped, everybody heard", UP_MISSING, MISSING, DOWN, LINKS), ("both layers stale", partial(UP, UP_MISSING, {"a", "c"}), MISSING, DOWN, BROKEN)) RESULT = [(name, measure(over, ol, under, ul)) for name, over, ol, under, ul in REGIME] print(f"{'regime':<32s} {'reached':>7s} {'overlay loop':>16s} " f"{'tunnel black hole':>18s}") for name, (s, oa, ua) in RESULT: print(f"{name:<32s} {s['reached']:7d} {s['overlay loop']:16d} " f"{s['tunnel black hole']:18d}") print() print(f"{'regime':<32s} {'overlay hops':>14s} {'underlay hops':>20s}") for name, (s, oa, ua) in RESULT: print(f"{name:<32s} {oa:14d} {ua:20d}") print() print("a tunnel's length in the underlay") print(f"{'tunnel':>6s} {'converged':>11s} {'after break':>14s} {'with old table':>15s}") for x, y in OVERLAY: _, a0 = forward(x, y, DOWN, LINKS) k1, a1 = forward(x, y, DOWN_NEW, BROKEN) k2, a2 = forward(x, y, DOWN, BROKEN) print(f"{x + '-' + y:>6s} {a0:11d} {a1:14d} " f"{('black hole' if k2 != 'reached' else str(a2)):>15s}")
regime reached overlay loop tunnel black hole both layers converged 40 0 0 underlay broke, converged 40 0 0 underlay broke, table stale 19 0 21 tunnel dropped, two ends heard 28 12 0 tunnel dropped, everybody heard 40 0 0 both layers stale 17 3 20 regime overlay hops underlay hops both layers converged 74 188 underlay broke, converged 74 211 underlay broke, table stale 40 124 tunnel dropped, two ends heard 77 205 tunnel dropped, everybody heard 97 264 both layers stale 41 134 a tunnel's length in the underlay tunnel converged after break with old table a-c 2 2 2 a-d 3 3 3 a-e 3 4 black hole b-d 2 2 2 b-g 2 3 black hole c-f 2 3 black hole d-h 4 4 4 e-g 2 2 2 f-h 2 2 2
The Overlay Never Sees the Break
The first two regimes measure the chord breaking. All forty of the forty packets arrive in both regimes, and overlay hops are 74 in both. Not a single row of the overlay’s table changed; as far as the overlay is concerned, nothing happened.
Underlay hops climb from 188 to 211. The third table says where the twenty-three
extra hops come from: the a-e tunnel goes from three hops to four, the b-g and
c-f tunnels go from two hops each to three each. These were the tunnels using the
chord; once the chord was gone, the underlay built them from the other side of the ring.
This is the overlay’s most advertised feature, and the measurement confirms it: as long as the underlay repairs itself, the overlay never sees the break at all. But the measurement gives the cost too. An observer watching the overlay cannot see the twenty-three extra hops, because nothing has changed in its own counter. The layer hides the fault, and hides the cost along with it.
Correct Table, Dead Packet
The third regime measures the same break with the underlay not yet converged. The overlay’s table still has not changed, and it is still correct; only 19 of the forty packets arrive, and 21 fall into a tunnel black hole.
The third table’s last column names three tunnels: a-e, b-g, and c-f cannot be
delivered with the old underlay table. The overlay still counts these three links as
standing and sends packets to them.
This is the first form of two-layer disagreement: the table above is flawless, and the packet still dies. A check that looks only at the overlay’s own metrics reports no fault at all — the overlay’s neighborhoods are complete, its paths are valid, its hop count is even lower than expected (40, because a dying packet stops spending hops). The fault is a layer below, and the layer above cannot see it.
Underlay Flawless, Overlay in a Loop
The fourth regime turns the disagreement around. In this regime, the underlay’s table
is the oracle itself: there is not a single wrong decision in the underlay, and all
nine of the nine tunnels are deliverable. The only thing that changes is in the
overlay — the a-c tunnel has dropped, and only a and c have heard about it.
The result: 28 of the forty packets arrive, 12 enter an overlay loop. Black hole is zero. The fifth regime measures the same tunnel drop when everybody has heard about it: 40 arrive, overlay hops climb to 97, underlay hops to 264.
The course’s second claim gets paid off again here, one layer up. Partial
information produces a fault more expensive than total ignorance: when everybody has
heard, forty packets arrive; when only the two ends have heard, twelve packets circle in
the network. And the third claim gets paid off a second time too: not a single one of
the twelve packets was put into a loop by a single table. The loop is a disagreement
between two overlay tables — a knows the tunnel has dropped, d does not, and sends
the packet back.
The sharpest point is this: the underlay cannot see this loop. What the underlay
sees is tunnel deliveries, each valid on its own. The tunnel from a to d was
delivered, the tunnel from d to a was delivered too; both are correct. The loop is
visible only to an eye that puts the two deliveries side by side, and the underlay
has no such eye.
Both Layers at Once
The sixth regime stacks the two disagreements on top of each other: the a-c tunnel
has dropped and only the two ends have heard, and at the same time the chord has
broken and the underlay’s tables have gone stale. 17 of the forty packets
arrive — fewer than either the underlay fault alone (19) or the overlay fault alone
(28).
The real observation is in how the fates are distributed. Overlay loop drops from 12 to 3, tunnel black hole from 21 to 20. Most of the packets that would have entered a loop instead fall into a tunnel black hole and die at the very first turn: the fault below hides the fault above. An eye watching the overlay sees the loop count drop and might mistake it for an improvement. The hop counts point the same way — overlay from 77 to 41, underlay from 205 to 134. The network’s worst state is the state in which every counter looks the calmest.
Two Counters, Two Diagnoses
The counters’ separateness separates the diagnosis too. In the regime that enters a loop, the overlay spends 77 hops, the underlay 205 hops: every hop in the overlay is worth more than two and a half hops in the underlay on average, and a loop in the overlay layer grows by this factor in the underlay.
Two observers see two separate things. The counter watching the overlay sees the loop as a loop: packets are circling, the hop limit is burning through. The counter watching the underlay sees only a rise in load: there are more packets on the links than expected, and no delivery is failing. The course’s shared finding that “a loop looks like congestion” is, in a two-layer network, a finding that changes depending on which layer it is viewed from.
This is not a reason not to use overlays; it is a reason overlays cannot be used without watching both layers at once. In a single-layer network, the table and the link set stand in the same place, and a fault shows up in both at once. In three of the six overlay regimes measured, a packet dies, and each of the three has a different symptom: one only a black hole, one only a loop, one both at once.
Summary
- An overlay network is a logical topology built with tunnels; an overlay link declares a neighborhood, not a cable. The real set of links beneath it is called the underlay, and even though the two layers’ tables sit on the same device, neither reads the other.
- When the underlay repairs itself, the overlay never sees the break at all: overlay hops stay at 74, underlay hops climb from 188 to 211. The layer hides the fault, and hides the cost along with it.
- If the overlay works with its correct table before the underlay converges, 21
packets fall into a tunnel black hole; the
a-e,b-g, andc-ftunnels that used the chord cannot be delivered. The table above is flawless, and the packet still dies. - With not a single wrong decision in the underlay, the overlay tables’ partial information puts 12 packets into a loop; when everybody has heard, all forty of the forty packets arrive. The loop is a disagreement between two overlay tables, and the underlay cannot see it.
- 77 hops in the overlay are 205 hops in the underlay; the counter watching the overlay sees a loop, the counter watching the underlay sees only a rise in load.
- When both layers go stale at once, reached packets drop to 17, but loop drops to 3: the black hole below hides the loop above, and the worst state looks the calmest in the counters.
Next Step
Up to this point, the topology was given in every measurement. Eight nodes, nine links, and a chord cutting the ring were laid down from the start; what was measured was always the response given to it — which table converges in how many rounds, how much a given policy lengthens the path, which layer sees the break. The topology itself was never questioned. But the topology is a choice too: which node connects to which, how many backup paths are left, how many nodes’ tables a break will change are all decided when the network is laid out. The next topic measures this choice and shows that the choice directly touches the convergence round.
To keep your progress and take notes, Log in
My notes
Log in to take notes.