slides: "Hands-on BGP", restructured into five sections
- Title is now "Hands-on BGP"; the AS-path diagram is gone from the cover. - Sections: IPv6 addresses and prefixes; where AS numbers and prefixes come from (IANA, RIRs, the RIPE database, IRR vs RPKI); BGP and the bytes of an UPDATE; IP transit vs Internet exchanges (the peering LAN as an Ethernet segment, route servers); the lab (ferrix, pr01.rue, SwissIX, NL-ix, France-IX, DE-CIX, transit). - The UPDATE walked through in section 3 is a real 94-byte capture from ferrix for 2a0d:d741:1::/48. Vertical slides light up one part at a time with its decode; the generator asserted every quoted number against the capture. Session counts come from the tracked bird.conf, the route6 object from the RPSL file, SwissIX's LAN from PeeringDB. - New components: focusable bytes, decode table, prefix bits, and SVG diagrams drawn in the theme's colours. - Opening index.html straight from disk used to give a title and empty panels, because browsers block the module and the section files there. The page now explains that, and also reports a failed reveal.js load. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
106edd1df0
commit
1399cbd39f
15 files changed
+754
-245
No files matched your search
+24
-4
@@ -7,7 +7,22 @@ Sans and Mono, monokai code with glowing stepped lines, 16:9 with fade
|
||||
transitions, and the content in one Markdown file per section.
|
||||
|
||||
What is ours: the palette, and the corner motif. His ring-and-thread became a
|
||||
chain of nodes and links, an AS path, which also opens the title slide.
|
||||
chain of nodes and links, an AS path.
|
||||
|
||||
## The talk
|
||||
|
||||
| Section | File |
|
||||
|---|---|
|
||||
| IP addresses and prefixes (IPv6) | `sections/01-addresses.md` |
|
||||
| Where AS numbers and prefixes come from (IANA, RIPE) | `sections/02-registries.md` |
|
||||
| BGP and the bytes of an UPDATE | `sections/03-bgp-update.md` |
|
||||
| IP transit and Internet exchanges | `sections/04-transit-and-ix.md` |
|
||||
| The lab: ferrix, pr01.rue and its exchanges | `sections/05-lab.md` |
|
||||
|
||||
The UPDATE in section 3 is a real one captured from ferrix. Its byte slides
|
||||
step through it one part at a time (press down); every number on them was
|
||||
checked against the capture when the slides were generated. If you replace the
|
||||
capture, regenerate rather than edit the hex by hand.
|
||||
|
||||
| File | Holds |
|
||||
|---|---|
|
||||
@@ -27,8 +42,10 @@ For a full-bleed title image, empty the title `<section>` and give it
|
||||
|
||||
## Show it
|
||||
|
||||
The sections are loaded over HTTP, so open the deck through a server, not as a
|
||||
file:
|
||||
The sections are loaded over HTTP, so open the deck through a server, not by
|
||||
double-clicking `index.html`. Opened from disk, browsers block reveal.js and
|
||||
the section files, and you would see a title and empty panels; the page now
|
||||
says so instead:
|
||||
|
||||
python3 -m http.server 8000 --directory slides
|
||||
|
||||
@@ -69,7 +86,10 @@ Apply a class to the element above with `<!-- .element: class="..." -->`.
|
||||
|
||||
Blocks: `<div class="cols">` two columns, `<div class="boxes">` labelled cards
|
||||
(`us`, `ok`, `bad`), `<pre class="bytes">` BGP bytes in the colours of the lab
|
||||
page. Code fences take a language and optional line steps, e.g.
|
||||
page (add `focus`, and `on` to the spans to keep lit, to dim the rest),
|
||||
`<table class="decode">` for the explanation under them,
|
||||
`<svg class="diagram">` for diagrams drawn in the theme's colours (`hot`,
|
||||
`fabric`, `link`, `bgp`, `traffic`). Code fences take a language and optional line steps, e.g.
|
||||
` ```bird [1-3|5-9] `; `bird` is a small highlighter defined in `index.html`.
|
||||
|
||||
`<!-- .slide: class="bare" -->` drops the panel, the motif and the wordmark
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 480" font-family="sans-serif">
|
||||
<rect width="960" height="480" rx="12" fill="#11131f" stroke="#4f526b" stroke-dasharray="10 8"/>
|
||||
<text x="480" y="230" text-anchor="middle" font-size="40" fill="#eceff9">your picture here</text>
|
||||
<text x="480" y="280" text-anchor="middle" font-size="22" fill="#7d7f99">slides/images/</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 391 B |
+39
-18
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>BGP hands-on: announce your own prefix</title>
|
||||
<title>Hands-on BGP</title>
|
||||
<!--
|
||||
Deck structure and look follow Matt Godbolt's newer talks (e.g.
|
||||
github.com/mattgodbolt/what-happens-beneath-accu-2026): reveal.js with
|
||||
@@ -26,16 +26,8 @@
|
||||
<!-- Title slide. For a full-bleed image instead, empty it and add
|
||||
data-background="images/title.png" like Matt does. -->
|
||||
<section class="title-slide">
|
||||
<svg class="as-path" viewBox="0 0 1000 90" preserveAspectRatio="xMinYMid meet" aria-hidden="true">
|
||||
<line x1="20" y1="30" x2="980" y2="30" />
|
||||
<g class="you"><circle cx="20" cy="30" r="11" /><text x="4" y="72">you</text></g>
|
||||
<g><circle cx="250" cy="30" r="11" /><text x="196" y="72">AS4200000001</text></g>
|
||||
<g><circle cx="500" cy="30" r="11" /><text x="463" y="72">AS210036</text></g>
|
||||
<g><circle cx="750" cy="30" r="11" /><text x="722" y="72">AS42476</text></g>
|
||||
<g><circle cx="980" cy="30" r="11" /><text x="890" y="72">the Internet</text></g>
|
||||
</svg>
|
||||
<h1>Announce your own prefix</h1>
|
||||
<h3>A hands-on introduction to BGP</h3>
|
||||
<h1>Hands-on BGP</h1>
|
||||
<h3>Announce your own prefix to the Internet</h3>
|
||||
<p class="byline">Rayhaan Jaufeerally · Network Security · ETH Zürich, 2026</p>
|
||||
</section>
|
||||
|
||||
@@ -45,16 +37,41 @@
|
||||
--- next vertical slide (goes down, for detail you may skip)
|
||||
Notes: everything after this is speaker notes (press S)
|
||||
-->
|
||||
<section data-markdown="sections/01-intro.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/02-bgp.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/03-lab.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/04-communities.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/05-wrap-up.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/01-addresses.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/02-registries.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/03-bgp-update.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/04-transit-and-ix.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
<section data-markdown="sections/05-lab.md" data-separator="^-----" data-separator-vertical="^---" data-separator-notes="^Notes:"></section>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Sits where Matt's decks carry the employer logo. -->
|
||||
<div class="wordmark"><b>ferrix</b>_bgp · netsec 2026</div>
|
||||
|
||||
<div id="deck-help" hidden>
|
||||
<h2>The slides did not load</h2>
|
||||
<p id="deck-help-why"></p>
|
||||
<pre>python3 -m http.server 8000 --directory slides</pre>
|
||||
<p>then open <code>http://localhost:8000</code>. Details in <code>slides/README.md</code>.</p>
|
||||
</div>
|
||||
<!-- A classic script: it still runs when the browser refuses to run the
|
||||
module below, which is exactly the case it has to explain. -->
|
||||
<script>
|
||||
(function () {
|
||||
function help(why) {
|
||||
document.getElementById("deck-help-why").textContent = why;
|
||||
document.getElementById("deck-help").hidden = false;
|
||||
}
|
||||
if (location.protocol === "file:") {
|
||||
help("This page was opened straight from disk. Browsers block a page opened that way from loading reveal.js and the section files, so serve the folder over HTTP:");
|
||||
return;
|
||||
}
|
||||
window.addEventListener("deck-failed", function (e) { help(e.detail + " Serve the folder over HTTP, and run slides/vendor-reveal.sh if there is no network:"); });
|
||||
setTimeout(function () {
|
||||
if (!window.deck) help("reveal.js has not started after 10 seconds. Without a network it needs the local copy from slides/vendor-reveal.sh. Serve the folder like this:");
|
||||
}, 10000);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script type="module">
|
||||
const VERSION = "6.0.2";
|
||||
const LOCAL = "./reveal.js/dist";
|
||||
@@ -69,6 +86,10 @@
|
||||
return CDN;
|
||||
}
|
||||
const base = await pickBase();
|
||||
const fail = (what) => (e) => {
|
||||
window.dispatchEvent(new CustomEvent("deck-failed", { detail: `${what} (${e && e.message ? e.message : e}).` }));
|
||||
throw e;
|
||||
};
|
||||
|
||||
const deckStyle = document.getElementById("deck-style");
|
||||
await Promise.all(
|
||||
@@ -89,7 +110,7 @@
|
||||
["reveal.mjs", "plugin/markdown.mjs", "plugin/highlight.mjs", "plugin/notes.mjs"].map(
|
||||
(m) => import(/* @vite-ignore */ `${base}/${m}`),
|
||||
),
|
||||
);
|
||||
).catch(fail(`Could not load reveal.js from ${base}`));
|
||||
|
||||
// BIRD configuration, so router config on slides is highlighted. Same
|
||||
// trick Matt uses for the assembly dialects in his talks.
|
||||
@@ -136,7 +157,7 @@
|
||||
plugins: [Markdown, Highlight, Notes],
|
||||
});
|
||||
|
||||
await deck.initialize();
|
||||
await deck.initialize().catch(fail("reveal.js failed to start"));
|
||||
window.deck = deck; // handy in the console: deck.slide(3), deck.getTotalSlides()
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# IP addresses and prefixes
|
||||
|
||||
Notes:
|
||||
Section 1. IPv6 only: the whole lab is IPv6, and the ideas carry over to IPv4
|
||||
unchanged (32 bits, dotted decimal, /24 where we say /48).
|
||||
|
||||
-----
|
||||
|
||||
## An IPv6 address is 128 bits
|
||||
|
||||
```text
|
||||
2a0d:d741:0001:0000:0000:0000:0000:0001 eight groups of 16 bits, in hex
|
||||
2a0d:d741:1:0:0:0:0:1 drop leading zeros in a group
|
||||
2a0d:d741:1::1 one run of zero groups becomes ::
|
||||
```
|
||||
|
||||
`::` may appear once, or the address would be ambiguous.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
Notes:
|
||||
Ask: why only once? Because 2a0d::1::1 could put the zeros in several places.
|
||||
|
||||
-----
|
||||
|
||||
## A prefix is a range of addresses
|
||||
|
||||
`2a0d:d741:1::/48`
|
||||
|
||||
<p class="bits"><span class="fixed">2a0d:d741:0001</span><span class="free">xxxx:xxxx:xxxx:xxxx:xxxx</span></p>
|
||||
|
||||
The first <span class="fragment pop">48</span> bits are fixed. The other 80 are yours.
|
||||
|
||||
Notes:
|
||||
2^80 addresses in one student prefix. About 1.2 million billion billion.
|
||||
The /n is a count of leading bits, nothing more.
|
||||
|
||||
-----
|
||||
|
||||
## Prefixes nest
|
||||
|
||||
| Prefix | Who | Holds |
|
||||
|---|---|---|
|
||||
| `2a0d:d740::/29` | the network we borrow from | 524,288 /48s |
|
||||
| `2a0d:d741::/40` | this lab | 256 /48s |
|
||||
| `2a0d:d741:<n>::/48` | **you** | 65,536 /64s |
|
||||
| `…/64` | one LAN | the hosts on it |
|
||||
|
||||
`<n>` is your student number, written *in hex*.
|
||||
|
||||
<!-- .element: class="fragment note" -->
|
||||
|
||||
Notes:
|
||||
Student 10 is 2a0d:d741:a::/48, student 16 is 2a0d:d741:10::/48.
|
||||
A /40 holds exactly 256 /48s, which caps the class size at 255.
|
||||
|
||||
-----
|
||||
|
||||
## The most specific route wins
|
||||
|
||||
```text [1-3|3]
|
||||
2a0d:d740::/29 via AS210036 the aggregate
|
||||
2a0d:d741::/40 via AS210036 the lab
|
||||
2a0d:d741:1::/48 via AS210036 AS… student 1 <-- chosen for 2a0d:d741:1::1
|
||||
```
|
||||
|
||||
Routers forward on the *longest matching prefix*, before anything else is compared.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
Notes:
|
||||
This is the single most important forwarding rule for today. It is also why a
|
||||
hijacker announces a more specific prefix: it wins everywhere it is accepted,
|
||||
no matter how good the legitimate route is.
|
||||
|
||||
-----
|
||||
|
||||
## How small can a prefix be?
|
||||
|
||||
<div class="boxes">
|
||||
<div class="ok">IPv6: up to <b>/48</b></div>
|
||||
<div class="ok">IPv4: up to <b>/24</b></div>
|
||||
<div class="bad">anything longer: filtered by almost everyone</div>
|
||||
</div>
|
||||
|
||||
Not a protocol rule. A convention, so the global table stays finite.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
Notes:
|
||||
Which is why the lab hands out /48s: the smallest thing the Internet at large
|
||||
will carry. The global IPv6 table is around 230k routes, IPv4 around 1M.
|
||||
@@ -1,31 +0,0 @@
|
||||
## Today
|
||||
|
||||
* What BGP is, in ten minutes <!-- .element: class="fragment" -->
|
||||
* You announce a real prefix to the real Internet <!-- .element: class="fragment" -->
|
||||
* You steer where it goes with communities <!-- .element: class="fragment" -->
|
||||
* We look at what could go wrong <!-- .element: class="fragment" -->
|
||||
|
||||
Notes:
|
||||
Speaker notes go after a line that starts with "Notes:". Press S to open the
|
||||
speaker view; it shows these, a timer, and the next slide.
|
||||
|
||||
-----
|
||||
|
||||
The Internet is about
|
||||
<span class="fragment pop">75,000</span>
|
||||
networks that agreed to talk to each other.
|
||||
|
||||
<!-- .element: class="big" -->
|
||||
|
||||
Notes:
|
||||
One idea per slide, large. The class="big" comment applies to the paragraph
|
||||
above it. "pop" is a fragment that grows when it appears.
|
||||
A slide with class "bare" drops the panel and the path motif: <!-- .slide: class="bare" -->
|
||||
|
||||
-----
|
||||
|
||||
<img class="r-stretch blur-edges" src="images/placeholder.svg" alt="Replace with a picture">
|
||||
|
||||
Replace `images/placeholder.svg`. `r-stretch` makes an image fill the slide.
|
||||
|
||||
<!-- .element: class="attribution" -->
|
||||
@@ -1,53 +0,0 @@
|
||||
## An autonomous system
|
||||
|
||||
<div class="boxes">
|
||||
<div class="us">AS210036<br>our upstream</div>
|
||||
<div>AS559<br>SWITCH</div>
|
||||
<div>AS6939<br>Hurricane Electric</div>
|
||||
<div>AS13335<br>Cloudflare</div>
|
||||
</div>
|
||||
|
||||
A network under one administration, with a number.
|
||||
|
||||
Notes:
|
||||
"boxes" lays out small labelled cards. Classes: us, ok, bad.
|
||||
|
||||
-----
|
||||
|
||||
## A route is a prefix plus a promise
|
||||
|
||||
```text
|
||||
2a0d:d741:1::/48 via AS210036 AS4200000001
|
||||
^ nearest ^ origin
|
||||
```
|
||||
|
||||
"Send me traffic for this prefix. It crossed these networks to reach you."
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
-----
|
||||
|
||||
## What actually goes on the wire
|
||||
|
||||
<div class="legend"><span class="hh">header</span><span class="hl">lengths</span><span class="ha">path attributes</span><span class="hn">NLRI</span></div>
|
||||
|
||||
<pre class="bytes"><span class="hh">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh">00 50</span> <span class="hh">02</span> <span class="hl">00 00</span> <span class="hl">00 35</span> <span class="ha">40 01 01 00</span> <span class="ha2">40 02 0a 02 02 00 00 fd e8 00 00 fd e8</span> <span class="ha">40 03 04 7f 00 00 01</span> <span class="ha2">80 04 04 00 00 00 32</span> <span class="ha">c0 08 04 fd e8 00 64</span> <span class="hn">18 0a 64 01</span></pre>
|
||||
|
||||
Same colours as the bytes view on the lab page, so you can point from one to the other.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
---
|
||||
|
||||
## Going deeper (a vertical slide)
|
||||
|
||||
Press <kbd>↓</kbd>. Put detail here that you can skip when short of time.
|
||||
|
||||
| Attribute | Type | Meaning |
|
||||
|---|---|---|
|
||||
| ORIGIN | 1 | how the route entered BGP |
|
||||
| AS_PATH | 2 | networks it crossed |
|
||||
| COMMUNITIES | 8 | 32-bit tags, meaning by agreement |
|
||||
| LARGE_COMMUNITIES | 32 | three 32-bit numbers |
|
||||
|
||||
<!-- .element: class="borders" -->
|
||||
@@ -0,0 +1,89 @@
|
||||
# Where numbers come from
|
||||
|
||||
Notes:
|
||||
Section 2. Nobody "owns" addresses or AS numbers; they are registered to you.
|
||||
|
||||
-----
|
||||
|
||||
## A hierarchy of registries
|
||||
|
||||
<div class="boxes">
|
||||
<div>IANA<br><span class="small">the root</span></div>
|
||||
<div class="us">RIPE NCC<br><span class="small">Europe, Middle East</span></div>
|
||||
<div>ARIN</div>
|
||||
<div>APNIC</div>
|
||||
<div>LACNIC</div>
|
||||
<div>AFRINIC</div>
|
||||
</div>
|
||||
|
||||
IANA hands large blocks to five regional registries. They hand smaller ones to members (LIRs), who assign to end users.
|
||||
|
||||
Notes:
|
||||
RIR = Regional Internet Registry. LIR = Local Internet Registry, a member of
|
||||
an RIR, typically an ISP. Our space comes from RIPE NCC via an LIR.
|
||||
|
||||
-----
|
||||
|
||||
## AS numbers
|
||||
|
||||
* 16 bits at first: `1` to `65535` <!-- .element: class="fragment" -->
|
||||
* 32 bits since RFC 6793: up to `4294967295` <!-- .element: class="fragment" -->
|
||||
* Old routers see `AS23456` (AS_TRANS) in place of a big one <!-- .element: class="fragment" -->
|
||||
* Private use: `64512–65534` and `4200000000–4294967294` <!-- .element: class="fragment" -->
|
||||
|
||||
The lab daemon is `AS4200000001`. It is stripped before the Internet sees your route.
|
||||
|
||||
<!-- .element: class="fragment note" -->
|
||||
|
||||
Notes:
|
||||
RFC 6996 reserves the private ranges. The upstream router removes the private
|
||||
AS from the path, so the origin everybody else sees is AS210036.
|
||||
|
||||
-----
|
||||
|
||||
## The RIPE database says who may announce what
|
||||
|
||||
```text [1-5|3]
|
||||
route6: 2a0d:d741:1::/48
|
||||
descr: ETHZ Netsec 2026 BGP lab - student 1
|
||||
origin: AS210036
|
||||
mnt-by: mnt-ch-ray-1
|
||||
source: RIPE
|
||||
```
|
||||
|
||||
One of these exists for every student prefix. Networks build their filters from them.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
Notes:
|
||||
This is a real object; try the whois on the next slide. `mnt-by` names the
|
||||
maintainer: whoever holds its credentials can change the object. An `inet6num`
|
||||
object records the address block itself, a `route6` object who may originate it.
|
||||
|
||||
-----
|
||||
|
||||
## Two ways to say "this origin is allowed"
|
||||
|
||||
| | IRR (`route6`) | RPKI (ROA) |
|
||||
|---|---|---|
|
||||
| What it is | an entry in a database | a signed certificate |
|
||||
| Who can create it | whoever holds the maintainer | only the holder of the addresses |
|
||||
| Says | prefix + origin AS | prefix + origin AS + **max length** |
|
||||
| Used for | building prefix filters | dropping "invalid" routes |
|
||||
|
||||
Notes:
|
||||
Max length matters for us: a ROA for the /40 with max length 40 would make
|
||||
every student /48 RPKI-invalid, and many networks would drop it.
|
||||
|
||||
-----
|
||||
|
||||
## Look it up yourself
|
||||
|
||||
```bash
|
||||
whois -h whois.ripe.net 2a0d:d741:1::/48
|
||||
whois -h whois.ripe.net AS210036
|
||||
```
|
||||
|
||||
Or in a browser: RIPEstat, bgp.tools, or a looking glass at an exchange.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
@@ -0,0 +1,147 @@
|
||||
# BGP, down to the bytes
|
||||
|
||||
Notes:
|
||||
Section 3. The aim: by the end, the bytes view on the lab page reads like text.
|
||||
|
||||
-----
|
||||
|
||||
## BGP in one slide
|
||||
|
||||
* Runs over TCP, port `179`, between neighbours you configure by hand <!-- .element: class="fragment" -->
|
||||
* Each side tells the other its best route per prefix <!-- .element: class="fragment" -->
|
||||
* Only *changes* are sent: no periodic refresh <!-- .element: class="fragment" -->
|
||||
* If the session drops, every route learned over it is gone <!-- .element: class="fragment" -->
|
||||
|
||||
Notes:
|
||||
No discovery, no authentication of content, no notion of truth. A neighbour
|
||||
says "I can reach X" and you believe it, subject to your filters.
|
||||
|
||||
-----
|
||||
|
||||
## Four kinds of message
|
||||
|
||||
| Type | Name | Says |
|
||||
|---|---|---|
|
||||
| 1 | OPEN | who I am: AS number, router ID, capabilities |
|
||||
| 2 | **UPDATE** | these prefixes are reachable, those no longer are |
|
||||
| 3 | NOTIFICATION | something is wrong, I am closing the session |
|
||||
| 4 | KEEPALIVE | still here |
|
||||
|
||||
OPEN, OPEN, KEEPALIVE, KEEPALIVE, and then it is all UPDATEs.
|
||||
|
||||
<!-- .element: class="fragment note" -->
|
||||
|
||||
Notes:
|
||||
There is a fifth, ROUTE-REFRESH: "send me everything again, my policy changed".
|
||||
|
||||
-----
|
||||
|
||||
## The shape of an UPDATE
|
||||
|
||||
| Bytes | Field |
|
||||
|---|---|
|
||||
| 19 | header: marker, length, type |
|
||||
| 2 + n | withdrawn routes: prefixes that are no longer reachable |
|
||||
| 2 + n | path attributes: everything *about* the route |
|
||||
| the rest | NLRI: the IPv4 prefixes being announced |
|
||||
|
||||
One UPDATE carries one set of attributes, and every prefix that shares them.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
-----
|
||||
|
||||
## A real one: 94 bytes
|
||||
|
||||
<div class="legend"><span class="hh">header</span><span class="hl">lengths</span><span class="ha">path attributes</span><span class="hn">NLRI</span></div>
|
||||
|
||||
<pre class="bytes"><span class="hh">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh">00 5e</span> <span class="hh">02</span> <span class="hl">00 00</span> <span class="hl">00 47</span> <span class="ha">40 01 01 00</span> <span class="ha2">40 02 06 02 01 fa 56 ea 01</span> <span class="ha">80 0e 1c 00 02 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 2a 0d d7 41 00 01</span> <span class="ha2">c0 20 18 00 03 34 74 00 00 00 00 00 00 00 00 00 03 34 74 00 00 00 01 00 00 a5 ec</span></pre>
|
||||
|
||||
`2a0d:d741:1::/48`, as the lab daemon sent it. The same view is on the lab page under *bytes*.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
Notes:
|
||||
Captured from ferrix, not typed. Press down to walk through it part by part.
|
||||
Note there is nothing yellow: the NLRI field is empty. Hold that thought.
|
||||
|
||||
---
|
||||
|
||||
## Header
|
||||
|
||||
<pre class="bytes focus"><span class="hh on">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh on">00 5e</span> <span class="hh on">02</span> <span class="hl">00 00</span> <span class="hl">00 47</span> <span class="ha">40 01 01 00</span> <span class="ha2">40 02 06 02 01 fa 56 ea 01</span> <span class="ha">80 0e 1c 00 02 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 2a 0d d7 41 00 01</span> <span class="ha2">c0 20 18 00 03 34 74 00 00 00 00 00 00 00 00 00 03 34 74 00 00 00 01 00 00 a5 ec</span></pre>
|
||||
|
||||
<table class="decode"><tr><td>ff × 16</td><td>marker. Once carried authentication, now just filler to find message boundaries</td></tr><tr><td>00 5e</td><td>length of the whole message: 94 bytes (maximum 4096)</td></tr><tr><td>02</td><td>type 2 = UPDATE</td></tr></table>
|
||||
|
||||
---
|
||||
|
||||
## Two lengths
|
||||
|
||||
<pre class="bytes focus"><span class="hh">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh">00 5e</span> <span class="hh">02</span> <span class="hl on">00 00</span> <span class="hl on">00 47</span> <span class="ha">40 01 01 00</span> <span class="ha2">40 02 06 02 01 fa 56 ea 01</span> <span class="ha">80 0e 1c 00 02 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 2a 0d d7 41 00 01</span> <span class="ha2">c0 20 18 00 03 34 74 00 00 00 00 00 00 00 00 00 03 34 74 00 00 00 01 00 00 a5 ec</span></pre>
|
||||
|
||||
<table class="decode"><tr><td>00 00</td><td>0 bytes of withdrawn routes: nothing is being taken back</td></tr><tr><td>00 47</td><td>71 bytes of path attributes follow</td></tr><tr><td></td><td>94 − 19 − 2 − 2 − 71 = 0 bytes left over for NLRI</td></tr></table>
|
||||
|
||||
---
|
||||
|
||||
## ORIGIN
|
||||
|
||||
<pre class="bytes focus"><span class="hh">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh">00 5e</span> <span class="hh">02</span> <span class="hl">00 00</span> <span class="hl">00 47</span> <span class="ha on">40 01 01 00</span> <span class="ha2">40 02 06 02 01 fa 56 ea 01</span> <span class="ha">80 0e 1c 00 02 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 2a 0d d7 41 00 01</span> <span class="ha2">c0 20 18 00 03 34 74 00 00 00 00 00 00 00 00 00 03 34 74 00 00 00 01 00 00 a5 ec</span></pre>
|
||||
|
||||
<table class="decode"><tr><td>40</td><td>flags: well-known, transitive</td></tr><tr><td>01</td><td>type 1 = ORIGIN</td></tr><tr><td>01</td><td>1 byte of value</td></tr><tr><td>00</td><td>IGP: the route was originated inside this AS</td></tr></table>
|
||||
|
||||
Every attribute is *flags, type, length, value*.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
---
|
||||
|
||||
## AS_PATH
|
||||
|
||||
<pre class="bytes focus"><span class="hh">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh">00 5e</span> <span class="hh">02</span> <span class="hl">00 00</span> <span class="hl">00 47</span> <span class="ha">40 01 01 00</span> <span class="ha2 on">40 02 06 02 01 fa 56 ea 01</span> <span class="ha">80 0e 1c 00 02 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 2a 0d d7 41 00 01</span> <span class="ha2">c0 20 18 00 03 34 74 00 00 00 00 00 00 00 00 00 03 34 74 00 00 00 01 00 00 a5 ec</span></pre>
|
||||
|
||||
<table class="decode"><tr><td>40 02 06</td><td>well-known, transitive; type 2; 6 bytes</td></tr><tr><td>02</td><td>an AS_SEQUENCE, order matters</td></tr><tr><td>01</td><td>of 1 AS number</td></tr><tr><td>fa 56 ea 01</td><td>4200000001, the lab daemon. Four bytes each (RFC 6793)</td></tr></table>
|
||||
|
||||
Each network prepends itself on the way out. The length of this list is what best-path selection compares.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
---
|
||||
|
||||
## MP_REACH_NLRI: where IPv6 lives
|
||||
|
||||
<pre class="bytes focus"><span class="hh">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh">00 5e</span> <span class="hh">02</span> <span class="hl">00 00</span> <span class="hl">00 47</span> <span class="ha">40 01 01 00</span> <span class="ha2">40 02 06 02 01 fa 56 ea 01</span> <span class="ha on">80 0e 1c 00 02 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 2a 0d d7 41 00 01</span> <span class="ha2">c0 20 18 00 03 34 74 00 00 00 00 00 00 00 00 00 03 34 74 00 00 00 01 00 00 a5 ec</span></pre>
|
||||
|
||||
<table class="decode"><tr><td>80 0e 1c</td><td>optional, non-transitive; type 14; 28 bytes</td></tr><tr><td>00 02 · 01</td><td>address family IPv6, unicast</td></tr><tr><td>10 · 00…01</td><td>next hop, 16 bytes: ::1</td></tr><tr><td>00</td><td>reserved</td></tr><tr><td>30 · 2a 0d d7 41 00 01</td><td>48 bits of prefix: 2a0d:d741:1::/48</td></tr></table>
|
||||
|
||||
Notes:
|
||||
BGP-4 was built for IPv4: its NLRI field cannot carry anything else. RFC 4760
|
||||
bolts other address families on as an attribute, each with its own next hop.
|
||||
A prefix is sent as a bit count plus only as many bytes as the count needs.
|
||||
The next hop is ::1 because the daemon and the router share a machine.
|
||||
|
||||
---
|
||||
|
||||
## LARGE_COMMUNITIES
|
||||
|
||||
<pre class="bytes focus"><span class="hh">ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff</span> <span class="hh">00 5e</span> <span class="hh">02</span> <span class="hl">00 00</span> <span class="hl">00 47</span> <span class="ha">40 01 01 00</span> <span class="ha2">40 02 06 02 01 fa 56 ea 01</span> <span class="ha">80 0e 1c 00 02 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 30 2a 0d d7 41 00 01</span> <span class="ha2 on">c0 20 18 00 03 34 74 00 00 00 00 00 00 00 00 00 03 34 74 00 00 00 01 00 00 a5 ec</span></pre>
|
||||
|
||||
<table class="decode"><tr><td>c0 20 18</td><td>optional, transitive; type 32; 24 bytes = two communities</td></tr><tr><td>00033474 · 0 · 0</td><td>210036:0:0 our router: announce nowhere…</td></tr><tr><td>00033474 · 1 · 0000a5ec</td><td>210036:1:42476 …except to AS42476, the SwissIX route servers</td></tr></table>
|
||||
|
||||
Three 32-bit numbers. They mean whatever the receiving network says they mean.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
-----
|
||||
|
||||
## The flags byte
|
||||
|
||||
| Bit | Set means | Clear means |
|
||||
|---|---|---|
|
||||
| `0x80` | optional | well-known: every BGP speaker must understand it |
|
||||
| `0x40` | transitive: pass it on, even if not understood | drop it at the next hop |
|
||||
| `0x20` | partial: someone on the way did not understand it | |
|
||||
| `0x10` | length field is 2 bytes | 1 byte |
|
||||
|
||||
Transitive is why a community you set can act three networks away.
|
||||
|
||||
<!-- .element: class="fragment note" -->
|
||||
@@ -1,61 +0,0 @@
|
||||
## The lab
|
||||
|
||||
<div class="cols">
|
||||
<div>
|
||||
|
||||
* Open the status page
|
||||
* Your prefix is `2a0d:d741:<n>::/48`
|
||||
* `n` is your number, **in hex**
|
||||
* Use your name as owner
|
||||
|
||||
</div>
|
||||
<div>
|
||||
|
||||
```text
|
||||
you ─▶ ferrix ─▶ AS210036 ─▶ SwissIX ─▶ …
|
||||
AS42000… (BIRD)
|
||||
```
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Notes:
|
||||
"cols" gives two equal columns. Leave a blank line after the opening div and
|
||||
before the closing one, or the Markdown inside is not parsed.
|
||||
|
||||
-----
|
||||
|
||||
## The router's side
|
||||
|
||||
```bird [1-3|5-9|11]
|
||||
filter ferrix_import {
|
||||
if !(net ~ [ 2a0d:d741::/40{48,48} ]) then reject;
|
||||
if bgp_path.first != 4200000001 then reject;
|
||||
|
||||
bgp_community.filter([ (65535, 65281), (65535, 65282) ]);
|
||||
bgp_large_community.filter([ (42476, *, *), (210036, 0..3, *) ]);
|
||||
bgp_ext_community.empty;
|
||||
|
||||
dest = RTD_UNREACHABLE;
|
||||
accept;
|
||||
}
|
||||
```
|
||||
|
||||
`[1-3|5-9|11]` steps through the highlighted lines on each click.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
-----
|
||||
|
||||
## Live
|
||||
|
||||
<iframe class="live" data-src="about:blank" data-preload width="1100" height="440"></iframe>
|
||||
|
||||
Point `data-src` at the status page to have it live on the slide.
|
||||
|
||||
<!-- .element: class="attribution" -->
|
||||
|
||||
Notes:
|
||||
A live page on the slide is very much the Godbolt move. It needs the network,
|
||||
and a page behind a password will prompt inside the frame. Have a screenshot
|
||||
on a vertical slide below as the fallback.
|
||||
@@ -1,25 +0,0 @@
|
||||
## Communities
|
||||
|
||||
Tags on a route. They mean whatever the receiving network says they mean.
|
||||
|
||||
<div class="boxes">
|
||||
<div class="ok">NO_EXPORT<br><code>65535:65281</code></div>
|
||||
<div class="bad">BLACKHOLE<br><code>65535:666</code></div>
|
||||
<div class="us">210036:0:0<br>announce nowhere</div>
|
||||
<div>42476:1:559<br>SwissIX: only SWITCH</div>
|
||||
</div>
|
||||
|
||||
-----
|
||||
|
||||
## Two hops, one idea
|
||||
|
||||
| You set | Who acts | Effect |
|
||||
|---|---|---|
|
||||
| `210036:0:0` `210036:1:42476` | our router | only the SwissIX route servers |
|
||||
| `42476:0:0` `42476:1:559` | SwissIX | only SWITCH |
|
||||
|
||||
<!-- .element: class="borders" -->
|
||||
|
||||
Now find your prefix on a looking glass. Who can see it?
|
||||
|
||||
<!-- .element: class="fragment note" -->
|
||||
@@ -0,0 +1,115 @@
|
||||
# Transit and exchanges
|
||||
|
||||
Notes:
|
||||
Section 4. Two very different ways of getting routes, and what an Internet
|
||||
exchange physically is.
|
||||
|
||||
-----
|
||||
|
||||
## Two ways to reach other networks
|
||||
|
||||
<div class="cols">
|
||||
<div>
|
||||
|
||||
### IP transit
|
||||
|
||||
* You **pay** a provider
|
||||
* They give you routes to *everyone*
|
||||
* They announce you to *everyone*
|
||||
|
||||
</div>
|
||||
<div>
|
||||
|
||||
### Peering
|
||||
|
||||
* Usually **free**, by mutual benefit
|
||||
* You exchange *your own* routes, and your customers'
|
||||
* Traffic between the two of you only
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Notes:
|
||||
Transit is a customer-provider relationship; peering is between equals. A peer
|
||||
does not carry your traffic to third parties. Most networks have both: transit
|
||||
as the fallback, peering to keep traffic cheap and close.
|
||||
|
||||
-----
|
||||
|
||||
## An exchange is a big Ethernet switch
|
||||
|
||||
<svg class="diagram" viewBox="0 0 1000 400" role="img" aria-label="Members attached to a shared Ethernet peering LAN, with a route server">
|
||||
<g class="fabric"><rect x="60" y="175" width="880" height="56" rx="10"/></g>
|
||||
<text x="500" y="200" class="accent">peering LAN: one Ethernet segment, one subnet</text>
|
||||
<text x="500" y="220" class="small">SwissIX 2001:7f8:24::/64</text>
|
||||
<g class="hot"><rect x="70" y="40" width="180" height="70" rx="8"/></g>
|
||||
<text x="160" y="70">AS210036</text><text x="160" y="92" class="small">::c9</text>
|
||||
<rect x="300" y="40" width="180" height="70" rx="8"/><text x="390" y="70">AS559 SWITCH</text><text x="390" y="92" class="small">::35</text>
|
||||
<rect x="530" y="40" width="180" height="70" rx="8"/><text x="620" y="70">AS6939 HE</text><text x="620" y="92" class="small">::aa</text>
|
||||
<rect x="760" y="40" width="180" height="70" rx="8"/><text x="850" y="70">AS13335</text><text x="850" y="92" class="small">Cloudflare</text>
|
||||
<line class="link" x1="160" y1="110" x2="160" y2="175"/><line class="link" x1="390" y1="110" x2="390" y2="175"/>
|
||||
<line class="link" x1="620" y1="110" x2="620" y2="175"/><line class="link" x1="850" y1="110" x2="850" y2="175"/>
|
||||
<rect x="385" y="300" width="230" height="70" rx="8"/><text x="500" y="330">route servers</text><text x="500" y="352" class="small">AS42476 ::a5ec:a:1</text>
|
||||
<line class="link" x1="500" y1="231" x2="500" y2="300"/>
|
||||
<path class="bgp" d="M 140 110 C 140 290, 300 335, 385 335"/>
|
||||
<path class="bgp" d="M 410 110 C 410 250, 440 270, 470 300"/>
|
||||
<path class="traffic" d="M 180 110 C 180 165, 370 165, 370 110"/>
|
||||
<text x="275" y="138" class="small" style="fill:#4fd98a">traffic</text>
|
||||
<text x="215" y="300" class="small accent">BGP</text>
|
||||
</svg>
|
||||
|
||||
Notes:
|
||||
Every member plugs one router port into the same layer-2 network and gets one
|
||||
address in a shared subnet. No routing inside the exchange: just Ethernet.
|
||||
Dashed blue is a BGP session, green is where the packets actually go.
|
||||
a5ec is 42476 in hex: the route server's address spells its AS number.
|
||||
|
||||
-----
|
||||
|
||||
## What that implies
|
||||
|
||||
* Your neighbour is *on your LAN*: one hop, found by neighbour discovery <!-- .element: class="fragment" -->
|
||||
* A route's next hop is the peer's LAN address, so traffic goes **directly** member to member <!-- .element: class="fragment" -->
|
||||
* The exchange never routes your packets. It switches frames <!-- .element: class="fragment" -->
|
||||
* So the LAN is policed hard: one MAC address per port, no stray broadcasts, no proxy ARP <!-- .element: class="fragment" -->
|
||||
|
||||
Notes:
|
||||
A misbehaving port can hurt every member, which is why exchanges publish strict
|
||||
rules for what may appear on the peering LAN and quarantine ports that break them.
|
||||
|
||||
-----
|
||||
|
||||
## Route servers
|
||||
|
||||
Without one, peering with 200 members is 200 BGP sessions.
|
||||
|
||||
* One session to the route server brings routes from everyone who uses it <!-- .element: class="fragment" -->
|
||||
* It is **not** in the traffic path, and leaves the next hop alone <!-- .element: class="fragment" -->
|
||||
* It does not add its own AS to the path <!-- .element: class="fragment" -->
|
||||
* You steer it with communities: `42476:0:<as>` "not to them", `42476:1:<as>` "only to them" <!-- .element: class="fragment" -->
|
||||
|
||||
Notes:
|
||||
A route server is a BGP speaker that only redistributes. Because it is
|
||||
transparent, the AS path looks exactly as if you peered with each member
|
||||
directly. We will use those communities in the lab.
|
||||
|
||||
-----
|
||||
|
||||
## Our upstream router, for real
|
||||
|
||||
| Where | BGP sessions | Neighbour networks |
|
||||
|---|---|---|
|
||||
| Transit (CommunityRack) | 2 | 1 |
|
||||
| SwissIX, Zürich | 28 | 12 |
|
||||
| DE-CIX, Frankfurt | 26 | 8 |
|
||||
| France-IX, Paris | 23 | 10 |
|
||||
| NL-ix, Amsterdam | 22 | 6 |
|
||||
|
||||
One small router, `pr01.rue`, AS210036. IPv4 and IPv6 are separate sessions.
|
||||
|
||||
<!-- .element: class="note" -->
|
||||
|
||||
Notes:
|
||||
Counted from its BIRD configuration. It is also on two smaller Swiss exchanges.
|
||||
The same network (Cloudflare, Apple, Hurricane Electric) often appears at
|
||||
several exchanges, which matters when you choose where to announce.
|
||||
@@ -0,0 +1,117 @@
|
||||
# The lab
|
||||
|
||||
Notes:
|
||||
Section 5. What the students are about to touch, and what stands between a
|
||||
typo and the Internet.
|
||||
|
||||
-----
|
||||
|
||||
## What you are connected to
|
||||
|
||||
<svg class="diagram" viewBox="0 0 1000 430" role="img" aria-label="Browser to ferrix to the BIRD router pr01.rue, which peers at four exchanges and buys transit">
|
||||
<rect x="20" y="170" width="150" height="80" rx="8"/><text x="95" y="205">you</text><text x="95" y="228" class="small">a browser</text>
|
||||
<g class="hot"><rect x="230" y="170" width="200" height="80" rx="8"/></g><text x="330" y="202" class="accent">ferrix</text><text x="330" y="226" class="small">AS4200000001</text>
|
||||
<rect x="490" y="170" width="200" height="80" rx="8"/><text x="590" y="202">pr01.rue (BIRD)</text><text x="590" y="226" class="small">AS210036</text>
|
||||
<line class="link" x1="170" y1="210" x2="230" y2="210"/><text x="200" y="160" class="small">HTTPS</text>
|
||||
<line class="bgp" x1="430" y1="210" x2="490" y2="210"/><text x="460" y="160" class="small accent">BGP</text>
|
||||
<text x="330" y="280" class="small">web page + BGP speaker</text><text x="590" y="280" class="small">filters, then decides where</text>
|
||||
<rect x="780" y="20" width="200" height="56" rx="8"/><text x="880" y="54">SwissIX</text>
|
||||
<rect x="780" y="98" width="200" height="56" rx="8"/><text x="880" y="132">NL-ix</text>
|
||||
<rect x="780" y="176" width="200" height="56" rx="8"/><text x="880" y="210">France-IX</text>
|
||||
<rect x="780" y="254" width="200" height="56" rx="8"/><text x="880" y="288">DE-CIX</text>
|
||||
<rect x="780" y="352" width="200" height="56" rx="8"/><text x="880" y="386">transit</text>
|
||||
<path class="bgp" d="M 690 195 C 740 195, 730 48, 780 48"/><path class="bgp" d="M 690 203 C 740 203, 735 126, 780 126"/>
|
||||
<path class="bgp" d="M 690 210 L 780 204"/><path class="bgp" d="M 690 217 C 740 217, 735 282, 780 282"/>
|
||||
<path class="bgp" d="M 690 225 C 740 225, 730 380, 780 380"/>
|
||||
</svg>
|
||||
|
||||
Notes:
|
||||
ferrix is a small BGP daemon written for this course; it runs on the same
|
||||
machine as the router. Both dashed hops are real BGP sessions. Everything to
|
||||
the right of pr01 is the actual Internet.
|
||||
|
||||
-----
|
||||
|
||||
## Your prefix
|
||||
|
||||
`2a0d:d741:<n>::/48`
|
||||
|
||||
* `<n>` is your number **in hex**: student 10 is `2a0d:d741:a::/48` <!-- .element: class="fragment" -->
|
||||
* Put your name in *owner*: only the owner can withdraw a route <!-- .element: class="fragment" -->
|
||||
* One prefix each <!-- .element: class="fragment" -->
|
||||
|
||||
Notes:
|
||||
Put the URL and the class password on the board. The page is a snapshot by
|
||||
default; turn on auto-refresh at the top right to watch things change.
|
||||
|
||||
-----
|
||||
|
||||
## What happens when you press *Announce*
|
||||
|
||||
1. ferrix builds an UPDATE. Click *bytes* to see it, hover to decode it <!-- .element: class="fragment" -->
|
||||
2. pr01 checks it against its import filter <!-- .element: class="fragment" -->
|
||||
3. pr01 decides, per neighbour, whether to pass it on <!-- .element: class="fragment" -->
|
||||
4. Within a minute or so, the Internet can see your prefix <!-- .element: class="fragment" -->
|
||||
5. `ping 2a0d:d741:<n>::1` answers, from anywhere <!-- .element: class="fragment" -->
|
||||
|
||||
Notes:
|
||||
Step 5: pr01 answers for every address in the lab space, so reachability of
|
||||
your prefix depends only on whether your announcement got out.
|
||||
|
||||
-----
|
||||
|
||||
## What stands between you and an outage
|
||||
|
||||
```bird [2-3|5-7|9]
|
||||
filter ferrix_import {
|
||||
if !(net ~ [ 2a0d:d741::/40{48,48} ]) then reject; # only lab /48s
|
||||
if bgp_path.first != 4200000001 then reject; # only from ferrix
|
||||
|
||||
bgp_community.filter([ (65535, 65281), (65535, 65282) ]);
|
||||
bgp_large_community.filter([ (42476, *, *), (210036, 0..3, *) ]);
|
||||
bgp_ext_community.empty; # drop what we did not offer
|
||||
|
||||
dest = RTD_UNREACHABLE; # announce-only
|
||||
accept;
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
This is the router's real import filter. ferrix refuses anything outside the
|
||||
lab /40 before it gets this far, and pr01 takes at most 130 routes from it.
|
||||
Two independent nets, because the web form has no idea who you are.
|
||||
|
||||
-----
|
||||
|
||||
## Steering your route
|
||||
|
||||
| You add | Who acts | Effect |
|
||||
|---|---|---|
|
||||
| nothing | | announced everywhere |
|
||||
| `210036:0:0` | pr01 | announced nowhere |
|
||||
| `210036:0:0` `210036:1:42476` | pr01 | only to the SwissIX route servers |
|
||||
| + `42476:0:0` `42476:1:559` | SwissIX | …and from there only to SWITCH |
|
||||
| `NO_EXPORT` | pr01 | accepted, never passed on |
|
||||
|
||||
Same idea at two hops: *never there*, *only there*, *nowhere*.
|
||||
|
||||
<!-- .element: class="fragment note" -->
|
||||
|
||||
Notes:
|
||||
210036:0:<as> never to that AS, 210036:1:<as> to that AS, 210036:2/3:<n> the
|
||||
same by exchange (1 SwissIX, 2 NL-ix, 3 France-IX, 4 DE-CIX). A "never" always
|
||||
wins. The preset menu next to the field has all of these.
|
||||
|
||||
-----
|
||||
|
||||
## Your turn
|
||||
|
||||
1. Announce your prefix with no options. Find it on a looking glass
|
||||
2. Read the bytes: where is your AS number? Where is your prefix?
|
||||
3. Restrict it to the SwissIX route servers. Who still sees it?
|
||||
4. Narrow it to SWITCH. Can you reach it from the ETH network? From your phone?
|
||||
5. Withdraw it and watch it disappear
|
||||
|
||||
Notes:
|
||||
Looking glasses: bgp.tools, RIPEstat, and the exchange's own. Global
|
||||
visibility takes a minute or two to settle after each change.
|
||||
@@ -1,21 +0,0 @@
|
||||
## What could go wrong?
|
||||
|
||||
* Anyone can announce anything <!-- .element: class="fragment" -->
|
||||
* Filters are the only thing between a typo and an outage <!-- .element: class="fragment" -->
|
||||
* IRR objects and RPKI say who *may* announce a prefix <!-- .element: class="fragment" -->
|
||||
|
||||
-----
|
||||
|
||||
> "The Internet works because a lot of people are careful, most of the time."
|
||||
|
||||
Quotes use a plain Markdown blockquote.
|
||||
|
||||
<!-- .element: class="attribution" -->
|
||||
|
||||
-----
|
||||
|
||||
## Thank you
|
||||
|
||||
Questions?
|
||||
|
||||
<p class="note">Slides: <code>slides/</code> in the ferrix_bgp repository</p>
|
||||
@@ -175,3 +175,111 @@
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* ---- bytes with one part in focus: everything not .on is dimmed --------------- */
|
||||
|
||||
.bytes.focus span:not(.on) {
|
||||
opacity: 0.22;
|
||||
}
|
||||
|
||||
.bytes.focus span.on {
|
||||
box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.9);
|
||||
}
|
||||
|
||||
/* Small two-column explanation under a bytes block. */
|
||||
.reveal table.decode {
|
||||
font-size: 58%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.reveal table.decode td:first-child {
|
||||
font-family: var(--r-code-font);
|
||||
color: var(--accent-soft);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ---- bits of an address: fixed part vs. free part ------------------------------ */
|
||||
|
||||
.bits {
|
||||
font-family: var(--r-code-font);
|
||||
font-size: 80%;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.bits .fixed {
|
||||
color: var(--ground);
|
||||
background: var(--accent);
|
||||
border-radius: 4px 0 0 4px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.bits .free {
|
||||
color: var(--ink);
|
||||
background: var(--ground);
|
||||
border: 1px solid var(--rule);
|
||||
border-left: none;
|
||||
border-radius: 0 4px 4px 0;
|
||||
padding: 1px 6px;
|
||||
}
|
||||
|
||||
/* ---- diagrams: inline SVG drawn with the theme's colours ------------------------ */
|
||||
|
||||
.reveal svg.diagram {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 470px;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.diagram rect,
|
||||
.diagram ellipse {
|
||||
fill: var(--ground);
|
||||
stroke: var(--rule);
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.diagram .hot rect {
|
||||
stroke: var(--accent);
|
||||
}
|
||||
|
||||
.diagram .fabric rect {
|
||||
fill: rgba(var(--accent-rgb), 0.18);
|
||||
stroke: var(--accent);
|
||||
}
|
||||
|
||||
.diagram text {
|
||||
fill: var(--ink);
|
||||
font-family: "IBM Plex Sans", sans-serif;
|
||||
font-size: 19px;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.diagram text.small {
|
||||
font-size: 14px;
|
||||
fill: var(--muted);
|
||||
font-family: "IBM Plex Mono", monospace;
|
||||
}
|
||||
|
||||
.diagram text.accent {
|
||||
fill: var(--accent);
|
||||
}
|
||||
|
||||
.diagram .link {
|
||||
stroke: var(--muted);
|
||||
stroke-width: 2.5;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.diagram .bgp {
|
||||
stroke: var(--accent);
|
||||
stroke-width: 2.5;
|
||||
stroke-dasharray: 7 6;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.diagram .traffic {
|
||||
stroke: #4fd98a;
|
||||
stroke-width: 4;
|
||||
fill: none;
|
||||
}
|
||||
+23
-27
@@ -6,7 +6,7 @@
|
||||
* markers, links and progress bar, glowing highlighted code lines.
|
||||
*
|
||||
* Made our own: the palette is ours (change it in :root below), and his
|
||||
* "thread" motif becomes a chain of nodes and links, an AS path.
|
||||
* "thread" corner motif becomes a chain of nodes and links, an AS path.
|
||||
*
|
||||
* Try accents without editing: index.html?accent=green (blue, green,
|
||||
* amber, magenta). Make one permanent by copying its values into :root.
|
||||
@@ -379,7 +379,7 @@
|
||||
.reveal section.title-slide h3 {
|
||||
font-weight: 400;
|
||||
color: var(--accent);
|
||||
margin-bottom: 1.6em;
|
||||
margin-bottom: 2.2em;
|
||||
}
|
||||
|
||||
.reveal section.title-slide .byline {
|
||||
@@ -388,37 +388,33 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.reveal section.title-slide .as-path {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
height: 90px;
|
||||
margin: 0 0 1em;
|
||||
/* ---- shown by index.html when the deck cannot start --------------------------- */
|
||||
|
||||
#deck-help {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 100;
|
||||
padding: 8vh 10vw;
|
||||
background: var(--ground);
|
||||
color: var(--ink);
|
||||
font: 20px/1.5 "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.as-path circle {
|
||||
fill: var(--ground);
|
||||
stroke: var(--accent);
|
||||
stroke-width: 3;
|
||||
#deck-help h2 {
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.as-path line {
|
||||
stroke: var(--accent);
|
||||
stroke-width: 3;
|
||||
#deck-help pre,
|
||||
#deck-help code {
|
||||
font-family: var(--r-code-font);
|
||||
color: var(--accent-soft);
|
||||
}
|
||||
|
||||
.as-path text {
|
||||
font-family: "IBM Plex Mono", monospace;
|
||||
font-size: 15px;
|
||||
fill: var(--muted);
|
||||
}
|
||||
|
||||
.as-path .you circle {
|
||||
fill: var(--accent);
|
||||
}
|
||||
|
||||
.as-path .you text {
|
||||
fill: var(--ink-strong);
|
||||
#deck-help pre {
|
||||
background: var(--panel);
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* ---- print ------------------------------------------------------------------ */
|
||||
|
||||
Reference in new issue
Block a user