Networking: BGP for Small Networks — The Safe Minimal Setup

Was this helpful?

You don’t deploy BGP because it’s fun. You deploy it because your business finally outgrew “one ISP and a prayer,”
or because your SaaS customers started asking why your IPs move like a couch through a narrow stairwell every time the
provider blinks.

The harsh part: BGP isn’t hard in the “PhD math” way. It’s hard in the “one wrong default can melt a weekday” way.
The safe minimal setup is about refusing complexity until you’ve earned it.

What you actually need (and what you don’t)

Small networks don’t need “advanced BGP.” They need predictable BGP. If you’re multihoming with two upstreams,
your goal is: keep your own prefixes reachable, keep everyone else’s routes sane, and fail over without turning into
a route leak headline.

Here’s the safe minimal definition:

  • One ASN (your own, or a provider-assigned ASN if you truly can’t get one).
  • One or more provider sessions (eBGP), ideally on separate routers.
  • Announce only what you own (exact prefixes, correct origin AS).
  • Accept only what you intend (full table if you must, default-only if you can).
  • Hard filters on both inbound and outbound.
  • Limits (max-prefix, rate limits, and session guards).
  • Observability that shows session state, route counts, and actual traffic paths.
  • Documented rollback that works at 3 a.m.

What you do not need on day one:

  • Traffic engineering via ten layers of communities you don’t understand.
  • Exotic path hunting with AS-path prepends in five places “for redundancy.”
  • Graceful restart everywhere because someone said it’s “cleaner.”
  • Route reflectors and iBGP mesh gymnastics in a network that fits on one whiteboard.

A small network can run BGP like a seatbelt: simple, boring, and rarely noticed. That’s the point.

Short historical context and interesting facts

Some context helps because BGP behavior often looks “odd” until you remember what it was built for: policy, not
shortest-path perfection.

  1. BGP replaced EGP as the Internet moved from a tree-like topology to a messy mesh of autonomous systems.
  2. BGP is a path-vector protocol: it carries an AS path to avoid loops, not a full topology graph like link-state protocols.
  3. CIDR and BGP grew up together in the early 1990s to slow routing table explosion by enabling aggregation.
  4. The “default-free zone” became a thing when many core routers carried full routes with no default route at all.
  5. Route leaks keep happening because BGP’s trust model assumes peers behave, and humans frequently do not.
  6. Communities were added to let networks tag routes for policy without rewriting the base protocol every time.
  7. Multiprotocol BGP (MP-BGP) enabled VPNs (like L3VPN) and IPv6 at scale without inventing a totally new protocol.
  8. RPKI is comparatively new and still unevenly deployed, but it’s one of the first widely used mechanisms to reduce origin hijacks.

The punchline: BGP is old enough to vote, and some of its assumptions are older than your monitoring stack.

Threat model for small networks: what can go wrong

For small networks, “BGP security” isn’t about nation-state adversaries. It’s about everyday failure modes:
fat-finger, miscommunication, and vendor defaults that look harmless until they aren’t.

Failure mode: you announce what you don’t own

This is the classic. A typo in a prefix-list, an overly broad aggregate, or a “temporary test” that never got reverted.
Upstreams may filter, but you shouldn’t outsource your safety to their diligence.

Failure mode: you accept garbage and blackhole yourself

Taking a full table and installing it into a small router with insufficient memory is a reliable way to invent new
packet loss patterns. Taking default-only but forgetting to pin next-hops or local-pref can produce weird flaps.

Failure mode: route leak via transit policies

A route leak is when you accidentally provide transit between two networks that never agreed to it. Your network becomes
an unintended hallway. Traffic follows the hallway until it collapses.

Failure mode: control plane says “up” while the data plane is on fire

BGP sessions can be Established and happy while MTU, ACLs, or asymmetry quietly murder throughput.
BGP is a control plane protocol. It’s not a therapist.

One quote worth keeping in your head: “Hope is not a strategy.” — Gene Kranz.

Joke #1: BGP is the only place where “trust” is a configuration option, not a relationship status.

The safe minimal design: decisions you commit to

1) Pick your routing model: default-only or full table

If your network is small, you likely don’t need a full Internet table. Default-only (0.0.0.0/0 and ::/0) reduces
memory pressure and operational risk. Full table gives you finer control and sometimes better performance, but it also
gives you 900k+ ways to get hurt.

