BGP Basics
BGP Basics
BGP is the inter-domain workhorse and also appears inside modern DC fabrics. This chapter stays vendor-agnostic and free-image-only: eBGP and iBGP ideas, sessions, advertisements, and path selection at a practitioner level—implemented with FRR.
Learning goals
By the end of this chapter you can:
- Explain ASNs, eBGP vs iBGP roles
- Bring up a BGP session on FRR to Established
- Advertise a prefix and see it on the peer
- Apply the path selection process at a high level
- Break a session and observe withdrawal
Concepts
Autonomous systems
An AS is a policy domain with an ASN. Labs use private ASNs:
| Range | Notes |
|---|---|
| 64512–65534 | 16-bit private |
| 4200000000+ | 32-bit private space (use docs for exact ranges) |
Example: AS65001 and AS65002 as “two sites” or “customer and ISP.”
eBGP vs iBGP
| eBGP | iBGP | |
|---|---|---|
| Between | Different ASNs | Same ASN |
| Typical TTL | 1 (direct) | multi-hop ok with care |
| Default next-hop | Peer address | Needs next-hop-self often for reachability |
| Scale | Edge policy | Route reflection / confed for large iBGP |
Session state
Idle → Connect → Active → OpenSent → OpenConfirm → Established
Only Established exchanges routes.
Path selection overview
BGP is policy-heavy. Simplified order of preference ideas:
- Prefer higher local preference (inbound influence)
- Prefer shorter AS path
- Origin, MED, eBGP over iBGP, IGP metric to next hop, router-id, etc.
You will not memorize every tie-breaker today—know that policy beats pure shortest path.
NLRI and attributes
Routes carry attributes (AS_PATH, NEXT_HOP, LOCAL_PREF, MED, communities…). Filters rewrite attributes; that is policy.
Lab A: two AS eBGP
h1--r1 (AS65001) -------- r2 (AS65002)--h2
10.0.0.1/30 10.0.0.2/30
Advertise LANs (or loopbacks) across eBGP.
Topology
name: bgp-ebgp
topology:
nodes:
r1:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/r1:/etc/frr
r2:
kind: linux
image: quay.io/frrouting/frr:10.2.1
binds:
- ./config/r2:/etc/frr
h1:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils
- ip addr add 192.168.1.10/24 dev eth1 && ip link set eth1 up
- ip route add default via 192.168.1.1
h2:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils
- ip addr add 192.168.2.10/24 dev eth1 && ip link set eth1 up
- ip route add default via 192.168.2.1
links:
- endpoints: ["r1:eth1", "r2:eth1"]
- endpoints: ["h1:eth1", "r1:eth2"]
- endpoints: ["h2:eth1", "r2:eth2"]daemons
zebra=yes
bgpd=yes
r1 frr.conf
frr version 10.2.1
frr defaults traditional
hostname r1
!
interface eth1
ip address 10.0.0.1/30
!
interface eth2
ip address 192.168.1.1/24
!
interface lo
ip address 1.1.1.1/32
!
router bgp 65001
bgp router-id 1.1.1.1
no bgp ebgp-requires-policy
neighbor 10.0.0.2 remote-as 65002
!
address-family ipv4 unicast
network 192.168.1.0/24
network 1.1.1.1/32
neighbor 10.0.0.2 activate
exit-address-family
!
line vty
no bgp ebgp-requires-policyeases labs on modern FRR that otherwise require explicit export policy. In real life, prefer explicit policies (next chapter).
r2
ASN 65002, IP 10.0.0.2/30, LAN 192.168.2.0/24, networks advertised symmetrically, neighbor 10.0.0.1 remote-as 65001.
Verify session
sudo containerlab deploy -t bgp-ebgp.clab.yml
docker exec clab-bgp-ebgp-r1 vtysh -c 'show bgp summary'
docker exec clab-bgp-ebgp-r1 vtysh -c 'show bgp ipv4 unicast'
docker exec clab-bgp-ebgp-r1 vtysh -c 'show ip route'
docker exec clab-bgp-ebgp-h1 ping -c 3 192.168.2.10Predict
show bgp summarystate Established, prefixes received > 0
- Kernel has remote LAN via BGP next hop 10.0.0.2
- Ping works both ways
Lab B: iBGP sketch (optional same day)
Two routers same ASN, loopbacks as session endpoints, IGP or statics for loopback reachability first.
router bgp 65001
neighbor 2.2.2.2 remote-as 65001
neighbor 2.2.2.2 update-source lo
neighbor 2.2.2.2 next-hop-self
Rule: iBGP needs underlying reachability to the session address. OSPF underlay + iBGP overlay is a common pattern (underlay vs overlay planes!).
Session failure drill
docker exec clab-bgp-ebgp-r1 ip link set eth1 down
docker exec clab-bgp-ebgp-r1 vtysh -c 'show bgp summary'
docker exec clab-bgp-ebgp-r2 vtysh -c 'show bgp summary'
docker exec clab-bgp-ebgp-r2 vtysh -c 'show ip route 192.168.1.0'
# routes withdraw after hold timers — observe timing
docker exec clab-bgp-ebgp-r1 ip link set eth1 upPredict: session drops; prefixes withdrawn; ping fails until re-established.
Optional: neighbor x shutdown in vtysh for cleaner control-plane inject.
Next-hop reachability drill
Install BGP route whose next hop is unreachable (misconfigured).
Symptom: BGP table shows path but not installed in FIB / not usable.
vtysh -c 'show bgp ipv4 unicast'
vtysh -c 'show ip route'Compare “known in BGP” vs “installed.”
verify.sh
#!/usr/bin/env bash
set -euo pipefail
fail() { echo "FAIL: $*" >&2; exit 1; }
docker exec clab-bgp-ebgp-r1 vtysh -c 'show bgp summary' | grep -q Established \
|| fail "session not Established"
docker exec clab-bgp-ebgp-h1 ping -c 2 -W 1 192.168.2.10 || fail "ping"
docker exec clab-bgp-ebgp-h2 ping -c 2 -W 1 192.168.1.10 || fail "reverse ping"
echo OKSafety habits
- Do not experiment with BGP on real Internet edges without change control
- Private ASNs in labs only unless you know what you are doing
- Explicit export policy in anything beyond throwaway labs
- Cap lab prefixes; never leak real full tables into tiny FRR VMs by accident
Common mistakes
| Mistake | Result |
|---|---|
| wrong remote-as | session fails |
| no underlay to iBGP peer | idle/active |
| missing activate / AF | Established but no routes |
| ebgp-requires-policy deny | no prefixes without route-maps |
| next hop unreachable | BGP path not used |
Summary
- BGP sessions must be Established before routes flow
- eBGP links ASNs; iBGP needs underlay reachability
- Path selection is policy-centric, not pure SPF
- FRR lab: advertise LANs, ping through, shut session
- Prefer explicit policies as you leave pure lab mode
Next: policy and filters—prefix lists, route-maps-as-idea, and preventing loops/leaks.