Chapter 04 · Part II · Interior routing

Distance vector in depth

A distance-vector router never sees the network. It hears its neighbors' claims, adds the cost of the link to each one, keeps the best, and repeats the result to everyone else. That one rule builds working routing tables across a network, and it also explains why routers sometimes count slowly upward while packets go round in circles. This chapter covers the rule, the protocol that made it famous, the failure that made it infamous, and the two designs that fixed it properly.

16RIP's "infinity": a route with metric 16 is unreachable, so no RIP path can be longer than 15 hops (RFC 2453)
30 show often a RIP router sends its whole table to its neighbors, unasked (RFC 2453 §3.8)
UDP 520the port RIP messages travel on; RIPng for IPv6 uses 521 (RFC 2453, RFC 2080)

Common mix-up: split horizon does not cure counting to infinity. It stops two routers from bouncing a dead route between themselves, but in a loop of three or more routers each one can learn the stale route from a different neighbor, and the count goes on. RFC 2453 says so directly. The real cure is a rule about which neighbors may be trusted at all, which is what EIGRP and Babel added.

The idea

Bellman-Ford, by rumor

If distance vector and link state are new to you, start with dynamic routing on networks.jelia.nyc, which introduces both. This chapter assumes that introduction and goes into the machinery.

A distance-vector router knows three things: the networks it is directly attached to, the cost of each of its own links, and whatever its neighbors last told it. Every so often each router sends every neighbor a list of destinations with one number beside each, its current distance. That list is the distance vector. A router receiving it adds the cost of the link it arrived on, compares the totals with what it already has, and keeps the smallest. It never learns which routers lie beyond its neighbor, only how far away the neighbor says the destination is.

That is the Bellman-Ford shortest-path method, run in pieces. Richard Bellman and Lester Ford described the centralized version in the 1950s; the distributed version, where each router computes only its own row and passes it on, is the oldest routing algorithm on the internet. The ARPANET used it from the start, which the history chapter tells.

D(X) = min over neighbors n of [ c(X,n) + D(n) ]
X's distance to a destination is the smallest, over all its neighbors n, of the link cost from X to n plus the distance n claims. A directly attached network is the starting point: its distance is the interface's own cost, 1 in RIP.

Here is the rule at work on four routers. R1 is attached to network 192.0.2.0/24 at cost 1. The links are R1–R2 cost 1, R1–R3 cost 4, R2–R3 cost 1 and R3–R4 cost 1. In each round, every router hears every neighbor's distance from the round before and applies the rule.

RoundR1R2R3R4
01 (attached)∞∞∞
112 via R15 via R1∞
212 via R13 via R26 via R3
312 via R13 via R24 via R3
41234

Two things are worth noticing. R3 first takes the expensive direct link to R1, then switches when R2's cheaper news reaches it; R4 inherits the expensive figure for one round and then corrects it. And the whole network settles in three rounds, round 4 being the round in which nothing changes. Good news travels fast: a newly reachable destination, or a cheaper path, needs at most one round per hop of the longest shortest path. Bad news is a different story, and it is most of this chapter.

Go deeper: why it settles at all, even out of step

The table above assumes everyone speaks at once, in rounds. Real routers do not: their timers drift, packets are delayed, and some updates are lost. Dimitri Bertsekas and Robert Gallager proved in Data Networks that the distributed algorithm still arrives at the correct shortest distances under asynchronous operation, provided every router keeps hearing from its neighbors, all link costs are positive, and the topology eventually stops changing. Babel's specification leans on the same robustness: Bellman-Ford's convergence survives routers that delay or discard updates (RFC 8966 §2.4), which is exactly the freedom the loop-free designs later in this chapter use.

The guarantee is about the end state, not the journey. While the network is still changing, the tables can be inconsistent with each other, and a packet that arrives during that window follows whatever the tables say at that moment. Everything below is about what happens in that window.

The textbook protocol

RIP, the Routing Information Protocol

