← All posts
Deep Dive

BGP Fault-Finding with Python: Turning show bgp Into Answers

A practical pattern for catching the one peer that quietly fell out of ESTABLISHED.

NAPT Team12 min read
BGP finite state machineIDLECONNECTACTIVEOPENSENTESTAB.A peer stuck below ESTABLISHED is the signal a fault-finder script hunts for.
The BGP finite state machine — a healthy peer reaches ESTABLISHED and stays there.

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.

python
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.

python
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}
Info: A short uptime is not proof of a fault on its own — a planned change resets the timer too. Pair it with flap history or a second poll a minute later to confirm churn.

Make the output impossible to miss

Color-code by severity so the broken row jumps out of a wall of green.

python
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.

#bgp#diagnostics#python

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 →
New to NAPT? Start with the Setup Guide

Related posts