From 1399cbd39ffe6cb188f6f8f98397d291586f45d3 Mon Sep 17 00:00:00 2001 From: Rayhaan Jaufeerally Date: Sun, 20 Sep 2026 21:41:31 +0200 Subject: [PATCH] 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 --- slides/README.md | 28 ++++- slides/images/placeholder.svg | 5 - slides/index.html | 57 +++++++---- slides/sections/01-addresses.md | 92 +++++++++++++++++ slides/sections/01-intro.md | 31 ------ slides/sections/02-bgp.md | 53 ---------- slides/sections/02-registries.md | 89 ++++++++++++++++ slides/sections/03-bgp-update.md | 147 +++++++++++++++++++++++++++ slides/sections/03-lab.md | 61 ----------- slides/sections/04-communities.md | 25 ----- slides/sections/04-transit-and-ix.md | 115 +++++++++++++++++++++ slides/sections/05-lab.md | 117 +++++++++++++++++++++ slides/sections/05-wrap-up.md | 21 ---- slides/style.css | 108 ++++++++++++++++++++ slides/theme.css | 50 +++++---- 15 files changed, 754 insertions(+), 245 deletions(-) delete mode 100644 slides/images/placeholder.svg create mode 100644 slides/sections/01-addresses.md delete mode 100644 slides/sections/01-intro.md delete mode 100644 slides/sections/02-bgp.md create mode 100644 slides/sections/02-registries.md create mode 100644 slides/sections/03-bgp-update.md delete mode 100644 slides/sections/03-lab.md delete mode 100644 slides/sections/04-communities.md create mode 100644 slides/sections/04-transit-and-ix.md create mode 100644 slides/sections/05-lab.md delete mode 100644 slides/sections/05-wrap-up.md diff --git a/slides/README.md b/slides/README.md index 58f859b..323f079 100644 --- a/slides/README.md +++ b/slides/README.md @@ -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 `
` 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 ``. Blocks: `
` two columns, `
` labelled cards (`us`, `ok`, `bad`), `
` 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),
+`` for the explanation under them,
+`` 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`.
 
 `` drops the panel, the motif and the wordmark
diff --git a/slides/images/placeholder.svg b/slides/images/placeholder.svg
deleted file mode 100644
index 176616d..0000000
--- a/slides/images/placeholder.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-  
-  your picture here
-  slides/images/
-
diff --git a/slides/index.html b/slides/index.html
index 5c9dbd9..24f67bd 100644
--- a/slides/index.html
+++ b/slides/index.html
@@ -3,7 +3,7 @@
   
-    BGP hands-on: announce your own prefix
+    Hands-on BGP
- -

Announce your own prefix

-

A hands-on introduction to BGP

+

Hands-on BGP

+

Announce your own prefix to the Internet

@@ -45,16 +37,41 @@ --- next vertical slide (goes down, for detail you may skip) Notes: everything after this is speaker notes (press S) --> -
-
-
-
-
+
+
+
+
+
ferrix_bgp · netsec 2026
+ + + + diff --git a/slides/sections/01-addresses.md b/slides/sections/01-addresses.md new file mode 100644 index 0000000..4093d10 --- /dev/null +++ b/slides/sections/01-addresses.md @@ -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. + + + +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` + +

2a0d:d741:0001xxxx:xxxx:xxxx:xxxx:xxxx

