New gobgp service: GoBGP peers eBGP-multihop with the AS57355 lab route server (Bromirski) for the full real IPv4 + IPv6 Internet table and BMP-exports it to the OpenBMP collector, landing in ip_rib as a monitored peer. Config follows the route server's published peering spec: local AS 65001, no password, keepalive 3600 / hold-time 7200, IPv4 feed on the v4 session and IPv6 feed on the v6 session. gobgp/mrt-refresh.sh is a cron-safe fallback that injects RouteViews MRT RIB dumps when the live session is down. The live BGP session is not started here — bringing gobgp up establishes the external session and loads ~1M routes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
105 lines
3.8 KiB
Bash
Executable File
105 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# mrt-refresh.sh -- MRT full-table fallback loader for the OpenBMP GoBGP feed.
|
|
#
|
|
# Roadmap E1. The live route server (AS57355) is a single volunteer-run host
|
|
# with no SLA. When it is unreachable, the global table in PostgreSQL ip_rib
|
|
# would otherwise age out. This script downloads the latest RouteViews full
|
|
# MRT RIB dump and injects it into the running gobgpd so the table stays warm.
|
|
#
|
|
# Designed to be idempotent and cron-safe at a 2-hour cadence:
|
|
# - it only downloads a dump it does not already have,
|
|
# - it only injects when the live route server session is NOT established,
|
|
# - concurrent runs are guarded by a flock.
|
|
#
|
|
# Run it INSIDE the gobgp container (it shells out to the local `gobgp` CLI):
|
|
# docker exec obmp-gobgp /config/mrt-refresh.sh
|
|
#
|
|
# Example crontab entry on the docker host (every 2 hours):
|
|
# 0 */2 * * * docker exec obmp-gobgp /config/mrt-refresh.sh >> /var/log/gobgp-mrt.log 2>&1
|
|
|
|
set -euo pipefail
|
|
|
|
# --- tunables ---------------------------------------------------------------
|
|
MRT_DIR="${MRT_DIR:-/config/mrt}"
|
|
RV_BASE="${RV_BASE:-https://archive.routeviews.org/route-views/bgpdata}"
|
|
GOBGP="${GOBGP:-gobgp}"
|
|
LOCKFILE="${LOCKFILE:-/tmp/gobgp-mrt-refresh.lock}"
|
|
# RouteViews publishes a full RIB dump every 2 hours; dumps land a few minutes
|
|
# after the even hour, so we look back a safe margin.
|
|
LOOKBACK_HOURS="${LOOKBACK_HOURS:-4}"
|
|
|
|
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*"; }
|
|
|
|
# --- single-instance guard --------------------------------------------------
|
|
exec 9>"${LOCKFILE}"
|
|
if ! flock -n 9; then
|
|
log "another mrt-refresh run is in progress; exiting"
|
|
exit 0
|
|
fi
|
|
|
|
mkdir -p "${MRT_DIR}"
|
|
|
|
# --- skip if the live route server is up ------------------------------------
|
|
# If any AS57355 neighbor is Established, the live feed is authoritative and
|
|
# we must NOT inject a stale MRT dump on top of it.
|
|
if ${GOBGP} neighbor 2>/dev/null | grep -qiE 'Establ'; then
|
|
log "a BGP session is Established; live feed is healthy, skipping MRT inject"
|
|
exit 0
|
|
fi
|
|
log "no Established BGP session; proceeding with MRT fallback"
|
|
|
|
# --- locate the most recent available RIB dump -----------------------------
|
|
# RouteViews RIB dumps:
|
|
# <RV_BASE>/YYYY.MM/RIBS/rib.YYYYMMDD.HHMM.bz2
|
|
# RIB dumps are taken at even hours (00,02,04,...,22) UTC.
|
|
found_url=""
|
|
found_file=""
|
|
now_epoch="$(date -u +%s)"
|
|
for ((h = 0; h <= LOOKBACK_HOURS; h++)); do
|
|
ts_epoch=$(( now_epoch - h * 3600 ))
|
|
hh="$(date -u -d "@${ts_epoch}" +%H)"
|
|
# only even hours carry RIB dumps
|
|
if (( 10#${hh} % 2 != 0 )); then
|
|
continue
|
|
fi
|
|
ym="$(date -u -d "@${ts_epoch}" +%Y.%m)"
|
|
ymd="$(date -u -d "@${ts_epoch}" +%Y%m%d)"
|
|
fname="rib.${ymd}.${hh}00.bz2"
|
|
url="${RV_BASE}/${ym}/RIBS/${fname}"
|
|
if curl -fsI --max-time 30 "${url}" >/dev/null 2>&1; then
|
|
found_url="${url}"
|
|
found_file="${fname}"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ -z "${found_url}" ]]; then
|
|
log "ERROR: no RouteViews RIB dump found within ${LOOKBACK_HOURS}h lookback"
|
|
exit 1
|
|
fi
|
|
|
|
dest="${MRT_DIR}/${found_file}"
|
|
|
|
# --- download (idempotent) --------------------------------------------------
|
|
if [[ -s "${dest}" ]]; then
|
|
log "already have ${found_file}; reusing cached copy"
|
|
else
|
|
log "downloading ${found_url}"
|
|
tmp="${dest}.partial.$$"
|
|
curl -fsSL --max-time 600 -o "${tmp}" "${found_url}"
|
|
mv -f "${tmp}" "${dest}"
|
|
log "downloaded $(du -h "${dest}" | cut -f1) -> ${dest}"
|
|
fi
|
|
|
|
# --- inject into the running gobgpd -----------------------------------------
|
|
# `gobgp mrt inject global` reads the bz2 dump directly and installs every
|
|
# prefix into the global RIB; BMP export to the collector follows automatically.
|
|
log "injecting ${found_file} into gobgpd global RIB"
|
|
${GOBGP} mrt inject global "${dest}"
|
|
log "MRT inject complete"
|
|
|
|
# --- housekeeping: keep only the 4 most recent dumps ------------------------
|
|
( cd "${MRT_DIR}" && ls -1t rib.*.bz2 2>/dev/null | tail -n +5 | xargs -r rm -f )
|
|
log "done"
|