import type { Metadata } from 'next'; import Link from 'next/link'; import { BgpLive } from '@/components/bgp/BgpLive'; import { BgpSeriesChart } from '@/components/bgp/BgpSeriesChart'; import { Section, StatusDot } from '@/components/ui/primitives'; import { apiGet } from '@/lib/api'; import { fmt, fmtInt } from '@/lib/format'; import { Time } from '@/lib/time'; import type { BgpStats } from '@/lib/types'; export const dynamic = 'force-dynamic'; export const metadata: Metadata = { title: 'BGP', description: 'Live BGP updates and withdrawals per second versus baseline, collector health, one-hour series and top origin ASNs.' }; export default async function BgpPage() { const b = await apiGet('/api/v1/bgp/stats'); return (

Routing component

BGP

Announcements and withdrawals from RIPE RIS Live collectors, normalised and compared with a rolling baseline. Withdrawal spikes, origin-ASN changes and collector disagreement feed the Routing component.

updated every 5 s from real counters}>
per minute}>
{fmtInt(b.collectors.length)} · {fmtInt(b.peers)} peers} className="min-w-0">
{b.collectors.map((c) => ( ))}
Collector Location Ann./s Wd./s Peers Last msg Fresh
{c.id} {c.location} {fmt(c.announcements_per_s)} {fmt(c.withdrawals_per_s)} {fmtInt(c.peers)}
{b.top_origins_1h.map((o) => { const share = o.announcements + o.withdrawals ? o.withdrawals / (o.announcements + o.withdrawals) : 0; return ( ); })}
Origin ASN Announcements Withdrawals Wd. share
AS{o.asn} {o.name} {fmtInt(o.announcements)} 0.3 ? 'var(--p-high)' : undefined }}> {fmtInt(o.withdrawals)} {Math.round(share * 100)} %
); }