My opinionated rule:

  • If you have one edge router: default-only is usually correct.
  • If you have two edge routers and real traffic engineering needs: consider full table, but only with hardware that can take it.
  • If you’re doing DDoS scrubbing, complex multi-exit, or large CDN traffic: full table becomes more defensible.

2) Two routers if you can afford them

One router is a single point of failure. Two routers is a lot of paperwork. Still: if you can swing two modest boxes,
do it. Put them on separate power, separate uplinks, and preferably separate upstream handoffs.

3) Keep iBGP small and obvious

If you’re running two edge routers, you’ll likely run iBGP between them. Keep it simple:
one session each way, clear route policies, and a single IGP (or static) to carry next-hops.
You are not building a tier-1 backbone. Act accordingly.

4) Separate policy from plumbing

Your BGP daemon can be FRR, BIRD, Junos, IOS, EOS—it doesn’t matter as much as your discipline.
Create a policy structure you can audit:

  • Inbound filter: what you accept, what you reject, and what you tag.
  • Outbound filter: what you originate, what you export, and how you mark it.
  • Session guardrails: max-prefix, TTL security (where relevant), MD5/TCP-AO if supported, and sane timers.

5) Decide on your advertisement strategy: exacts first

Start with exact prefixes. Announce only the specific blocks you own and intend to originate. Aggregates can come later,
and only when you’re confident you won’t accidentally swallow address space you don’t control.

Filtering: your real firewall is policy

In BGP, filtering is the difference between “a network” and “an accident.”
You need outbound filters to prevent leaks and inbound filters to prevent nonsense from being installed.

Outbound filtering: only announce your prefixes

For a small network, the outbound policy is usually:

  • Permit your owned prefixes (and only those).
  • Set your own communities if you use them.
  • Reject everything else.

If you are a customer (not a transit provider), you should not export the full table you learned from ISP A to ISP B.
That’s the route leak archetype.

Inbound filtering: accept what you can handle

Your inbound policy depends on whether you take default-only or full routes:

  • Default-only: accept 0.0.0.0/0 and ::/0 from each upstream, plus maybe a small set of provider-specific routes if needed.
  • Full table: accept everything after dropping bogons, martians, too-long prefixes, and invalid RPKI origins.

Baseline bogon/martian ideas

At minimum, drop routes for RFC1918, carrier-grade NAT space, loopback, link-local, multicast, and other obvious non-global ranges.
You can also drop too-specific routes (e.g., IPv4 longer than /24 and IPv6 longer than /48) unless you explicitly need them.

Your upstream may already filter these. Great. Still filter them yourself. Redundancy is not just for power supplies.

RPKI: cheap safety, high ROI

RPKI validation checks whether the origin AS is authorized to announce a prefix (based on ROAs).
It does not solve every BGP security problem. It does reduce the blast radius of origin mistakes and some hijacks.

Minimal RPKI stance for small networks:

  • Run a validator (like Routinator) internally.
  • Configure your routers/daemons to do origin validation.
  • Reject RPKI-invalid routes on inbound from transits (or at least de-preference them heavily).
  • Publish ROAs for your own prefixes correctly (and keep them updated).

If you only do one “modernization” thing, do this one. It’s the closest thing BGP has to wearing a helmet.

Limits and timers: avoid surprise saturation

Limits aren’t about being cautious. They’re about ensuring failures fail fast, loudly, and in a contained way.

Max-prefix limits

If you take default-only, your max-prefix should be tiny (like 10–100, depending on your upstream’s extras).
If you take full routes, size it to your expected table plus headroom, but not infinite headroom.

Your decision is philosophical: do you want the session to drop when something weird happens (fail-closed),
or do you want to keep it up and hope your box survives (fail-open)? For small networks, fail-closed is usually kinder.

Keepalives and hold timers

Defaults are usually fine. Tuning timers to “fail over faster” often just makes you flap faster.
If you need sub-second convergence, you’re not in “safe minimal” territory anymore; you’re in “engineer the whole stack” land.

Graceful restart: useful, but easy to misuse

Graceful restart can hide control-plane restarts, but it can also preserve stale forwarding and make failure diagnosis weird.
If you enable it, test it. Then test it again with partial failures.

Joke #2: Graceful restart is like putting your router on “Do Not Disturb.” It’s calm until you realize it missed the fire alarm.

Data plane checks: don’t trust the control plane

BGP will happily exchange routes over a TCP session while your actual traffic dies due to MTU, ACLs, asymmetric routing,
or an upstream silently blackholing traffic during mitigation.

Minimal operational stance:

  • Always validate reachability of your own prefixes from outside (not just from inside).
  • Keep a known-good test host in a different network (a cheap VM elsewhere is fine).
  • Track packet loss and latency per uplink, not just “BGP Established.”

Practical tasks: commands, outputs, and decisions (12+)

These are real tasks you can run on a Linux-based router, a route server, or a troubleshooting box.
I’ll use FRR-style vtysh and common Linux tools because they’re broadly available.
The key is the workflow: command → interpret output → make a decision.

Task 1: Verify BGP sessions are Established (FRR)

cr0x@server:~$ vtysh -c "show ip bgp summary"
BGP router identifier 203.0.113.2, local AS number 64512
BGP table version is 128, main routing table version 128
Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
198.51.100.1    4      65001    9132    9050      128    0    0 2d03h        1
203.0.113.1     4      65002    8321    8204      128    0    0 2d03h        1

What it means: Both neighbors are up for ~2 days and each is sending 1 prefix (likely default-only).
Decision: If you expected full routes and you see “1”, your inbound policy is default-only (or broken).
If you expected default-only and you see “900000”, your filters are wrong or your upstream is giving you the full table.

Task 2: Check received routes from an upstream and confirm filtering

cr0x@server:~$ vtysh -c "show ip bgp neighbor 198.51.100.1 received-routes" | head
BGP table version is 128, local router ID is 203.0.113.2
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath
Origin codes: i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
*> 0.0.0.0/0        198.51.100.1             0    100      0 65001 i

What it means: You’re receiving only default. That’s consistent with default-only design.
Decision: If you see RFC1918 or other junk here, tighten inbound filters immediately.

Task 3: Confirm you only advertise your intended prefixes

cr0x@server:~$ vtysh -c "show ip bgp neighbor 198.51.100.1 advertised-routes"
BGP table version is 128, local router ID is 203.0.113.2

   Network          Next Hop            Metric LocPrf Weight Path
*> 203.0.113.0/24   0.0.0.0                  0         32768 i

What it means: You advertise only 203.0.113.0/24. Good.
Decision: If you see 0.0.0.0/0 or a full table here as a customer network, you’re leaking. Shut it down: disable export, then fix policy.

Task 4: Validate your router’s RIB vs BGP RIB (Linux)

cr0x@server:~$ ip route show default
default via 198.51.100.1 dev eth1 proto bgp metric 20

What it means: The kernel default route is installed via BGP on eth1.
Decision: If your preferred uplink should be ISP2 but this points at ISP1, adjust local-pref (preferred) or weight (vendor-specific).

Task 5: Check route counts at a glance (BIRD)

cr0x@server:~$ birdc show protocols all | sed -n '1,14p'
BIRD 2.0.12 ready.
Name       Proto      Table      State  Since         Info
up_isp1    BGP        master4    up     2026-02-04    Established
  BGP state:          Established
  Neighbor address:   198.51.100.1
  Neighbor AS:        65001
  Routes:             1 imported, 1 exported, 1 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:         2          0          0          0          2
    Export updates:         2          0          0          0          2

What it means: BIRD confirms your intended “default-only” shape.
Decision: If “rejected” spikes, your filter is catching something; figure out whether it’s correct filtering or accidental blocking.

Task 6: Check that your prefix is visible externally (from a remote probe)

cr0x@server:~$ whois -h whois.radb.net 203.0.113.0/24 | head
route:          203.0.113.0/24
origin:         AS64512
descr:          Example Network
mnt-by:         EXAMPLENET-MNT
changed:        noc@example.net 20250101
source:         RADB

What it means: There’s a route object (routing registry) indicating your intent to originate this prefix.
Decision: If your upstream uses IRR-based filtering and this is missing/wrong, your announcements may be filtered. Fix the registry object or upstream filter authorization.

Task 7: Verify ROA status for your prefix (Routinator)

cr0x@server:~$ routinator validate 203.0.113.0/24 | head
203.0.113.0/24 AS64512 valid (maxLength 24)