RIP is distance vector written down as plainly as possible. Version 1 (RFC 1058, 1988) documented a protocol that was already widely deployed through BSD Unix's routed. Version 2 (RFC 2453, 1998) is the one still in use. Its metric is a hop count: every network usually costs 1, a route's metric is the number of networks crossed, and 16 means unreachable. That choice caps any RIP network at a diameter of 15 hops, a limit the RFC calls deliberate: the designers considered the basic protocol unsuitable for anything larger.

Every 30 seconds each router sends its full table to every neighbor as UDP datagrams on port 520. RIP-2 sends them to the multicast group 224.0.0.9, so hosts that are not listening do not have to process them. The receiving rules are short. A route from the neighbor you already use is always believed, whether it got better or worse. A route from anyone else is adopted only if it is strictly better. Each route has a 180-second timeout, refreshed whenever the current next hop mentions it; if the timeout expires, the route's metric is set to 16 and a 120-second garbage-collection timer starts, during which the router keeps advertising the route as unreachable so its neighbors hear the bad news before it is deleted.

Timer or constantValue in RFC 2453What it does
Update30 s, with a small random offsetSend the whole table to all neighbors. The jitter stops routers synchronizing with each other.
Timeout180 sNo word from the next hop for six update periods: the route is presumed dead and set to metric 16.
Garbage collection120 sKeep advertising the dead route at 16 for this long, then delete it.
Triggered update1 to 5 s random delayWhen a metric changes, tell the neighbors soon instead of waiting up to 30 s; the delay limits storms of updates.
Infinity16Any metric of 16 or more means unreachable. Small on purpose, for reasons the next section makes clear.

The message is as plain as the rules. A 4-byte header carries a command (1 for a request, 2 for a response) and a version, and is followed by between 1 and 25 route entries of 20 bytes each. That makes the largest message 504 bytes of RIP data, which keeps it inside the 512-byte datagram limit that RIP-1 set. A full table that needs more than 25 entries goes out as several messages.

BytesField (RIP-2 route entry)Example
0–1Address family identifier: 2 for IPv4 (0xFFFF marks an authentication entry)00 02
2–3Route tag: marks routes imported from another protocol, so they can be told apart00 00
4–7IP address of the destinationC0 00 02 00 = 192.0.2.0
8–11Subnet mask: the field that made RIP-2 classlessFF FF FF 00 = /24
12–15Next hop: 0.0.0.0 means "send it to me"; another address on the same subnet means "send it there directly"00 00 00 00
16–19Metric: 1 to 15, or 16 for unreachable00 00 00 03
Go deeper: RIP-1 versus RIP-2, RIPng, and authentication

RIP-1 carried no subnet mask, so a receiver had to guess the prefix length from the address class, which broke as soon as networks were subnetted unevenly. RIP-2 reused fields that RIP-1 required to be zero for the mask, the next hop and the route tag, so old and new routers could share a link. It also added multicast to 224.0.0.9 and a way to authenticate messages: the first entry of a message can be an authentication entry, marked by address family 0xFFFF. The original scheme sent a plain-text password; RFC 4822 replaced it with keyed cryptographic digests, which is what any RIP deployment should use.

RIPng (RFC 2080) is the same design for IPv6. It runs over UDP port 521, carries IPv6 prefixes with a prefix length, and keeps the hop count, the 15-hop diameter and the 30-second timer. It leaves authentication to IPsec rather than carrying its own.

RIP's weaknesses are all in plain view: the metric ignores bandwidth and delay, the diameter is capped, every router resends its full table every 30 seconds whether anything changed or not, and bad news can take minutes to spread. The next section shows why.

The famous failure

Counting to infinity

Take the simplest network that can fail: three routers in a line, R1–R2–R3, each link costing 1, with 192.0.2.0/24 attached to R1. Before anything breaks, R1 is at 1, R2 at 2 through R1, and R3 at 3 through R2. Now the R1–R2 link fails. R2 notices at once, because the interface went down, and marks the route unreachable. R3 has not heard yet, and its routine update happens to arrive first.

StepWhat happensR2R3
0R1–R2 fails; R2 loses its route16 (unreachable)3 via R2
1R3 says "3". R2 has nothing better, so it believes it4 via R33 via R2
2R2 says "4". R2 is R3's next hop, so R3 must accept it4 via R35 via R2
3R3 says "5". R3 is R2's next hop: accepted6 via R35 via R2
…each update pushes the other router up by one……
13R3 says "15"; R2 computes 16, which is infinity16 (unreachable)15 via R2
14R2 says "16"; R3 computes 17, also unreachable1616 (unreachable)

