tutorial

How to Monitor Bird Internet Routing Daemon with Vigilmon

Bird Internet Routing Daemon (BIRD) is one of the most widely deployed open-source routing daemons, powering BGP sessions on bare-metal networks, Kubernetes ...

Bird Internet Routing Daemon (BIRD) is one of the most widely deployed open-source routing daemons, powering BGP sessions on bare-metal networks, Kubernetes CNI plugins, and IXP route servers worldwide. When a BGP session drops or a route disappears, Bird usually silently recovers or fails-safe — leaving operators unaware until traffic takes the wrong path or stops flowing entirely.

This tutorial shows you how to build complete observability for Bird deployments using Vigilmon: monitoring BGP session state, protocol health, and the Bird daemon process itself.


Why Bird needs external monitoring

Bird's self-healing mechanisms are also its blind spots:

  • BGP session flaps — a session can drop and re-establish dozens of times before Bird gives up. Each flap re-converges the routing table, causing micro-outages that are invisible unless you're watching.
  • Stuck sessions — a BGP peer can remain in Active state indefinitely, waiting for a TCP connection that never arrives, while Bird logs nothing actionable.
  • Route leaks and missing prefixes — a peer might be Established while advertising zero routes, or more routes than expected, due to a filter misconfiguration. Session state alone doesn't tell you.
  • Protocol-level failures — OSPF or static protocol failures may not affect BGP uptime but still silently break reachability for specific subnets.
  • Process failurebird and bird6 are separate daemons. Either can crash independently.

Monitoring Bird means watching protocol state, route counts, and process health — not just whether the binary is running.


What you'll need

  • A running Bird installation (Bird 1.x or Bird 2.x)
  • The birdc command-line socket control tool (bundled with Bird)
  • A free Vigilmon account

Step 1: Check Bird protocol and BGP session state

Bird's control socket (birdc) gives you real-time protocol status. Build a probe that checks all BGP sessions are Established:

#!/bin/bash
# bird-bgp-probe.sh

HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_HEARTBEAT_ID"
LOG="/var/log/bird-probe.log"

# For Bird 2: use 'birdc'; for Bird 1: may be 'birdc' or 'birdc6'
BIRDC="birdc"

# Check Bird daemon is running
if ! systemctl is-active --quiet bird; then
    echo "$(date): FAIL — bird service not running" >> "$LOG"
    exit 1
fi

# Get all BGP protocol states
bgp_output=$($BIRDC show protocols all 2>/dev/null | grep -E "^[[:space:]]*BGP|State:|Routes:")

# Check for any non-Established sessions
if echo "$bgp_output" | grep -q "State:[[:space:]]*Active\|State:[[:space:]]*Idle\|State:[[:space:]]*Connect"; then
    echo "$(date): FAIL — one or more BGP sessions not Established" >> "$LOG"
    echo "$bgp_output" >> "$LOG"
    exit 1
fi

# All sessions healthy — ping heartbeat
curl -s "$HEARTBEAT_URL" --max-time 10 --retry 2

Make it executable and add to crontab:

chmod +x /opt/scripts/bird-bgp-probe.sh
* * * * * /opt/scripts/bird-bgp-probe.sh

In Vigilmon:

  1. Monitors → New Monitor → Heartbeat
  2. Name: Bird BGP Sessions
  3. Interval: 5 minutes

Step 2: Monitor individual BGP peer health with route counts

A BGP session in Established state can still be broken if it's advertising or receiving zero prefixes. Add route-count checks per peer:

#!/bin/bash
# bird-route-probe.sh
# Checks that each critical BGP peer is Established AND has routes

HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_ROUTE_HEARTBEAT"
LOG="/var/log/bird-route-probe.log"

# Define your critical BGP peers (protocol names as seen in 'birdc show protocols')
CRITICAL_PEERS=("upstream1" "upstream2" "peer_as65001")
MIN_ROUTES=1  # minimum expected imported routes

all_ok=true

for peer in "${CRITICAL_PEERS[@]}"; do
    output=$(birdc show protocols all "$peer" 2>/dev/null)

    state=$(echo "$output" | grep -oP '(?<=BGP state:\s{1,10})\w+')
    imported=$(echo "$output" | grep -oP '(?<=Import updates:\s{1,10})\d+' | head -1)

    if [ "$state" != "Established" ]; then
        echo "$(date): FAIL — $peer state is '$state'" >> "$LOG"
        all_ok=false
        continue
    fi

    # Check route table for this peer
    route_count=$(birdc show route protocol "$peer" count 2>/dev/null | grep -oP '\d+(?= routes)')
    if [ -z "$route_count" ] || [ "$route_count" -lt "$MIN_ROUTES" ]; then
        echo "$(date): FAIL — $peer established but route count is '$route_count'" >> "$LOG"
        all_ok=false
    fi
done

if $all_ok; then
    curl -s "$HEARTBEAT_URL" --max-time 10 --retry 2
fi
*/5 * * * * /opt/scripts/bird-route-probe.sh

Step 3: Expose a Bird status HTTP endpoint

For integrations with Vigilmon's HTTP monitors, run a lightweight status server on your routing host:

#!/usr/bin/env python3
# bird-status-server.py — serves Bird health over HTTP

import subprocess
import json
from http.server import HTTPServer, BaseHTTPRequestHandler