What it means: Your prefix has a valid ROA for your ASN.
Decision: If it’s “invalid” or “notfound,” fix ROAs. If your upstream drops invalids, you’ll disappear in a way that looks like “BGP is up but nobody can reach us.”

Task 8: Check RPKI validation state on the router (FRR example)

cr0x@server:~$ vtysh -c "show bgp rpki summary"
RPKI cache servers:
1) 127.0.0.1:3323  pref 1  state Established  uptime 2d03h  serial 12981
Prefix records: 214532

What it means: Your router is talking to the local validator, and it has RPKI data.
Decision: If state isn’t Established, your “reject invalids” policy may silently stop working. Fix RTR connectivity first.

Task 9: Confirm you’re not melting your router (memory/CPU quick check)

cr0x@server:~$ top -b -n1 | head -n 8
top - 10:12:54 up 32 days,  4:19,  1 user,  load average: 0.22, 0.18, 0.15
Tasks: 134 total,   1 running, 133 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.4 us,  0.5 sy,  0.0 ni, 97.8 id,  0.2 wa,  0.0 hi,  0.1 si,  0.0 st
MiB Mem :   7984.2 total,   4231.7 free,    912.4 used,   2840.1 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   6589.4 avail Mem

What it means: Plenty of headroom. Good for full routes? Maybe. Good for default-only? Definitely.
Decision: If you’re swapping or CPU is pinned during updates, reduce route intake (default-only), increase hardware, or move BGP to a control-plane box with a clean FIB programming approach.

Task 10: Check for packet loss on the uplink interface

cr0x@server:~$ ip -s link show dev eth1
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:11:22:33 brd ff:ff:ff:ff:ff:ff
    RX:  bytes  packets  errors  dropped  missed  mcast
    9876543210  9123456  0       12       0       0
    TX:  bytes  packets  errors  dropped  carrier collsns
    1234567890  7345678  0       0        0       0

What it means: Some RX drops exist. Could be policing, buffer pressure, or driver issues.
Decision: If drops climb during peak, you likely have congestion or shaping mismatch. Don’t “fix” this with BGP. Fix it with capacity, QoS, or interface tuning.

Task 11: Validate MTU with do-not-fragment ping

cr0x@server:~$ ping -M do -s 1472 -c 3 198.51.100.1
PING 198.51.100.1 (198.51.100.1) 1472(1500) bytes of data.
1472 bytes from 198.51.100.1: icmp_seq=1 ttl=64 time=0.61 ms
1472 bytes from 198.51.100.1: icmp_seq=2 ttl=64 time=0.58 ms
1472 bytes from 198.51.100.1: icmp_seq=3 ttl=64 time=0.60 ms

--- 198.51.100.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms

What it means: Path MTU looks fine for 1500-byte Ethernet.
Decision: If this fails and smaller sizes succeed, you have an MTU blackhole risk. Fix MTU/MSS clamping before blaming BGP for “random” slowness.

Task 12: Check actual egress path selection with traceroute

cr0x@server:~$ traceroute -n -w 1 -q 1 1.1.1.1 | head
traceroute to 1.1.1.1 (1.1.1.1), 30 hops max, 60 byte packets
 1  198.51.100.1  0.530 ms
 2  198.51.100.254  1.212 ms
 3  203.0.113.254  2.891 ms

What it means: You’re exiting via ISP1.
Decision: If you intended ISP2 as primary, change local-pref/weight or default-route preference. Don’t just prepend and hope; control inbound/outbound separately.

Task 13: Confirm kernel sees the expected BGP-learned routes (size sanity)

cr0x@server:~$ ip route | grep -c "proto bgp"
1

What it means: You installed exactly one BGP route (likely default). That’s your stated intent in default-only mode.
Decision: If this count explodes unexpectedly, your daemon may be installing full routes. Confirm policies and whether you should be using a separate VRF/table.

Task 14: Spot a route leak pattern by checking AS-path on unexpected routes