For the whole of that exchange, R2 thinks the destination is through R3 and R3 thinks it is through R2. A packet for 192.0.2.0/24 that reaches either one bounces between them, losing one from its TTL at every hop, until the TTL reaches zero and the packet is dropped. (How TTL works is covered in troubleshooting on networks.jelia.nyc.) That is a forwarding loop, and the slow climb of the metric is counting to infinity.

Nothing stops the count except the ceiling. If infinity were a million, the routers would count to a million. That is why RIP's infinity is a modest 16: it is not a property of networks, it is how long you are prepared to wait. Without triggered updates, each step can wait for the next 30-second update, so the thirteen or so steps above can take several minutes. With triggered updates each step takes a few seconds, but the loop still exists for as long as the count lasts.

The root of it is that a distance vector carries no information about the path. When R3 says "3", R2 cannot tell that R3's 3 was computed through R2 itself. Every fix below either withholds information that might be circular, or adds information that proves it is not.

Go deeper: the loop of three

Add a fourth router so that R2, R3 and R4 form a triangle, with R1 hanging off R2. R3 and R4 both reach 192.0.2.0/24 through R2, at distance 3. When R1–R2 fails, R2 tells R3 and R4 the route is gone. But suppose R4's periodic update to R3, "I can reach it at 3", crosses R2's warning on the wire. R3 accepts the warning from R2, then hears R4's offer, which is now better than nothing: R3 switches to 4 via R4. R4 does the mirror image and switches to 4 via R3.

From here the poison of the next section does not help. R3 now routes through R4, so it is free to tell R2 "4"; R2 believes it and routes through R3. R2 tells R4, R4 tells R3, and the count circles the triangle, three routers taking turns to deceive each other. RFC 2453 §3.4.4 describes exactly this case: "A may believe it has a route through B, B through C, and C through A. Split horizon cannot stop such a loop." The simulator below lets you watch both halves of the story: the triangle, where split horizon alone leaves R3 and R4 pointing at each other, and the six-router mesh, where a loop of three routers counts upward with split horizon, poison reverse and triggered updates all switched on.

Instrument 1

Break a link and watch the rumors

Each circle is a router running RIP's rules for one destination, 192.0.2.0/24, attached to R1. The number under a router is its current metric and the arrow shows its next hop. Amber dots are updates in flight, labelled with the metric they carry; a dash means "unreachable". Choose a link, press Break, then Run, or press Next update to jump to the next moment an update arrives. Time is simulated in seconds: each router sends its periodic update every 30 seconds at its own point in the cycle, triggered updates wait 1 to 5 seconds, and routes time out after 180, as in RFC 2453. Tap a router to see its table and to send a test packet from it.

Time since last change0 s
Updates sent0
Highest metric seen–
Test packet–

Try this. On the line, break R1–R2 with every option off and Run: the metrics climb to 16 while R2 and R3 point at each other (send a packet from R3 while it happens). Switch on split horizon and try again. On the triangle, split horizon alone leaves R3 and R4 pointing at each other until the 180-second timeout; add poison reverse and the loop is cut short; add hold-down and it never forms. On the mesh, split horizon, poison reverse and triggered updates are all on, and a loop of three routers still counts upward. Hold-down stops it, but watch R3 ignore the good path over the R1–R3 link for 90 seconds.

Fixes, and their limits

Four patches, and what each can't fix

The classic distance-vector protocols collected a set of rules to make counting to infinity rarer and shorter. Each one is cheap and each one helps. None of them makes loops impossible.

Split horizon: never advertise a route back out of the interface you learned it from. R3 learned its route from R2, so it says nothing about that destination to R2, and R2 can never be fooled by its own echo. Poison reverse is the stronger form RIP recommends: instead of saying nothing, R3 tells R2 the route is at 16. Silence leaves R2 to wait for a timeout before it forgets an old claim; poison kills the claim at once. The price is bigger updates, since every route is mentioned on every interface, in many cases as unreachable.

