19 KiB
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, 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 | 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 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.
An OPEN message example
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
| 04 · 5b a0 · 00 f0 · 0a ff 00 01 · 1a | version 4; AS 23456 (AS_TRANS, see below); hold time 240 s; router ID 10.255.0.1; 26 bytes of parameters |
| 02 18 | parameter type 2, capabilities, 24 bytes |
| 01 04 00 02 00 01 | multiprotocol: AFI 2 (IPv6), SAFI 1 (unicast). Without this, no IPv6 routes |
| 41 04 00 03 34 74 | 4-byte AS: the real number, 210036 |
| 02 00 · 06 00 · 40 02 00 00 · 46 00 · 47 00 | route refresh, extended message, graceful restart, enhanced refresh, long-lived GR |
Notes: 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.
The shape of an UPDATE
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.
A real one: 89 bytes
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.