cr0x@server:~$ vtysh -c "show ip bgp 8.8.8.0/24"
BGP routing table entry for 8.8.8.0/24
Paths: (1 available, best #1, table default)
  65001 15169
    198.51.100.1 from 198.51.100.1 (198.51.100.1)
      Origin IGP, localpref 100, valid, external, best

What it means: You learned this route from ISP1. Normal if you take full routes.
Decision: If you’re default-only but you see specifics like this installed, your inbound filter is not doing what you think it’s doing.

Task 15: Check BGP flap history to detect intermittent transport issues

cr0x@server:~$ vtysh -c "show ip bgp neighbor 198.51.100.1"
BGP neighbor is 198.51.100.1, remote AS 65001, local AS 64512, external link
  BGP version 4, remote router ID 198.51.100.1
  BGP state = Established, up for 2d03h
  Last read 00:00:19, Last write 00:00:21
  Connections established 3; dropped 2
  Last reset 1d01h, due to Hold Timer Expired

What it means: The session has dropped twice, last due to hold timer expiration. That’s often transport loss or CPU starvation.
Decision: If hold expirations correlate with congestion or DDoS, raise transport reliability first (QoS, policing coordination, control-plane protection).

Three corporate mini-stories from the trenches

Mini-story 1: The incident caused by a wrong assumption

A mid-sized SaaS company multihomed for the first time. Two upstreams, one router, FRR. They had a change window,
a runbook, and a Slack channel named something confident like #bgp-cutover.

The wrong assumption: “Our upstream will filter anything we shouldn’t announce.” The engineer wrote an outbound policy
that was meant to advertise only their /24, but they also redistributed connected routes. A management subnet happened
to be public space from a prior acquisition and was still on an interface. It got announced.

Nothing looked broken internally. BGP was Established. Their own service IPs stayed up. The only sign was an odd bump
in inbound traffic on the management interface and a few monitoring alerts about elevated CPU.

Then the upstream noticed. The upstream shut down the BGP session—hard. Outbound connectivity failed over to the second ISP,
but inbound traffic didn’t recover cleanly. Some clients still hit the withdrawn path for minutes, because caching and propagation
are not obligated to match your maintenance window.

The fix was simple and humiliating: explicit outbound prefix-lists, no redistribution into eBGP, and a pre-change check that
prints the advertised routes and requires a human to sign off. The postmortem’s best line was: “We outsourced correctness to someone
with different incentives.”

Mini-story 2: The optimization that backfired

A retail company wanted “faster failover.” They read about BFD and aggressive timers. Their edge was two routers, each with two sessions.
The team enabled shorter BGP keepalives and hold timers, and they also turned on BFD across the board.

For a week, it looked great. A link failure failed over quickly. Everyone felt clever. Then a benign upstream maintenance event
introduced intermittent microbursts of packet loss on one circuit. Not enough to harm TCP flows much. More than enough to annoy BFD.

The result was a failure mode that’s hard to explain to non-networkers: the sessions flapped repeatedly, routes churned,
CPU climbed, and packet loss got worse because the control plane was chewing on reconvergence work. The “optimization” created
self-inflicted instability. The network was fast to fail, slow to heal.

They rolled back to more conservative timers and enabled BFD only where the transport was clean and well understood. The enduring lesson:
convergence is a system property. If you squeeze one part too hard, something else bulges.

Mini-story 3: The boring but correct practice that saved the day

A small hosting provider ran a minimal BGP setup for years: strict prefix-lists, max-prefix limits, RPKI validation, and a nightly job
that diffed “advertised routes per neighbor” against an expected file. It wasn’t glamorous. It was also the reason they slept.

One afternoon, they received a call from an upstream: “We’re seeing an unusual number of prefixes from your session.” Internally,
their monitoring had already paged. The diff job detected that their router was about to export more than the expected two prefixes.
Max-prefix on export isn’t universal, but their policy was strict: deny all except an explicit list.

The root cause was a config management mistake: a template variable expansion produced a broader prefix-list on one router only.
The strict “deny all else” policy prevented exporting anything unexpected, so the blast radius was limited to “we didn’t announce one
of our intended prefixes for a few minutes” instead of “we leaked the table.”

They corrected the template, re-deployed, and closed the incident with barely any customer impact. The saving grace wasn’t genius.
It was boredom: explicit allowlists, diffable expectations, and refusing to rely on upstream mercy.

Fast diagnosis playbook

When something’s wrong, your job is to find the bottleneck quickly, not to admire the wreckage. Here’s the order that
tends to produce answers fast.

First: is it control plane, data plane, or policy?

  • Control plane check: Are sessions Established? Are prefixes received/sent in expected counts?
  • Data plane check: Can you ping/traceroute out? Can others reach your prefixes? Any drops/errors?
  • Policy check: Did local-pref/weight change? Any new filters, RPKI changes, or max-prefix trips?

Second: validate your own announcements

  • On the router: verify advertised routes per neighbor match your allowlist.
  • Externally: verify ROAs are valid and registries align with what upstream expects.
  • Check that origin AS is correct and stable.

Third: verify inbound routing symmetry and next-hops

  • Are you receiving a default from both? Is the preferred one winning?
  • Is return traffic coming back via the same ISP you expect? If not, do you have stateful firewalls that will hate it?
  • Is your IGP/static routing consistent with BGP next-hops?

Fourth: look for resource exhaustion and churn

  • CPU spikes during route updates can cause hold timer expirations.
  • Memory pressure can cause route processing delays and weird FIB programming lag.
  • Logs: session resets, prefix-limit events, RPKI cache disconnects.

Fifth: isolate by forcing a clean failover (carefully)

If you have two upstreams, temporarily shut one BGP session (or set local-pref) and observe. If the problem disappears,
the issue is likely upstream-specific or policy-specific. If it persists, it’s probably your edge or downstream network.

Common mistakes: symptom → root cause → fix

1) Symptom: Internet “works” but some sites time out