Triggered updates: when a metric changes, send an update within a few seconds instead of waiting for the next 30-second cycle. Bad news then outruns most stale news. RFC 2453 notes that if the network sat still while the cascade ran, counting to infinity could not happen; but regular updates keep firing during the cascade, and one that leaves a router just before the bad news arrives restarts the trouble.

Hold-down: after a route gets worse or goes unreachable, refuse any offer that is no better than the route you just lost, for a fixed time. The stale offers that drive the count are refused, and by the time the timer ends the bad news has usually reached everyone. Hold-down is not in RFC 2453; it came from vendor implementations. Its cost is that it refuses good news too: a genuine new path is ignored until the timer ends, so traffic is dropped when it could have been rerouted.

PatchFixesDoes not fixCosts
Split horizonTwo routers echoing a route back to each otherLoops of three or more routersStale claims linger until the 180 s timeout
Poison reverseThe same, and kills old claims at onceLoops of three or more routersLarger updates
Triggered updatesMost races, by sending bad news fastA periodic update that crosses the bad news in flightBursts of update traffic, hence the 1–5 s delay
Hold-downMost stale offers, including in loopsStale news that outlives the timerIgnores real alternatives too: slower recovery
Small infinityPuts an end to every countThe loop itself, while it lastsLimits the network to 15 hops
Go deeper: why all four are heuristics

Each patch works by withholding or delaying information, and each one bets on timing: that bad news will get there first, or that it will have arrived everywhere before a timer runs out. In a network with real delays, packet loss and several failures at once, a bet can lose. What the patches never do is let a router tell whether a neighbor's route runs back through itself. Path-vector protocols such as BGP solve that by carrying the whole path, so a router can see its own identity in it (chapter 8). The designs in the next section solve it by a sharper argument that needs only one more number.

Loop-free by construction

The feasibility condition

In the late 1980s and early 1990s J. J. Garcia-Luna-Aceves, working at SRI International, published the Diffusing Update Algorithm, DUAL. Cisco built it into EIGRP, its Enhanced Interior Gateway Routing Protocol, and in 2016 published EIGRP as an informational RFC, RFC 7868. DUAL keeps the distance-vector exchange but adds one memory and one test, and with them it never forms a loop, even for an instant.

The memory is the feasible distance (FD): the lowest distance this router has had to the destination since the destination last settled. Note "lowest since": if the current route gets worse, the FD does not rise with it. The test is the feasibility condition. Each neighbor advertises its own distance, called its reported distance (RD). A neighbor is safe to use only if its reported distance is strictly less than our feasible distance.

neighbor n is feasible ⇔ RD(n) < FD(me)
A neighbor may be used only if it is closer to the destination than this router has ever been since the route last settled. Strictly closer: equal is not good enough.

Why it works fits in three sentences. Suppose neighbor n's route ran back through me. Then n's distance would be my distance plus at least one positive link cost, so it would be larger than my current distance, which can never be smaller than my FD. So a neighbor whose RD is below my FD cannot be routing through me, and choosing it cannot close a loop. Apply that at every router and every next-hop pointer leads strictly downhill toward the destination; a chain that always goes downhill cannot come back to where it started.

DUAL names the results. The successor is the neighbor on the least-cost path, and it must satisfy the condition. Any other neighbor that satisfies it is a feasible successor: a backup that is already proven loop-free. When the successor's link fails and the cheapest remaining path comes from a feasible successor, the router switches to it immediately, with no messages and no waiting. RFC 7868 calls the route PASSIVE in this state.

A worked example. Router A reaches 192.0.2.0/24 through three neighbors. B has link cost 1 and reports 1, total 2. C has link cost 4 and reports 1, total 5. D has link cost 3 and reports 3, total 6. A's best total is 2, through B, so its FD is 2. C reports 1, which is less than 2: C is a feasible successor. D reports 3, which is not less than 2, so D fails. D's path might run through A: A's 2 plus one more hop of cost 1 would be exactly D's 3. When B fails, the cheapest remaining total is C's 5, and C is feasible, so A moves to C at once.

