Files
ferrix/slides/index.html
T
Rayhaan JaufeerallyandClaude Fable 5.1 1399cbd39f 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>
2026-09-20 21:41:31 +02:00

165 lines
7.5 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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
no stock theme, a custom dark theme (theme.css), monokai code blocks,
16:9, fade transitions, and one Markdown file per section.
reveal.js is loaded from ./reveal.js/dist if present (run
./vendor-reveal.sh once; works offline), otherwise from the CDN. Its
stylesheets are inserted BEFORE ours by the loader below, so theme.css
and style.css always have the last word.
-->
<link rel="stylesheet" href="theme.css" id="deck-style" />
<link rel="stylesheet" href="style.css" />
<link rel="icon" href="images/favicon.svg" type="image/svg+xml" />
<link rel="shortcut icon" href="images/favicon.svg" />
</head>
<body>
<div class="reveal">
<div class="slides">
<!-- Title slide. For a full-bleed image instead, empty it and add
data-background="images/title.png" like Matt does. -->
<section class="title-slide">
<h1>Hands-on BGP</h1>
<h3>Announce your own prefix to the Internet</h3>
<p class="byline">Rayhaan Jaufeerally &middot; Network Security &middot; ETH Z&uuml;rich, 2026</p>
</section>
<!--
One Markdown file per section. Inside a file:
----- next horizontal slide
--- next vertical slide (goes down, for detail you may skip)
Notes: everything after this is speaker notes (press S)
-->
<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 &middot; 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";
const CDN = `https://cdn.jsdelivr.net/npm/reveal.js@${VERSION}/dist`;
// Prefer the vendored copy so the deck works without a network.
async function pickBase() {
try {
const r = await fetch(`${LOCAL}/reveal.css`, { method: "HEAD" });
if (r.ok) return LOCAL;
} catch (_) {}
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(
["reset.css", "reveal.css", "plugin/highlight/monokai.css"].map(
(href) =>
new Promise((resolve) => {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = `${base}/${href}`;
link.onload = link.onerror = resolve;
deckStyle.before(link);
}),
),
);
const [{ default: Reveal }, { default: Markdown }, { default: Highlight }, { default: Notes }] =
await Promise.all(
["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.
function bird() {
return {
name: "bird",
keywords: {
keyword:
"protocol template filter function define table if then else case return accept reject " +
"import export where none all limit action block neighbor local as direct multihop passive " +
"description ipv4 ipv6 bgp kernel device static pipe include router id",
built_in:
"net proto source dest bgp_path bgp_community bgp_large_community bgp_ext_community " +
"bgp_med bgp_local_pref bgp_next_hop",
literal: "true false on off RTD_UNREACHABLE RTS_BGP",
},
contains: [
{ className: "comment", begin: "#", end: "$" },
{ className: "string", begin: '"', end: '"' },
{ className: "number", begin: "\\b[0-9a-fA-F:]*::?[0-9a-fA-F:]*(/[0-9]+)?(\\{[0-9]+,[0-9]+\\})?\\b" },
{ className: "number", begin: "\\b[0-9]+(\\.[0-9]+){3}(/[0-9]+)?\\b" },
{ className: "number", begin: "\\b[0-9]+\\b" },
],
};
}
// ?accent=green|amber|magenta previews another accent; blue is the default.
const accent = new URLSearchParams(location.search).get("accent");
if (accent) document.documentElement.dataset.accent = accent;
// 16:9. Nudge scaleFactor to fit the projector, as Matt does.
const scaleFactor = 0.65;
const deck = new Reveal({
hash: true,
transition: "fade",
slideNumber: false,
margin: 0.15,
width: 1920 * scaleFactor,
height: 1080 * scaleFactor,
markdown: { smartypants: true },
highlight: {
beforeHighlight: (hljs) => hljs.registerLanguage("bird", bird),
},
plugins: [Markdown, Highlight, Notes],
});
await deck.initialize().catch(fail("reveal.js failed to start"));
window.deck = deck; // handy in the console: deck.slide(3), deck.getTotalSlides()
</script>
</body>
</html>