Root cause: MTU blackhole or broken PMTUD, often across tunnels or provider handoffs.

Fix: Validate MTU with DF pings; implement MSS clamping on edge for TCP; align MTU across handoffs.

2) Symptom: BGP Established, but nobody can reach your IPs

Root cause: You’re not actually advertising your prefix (policy mistake), or upstream filters it (IRR/RPKI mismatch).

Fix: Check advertised-routes; confirm origin AS; validate ROAs; ensure registry objects match upstream filtering requirements.

3) Symptom: Router CPU spikes and sessions flap during peak

Root cause: Control-plane overload from full table updates, too-aggressive timers, or route churn.

Fix: Increase timers to sane defaults; reduce routes (default-only); ensure control-plane protection; consider separate routing hardware.

4) Symptom: Suddenly receiving way more routes than usual

Root cause: Upstream leaked full routes to your default-only session, or your inbound filter changed.

Fix: Enforce inbound filters; set strict max-prefix; coordinate with upstream; consider rejecting anything except default if that’s your design.

5) Symptom: Your upstream threatens disconnection for “leaking routes”

Root cause: You exported learned routes to another neighbor, or redistributed IGP/connected into eBGP.

Fix: Remove redistribution into eBGP; implement explicit outbound allowlist; validate advertised routes before enabling sessions.

6) Symptom: Failover works outbound, but inbound traffic sticks to the dead ISP

Root cause: Inbound traffic depends on remote networks’ path selection; your announcement changes are not immediate or preferred.

Fix: Use appropriate communities with providers; ensure both upstreams see your announcements; consider more-specific advertisements for controlled failover (carefully).

7) Symptom: RPKI “broke the Internet” after enabling it

Root cause: You rejected invalids but your own ROAs were wrong, or validator connectivity failed and policy defaulted unexpectedly.

Fix: Validate your own prefixes first; ensure router has stable RTR connection; implement staged policy (prefer valid, de-prefer unknown, reject invalid) if you must.

8) Symptom: Asymmetric routing breaks stateful firewall sessions

Root cause: Different uplinks for inbound vs outbound, plus a firewall expecting symmetry.

Fix: Either design for symmetry (policy/local-pref) or deploy state synchronization / routing-aware firewalling; avoid “random” ECMP across stateful devices.

Checklists / step-by-step plan

Phase 0: Before you touch BGP

  • Get address space and ASN sorted: who owns what, who originates what.
  • Decide default-only vs full table; size hardware accordingly.
  • Build an out-of-band management path that doesn’t depend on the new BGP design.
  • Write an allowlist of prefixes you will announce (exact prefixes, correct mask lengths).
  • Decide your max-prefix values per neighbor and document them.

Phase 1: Bring up sessions safely (one at a time)

  1. Configure neighbor with outbound deny-all temporarily.
  2. Establish BGP session and confirm it stays Established for at least 15–30 minutes.
  3. Enable inbound policy (default-only or full table) and confirm received prefix count matches expectation.
  4. Enable outbound allowlist and confirm advertised prefix list matches your expected file.
  5. Validate external reachability for your prefixes from a remote probe.