Change one number and the protocols part ways. If D's link cost were 1, D's total would be 4, cheaper than C's 5 but still not feasible. RFC 7868 requires the least-cost path to come from a feasible neighbor before a route may stay PASSIVE, so EIGRP would not settle for C: it would go ACTIVE and ask. Babel simply ignores routes that fail the condition and would take C. Instrument 2 lets you try both.

The condition is sufficient but not necessary, as RFC 7868 puts it: every path that passes is loop-free, but some loop-free paths fail. When the successor is lost and no neighbor passes, the route goes ACTIVE. The router freezes its route, sends a QUERY to every neighbor, and waits for every REPLY before choosing again and resetting its FD. Neighbors with no feasible successor of their own pass the query on, so the computation spreads out from the failure and then collapses back, which is why it is called diffusing. A query that is not answered in time leaves the route stuck in active; Cisco's implementation allows 3 minutes, with a check-up query at the halfway mark.

Go deeper: EIGRP's metric and why FD only goes down while passive

EIGRP's metric is not a hop count. With the default coefficients (K1 = K3 = 1, the others 0), it combines the slowest bandwidth along the path with the sum of the delays, scaled up by 256, so a path's cost reflects how fast and how far it is (RFC 7868 §5.5). The feasibility condition does not care what the metric means, only that each link adds a positive amount to it.

The FD is defined as the least distance since the last transition from ACTIVE to PASSIVE. While passive, a router may switch to a feasible successor with a worse total, but its FD stays where it was; letting it rise would loosen the test and could admit a neighbor that routes through it. Only a completed diffusing computation, which has confirmed with every neighbor that the old information is gone, may reset the FD to a larger value. The explorer below keeps the FD exactly this way, so you can watch it refuse to rise.

Instrument 2

Which neighbors are safe?

Router A has up to four neighbors, B to E, each offering a route to 192.0.2.0/24. Pick a neighbor (tap it, or use the buttons) and set its link cost and reported distance. The explorer applies DUAL's rules: it computes each total, the feasible distance, the successor and the feasible successors, and for a neighbor that fails the test it draws the loop that the test is guarding against. Then fail the successor's link and see whether A can switch on its own. In Babel mode, failure leads to a request for a new sequence number instead of a query.

Feasible distance–
Successor–
Feasible successors–
Route state–

Start with "Backup ready": fail B and A moves to C at once. Then load "Cheaper is not safer" and fail B, first in EIGRP mode (D is cheapest but unproven, so the route goes active) and then in Babel mode (D is ignored and C is used). Finally load "No safe backup" and fail B: nobody passes, and the route has to go active (EIGRP) or ask for a new sequence number (Babel).

A newer design

Babel: sequence numbers instead of a freeze

Babel, designed by Juliusz Chroboczek and standardized as RFC 8966 in 2021, uses the same kind of feasibility condition, which its RFC says is derived from EIGRP's. A Babel router remembers, for each source, the smallest metric it has ever advertised, and accepts an update only if the advertised metric is strictly smaller. The condition has the same weakness too. A router can find that every route it hears fails the test even though a perfectly good path exists, because the test is only sufficient. RFC 8966 calls this starvation.

EIGRP answers starvation by stopping everyone involved and asking. Babel adds a second number instead. Every route carries a sequence number, set by the router that originates the prefix and passed along unchanged by everyone else. The pair of sequence number and metric is the route's distance, and the feasibility test compares pairs: an update is feasible if its sequence number is newer than the one in the feasible distance, or if it is the same and the metric is strictly smaller.

update (s′, m′) is feasible ⇔ s′ > s, or s′ = s and m′ < m, where FD = (s, m)
A newer sequence number makes any route acceptable. Within one sequence number, the EIGRP-style rule applies: strictly smaller metric only.

A starving router sends a seqno request toward the source. Requests are forwarded without regard to feasibility, so they get through even along routes that cannot yet be used. The source answers by incrementing its sequence number and announcing again. The new number spreads outward, and every router that hears it may take the route at whatever metric it now costs, because no router anywhere can have a feasible distance with a sequence number that has only just been invented. Only the routers that need help are involved; there is no network-wide freeze.