+ +The first 48 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:::/48` | **you** | 65,536 /64s | +| `…/64` | one LAN | the hosts on it | + +`` is your student number, written *in hex*. + + + +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. + + + +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? + +
+
IPv6: up to /48
+
IPv4: up to /24
+
anything longer: filtered by almost everyone
+
+ +Not a protocol rule. A convention, so the global table stays finite. + + + +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. diff --git a/slides/sections/01-intro.md b/slides/sections/01-intro.md deleted file mode 100644 index c84b356..0000000 --- a/slides/sections/01-intro.md +++ /dev/null @@ -1,31 +0,0 @@ -## Today - -* What BGP is, in ten minutes -* You announce a real prefix to the real Internet -* You steer where it goes with communities -* We look at what could go wrong - -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 -75,000 -networks that agreed to talk to each other. - - - -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: - ------ - -Replace with a picture - -Replace `images/placeholder.svg`. `r-stretch` makes an image fill the slide. - - diff --git a/slides/sections/02-bgp.md b/slides/sections/02-bgp.md deleted file mode 100644 index 9ca0309..0000000 --- a/slides/sections/02-bgp.md +++ /dev/null @@ -1,53 +0,0 @@ -## An autonomous system - -
-
AS210036
our upstream
-
AS559
SWITCH
-
AS6939
Hurricane Electric
-
AS13335
Cloudflare
-
- -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." - - - ------ - -## What actually goes on the wire - -
headerlengthspath attributesNLRI
- -
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 50 02 00 00 00 35 40 01 01 00 40 02 0a 02 02 00 00 fd e8 00 00 fd e8 40 03 04 7f 00 00 01 80 04 04 00 00 00 32 c0 08 04 fd e8 00 64 18 0a 64 01
- -Same colours as the bytes view on the lab page, so you can point from one to the other. - - - ---- - -## Going deeper (a vertical slide) - -Press ↓. 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 | - - diff --git a/slides/sections/02-registries.md b/slides/sections/02-registries.md new file mode 100644 index 0000000..9269e99 --- /dev/null +++ b/slides/sections/02-registries.md @@ -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 + +
+
IANA
the root
+
RIPE NCC
Europe, Middle East
+
ARIN
+
APNIC
+
LACNIC
+
AFRINIC
+
+ +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` +* 32 bits since RFC 6793: up to `4294967295` +* Old routers see `AS23456` (AS_TRANS) in place of a big one +* Private use: `64512–65534` and `4200000000–4294967294` + +The lab daemon is `AS4200000001`. It is stripped before the Internet sees your route. + + + +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. + + + +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. + + diff --git a/slides/sections/03-bgp-update.md b/slides/sections/03-bgp-update.md new file mode 100644 index 0000000..ec83090 --- /dev/null +++ b/slides/sections/03-bgp-update.md @@ -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 +* Each side tells the other its best route per prefix +* Only *changes* are sent: no periodic refresh +* If the session drops, every route learned over it is gone + +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. + + + +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. + + + +----- + +## A real one: 94 bytes + +
headerlengthspath attributesNLRI
+ +
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 5e 02 00 00 00 47 40 01 01 00 40 02 06 02 01 fa 56 ea 01 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 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
+ +`2a0d:d741:1::/48`, as the lab daemon sent it. The same view is on the lab page under *bytes*. + + + +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 + +
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 5e 02 00 00 00 47 40 01 01 00 40 02 06 02 01 fa 56 ea 01 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 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
+ +
ff × 16marker. Once carried authentication, now just filler to find message boundaries
00 5elength of the whole message: 94 bytes (maximum 4096)
02type 2 = UPDATE
+ +--- + +## Two lengths + +
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 5e 02 00 00 00 47 40 01 01 00 40 02 06 02 01 fa 56 ea 01 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 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
+ +
00 000 bytes of withdrawn routes: nothing is being taken back
00 4771 bytes of path attributes follow
94 − 19 − 2 − 2 − 71 = 0 bytes left over for NLRI
+ +--- + +## ORIGIN + +
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 5e 02 00 00 00 47 40 01 01 00 40 02 06 02 01 fa 56 ea 01 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 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
+ +
40flags: well-known, transitive
01type 1 = ORIGIN
011 byte of value
00IGP: the route was originated inside this AS
+ +Every attribute is *flags, type, length, value*. + + + +--- + +## AS_PATH + +
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 5e 02 00 00 00 47 40 01 01 00 40 02 06 02 01 fa 56 ea 01 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 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
+ +
40 02 06well-known, transitive; type 2; 6 bytes
02an AS_SEQUENCE, order matters
01of 1 AS number
fa 56 ea 014200000001, the lab daemon. Four bytes each (RFC 6793)
+ +Each network prepends itself on the way out. The length of this list is what best-path selection compares. + + + +--- + +## MP_REACH_NLRI: where IPv6 lives + +
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 5e 02 00 00 00 47 40 01 01 00 40 02 06 02 01 fa 56 ea 01 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 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
+ +
80 0e 1coptional, non-transitive; type 14; 28 bytes
00 02 · 01address family IPv6, unicast
10 · 00…01next hop, 16 bytes: ::1
00reserved
30 · 2a 0d d7 41 00 0148 bits of prefix: 2a0d:d741:1::/48
+ +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 + +
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 5e 02 00 00 00 47 40 01 01 00 40 02 06 02 01 fa 56 ea 01 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 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
+ +
c0 20 18optional, transitive; type 32; 24 bytes = two communities
00033474 · 0 · 0210036:0:0 our router: announce nowhere…
00033474 · 1 · 0000a5ec210036:1:42476 …except to AS42476, the SwissIX route servers
+ +Three 32-bit numbers. They mean whatever the receiving network says they mean. + + + +----- + +## 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. + + diff --git a/slides/sections/03-lab.md b/slides/sections/03-lab.md deleted file mode 100644 index 5fa40f0..0000000 --- a/slides/sections/03-lab.md +++ /dev/null @@ -1,61 +0,0 @@ -## The lab - -
-
- -* Open the status page -* Your prefix is `2a0d:d741:::/48` -* `n` is your number, **in hex** -* Use your name as owner - -
-
- -```text - you ─▶ ferrix ─▶ AS210036 ─▶ SwissIX ─▶ … - AS42000… (BIRD) -``` - -
-
- -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. - - - ------ - -## Live - - - -Point `data-src` at the status page to have it live on the slide. - - - -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. diff --git a/slides/sections/04-communities.md b/slides/sections/04-communities.md deleted file mode 100644 index 796cb10..0000000 --- a/slides/sections/04-communities.md +++ /dev/null @@ -1,25 +0,0 @@ -## Communities - -Tags on a route. They mean whatever the receiving network says they mean. - -
-
NO_EXPORT
65535:65281
-
BLACKHOLE
65535:666
-
210036:0:0
announce nowhere
-
42476:1:559
SwissIX: only SWITCH
-
- ------ - -## 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 | - - - -Now find your prefix on a looking glass. Who can see it? - - diff --git a/slides/sections/04-transit-and-ix.md b/slides/sections/04-transit-and-ix.md new file mode 100644 index 0000000..ea8ce0f --- /dev/null +++ b/slides/sections/04-transit-and-ix.md @@ -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 + +
+
+ +### IP transit + +* You **pay** a provider +* They give you routes to *everyone* +* They announce you to *everyone* + +
+
+ +### Peering + +* Usually **free**, by mutual benefit +* You exchange *your own* routes, and your customers' +* Traffic between the two of you only + +
+
+ +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 + + + +peering LAN: one Ethernet segment, one subnet +SwissIX 2001:7f8:24::/64 + +AS210036::c9 +AS559 SWITCH::35 +AS6939 HE::aa +AS13335Cloudflare + + +route serversAS42476 ::a5ec:a:1 + + + + +traffic +BGP + + +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 +* A route's next hop is the peer's LAN address, so traffic goes **directly** member to member +* The exchange never routes your packets. It switches frames +* So the LAN is policed hard: one MAC address per port, no stray broadcasts, no proxy ARP + +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 +* It is **not** in the traffic path, and leaves the next hop alone +* It does not add its own AS to the path +* You steer it with communities: `42476:0:` "not to them", `42476:1:` "only to them" + +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. + + + +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. diff --git a/slides/sections/05-lab.md b/slides/sections/05-lab.md new file mode 100644 index 0000000..4ddc2e6 --- /dev/null +++ b/slides/sections/05-lab.md @@ -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 + + +youa browser +ferrixAS4200000001 +pr01.rue (BIRD)AS210036 +HTTPS +BGP +web page + BGP speakerfilters, then decides where +SwissIX +NL-ix +France-IX +DE-CIX +transit + + + + + +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:::/48` + +* `` is your number **in hex**: student 10 is `2a0d:d741:a::/48` +* Put your name in *owner*: only the owner can withdraw a route +* One prefix each + +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 +2. pr01 checks it against its import filter +3. pr01 decides, per neighbour, whether to pass it on +4. Within a minute or so, the Internet can see your prefix +5. `ping 2a0d:d741:::1` answers, from anywhere + +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*. + + + +Notes: +210036:0: never to that AS, 210036:1: to that AS, 210036:2/3: 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. diff --git a/slides/sections/05-wrap-up.md b/slides/sections/05-wrap-up.md deleted file mode 100644 index a0aaedc..0000000 --- a/slides/sections/05-wrap-up.md +++ /dev/null @@ -1,21 +0,0 @@ -## What could go wrong? - -* Anyone can announce anything -* Filters are the only thing between a typo and an outage -* IRR objects and RPKI say who *may* announce a prefix - ------ - -> "The Internet works because a lot of people are careful, most of the time." - -Quotes use a plain Markdown blockquote. - - - ------ - -## Thank you - -Questions? - -

Slides: slides/ in the ferrix_bgp repository

diff --git a/slides/style.css b/slides/style.css index 8a85c51..7b0dacb 100644 --- a/slides/style.css +++ b/slides/style.css @@ -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; +} diff --git a/slides/theme.css b/slides/theme.css index 9889be9..57e4cf6 100644 --- a/slides/theme.css +++ b/slides/theme.css @@ -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 ------------------------------------------------------------------ */