Phase 2: Add guardrails

  • Set max-prefix and define behavior on exceed (warn vs shutdown; I prefer shutdown for small networks).
  • Enable RPKI validation and choose policy (reject invalid is common; be deliberate about “notfound”).
  • Drop bogons/martians inbound; prevent too-specific routes unless required.
  • Ensure no redistribution of connected/IGP into eBGP unless explicitly intended and filtered.

Phase 3: Redundancy and controlled failover

  • Bring up second upstream with the same discipline: deny-all then allowlist.
  • Decide outbound preference (local-pref/weight) and test failover by shutting one session.
  • For inbound preference, use provider-supported communities or controlled more-specific announcements.
  • Test during a low-risk window; measure convergence and application impact.

Phase 4: Operate it like production

  • Monitor: session state, prefix counts, updates rate, CPU/memory, interface drops/errors.
  • Alert on: session down, prefix count deviation, RPKI validator disconnect, max-prefix events.
  • Change control: peer policy changes require a diff and a second pair of eyes.
  • Keep a rollback plan: disable export, drop sessions, revert config, verify reachability.

FAQ

Do I need BGP if I’m single-homed?

Usually no. If you have one ISP and no portable address space, BGP is mostly extra failure modes.
Use static/default routing and focus on redundancy elsewhere.

Default-only vs full table: what should I pick?

Default-only if you’re small and want stability. Full table if you have strong reasons: traffic engineering needs,
multiple exits with meaningful policy, or you’re operating at a scale where default-only causes real suboptimal routing.

Can I safely multihome with one router?

You can, but you’re buying partial redundancy. The router is still a single point of failure. If you do it, keep the design minimal,
and make sure you can remote in via an out-of-band path when you lock yourself out.

Should I use BFD to speed up failover?

Only if your transport is clean and you’ve tested it under real loss conditions. Aggressive detection can cause flapping,
and flapping can be worse than a slightly slower failover.

What are BGP communities and do I need them?

Communities are tags you attach to routes to request upstream behavior (like prepending, blackholing, or local-pref changes).
You don’t need them for the safe minimal setup, but they’re the cleanest way to influence inbound traffic once you understand the provider’s semantics.

Is RPKI mandatory?

Not mandatory, but it’s one of the best safety upgrades per hour of effort. Start by validating and monitoring; then move to rejecting invalids
once you’re confident your own ROAs are correct.

What’s the simplest way to prevent a route leak?

Outbound allowlists. Permit only your prefixes. Reject everything else. Do not redistribute connected or IGP routes into eBGP unless filtered down to that same allowlist.

Why does inbound failover sometimes take minutes?

Because inbound traffic depends on what the rest of the Internet believes. Withdrawal propagation, dampening, and remote caching all exist.
You can influence it with communities, more-specific advertisements, and good upstream choices, but you can’t force instant global convergence.

How do I know if the problem is my edge or my upstream?

Compare control plane vs data plane. If sessions are stable and your advertised routes are correct, but packet loss or latency spikes,
check interface stats, MTU, and upstream path quality. If you can fail over to a second upstream and the issue disappears, it’s likely upstream-specific.

Should I run iBGP between two edge routers?

If both originate the same prefixes and you want coordinated exit selection, yes—keep it minimal and explicit.
If your network is tiny and you can operate with independent defaults, you can avoid iBGP, but understand the trade-offs.

Conclusion: next steps that won’t hurt you

The safe minimal BGP setup is not about cleverness. It’s about restraint: explicit allowlists, strict inbound filters, sane limits,
and enough observability to catch mistakes before your upstream does.

Practical next steps:

  1. Write down your intended advertisements (exact prefixes) and treat that list like production code.
  2. Decide default-only vs full table and size your router accordingly—hardware constraints are policy constraints.
  3. Implement outbound allowlists and inbound filters (bogons, max-lengths, and max-prefix).
  4. Enable RPKI validation, validate your own ROAs, and pick a deliberate invalid/notfound policy.
  5. Build the fast diagnosis loop into your monitoring: session state, prefix counts, interface drops, and external reachability.

If you want to do traffic engineering after that, fine. Earn it. First make sure your network can’t accidentally become a transit provider
on a Tuesday.

← Previous
Pop!_OS 24.04 LTS Install: NVIDIA Drivers, Secure Boot, and a Clean Desktop
Next →
Fix Windows with PowerShell: Run SFC/DISM the Right Way

Leave a comment