A newer sequence number cannot create a loop, for a simple reason: it is only ever created by the source and travels away from it, so a router holding it already lies on a path that came from the source. Babel also keeps feasible distances per source, a pair of router-id and prefix, so two routers announcing the same prefix do not confuse each other's sequence numbers. The sequence number is 16 bits and wraps around, compared with the same kind of modular arithmetic TCP uses.

Go deeper: what else Babel does differently

Babel routers discover neighbors with Hello messages and measure each link with IHU ("I Heard You") messages, so a lossy wireless link can be given a higher cost than a clean cable; the RFC leaves the exact cost function to the implementation, and wireless link-quality estimation is one of the uses RFC 8965 highlights. Babel runs over UDP port 6696, to the multicast groups ff02::1:6 and 224.0.0.111, and one instance carries IPv6 and IPv4 routes together. Metrics are 16 bits, with 0xFFFF meaning infinity, but because loops cannot form there is nothing to count up to: infinity simply means retracted. Updates can be protected with the MAC authentication of RFC 8967.

Babel's applicability statement, RFC 8965, describes where it fits: wireless mesh networks, where it has seen what that RFC calls a moderate amount of successful deployment, and small unmanaged networks, where it serves as a more efficient replacement for RIP. Open-source implementations include the reference babeld and the babeld daemon in FRRouting.

Still running

Where distance vector lives today

In most enterprise and provider networks the interior protocol is now link state, OSPF or IS-IS (chapter 5, chapter 6), because every router can see the whole map and recompute quickly. Distance vector has kept three niches. RIP survives in small and older networks and in equipment where its simplicity is the point. EIGRP runs in many networks built on Cisco equipment, where its fast switch to a feasible successor is the main attraction. Babel is used in community mesh networks and small networks, especially where wireless links of varying quality carry traffic between routers.

And the protocol that holds the internet together is a close relative. BGP is a path-vector protocol: instead of a single distance, each route carries the list of autonomous systems it has passed through, and a router rejects any route whose list already contains its own number. Babel's RFC describes that as BGP's feasibility condition, a drastic but effective one. Chapter 8 starts there.

ProtocolMetricLoop handlingOn failure without a backup
RIP-2 / RIPngHop count, 16 = unreachableSplit horizon, poison reverse, triggered updates; counts to 16Counts upward, or times out after 180 s
EIGRP (DUAL)Bandwidth and delay, compositeFeasibility condition: RD < FDGoes ACTIVE: diffusing QUERY and REPLY
BabelAdditive, link-quality aware, 16-bitFeasibility condition on (seqno, metric)Seqno request to the source
BGP (path vector)Policy, then AS-path length and moreReject a path that already contains your ASWithdraws; neighbors pick another path
Cheat sheet

Terms from this chapter

Distance vector
A routing method in which each router tells its neighbors only its distance to each destination, and computes its own distances from theirs.
Bellman-Ford
The shortest-path rule distance vector runs: my distance is the smallest, over my neighbors, of link cost plus the neighbor's distance.
RIP
Routing Information Protocol: the textbook distance-vector protocol. Hop-count metric, 30-second updates, UDP 520, 16 means unreachable.
Counting to infinity
After a failure, routers that rely on each other's stale claims raise their metrics step by step until they reach the protocol's infinity; packets loop meanwhile.
Split horizon
Never advertise a route back to the neighbor you learned it from. Stops two-router loops, not longer ones.
Poison reverse
The stronger form of split horizon: advertise the route back to that neighbor as unreachable instead of leaving it out.
Hold-down
A timer during which a router refuses offers no better than the route it just lost. Blocks stale news, but blocks real alternatives too.
Feasible distance (FD)
The lowest distance a router has had to a destination since the route last settled.
Reported distance (RD)
The distance a neighbor advertises for a destination.
Feasibility condition
A neighbor may be used only if its reported distance is strictly less than our feasible distance; this guarantees it is not routing through us.
Feasible successor
A neighbor other than the current best that meets the feasibility condition: a proven loop-free backup that can be used at once.
Sequence number (Babel)
A counter set only by a route's source; a newer one makes a route feasible again and cures starvation without a network-wide freeze.
Where this comes from

Sources