<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Bgp · XB Field Notes</title><link>https://www.xbcatm.com/tags/bgp/</link><description>Illustrated field notes on HTTP, DNS, TLS, Caddy, SSH, releases, and recovery.</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://www.xbcatm.com/tags/bgp/index.xml" rel="self" type="application/rss+xml"/><item><title>BGP aggregation shrinks the routing table</title><link>https://www.xbcatm.com/posts/bgp-aggregation-shrinks-the-table/</link><pubDate>Fri, 08 Oct 2027 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/posts/bgp-aggregation-shrinks-the-table/</guid><description>Advertise a broad prefix instead of many small ones. Aggregation collapses contiguous routes into one entry so everyone carries less.</description><content:encoded>&lt;p&gt;Aggregation replaces a set of adjacent prefixes with one covering announcement, so every peer downstream stores one entry instead of dozens and stops processing updates for each component. The table gets smaller, and the churn of a flapping edge stops propagating outward.&lt;/p&gt;
&lt;p&gt;The tension is that a summary is a claim about reachability. Once the covering prefix is in the table, the forwarding engine acts on it for addresses whose component routes are gone, so a smaller table is bought with a blurrier failure signal.&lt;/p&gt;
&lt;h2 id="what-aggregation-actually-buys"&gt;What aggregation actually buys&lt;/h2&gt;
&lt;p&gt;A peer receiving &lt;code&gt;10.1.4.0/24&lt;/code&gt;, &lt;code&gt;10.1.7.0/24&lt;/code&gt;, &lt;code&gt;10.1.9.0/24&lt;/code&gt; and a covering &lt;code&gt;10.1.0.0/16&lt;/code&gt; stores four entries. Configure &lt;code&gt;aggregate-address 10.1.0.0/16 summary-only&lt;/code&gt; and the peer stores one. Suppression happens on egress: the more-specifics stay in the aggregator&amp;rsquo;s own table and keep forwarding its own traffic, they are simply not advertised. FRR is strict about this — a more-specific must exist in the BGP table, not merely in the RIB, before the aggregate is originated at all.&lt;/p&gt;
&lt;p&gt;The second prize is churn. Every flap of a component is an update the peer must parse, select and reinstall. Behind a summary those updates stop at the aggregator, so a customer network oscillating twice a minute costs the rest of the internet nothing. On a flapping edge that is the property wanted.&lt;/p&gt;
&lt;h2 id="summary-only-suppress-map-and-as-set"&gt;summary-only, suppress-map and as-set&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;summary-only&lt;/code&gt; suppresses every longer prefix to every neighbour. &lt;code&gt;suppress-map&lt;/code&gt; suppresses only the more-specifics a route map matches, for &amp;ldquo;summarise this block but keep that one exception&amp;rdquo;. &lt;code&gt;as-set&lt;/code&gt; changes what the path looks like: instead of collapsing components into the aggregator&amp;rsquo;s own AS, it emits an AS_SET of the real origin ASes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;as-set&lt;/code&gt; preserves loop detection but damages everything else. An AS_SET lengthens the path for AS-path comparison, gives origin validation nothing to check, and is being deprecated — FRR ships &lt;code&gt;bgp reject-as-sets&lt;/code&gt; to drop such routes both ways. The genuinely dangerous configuration is aggregating across different origins at all. Folding &lt;code&gt;10.1.4.0/24&lt;/code&gt; from AS64501 and &lt;code&gt;10.1.7.0/24&lt;/code&gt; from AS64502 into one &lt;code&gt;10.1.0.0/16&lt;/code&gt; originated by AS64500 tells every peer that AS64500 originates the whole block. A neighbour filtering on origin now accepts a prefix it should not, and one filtering on AS path no longer sees the customers. Detail is destroyed, not compressed.&lt;/p&gt;
&lt;h2 id="longest-prefix-match-is-the-only-forwarding-rule"&gt;Longest prefix match is the only forwarding rule&lt;/h2&gt;
&lt;p&gt;BGP decides reachability; the FIB decides forwarding, and the FIB has one rule — longest mask wins. The aggregate is never preferred or depreferenced, and the more-specific wins whenever it exists. Replaying this over a built table: with both present, a packet to &lt;code&gt;10.1.4.9&lt;/code&gt; matches &lt;code&gt;10.1.4.0/24&lt;/code&gt; via &lt;code&gt;AS_PATH 64500 64501&lt;/code&gt;. Withdraw that &lt;code&gt;/24&lt;/code&gt; while the aggregate survives and the same packet matches &lt;code&gt;10.1.0.0/16&lt;/code&gt;, with no change whatsoever to the aggregate. Withdraw the aggregate as well and the packet finally becomes &amp;ldquo;no route, ICMP unreachable&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;That is why announcing an aggregate without its more-specifics changes the forwarding path, not merely the table size. The summary is a standing promise and the FIB enforces it. It cuts the other way too: a more-specific is a traffic magnet, so whatever you announce more specifically receives that traffic no matter what the covering prefix claims.&lt;/p&gt;
&lt;h2 id="when-it-breaks"&gt;When it breaks&lt;/h2&gt;
&lt;p&gt;The classic failure is a summary advertised while a more-specific has been withdrawn somewhere else. The aggregate outlives its component, so traffic for the dead block is drawn to the aggregator and dropped inside it — a blackhole with no ICMP, no withdrawal to notice, no counter at the edge. In the replay, &lt;code&gt;10.1.4.9&lt;/code&gt; moves from the &lt;code&gt;/24&lt;/code&gt; to the &lt;code&gt;/16&lt;/code&gt; and is silently discarded. It presents as &amp;ldquo;some destinations in the &lt;code&gt;/16&lt;/code&gt; are unreachable and everything else is fine&amp;rdquo;, which sends the investigation to the wrong layer.&lt;/p&gt;
&lt;p&gt;The second failure is the flap that opens a temporary blackhole. Withdraw a component, re-announce it two seconds later, and for those two seconds every packet in that range matches the aggregate and dies. Blast radius scales with how much address space sits behind the summary: summarise fifty thousand customer addresses behind one &lt;code&gt;/16&lt;/code&gt; and one customer&amp;rsquo;s flap blacks out all fifty thousand. Mitigate by not summarising across origins, by keeping the more-specifics advertised and paying for the entries, or by using an unreachable-prefix announcement so the withdrawal propagates a discard instead of silence.&lt;/p&gt;
&lt;h2 id="check-it-quickly"&gt;Check it quickly&lt;/h2&gt;
&lt;p&gt;Confirm the aggregate and its components still agree:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;show bgp ipv4 unicast 10.1.0.0/16 longer-prefixes
show bgp ipv4 unicast 10.1.4.0/24
show bgp ipv4 unicast 10.1.0.0/16
show ip route 10.1.4.9
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first lists every component under the summary; the second proves the suspect one is still there. The third is where a lost origin shows up as &lt;code&gt;AS_SET&lt;/code&gt; or a bare aggregator AS, and the fourth shows what the FIB will really match — if it prints the &lt;code&gt;/16&lt;/code&gt; for an address whose &lt;code&gt;/24&lt;/code&gt; you expected, the component is gone and the aggregate is lying.&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc4271.html"&gt;RFC 4271 BGP-4&lt;/a&gt;, defines ATOMIC_AGGREGATE, AGGREGATOR and AS_SET, checked 2026-09-16.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.frrouting.org/en/latest/bgp.html"&gt;FRR BGP route aggregation&lt;/a&gt;, documents aggregate-address, summary-only, suppress-map, as-set and unreachable-prefix announcement, checked 2026-09-16.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc4632.html"&gt;RFC 4632 CIDR&lt;/a&gt;, the classless prefix and longest-match forwarding model, checked 2026-09-16.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>BGP is the Internet routing table</title><link>https://www.xbcatm.com/posts/bgp-is-the-internet-routing-table/</link><pubDate>Sun, 12 Sep 2027 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/posts/bgp-is-the-internet-routing-table/</guid><description>BGP lets independent networks tell the world what prefixes they serve and what paths they accept. Unlike interior protocols, it is a policy exchange as much as a reachability one.</description><content:encoded>&lt;p&gt;BGP is the only protocol that stitches tens of thousands of independently operated networks into one forwarding table. It carries reachability, but what it really carries is policy: each network says which prefixes it originates, which neighbours it learned them from, and — through filters — which ones it is willing to pass on.&lt;/p&gt;
&lt;p&gt;The tension is that this table is built on trust between parties who have no contract with each other. Nothing validates an announcement before it propagates, so a typo or a misconfigured filter is global within minutes and stays that way until a human notices.&lt;/p&gt;
&lt;h2 id="the-as-path-is-a-loop-check-and-a-policy-signal-at-once"&gt;The AS path is a loop check and a policy signal at once&lt;/h2&gt;
&lt;p&gt;On egress an eBGP speaker prepends its own AS number, and a receiver drops any update whose AS_PATH already contains its own AS. That is the entire loop-prevention mechanism, and it is why a route cannot be re-imported around a circle. iBGP does not prepend, which is why an iBGP-learned route carries the same AS_PATH as the eBGP route that brought it into the AS, and why an AS needs a full iBGP mesh or route reflectors to distribute it.&lt;/p&gt;
&lt;p&gt;The same field does two more jobs. Operators filter on it — reject anything containing a peer&amp;rsquo;s AS, accept only routes whose path ends in a customer&amp;rsquo;s AS — and path selection compares its length. One field, three responsibilities, and they conflict: prepending to make a path less attractive also makes it look like a route your filters should reject.&lt;/p&gt;
&lt;h2 id="why-the-table-is-about-a-million-prefixes"&gt;Why the table is about a million prefixes&lt;/h2&gt;
&lt;p&gt;The real numbers, from the CIDR Report snapshot taken for this article: 1,080,189 IPv4 prefixes, or 597,258 if you collapse everything that can be aggregated. Amazon alone originates 18,025 prefixes, of which 15,759 are more-specifics of larger blocks. Roughly half the table is more-specifics of address space that is already announced.&lt;/p&gt;
&lt;p&gt;That is a policy artifact, not a topology artifact. Multihoming creates a more-specific per provider, traffic engineering creates them per path, and a customer who wants their own routing decisions creates one more. Aggregation would halve the table, and nobody does it, because every one of those more-specifics is doing a job.&lt;/p&gt;
&lt;h2 id="path-selection-is-a-fixed-order-not-a-distance"&gt;Path selection is a fixed order, not a distance&lt;/h2&gt;
&lt;p&gt;BGP picks a path by walking a list and stopping at the first step that breaks the tie: highest weight, then highest local preference, then locally originated, then shortest AS path, then lowest origin type, then lowest MED, then eBGP over iBGP, then lowest IGP cost to the next hop, then lowest router ID. Weight and local preference are local to one router or one AS and never travel in an update.&lt;/p&gt;
&lt;p&gt;Running that over four candidate paths for one prefix: the decision lands on weight, because a weight of 100 beats 0 before anything else is read. Remove the weights and the decision moves to local preference. Remove local preference as well and it moves to AS-path length, where a two-AS path beats a three-AS path. The shortest path is step four of nine, which is why &amp;ldquo;BGP picks the shortest route&amp;rdquo; is not a useful statement.&lt;/p&gt;
&lt;h2 id="when-it-breaks"&gt;When it breaks&lt;/h2&gt;
&lt;p&gt;The classic incident shape is a leaked more-specific that hijacks traffic. An unrelated AS originates &lt;code&gt;198.51.100.128/25&lt;/code&gt; inside someone else&amp;rsquo;s &lt;code&gt;198.51.100.0/24&lt;/code&gt;, and longest-prefix-match hands it exactly half the victim&amp;rsquo;s address space — 128 of 256 addresses — with no withdrawal, no error, and the legitimate &lt;code&gt;/24&lt;/code&gt; still sitting in every table. It presents as partial unreachability and traffic appearing somewhere unexpected, and it is the shape documented in RFC 7908. RPKI origin validation is the mitigation, but it only answers whether an AS is allowed to originate a prefix; a ROA&amp;rsquo;s maxLength must cover the more-specific, and a forged AS path with a valid origin still validates.&lt;/p&gt;
&lt;p&gt;The second failure is the table outgrowing the hardware. A device with 1,000,000 IPv4 FIB entries is already 80,189 prefixes short of today&amp;rsquo;s table; at 1,200,000 it fits. When a FIB fills, the router keeps the sessions up and stops installing routes — some prefixes move to software forwarding, others are dropped, and the blast radius is that unrelated destinations stop working while BGP looks perfectly healthy.&lt;/p&gt;
&lt;h2 id="check-it-quickly"&gt;Check it quickly&lt;/h2&gt;
&lt;p&gt;Confirm what your router actually believes about a prefix:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;show bgp ipv4 unicast summary
show bgp ipv4 unicast 198.51.100.0/24
show bgp ipv4 unicast 198.51.100.0/24 longer-prefixes
show ip route 198.51.100.200
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first prints the total prefix count, which is how you notice a peer dumping routes at you. The second and third together show whether a more-specific exists and who originates it — a &lt;code&gt;/25&lt;/code&gt; you do not recognise is the whole incident. The fourth is the verdict the forwarding engine reached, and if it disagrees with what you expected from the first three, the hijack is already live.&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc4271.html"&gt;RFC 4271 BGP-4&lt;/a&gt;, the decision process and AS path loop detection, checked 2026-09-16.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6811.html"&gt;RFC 6811 prefix origin validation&lt;/a&gt;, what RPKI validation does and does not prove, checked 2026-09-16.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc7908.html"&gt;RFC 7908 route leaks&lt;/a&gt;, the problem statement for leaked announcements, checked 2026-09-16.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cidr-report.org/as2.0/"&gt;CIDR Report&lt;/a&gt;, current IPv4 table size and per-AS more-specific counts, checked 2026-09-16.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>