diff --git a/slides/README.md b/slides/README.md
index 323f079..1198b31 100644
--- a/slides/README.md
+++ b/slides/README.md
@@ -19,10 +19,18 @@ chain of nodes and links, an AS path.
| 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.
+The UPDATE in section 3 is `2a0d:d740::/48` as AS210036 announces it to the
+SwissIX route servers: next hop `2001:7f8:24::c9` (pr01's port on the peering
+LAN), MED 0 and the `210036:10:2` tag, which is what pr01's export filter puts
+on routes to peers. It was produced with ferrix's own encoder and parsed back
+to the same message, not captured off the wire; a capture from pr01 may differ
+in detail (BIRD can append a link-local next hop). The byte slides step through
+it one part at a time (press down), and every number on them was checked
+against the bytes when the slides were generated. To change the example,
+regenerate rather than edit the hex by hand.
+
+The deck deliberately has no fragments or stepped code: a slide shows
+everything at once. Two code blocks keep a static highlight on one line.
| File | Holds |
|---|---|
@@ -75,8 +83,6 @@ Apply a class to the element above with ``.
| Class | Effect |
|---|---|
-| `fragment` | appears on the next click |
-| `fragment pop` | appears, grows and takes the accent colour |
| `big` | one large statement on the slide |
| `note` | quiet italic aside |
| `attribution` | small credit under an image or quote |
diff --git a/slides/sections/01-addresses.md b/slides/sections/01-addresses.md
index 4093d10..a8f75f8 100644
--- a/slides/sections/01-addresses.md
+++ b/slides/sections/01-addresses.md
@@ -29,7 +29,7 @@ Ask: why only once? Because 2a0d::1::1 could put the zeros in several places.
` is your student number, written *in hex*.
-
+
Notes:
Student 10 is 2a0d:d741:a::/48, student 16 is 2a0d:d741:10::/48.
@@ -58,7 +58,7 @@ A /40 holds exactly 256 /48s, which caps the class size at 255.
## The most specific route wins
-```text [1-3|3]
+```text [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
diff --git a/slides/sections/02-registries.md b/slides/sections/02-registries.md
index 9269e99..6b72787 100644
--- a/slides/sections/02-registries.md
+++ b/slides/sections/02-registries.md
@@ -26,14 +26,14 @@ 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`
+* 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
@@ -43,7 +43,7 @@ AS from the path, so the origin everybody else sees is AS210036.
## The RIPE database says who may announce what
-```text [1-5|3]
+```text [3]
route6: 2a0d:d741:1::/48
descr: ETHZ Netsec 2026 BGP lab - student 1
origin: AS210036
diff --git a/slides/sections/03-bgp-update.md b/slides/sections/03-bgp-update.md
index ec83090..cb592f7 100644
--- a/slides/sections/03-bgp-update.md
+++ b/slides/sections/03-bgp-update.md
@@ -7,10 +7,10 @@ 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
+* 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
@@ -29,7 +29,7 @@ says "I can reach X" and you believe it, subject to your filters.
OPEN, OPEN, KEEPALIVE, KEEPALIVE, and then it is all UPDATEs.
-
+
Notes:
There is a fifth, ROUTE-REFRESH: "send me everything again, my policy changed".
@@ -51,41 +51,43 @@ One UPDATE carries one set of attributes, and every prefix that shares them.
-----
-## A real one: 94 bytes
+## A real one: 89 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
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
-`2a0d:d741:1::/48`, as the lab daemon sent it. The same view is on the lab page under *bytes*.
+`2a0d:d740::/48`, as AS210036 announces it to the SwissIX route servers.
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.
+Built with the lab daemon's own encoder and checked by parsing it back, with
+the attributes pr01 puts on routes it exports to peers. 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 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
-| ff × 16 | marker. Once carried authentication, now just filler to find message boundaries |
| 00 5e | length of the whole message: 94 bytes (maximum 4096) |
| 02 | type 2 = UPDATE |
+| ff × 16 | marker. Once carried authentication, now just filler to find message boundaries |
| 00 59 | length of the whole message: 89 bytes (maximum 4096) |
| 02 | type 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
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
-| 00 00 | 0 bytes of withdrawn routes: nothing is being taken back |
| 00 47 | 71 bytes of path attributes follow |
| 94 − 19 − 2 − 2 − 71 = 0 bytes left over for NLRI |
+| 00 00 | 0 bytes of withdrawn routes: nothing is being taken back |
| 00 42 | 66 bytes of path attributes follow |
| 89 − 19 − 2 − 2 − 66 = 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
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
| 40 | flags: well-known, transitive |
| 01 | type 1 = ORIGIN |
| 01 | 1 byte of value |
| 00 | IGP: the route was originated inside this AS |
@@ -97,37 +99,56 @@ 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
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
-| 40 02 06 | well-known, transitive; type 2; 6 bytes |
| 02 | an AS_SEQUENCE, order matters |
| 01 | of 1 AS number |
| fa 56 ea 01 | 4200000001, the lab daemon. Four bytes each (RFC 6793) |
+| 40 02 06 | well-known, transitive; type 2; 6 bytes |
| 02 | an AS_SEQUENCE, order matters |
| 01 | of 1 AS number |
| 00 03 34 74 | 210036, the origin. Four bytes each (RFC 6793) |
Each network prepends itself on the way out. The length of this list is what best-path selection compares.
+Notes:
+One entry, because SwissIX is one hop from the origin and the route server
+does not add itself. Seen from further away it reads e.g. 6939 210036.
+
+---
+
+## MULTI_EXIT_DISC
+
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
+
+| 80 04 04 | optional, non-transitive; type 4; 4 bytes |
| 00 00 00 00 | MED 0. Lower is preferred, among routes from the same neighbour AS |
+
+A hint to a neighbour about which of *your* entrances to use. Non-transitive: it goes one hop and no further.
+
+
+
---
## 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
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
-| 80 0e 1c | optional, non-transitive; type 14; 28 bytes |
| 00 02 · 01 | address family IPv6, unicast |
| 10 · 00…01 | next hop, 16 bytes: ::1 |
| 00 | reserved |
| 30 · 2a 0d d7 41 00 01 | 48 bits of prefix: 2a0d:d741:1::/48 |
+| 80 0e 1c | optional, non-transitive; type 14; 28 bytes |
| 00 02 · 01 | address family IPv6, unicast |
| 10 · 2001 07f8 0024 … 00c9 | next hop, 16 bytes: 2001:7f8:24::c9, our port on the SwissIX peering LAN |
| 00 | reserved |
| 30 · 2a 0d d7 40 00 00 | 48 bits of prefix: 2a0d:d740::/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.
+The next hop is an address on the exchange's shared LAN: whoever receives this
+route sends packets straight to that address across the switch. Remember ::c9
+for the exchange diagram in the next section.
+Routers may also append their link-local address here, making it 32 bytes.
---
## 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
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 59 02 00 00 00 42 40 01 01 00 40 02 06 02 01 00 03 34 74 80 04 04 00 00 00 00 80 0e 1c 00 02 01 10 20 01 07 f8 00 24 00 00 00 00 00 00 00 00 00 c9 00 30 2a 0d d7 40 00 00 c0 20 0c 00 03 34 74 00 00 00 0a 00 00 00 02
-| c0 20 18 | optional, transitive; type 32; 24 bytes = two communities |
| 00033474 · 0 · 0 | 210036:0:0 our router: announce nowhere… |
| 00033474 · 1 · 0000a5ec | 210036:1:42476 …except to AS42476, the SwissIX route servers |
+| c0 20 0c | optional, transitive; type 32; 12 bytes = one community |
| 00033474 · 0000000a · 00000002 | 210036:10:2, a tag our router puts on everything it exports to peers |
-Three 32-bit numbers. They mean whatever the receiving network says they mean.
+Three 32-bit numbers. They mean whatever the network named in the first one says they mean.
@@ -144,4 +165,4 @@ Three 32-bit numbers. They mean whatever the receiving network says they mean.
Transitive is why a community you set can act three networks away.
-
+
diff --git a/slides/sections/04-transit-and-ix.md b/slides/sections/04-transit-and-ix.md
index ea8ce0f..1500ce5 100644
--- a/slides/sections/04-transit-and-ix.md
+++ b/slides/sections/04-transit-and-ix.md
@@ -68,10 +68,10 @@ 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
+* 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
@@ -83,10 +83,10 @@ rules for what may appear on the peering LAN and quarantine ports that break the
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"
+* 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
diff --git a/slides/sections/05-lab.md b/slides/sections/05-lab.md
index 4ddc2e6..59a8430 100644
--- a/slides/sections/05-lab.md
+++ b/slides/sections/05-lab.md
@@ -36,9 +36,9 @@ the right of pr01 is the actual Internet.
`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
+* `` 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
@@ -48,11 +48,11 @@ 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
+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
@@ -60,29 +60,6 @@ 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 |
@@ -95,7 +72,7 @@ Two independent nets, because the web form has no idea who you are.
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
diff --git a/slides/style.css b/slides/style.css
index 7b0dacb..8a01d05 100644
--- a/slides/style.css
+++ b/slides/style.css
@@ -31,18 +31,6 @@
color: var(--ink-strong);
}
-/* A fragment that grows when it appears, for the one thing to look at. It
- grows by font size, not transform, so the text around it makes room. */
-.reveal .pop {
- transition: font-size 0.4s ease, color 0.4s ease;
-}
-
-.reveal .pop.visible {
- font-size: 1.5em;
- font-weight: 700;
- color: var(--accent);
-}
-
/* ---- layout ------------------------------------------------------------------ */
.container {