As presented. The palette is light on request of the reviewer; code blocks and byte dumps keep a dark ground so the byte colours still work. The OPEN walk lights the hovered bytes as an inverted block and its table cells are dark text on a tint of their group colour. build.py inlines reveal.js, the stylesheets, scripts and Markdown sections into slides/dist/hands-on-bgp.html for uploading. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
24 KiB
BGP in detail
Notes: We're going to look at some implementation details of the protocol
- Runs over TCP, port
179, and is exchanged typically between peering routers - Each side tells the other its best route per prefix
- Only changes are sent: no periodic refresh
- If the session drops, after a timeout the routes learned over that session are dropped
Notes: BGP is a very old protocol, and a lot of it's design predates the internet being something with adversarial participants. Security and extensions have had to be bolted on, in perhaps strange ways.
The four message types
| Type | Name | Says |
|---|---|---|
| 1 | OPEN | AS number, router ID, capabilities |
| 2 | UPDATE | these prefixes are reachable, those no longer are |
| 3 | NOTIFICATION | errors and informational messages: e.g. rebooting |
| 4 | KEEPALIVE | Heartbeat to keep the session up when there's no update |
OPEN, OPEN, KEEPALIVE, KEEPALIVE, and then a stream of UPDATEs.
Notes: There is actually a fifth type, ROUTE-REFRESH: "send me everything again, my policy changed".
OPEN: a handshake between peers.
Notes: Sent once, by each side, as soon as the TCP connection is up. The two sides must agree: the AS must be the one configured for the neighbour, the hold time becomes the smaller of the two, and only capabilities both announced are used. A 4-byte AS does not fit in "my AS", so that field carries 23456 and the real number rides in a capability, which is how our AS210036 arrives.
BGP Open message
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 37 01 04 5b a0 00 f0 0a ff 00 01 1a 02 18 01 04 00 02 00 01 02 00 06 00 40 02 00 00 41 04 00 03 34 74 46 00 47 00
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ffmarkersixteen bytes of ff.00 37length0x0037 = 55 bytes, header included. At most 4096, or 65535 with the extended-message capability01type1 = OPEN (2 UPDATE, 3 NOTIFICATION, 4 KEEPALIVE, 5 ROUTE-REFRESH)04versionBGP version 45b a0my AS0x5ba0 = 23456, AS_TRANS: the ASN is longer than 16 bits so is encoded in a capability instead00 f0hold time0x00f0 = 240 seconds. both peers use the minimum announced; a KEEPALIVE typically is sent every 1/3rd of this duration0a ff 00 01BGP identifier0a ff 00 01 = 10.255.0.1, the router ID. Looks like an IPv4 address, just needs to be a unique identifier.1aoptional parameters length0x1a = 26 bytes follow02parameter type2 = capabilities18parameter length0x18 = 24 bytes of capabilities follow, each as type, length, value01code1 = multiprotocol extensions04length400 02AFI0x0002 = IPv6. Address Family Identifier00reserved001SAFI1 = unicast. Subsequent Address Family Identifier.02code2 = route refresh: “you may ask me to resend everything”00length006code6 = messages up to 65535 bytes are supported00length040code0x40 = 64, graceful restart02length200 00flags and restart time0x0000: not restarting, restart time 0, and no address families listed.41code0x41 = 65, four-octet AS number04length400 03 34 74AS number00 03 34 74 = 210036: the real AS. Included here since it doesn't fit in the header46code0x46 = 7000length047code0x47 = 7100length0, no address families listedNotes: What BIRD on our upstream router sends the lab daemon, byte for byte. Hold time 240 is BIRD's default; keepalives go every third of it.
Update message format
Notes: One UPDATE carries one set of attributes, and every prefix that shares them. The withdrawn and NLRI fields can only hold IPv4; the next slides show where IPv6 goes. Lengths everywhere: a receiver can walk the message without understanding any of it, which is what lets unknown attributes pass through.
An example BGP update
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:d740::/48, as AS210036 announces it to the SwissIX route servers.
Notes: 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 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 | Start of message marker. |
| 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 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 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 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 |
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 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 |
| 00 03 34 74 | 210036, the origin. Four bytes each (RFC 6793) |
Every BGP router prepends its own AS number before announcing a route to an external peer, creating a map of which networks the announcement travelled through. This allows selecting the shortest path.
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 path you prefer traffic to come in on. Non-transitive: it goes one hop and no further.
MP_REACH_NLRI: announcing paths for non-IPv4 protocols
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 · 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 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 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 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 network named in the first one 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 |
Path attribute transitivity allows adding instructions for networks far away from direct neighbours.