def get_bird_status():
    try:
        # Check service
        svc = subprocess.run(["systemctl", "is-active", "bird"],
                             capture_output=True, text=True, timeout=5)
        if svc.stdout.strip() != "active":
            return {"status": "down", "reason": "service not active"}

        # Check for non-Established BGP sessions
        out = subprocess.run(["birdc", "show", "protocols"],
                              capture_output=True, text=True, timeout=10)
        lines = out.stdout.splitlines()
        problem_peers = [l.strip() for l in lines if "BGP" in l and "Established" not in l and "---" not in l]

        if problem_peers:
            return {"status": "degraded", "problem_peers": problem_peers}

        return {"status": "ok"}
    except Exception as e:
        return {"status": "error", "reason": str(e)}

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/health":
            status = get_bird_status()
            code = 200 if status["status"] == "ok" else 503
            body = json.dumps(status).encode()
            self.send_response(code)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(body)
        else:
            self.send_response(404)
            self.end_headers()
    def log_message(self, *args):
        pass

if __name__ == "__main__":
    HTTPServer(("127.0.0.1", 9179), Handler).serve_forever()

Run as a systemd service, then add an HTTP monitor in Vigilmon:

  • URL: http://YOUR_ROUTER_IP:9179/health
  • Expected status: 200
  • Name: Bird Routing Health

Step 4: Monitor the Bird daemon process directly

Add a TCP port check to confirm Bird's control socket is accepting connections, and a process heartbeat for belt-and-suspenders coverage:

#!/bin/bash
# bird-daemon-check.sh

HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_DAEMON_HEARTBEAT"

# Try to communicate with Bird via birdc
if birdc show status 2>/dev/null | grep -q "BIRD.*ready"; then
    curl -s "$HEARTBEAT_URL" --max-time 10
fi
* * * * * /opt/scripts/bird-daemon-check.sh

In Vigilmon:

  1. Monitors → New Monitor → Heartbeat
  2. Name: Bird Daemon Process
  3. Interval: 2 minutes — daemon crashes should alert quickly

Step 5: Monitor Bird configuration reload jobs

If you use automation to push Bird configs and reload (birdc configure), track those jobs with a heartbeat:

#!/bin/bash
# bird-config-reload.sh — called by your config management tool

HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_CONFIG_HEARTBEAT"

# Validate config first
if ! bird -p 2>/dev/null; then
    echo "$(date): Config parse FAILED — not reloading" >> /var/log/bird-deploy.log
    exit 1
fi

# Apply config
result=$(birdc configure 2>&1)

if echo "$result" | grep -q "Reconfigured"; then
    curl -s "$HEARTBEAT_URL" --max-time 10
    echo "$(date): Config reload successful" >> /var/log/bird-deploy.log
else
    echo "$(date): Config reload FAILED: $result" >> /var/log/bird-deploy.log
    exit 1
fi

Set the heartbeat interval to slightly longer than your expected reload cadence — if your automation runs hourly, set 90 minutes. A missed heartbeat means a missed reload.


Step 6: Configure alerting

Route Bird alerts to your network operations team:

  1. Alert Channels → Add Channel → Slack — use your #noc or #networking channel
  2. Add Channel → PagerDuty — for BGP session loss in production
  3. Assign all Bird monitors to both channels

Set 0-minute escalation for BGP session and route monitors — a missing route can affect end-user traffic within seconds.


Step 7: Build a routing infrastructure status page

  1. Status Pages → New Status Page
  2. Name: Routing Infrastructure
  3. Add monitors: Bird Daemon, BGP Sessions, Route Counts, Config Reload
  4. Set visibility to team-only unless you want public transparency
  5. Post the URL in #noc

Complete monitoring reference

| Monitor | Type | What it catches | |---------|------|-----------------| | Bird Daemon Process | Heartbeat | Daemon crash, socket unavailable | | Bird BGP Sessions | Heartbeat | Session flap, stuck Active/Idle state | | Per-peer Route Counts | Heartbeat | Empty RIB, filter misconfiguration | | Bird Routing Health | HTTP | Aggregated status endpoint | | Config Reload Job | Heartbeat | Missed or failed config deployment |


Troubleshooting common failures

  • BGP session stuck in Active — check TCP connectivity: telnet <peer-ip> 179. If it hangs, a firewall is blocking BGP port 179. Run birdc show protocols all <peer> for the full session log.
  • Session Established but zero routes — run birdc show route protocol <peer>. If empty, check your import filter: birdc show protocols all <peer> will show Import rejected counters.
  • birdc returns "Can't connect to Bird socket" — Bird crashed or the socket path changed. Check systemctl status bird and verify RuntimeDirectory in the Bird systemd unit.
  • Config reload returns "Reconfiguration in progress already" — Bird is still applying a previous config. Wait 10–30 seconds and retry; if it persists, check for a Bird lock file.

Next steps

  • RPKI validation — if you use Bird with an RTR server for RPKI, add a separate heartbeat that checks the RTR protocol state with birdc show protocols rtr1
  • BGP path selection logging — extend the probe to alert when a preferred path changes (birdc show route for <prefix> all changes its best-path source)

Start monitoring your Bird routing infrastructure today at vigilmon.online — free, no credit card.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →