BGP Fault-Finding with Python: Turning show bgp Into Answers
A practical pattern for catching the one peer that quietly fell out of ESTABLISHED.
BGP rarely fails loudly. One peer drops, the table reconverges, and the only evidence is a session that has been up for forty seconds instead of forty days. The goal of a fault-finder is to surface that one row before a customer does.
Read the state machine first
Every neighbor walks the same path: IDLE → CONNECT → ACTIVE → OPENSENT → OPENCONFIRM → ESTABLISHED. Anything short of ESTABLISHED is a fault. A peer flapping between ACTIVE and IDLE almost always means a reachability or authentication problem, not a policy one.
Parse neighbor state, do not eyeball it
Use a structured getter where you can. NAPALM's get_bgp_neighbors() returns a dict you can assert against directly.
from napalm import get_network_driver
driver = get_network_driver("ios")
with driver("10.0.0.11", "readonly", "••••") as dev:
peers = dev.get_bgp_neighbors()["global"]["peers"]
down = {ip: p for ip, p in peers.items() if not p["is_up"]}
for ip, p in down.items():
print(f"DOWN {ip} AS{p['remote_as']} prefixes={p['address_family']}")Detect flaps from uptime
A peer that is "up" but only for seconds is mid-flap. Convert the uptime string to seconds and threshold it.
def parse_uptime_to_seconds(s: str) -> int:
# handles "1w2d", "00:04:11", "2d03h"
import re
units = {"w": 604800, "d": 86400, "h": 3600, "m": 60, "s": 1}
if ":" in s:
h, m, sec = (int(x) for x in s.split(":"))
return h * 3600 + m * 60 + sec
total = 0
for value, unit in re.findall(r"(\d+)([wdhms])", s):
total += int(value) * units[unit]
return total
FLAP_THRESHOLD = 300 # 5 minutes
flapping = {ip: p for ip, p in peers.items()
if p["is_up"] and parse_uptime_to_seconds(p["uptime"]) < FLAP_THRESHOLD}Make the output impossible to miss
Color-code by severity so the broken row jumps out of a wall of green.
R, G, Y, X = "\033[31m", "\033[32m", "\033[33m", "\033[0m"
for ip, p in peers.items():
if not p["is_up"]:
print(f"{R}✗ {ip} DOWN{X}")
elif parse_uptime_to_seconds(p["uptime"]) < FLAP_THRESHOLD:
print(f"{Y}⚠ {ip} flapping ({p['uptime']}){X}")
else:
print(f"{G}✓ {ip} stable{X}")Scale it across a fabric
On a route-reflector design, run the check from the route reflector outward — it sees every client session in one place. NAPT emits one finding per down or flapping peer with a stable correlation key like bgp/peer-down/10.0.0.1, which the RCA engine can then stitch into a causal chain.
Was this helpful?
Generate scripts for the task covered in this post
Describe what you need and NAPT writes production-ready automation in Netmiko, NAPALM, or Nornir.
Open Script Generator →Related posts
From Noise to Narrative: How the RCA Engine Builds a Causal Story From Your Findings
The Root Cause Analysis engine reads every finding your scripts produce and stitches them into a single causal chain — root, contributing, symptom.
Read →The Streaming Console: A Live Terminal That Remembers Everything
Run any diagnostic script against any device, watch output stream in real time, and end up with structured findings the platform can reason about.
Read →Intent: Saying What You Mean and Proving the Network Agrees
Write a one-line statement of how the network should behave. The Intent engine compiles it into checks and tells you where reality diverges.
Read →