Add ExaBGP route injector, Grafana dashboards, and full documentation

- Add exabgp/ container: ExaBGP 5.x + Flask REST API for on-demand BGP
  route injection into CML IOS-XR lab (AS 65020 via eBGP from AS 65100)
- Add 6 injection scenarios: internet_sample, churn, blackhole, anycast,
  full_table, lab_prefixes
- Add inject.py CLI wrapper for the ExaBGP API
- Add iosxr_bgp_config.md with IOS-XR neighbor config and NETCONF script
- Add obmp-grafana/ dashboards and provisioning (17 dashboards)
- Update docker-compose.yml: add exabgp service, fix Kafka external
  listener IP, extend log retention from 90min to 720min
- Add DOCS.md: full project documentation including architecture, setup,
  user guide, sanity checks, troubleshooting, and command reference
- Update .gitignore: exclude .env and .claude/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sam 2026-03-05 14:46:37 -07:00
parent 3f38af5312
commit 233dadbb41
33 changed files with 13005 additions and 4 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.idea
*.log
.env
.claude/

746
DOCS.md Normal file
View File

@ -0,0 +1,746 @@
# OpenBMP + ExaBGP Route Injector — Full Documentation
## Table of Contents
1. [What Is This Project?](#1-what-is-this-project)
2. [Architecture](#2-architecture)
3. [Prerequisites](#3-prerequisites)
4. [Initial Setup (First Time)](#4-initial-setup-first-time)
5. [IOS-XR Router Configuration](#5-ios-xr-router-configuration)
6. [Starting and Stopping](#6-starting-and-stopping)
7. [Route Injection User Guide](#7-route-injection-user-guide)
8. [Grafana Dashboards](#8-grafana-dashboards)
9. [Sanity Checks](#9-sanity-checks)
10. [Relevant Commands Reference](#10-relevant-commands-reference)
11. [Troubleshooting](#11-troubleshooting)
12. [Data Retention](#12-data-retention)
13. [Environment Variables Reference](#13-environment-variables-reference)
---
## 1. What Is This Project?
This is a **BGP Monitoring Platform (BMP) lab stack** deployed via Docker Compose. It collects, stores, and visualizes BGP routing data from a Cisco IOS-XR lab network (running in Cisco Modeling Labs / CML).
**What it does:**
- Receives BMP (BGP Monitoring Protocol, RFC 7854) telemetry from routers on TCP port 5000
- Streams BMP data through Kafka into a TimescaleDB/PostgreSQL database
- Provides 17 Grafana dashboards for real-time and historical BGP analysis
- Includes an **ExaBGP route injector** that peers with the two CORE routers and injects synthetic BGP routes, enabling testing of BGP policy, route propagation, and Grafana dashboards without needing internet connectivity
**The lab network:**
- AS 65020 — 9 Cisco IOS-XR routers in CML (iBGP full mesh via route-reflectors)
- AS 65100 — ExaBGP container (eBGP peer to both CORE routers)
- CORE-01: `10.100.0.100` (CML-R9K-CORE-01)
- CORE-02: `10.100.0.200` (CML-R9K-CORE-02)
- Host IP: `10.40.40.202` (ExaBGP binds here; reachable from CML management network)
---
## 2. Architecture
```
IOS-XR Routers (9x, AS 65020)
BMP telemetry on TCP 5000
|
v
obmp-collector (openbmp/collector:2.2.3)
|
v
obmp-kafka (confluentinc/cp-kafka:7.1.1)
+ obmp-zookeeper (confluentinc/cp-zookeeper:7.1.1)
|
v
obmp-psql-app (openbmp/psql-app:2.2.2)
Java consumer — writes parsed BGP data to PostgreSQL
|
v
obmp-psql (openbmp/postgres:2.2.1)
PostgreSQL 14 + TimescaleDB
|
+---------> obmp-grafana (grafana/grafana:9.1.7) :3000
| 17 dashboards, PostgreSQL datasource
+---------> obmp-whois (openbmp/whois:2.2.0) :4300
WHOIS query server backed by the DB
ExaBGP (obmp-exabgp, built locally)
python:3.11-slim + exabgp 5.x + Flask API
Peers eBGP to CORE-01 and CORE-02 (AS 65100 -> AS 65020)
HTTP API on :5050 — inject/withdraw routes on demand
Routes propagate via iBGP mesh to all 9 routers -> BMP -> DB -> Grafana
```
### Container Summary
| Container | Image | Port(s) | Role |
|-----------|-------|---------|------|
| obmp-zookeeper | confluentinc/cp-zookeeper:7.1.1 | 2181 (internal) | Kafka coordination |
| obmp-kafka | confluentinc/cp-kafka:7.1.1 | 9092 | Message broker |
| obmp-collector | openbmp/collector:2.2.3 | 5000 | BMP receiver |
| obmp-psql-app | openbmp/psql-app:2.2.2 | 9005 | Kafka→PostgreSQL consumer |
| obmp-psql | openbmp/postgres:2.2.1 | 5432 | TimescaleDB storage |
| obmp-grafana | grafana/grafana:9.1.7 | 3000 | Visualization |
| obmp-whois | openbmp/whois:2.2.0 | 4300 | WHOIS query server |
| obmp-exabgp | local build | 5050 (host net) | BGP route injector |
---
## 3. Prerequisites
- Docker Engine (20.10+) and Docker Compose v2
- Host IP `10.40.40.202` reachable from the CML management network
- CML routers with BMP configured pointing to `10.40.40.202:5000`
- CML CORE routers configured with ExaBGP as eBGP neighbor (see Section 5)
- `OBMP_DATA_ROOT` directory created (default: `/var/openbmp`)
---
## 4. Initial Setup (First Time)
### 4.1 Clone the repository
```bash
git clone <this-repo-url>
cd obmp-docker
```
### 4.2 Create persistent data directories
```bash
export OBMP_DATA_ROOT=/var/openbmp
sudo mkdir -p $OBMP_DATA_ROOT
mkdir -p ${OBMP_DATA_ROOT}/config
mkdir -p ${OBMP_DATA_ROOT}/kafka-data
mkdir -p ${OBMP_DATA_ROOT}/zk-data
mkdir -p ${OBMP_DATA_ROOT}/zk-log
mkdir -p ${OBMP_DATA_ROOT}/postgres/data
mkdir -p ${OBMP_DATA_ROOT}/postgres/ts
mkdir -p ${OBMP_DATA_ROOT}/grafana
mkdir -p ${OBMP_DATA_ROOT}/grafana/dashboards
sudo chmod -R 777 $OBMP_DATA_ROOT
```
### 4.3 Initialise the database (first run only)
Create the init trigger file — this causes psql-app to create all tables on startup:
```bash
touch ${OBMP_DATA_ROOT}/config/init_db
```
> **Warning:** Do not create this file on subsequent runs unless you want to wipe and recreate the entire database.
### 4.4 Copy Grafana provisioning files
```bash
cp -r obmp-grafana/provisioning ${OBMP_DATA_ROOT}/grafana/
cp -r obmp-grafana/dashboards ${OBMP_DATA_ROOT}/grafana/
```
### 4.5 Start the stack
```bash
OBMP_DATA_ROOT=/var/openbmp docker compose -p obmp up -d
```
Wait ~2 minutes for all services to initialise (especially PostgreSQL and psql-app which run schema migrations).
### 4.6 Verify everything is running
```bash
docker compose -p obmp ps
docker compose -p obmp logs --tail=20 psql-app
```
---
## 5. IOS-XR Router Configuration
The ExaBGP container peers eBGP with both CORE routers. Each CORE router must be configured with:
### 5.1 Route policies (apply once per router)
```
route-policy EXABGP_IN
pass
end-policy
route-policy EXABGP_OUT
drop
end-policy
```
### 5.2 BGP neighbor block
```
router bgp 65020
neighbor 10.40.40.202
remote-as 65100
description ExaBGP-Route-Injector
ebgp-multihop 5
update-source MgmtEth0/RP0/CPU0/0
!
address-family ipv4 unicast
route-policy EXABGP_IN in
route-policy EXABGP_OUT out
next-hop-self
!
!
!
```
### 5.3 Static route for next-hop resolution
IOS-XR BGP does not use the default route (0.0.0.0/0) to resolve BGP next-hops. A more-specific static route for the ExaBGP host subnet is required in the default VRF:
```
router static
address-family ipv4 unicast
10.40.40.0/24 10.100.0.254
!
!
```
### 5.4 Config notes
| Knob | Why |
|------|-----|
| `remote-as 65100` | ExaBGP presents as AS 65100 (eBGP to your AS 65020 mesh) |
| `ebgp-multihop 5` | Host and router are on different subnets |
| `update-source MgmtEth0/RP0/CPU0/0` | ExaBGP is reachable via the management interface |
| `next-hop-self` | Replace ExaBGP's next-hop (10.40.40.202) with the CORE router's address when reflecting into iBGP — ensures all routers can resolve the next-hop |
| `EXABGP_OUT` drops | Prevents the lab from advertising its own prefixes back to ExaBGP |
| Static route | Required: IOS-XR BGP will not install injected routes as bestpaths without a specific route to the next-hop |
### 5.5 NETCONF alternative
See `exabgp/iosxr_bgp_config.md` for a Python/ncclient script that pushes all of the above config programmatically.
Credentials: `username=webui`, `password=cisco`, port 830.
---
## 6. Starting and Stopping
### Start all services
```bash
OBMP_DATA_ROOT=/var/openbmp docker compose -p obmp up -d
```
### Stop all services (preserve data)
```bash
docker compose -p obmp down
```
### Stop and remove all data (full reset)
```bash
docker compose -p obmp down -v
sudo rm -rf /var/openbmp
```
### Rebuild the ExaBGP container (after code changes)
```bash
docker compose -p obmp build exabgp
docker compose -p obmp up -d exabgp
```
### Restart a single service
```bash
docker compose -p obmp restart <service>
# e.g.:
docker compose -p obmp restart exabgp
docker compose -p obmp restart psql-app
```
---
## 7. Route Injection User Guide
The ExaBGP container exposes a Flask REST API on port 5050 (host network). The `inject.py` CLI wraps this API.
### 7.1 Setup
```bash
cd exabgp
pip install requests # only needed if running inject.py from the host
```
### 7.2 Check status
```bash
python3 inject.py status
```
Output shows API health, active route count, and peer states:
```json
{
"status": "ok",
"active_routes": 77,
"peers": {
"10.100.0.100": {"state": "up", "updated": "2026-03-05T10:00:00Z"},
"10.100.0.200": {"state": "up", "updated": "2026-03-05T10:00:00Z"}
}
}
```
### 7.3 List available scenarios
```bash
python3 inject.py scenarios
```
| Scenario | Routes | Description |
|----------|--------|-------------|
| `internet_sample` | ~94 | Partial internet table — real public prefixes, realistic AS paths (Cloudflare, Google, AWS, Azure, etc.) |
| `churn` | 30 | RFC documentation prefixes for announce/withdraw churn testing |
| `blackhole` | 5 | /32 prefixes with RTBH community (65100:666 + 65535:666) |
| `anycast` | 3 | Same prefixes with varying AS paths and MEDs (best-path testing) |
| `full_table` | 500+ | Large partial internet table with synthetic /24s |
| `lab_prefixes` | 8 | Enterprise/SP-style routes with communities and local-pref |
### 7.4 Load a scenario
```bash
python3 inject.py scenario internet_sample
```
Routes propagate: ExaBGP → CORE-01/CORE-02 (eBGP) → all 9 routers (iBGP) → BMP → Kafka → PostgreSQL → Grafana.
### 7.5 Withdraw a scenario
```bash
python3 inject.py withdraw-scenario internet_sample
```
### 7.6 Announce individual prefixes
```bash
python3 inject.py announce 10.0.0.0/8 \
--as-path 65100 3356 15169 \
--community 65100:100 \
--med 100
```
### 7.7 Withdraw individual prefixes
```bash
python3 inject.py withdraw 10.0.0.0/8
```
### 7.8 Withdraw everything
```bash
python3 inject.py withdraw-all
```
### 7.9 Generate route churn (populate history tables)
The `churn` command cycles the churn scenario repeatedly, generating `ip_rib_log` and `stats_chg_*` entries that power Grafana's history dashboards.
```bash
# 5 cycles, 30 seconds apart
python3 inject.py churn --count 5 --interval 30
# Run indefinitely until Ctrl+C
python3 inject.py churn
```
### 7.10 REST API directly (curl)
```bash
BASE=http://localhost:5050
# Health
curl $BASE/healthz
# List scenarios
curl $BASE/scenarios
# Load scenario
curl -X POST $BASE/scenario/internet_sample
# Announce custom prefix
curl -X POST $BASE/announce \
-H 'Content-Type: application/json' \
-d '{"prefixes":["10.0.0.0/8"],"as_path":[65100,3356,15169],"communities":["65100:100"]}'
# Withdraw all
curl -X POST $BASE/withdraw/all
# Peer state
curl $BASE/peers
```
### 7.11 Adding custom scenarios
Edit `exabgp/scenarios/__init__.py`. Add an entry to `SCENARIOS` following the existing pattern:
```python
SCENARIOS['my_scenario'] = {
'description': 'My custom routes',
'routes': [
_r('192.0.2.0/24', [65100, 65200], communities=['65100:100']),
],
}
```
The `scenarios/` directory is volume-mounted into the container, so changes are live without rebuilding. However, the Python module is imported at container start — **restart the container** after editing:
```bash
docker compose -p obmp restart exabgp
```
---
## 8. Grafana Dashboards
Access: `http://10.40.40.202:3000`
Default credentials: `admin` / `openbmp` (anonymous access also enabled)
### Dashboard Categories
| Category | Dashboard | Description |
|----------|-----------|-------------|
| General | OBMP Home | Overview / landing page |
| Base | Inventory | Router and peer inventory |
| Base | Looking Glass | Real-time RIB lookup by prefix |
| Base | ASN View | ASN-level routing view |
| History | Prefix History | Route change history for a prefix |
| History | Prefix History by ASN | Filtered by origin AS |
| History | Prefix History by Community | Filtered by BGP community |
| Tops | Top Prefixes | Most-updated prefixes |
| Tops | Top L3VPN Prefixes | L3VPN equivalent |
| Link State | LS Nodes | IS-IS link-state node database |
| Link State | LS Links | IS-IS link-state link database |
| Link State | LS Topology | Network topology map |
| Link State | LS Prefixes | Link-state prefix database |
| Link State | LS History | Link-state change history |
| L3VPN | L3VPN Looking Glass | VPN RIB lookup |
| L3VPN | L3VPN Prefix History | VPN route change history |
| L3VPN | L3VPN RIB Browser | Full VPN RIB browser |
> History dashboards require `ip_rib_log` and `stats_chg_*` table data. Run `inject.py churn` to populate these.
---
## 9. Sanity Checks
### 9.1 All containers running
```bash
docker compose -p obmp ps
```
All containers should show `running`. If any are restarting, check logs:
```bash
docker compose -p obmp logs --tail=50 <service>
```
### 9.2 ExaBGP peers up
```bash
python3 exabgp/inject.py status
```
Both `10.100.0.100` and `10.100.0.200` should show `"state": "up"`.
Or check from the router side:
```
show bgp neighbors 10.40.40.202
show bgp summary | inc 10.40.40.202
```
### 9.3 Routes accepted by CORE routers
After loading `internet_sample`:
```bash
# On CORE-01 or CORE-02:
show bgp summary
# Expect: 77 accepted prefixes, 77 are bestpaths from 10.40.40.202
show bgp 8.8.8.0/24
# Expect: best path via 10.40.40.202 (eBGP), also iBGP copies from other routers
```
### 9.4 Routes in OpenBMP database
```bash
docker exec -it obmp-psql psql -U openbmp -c "
SELECT count(DISTINCT prefix) AS unique_prefixes,
count(DISTINCT peer_hash_id) AS peers_reporting
FROM ip_rib
WHERE isIPv4 = true AND isWithdrawn = false;
"
```
Expect `~129 unique prefixes` and `56 peers_reporting` (9 routers × ~6 peers each) after loading `internet_sample`.
### 9.5 Kafka is healthy
```bash
docker exec -it obmp-kafka kafka-topics --bootstrap-server localhost:29092 --list
```
Should show topics like `openbmp.parsed.unicast_prefix`, `openbmp.parsed.peer`, etc.
### 9.6 Grafana datasource
Open `http://10.40.40.202:3000` → Configuration → Data Sources → OpenBMP → Test.
Should return "Database Connection OK".
### 9.7 BMP collector receiving data
```bash
docker compose -p obmp logs --tail=30 collector
```
Should show connections from router management IPs.
### 9.8 psql-app consumer is caught up
```bash
docker compose -p obmp logs --tail=30 psql-app
```
Should show periodic cron job outputs (RPKI sync, IRR sync, global_ip_rib updates).
---
## 10. Relevant Commands Reference
### Docker Compose
```bash
# Start stack
OBMP_DATA_ROOT=/var/openbmp docker compose -p obmp up -d
# Stop stack
docker compose -p obmp down
# Show status
docker compose -p obmp ps
# Follow logs (all services)
docker compose -p obmp logs -f
# Follow logs (specific service)
docker compose -p obmp logs -f exabgp
docker compose -p obmp logs -f psql-app
docker compose -p obmp logs -f collector
# Rebuild and restart ExaBGP
docker compose -p obmp build exabgp && docker compose -p obmp up -d exabgp
# Restart a service
docker compose -p obmp restart psql-app
```
### Route Injection (from `exabgp/` directory)
```bash
# API health and peer states
python3 inject.py status
# List active routes
python3 inject.py routes
# List scenarios
python3 inject.py scenarios
# Load a scenario
python3 inject.py scenario internet_sample
python3 inject.py scenario churn
python3 inject.py scenario blackhole
python3 inject.py scenario full_table
python3 inject.py scenario lab_prefixes
# Withdraw a scenario
python3 inject.py withdraw-scenario internet_sample
# Withdraw all active routes
python3 inject.py withdraw-all
# Announce a specific prefix
python3 inject.py announce 10.0.0.0/8 --as-path 65100 3356 15169 --community 65100:100
# Withdraw a specific prefix
python3 inject.py withdraw 10.0.0.0/8
# Run churn (populate history tables)
python3 inject.py churn --count 5 --interval 30
```
### Database Queries
```bash
# Connect to database
docker exec -it obmp-psql psql -U openbmp -d openbmp
# Count unique prefixes in RIB
SELECT count(DISTINCT prefix) FROM ip_rib WHERE isIPv4=true AND isWithdrawn=false;
# Show recent route changes
SELECT prefix, origin_as, iswithdrawn, timestamp
FROM ip_rib_log
ORDER BY timestamp DESC LIMIT 20;
# Show peer summary
SELECT name, state, timestamp_last_updated
FROM bgp_peers
ORDER BY state, name;
# Show routes from ExaBGP peer
SELECT prefix, origin_as, as_path
FROM ip_rib
WHERE peer_hash_id IN (
SELECT hash_id FROM bgp_peers WHERE peer_addr = '10.40.40.202'
)
AND isWithdrawn = false;
```
### IOS-XR Verification (on router CLI)
```
show bgp neighbors 10.40.40.202
show bgp neighbors 10.40.40.202 received routes
show bgp summary
show bgp 8.8.8.0/24
show bgp 1.1.1.0/24
show route 8.8.8.0/24
```
---
## 11. Troubleshooting
### ExaBGP container keeps restarting
Check logs:
```bash
docker compose -p obmp logs --tail=50 exabgp
```
Common causes and fixes:
| Symptom | Cause | Fix |
|---------|-------|-----|
| Exits after "welcome" banner | Missing or wrong env file path | `startup.sh` generates `/usr/local/etc/exabgp/exabgp.env` — verify this path exists in container |
| Process `api` killed 5 times | Wrong Python path in conf | Conf uses `/usr/local/bin/python3` — correct for python:3.11-slim |
| `drop = true` in env | ExaBGP drops privileges to nobody, can't bind 179 | `startup.sh` patches `drop = false` — check the sed lines ran |
| `__pycache__ Permission denied` during build | Root-owned cache from previous container run | `.dockerignore` excludes `**/__pycache__` — confirm file exists |
### BGP sessions not establishing
1. Verify host IP `10.40.40.202` is reachable from CML management network: `ping 10.40.40.202` from router
2. Check ExaBGP peer state: `python3 exabgp/inject.py status`
3. On router: `show bgp neighbors 10.40.40.202` — look for error codes
4. Common IOS-XR errors:
- `no-update-source-config` — add `update-source MgmtEth0/RP0/CPU0/0`
- `no-ipv6-address` — ensure only IPv4 unicast AF is configured (no IPv6)
- TCP refused — check port 179 is reachable (ExaBGP uses `network_mode: host`)
### Routes received but not bestpath
IOS-XR BGP requires a specific route to resolve the BGP next-hop (10.40.40.202). The default route (0.0.0.0/0) is insufficient.
```
router static
address-family ipv4 unicast
10.40.40.0/24 10.100.0.254
```
Verify: `show bgp 1.1.1.0/24` — should show `Status: s (active), bestpath`.
### Grafana shows no data
1. Check datasource: Configuration → Data Sources → OpenBMP → Test
2. Verify psql-app is writing: `docker compose -p obmp logs psql-app`
3. Check the database directly (see database queries above)
4. History dashboards need route churn — run `python3 inject.py churn`
### Kafka not starting
Zookeeper must be healthy first. Check:
```bash
docker compose -p obmp logs zookeeper
docker compose -p obmp restart kafka
```
### psql-app fails to start
Usually a PostgreSQL connection issue or schema mismatch. Check:
```bash
docker compose -p obmp logs psql-app
# If "relation does not exist" errors: re-trigger DB init
touch /var/openbmp/config/init_db
docker compose -p obmp restart psql-app
```
---
## 12. Data Retention
Configured in `docker-compose.yml` via `POSTGRES_DROP_*` environment variables:
| Table | Default Retention |
|-------|-------------------|
| peer_event_log | 1 year |
| stat_reports | 4 weeks |
| ip_rib_log | 4 weeks |
| alerts | 4 weeks |
| ls_nodes_log | 4 months |
| ls_links_log | 4 months |
| ls_prefixes_log | 4 months |
| stats_chg_byprefix | 4 weeks |
| stats_chg_byasn | 4 weeks |
| stats_chg_bypeer | 4 weeks |
| stats_ip_origins | 4 weeks |
| stats_peer_rib | 4 weeks |
| stats_peer_update_counts | 4 weeks |
Adjust in `docker-compose.yml` under the `psql-app` service environment block.
---
## 13. Environment Variables Reference
### ExaBGP container
| Variable | Default | Description |
|----------|---------|-------------|
| `EXABGP_LOCAL_IP` | `10.40.40.202` | Host IP ExaBGP binds to and uses as router-id |
| `EXABGP_LOCAL_AS` | `65100` | ExaBGP's AS number |
| `EXABGP_PEER_AS` | `65020` | AS of the IOS-XR lab |
| `EXABGP_PEER_1` | `10.100.0.100` | First CORE router to peer with |
| `EXABGP_PEER_2` | `10.100.0.200` | Second CORE router to peer with |
| `EXABGP_API_PORT` | `5050` | Flask API port |
### psql-app container (key variables)
| Variable | Default | Description |
|----------|---------|-------------|
| `MEM` | `3` | JVM heap in GB |
| `ENABLE_RPKI` | `1` | Enable RPKI sync from Cloudflare |
| `ENABLE_IRR` | `1` | Enable IRR sync |
| `ENABLE_DBIP` | `1` | Enable DB-IP geolocation import |
| `POSTGRES_REPORT_WINDOW` | `8 minute` | Aggregation window for summary tables |
### inject.py (CLI)
| Variable | Default | Description |
|----------|---------|-------------|
| `EXABGP_API` | `http://localhost:5050` | ExaBGP API base URL |

View File

@ -45,13 +45,12 @@ services:
# Change/add listeners based on your FQDN that the host and other containers can access. You can use
# an IP address as well. By default, only within the compose/containers can Kafka be accesssed
# using port 29092. Outside access can be enabled, but you should use an FQDN listener.
#KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://<FQDN>:9092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://obmp-kafka:29092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://obmp-kafka:29092,PLAINTEXT_HOST://10.40.40.202:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_NUM_PARTITIONS: 8
KAFKA_LOG_RETENTION_MINUTES: 90
KAFKA_LOG_RETENTION_MINUTES: 720
KAFKA_LOG_ROLL_MS: 3600000
KAFKA_LOG_SEGMENT_BYTES: 1073741824
KAFKA_MESSAGE_MAX_BYTES: 100000000
@ -198,6 +197,30 @@ services:
- POSTGRES_DROP_stats_peer_rib='4 weeks'
- POSTGRES_DROP_stats_peer_update_counts='4 weeks'
exabgp:
restart: unless-stopped
container_name: obmp-exabgp
build:
context: ./exabgp
dockerfile: Dockerfile
# Host networking so ExaBGP can reach CML routers directly on port 179
network_mode: host
environment:
# IP on the host that CML routers can reach (matches Kafka external listener)
- EXABGP_LOCAL_IP=10.40.40.202
# ExaBGP presents as AS 65100 (eBGP peer to your AS 65020 lab)
- EXABGP_LOCAL_AS=65100
- EXABGP_PEER_AS=65020
# CORE routers to peer with — these propagate routes into the iBGP mesh
- EXABGP_PEER_1=10.100.0.100
- EXABGP_PEER_2=10.100.0.200
# Flask API port (also on host network)
- EXABGP_API_PORT=5050
volumes:
# Mount scenarios dir so you can edit/add scenarios without rebuilding
- ./exabgp/scenarios:/exabgp/scenarios
# No ports: block needed — network_mode: host exposes directly
whois:
restart: unless-stopped
container_name: obmp-whois
@ -215,4 +238,4 @@ services:
- POSTGRES_USER=openbmp
- POSTGRES_DB=openbmp
- POSTGRES_HOST=obmp-psql
- POSTGRES_PORT=5432
- POSTGRES_PORT=5432

2
exabgp/.dockerignore Normal file
View File

@ -0,0 +1,2 @@
**/__pycache__
**/*.pyc

19
exabgp/Dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM python:3.11-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
procps \
&& rm -rf /var/lib/apt/lists/*
# Install ExaBGP and Flask API dependencies
RUN pip install --no-cache-dir exabgp flask requests
# ExaBGP writes its own config at startup; we just need the source tree
COPY . /exabgp/
WORKDIR /exabgp
RUN chmod +x /exabgp/startup.sh /exabgp/inject.py
# Flask API port
EXPOSE 5050
CMD ["/bin/bash", "/exabgp/startup.sh"]

View File

@ -0,0 +1,3 @@
exabgp
flask
requests

273
exabgp/api/server.py Normal file
View File

@ -0,0 +1,273 @@
#!/usr/bin/env python3
"""
ExaBGP Route Injection API Server
Runs as an ExaBGP process reads BGP events from stdin, writes BGP
commands to stdout. Flask API runs in a background thread so HTTP
requests trigger live route announcements/withdrawals.
API endpoints:
GET /healthz - health + active route count
GET /routes - list all active routes
POST /announce - announce prefixes
POST /withdraw - withdraw prefixes
POST /withdraw/all - withdraw everything
GET /scenarios - list available scenarios
POST /scenario/<name> - load a scenario
DELETE /scenario/<name> - withdraw a scenario
GET /peers - BGP peer state
"""
import sys
import os
import json
import threading
import time
import logging
from flask import Flask, request, jsonify
# --- logging to stderr so it doesn't pollute ExaBGP's stdout pipe ---
logging.basicConfig(
stream=sys.stderr,
level=logging.INFO,
format='%(asctime)s [API] %(levelname)s %(message)s',
)
log = logging.getLogger(__name__)
app = Flask(__name__)
# Thread-safe stdout for ExaBGP commands
_stdout_lock = threading.Lock()
# Active routes: prefix -> metadata dict
active_routes = {}
# Peer state received from ExaBGP events
peer_states = {}
# ---------------------------------------------------------------------------
# ExaBGP command helpers
# ---------------------------------------------------------------------------
def _send(cmd: str):
"""Write a command to ExaBGP via stdout."""
with _stdout_lock:
sys.stdout.write(cmd + '\n')
sys.stdout.flush()
log.info('→ ExaBGP: %s', cmd)
def _build_announce(prefix, next_hop='self', as_path=None, communities=None, med=None, local_pref=None):
parts = [f'announce route {prefix} next-hop {next_hop}']
if as_path:
parts.append(f'as-path [ {" ".join(str(a) for a in as_path)} ]')
if communities:
parts.append(f'community [ {" ".join(communities)} ]')
if med is not None:
parts.append(f'med {med}')
if local_pref is not None:
parts.append(f'local-preference {local_pref}')
return ' '.join(parts)
def _build_withdraw(prefix, next_hop='self'):
return f'withdraw route {prefix} next-hop {next_hop}'
def announce_route(prefix, next_hop='self', as_path=None, communities=None, med=None, local_pref=None):
cmd = _build_announce(prefix, next_hop, as_path, communities, med, local_pref)
_send(cmd)
active_routes[prefix] = {
'prefix': prefix,
'next_hop': next_hop,
'as_path': as_path or [],
'communities': communities or [],
'med': med,
'local_pref': local_pref,
'announced_at': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
}
def withdraw_route(prefix, next_hop='self'):
_send(_build_withdraw(prefix, next_hop))
active_routes.pop(prefix, None)
# ---------------------------------------------------------------------------
# Flask API routes
# ---------------------------------------------------------------------------
@app.route('/healthz')
def health():
return jsonify({
'status': 'ok',
'active_routes': len(active_routes),
'peers': peer_states,
})
@app.route('/routes', methods=['GET'])
def list_routes():
return jsonify({
'count': len(active_routes),
'routes': list(active_routes.values()),
})
@app.route('/announce', methods=['POST'])
def api_announce():
data = request.get_json(force=True)
prefixes = data.get('prefixes', [])
if not prefixes:
return jsonify({'error': 'prefixes list required'}), 400
next_hop = data.get('next_hop', 'self')
as_path = data.get('as_path', [])
communities = data.get('communities', [])
med = data.get('med')
local_pref = data.get('local_pref')
announced = []
for prefix in prefixes:
announce_route(prefix, next_hop, as_path, communities, med, local_pref)
announced.append(prefix)
return jsonify({'announced': announced, 'count': len(announced)})
@app.route('/withdraw', methods=['POST'])
def api_withdraw():
data = request.get_json(force=True)
prefixes = data.get('prefixes', [])
if not prefixes:
return jsonify({'error': 'prefixes list required'}), 400
withdrawn = []
for prefix in prefixes:
withdraw_route(prefix)
withdrawn.append(prefix)
return jsonify({'withdrawn': withdrawn, 'count': len(withdrawn)})
@app.route('/withdraw/all', methods=['POST'])
def api_withdraw_all():
prefixes = list(active_routes.keys())
for prefix in prefixes:
withdraw_route(prefix)
return jsonify({'withdrawn': prefixes, 'count': len(prefixes)})
# ---------------------------------------------------------------------------
# Scenario management
# ---------------------------------------------------------------------------
sys.path.insert(0, '/exabgp')
from scenarios import SCENARIOS
@app.route('/scenarios', methods=['GET'])
def list_scenarios():
return jsonify({
'scenarios': {
name: {
'description': s.get('description', ''),
'route_count': len(s.get('routes', [])),
}
for name, s in SCENARIOS.items()
}
})
@app.route('/scenario/<name>', methods=['POST'])
def load_scenario(name):
if name not in SCENARIOS:
return jsonify({'error': f'Unknown scenario: {name}. Available: {list(SCENARIOS)}'}), 404
scenario = SCENARIOS[name]
announced = []
for route in scenario['routes']:
prefix = route['prefix']
announce_route(
prefix,
next_hop=route.get('next_hop', 'self'),
as_path=route.get('as_path', []),
communities=route.get('communities', []),
med=route.get('med'),
local_pref=route.get('local_pref'),
)
announced.append(prefix)
log.info('Loaded scenario %s: %d routes', name, len(announced))
return jsonify({'scenario': name, 'announced': announced, 'count': len(announced)})
@app.route('/scenario/<name>', methods=['DELETE'])
def unload_scenario(name):
if name not in SCENARIOS:
return jsonify({'error': f'Unknown scenario: {name}'}), 404
scenario = SCENARIOS[name]
withdrawn = []
for route in scenario['routes']:
prefix = route['prefix']
if prefix in active_routes:
withdraw_route(prefix)
withdrawn.append(prefix)
log.info('Unloaded scenario %s: %d routes', name, len(withdrawn))
return jsonify({'scenario': name, 'withdrawn': withdrawn, 'count': len(withdrawn)})
@app.route('/peers', methods=['GET'])
def get_peers():
return jsonify({'peers': peer_states})
# ---------------------------------------------------------------------------
# ExaBGP event loop (main thread)
# ---------------------------------------------------------------------------
def parse_exabgp_event(line: str):
"""Parse ExaBGP neighbor state events from stdin."""
# ExaBGP text events look like:
# neighbor 10.100.0.100 up
# neighbor 10.100.0.100 down
parts = line.strip().split()
if len(parts) >= 3 and parts[0] == 'neighbor':
peer_ip = parts[1]
state = parts[2]
peer_states[peer_ip] = {'state': state, 'updated': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}
log.info('Peer %s%s', peer_ip, state)
def main():
api_port = int(os.environ.get('EXABGP_API_PORT', 5050))
# Start Flask in background thread
flask_thread = threading.Thread(
target=lambda: app.run(host='0.0.0.0', port=api_port, threaded=True),
daemon=True,
)
flask_thread.start()
log.info('Flask API listening on port %d', api_port)
# Main thread: read ExaBGP events from stdin
log.info('Waiting for ExaBGP events on stdin...')
while True:
try:
line = sys.stdin.readline()
if not line:
log.warning('ExaBGP stdin closed, exiting')
break
line = line.strip()
if line:
log.debug('← ExaBGP: %s', line)
parse_exabgp_event(line)
except KeyboardInterrupt:
break
except Exception as e:
log.error('Event loop error: %s', e)
if __name__ == '__main__':
main()

213
exabgp/inject.py Normal file
View File

@ -0,0 +1,213 @@
#!/usr/bin/env python3
"""
inject.py CLI wrapper for the ExaBGP Route Injection API
Usage:
inject.py status
inject.py routes
inject.py scenarios
inject.py announce <prefix> [<prefix>...] [--as-path ASN...] [--community STR...] [--med N] [--next-hop IP]
inject.py withdraw <prefix> [<prefix>...]
inject.py withdraw-all
inject.py scenario <name>
inject.py withdraw-scenario <name>
inject.py churn [--count N] [--interval SEC] # cycle announce/withdraw for ip_rib_log population
Environment:
EXABGP_API=http://localhost:5050 API base URL
"""
import sys
import os
import json
import time
import argparse
import requests
API = os.environ.get('EXABGP_API', 'http://localhost:5050')
def _post(path, data=None):
r = requests.post(f'{API}{path}', json=data or {}, timeout=10)
r.raise_for_status()
return r.json()
def _delete(path):
r = requests.delete(f'{API}{path}', timeout=10)
r.raise_for_status()
return r.json()
def _get(path):
r = requests.get(f'{API}{path}', timeout=10)
r.raise_for_status()
return r.json()
def _pp(data):
print(json.dumps(data, indent=2))
def cmd_status(args):
_pp(_get('/healthz'))
def cmd_routes(args):
data = _get('/routes')
print(f"Active routes: {data['count']}")
for r in data['routes']:
path = ' '.join(str(a) for a in r.get('as_path', []))
comms = ' '.join(r.get('communities', []))
parts = [r['prefix'], f'nh={r["next_hop"]}']
if path:
parts.append(f'as-path=[{path}]')
if comms:
parts.append(f'community=[{comms}]')
if r.get('med') is not None:
parts.append(f'med={r["med"]}')
print(' ' + ' '.join(parts))
def cmd_scenarios(args):
data = _get('/scenarios')
print(f"{'Name':<20} {'Routes':>6} Description")
print('-' * 70)
for name, info in data['scenarios'].items():
print(f"{name:<20} {info['route_count']:>6} {info['description']}")
def cmd_announce(args):
payload = {
'prefixes': args.prefixes,
'next_hop': args.next_hop,
'as_path': [int(a) for a in args.as_path] if args.as_path else [],
'communities': args.community or [],
}
if args.med is not None:
payload['med'] = args.med
data = _post('/announce', payload)
print(f"Announced {data['count']} route(s):")
for p in data['announced']:
print(f" + {p}")
def cmd_withdraw(args):
data = _post('/withdraw', {'prefixes': args.prefixes})
print(f"Withdrew {data['count']} route(s):")
for p in data['withdrawn']:
print(f" - {p}")
def cmd_withdraw_all(args):
data = _post('/withdraw/all')
print(f"Withdrew all {data['count']} route(s)")
def cmd_scenario(args):
data = _post(f'/scenario/{args.name}')
print(f"Loaded scenario '{args.name}': {data['count']} routes announced")
def cmd_withdraw_scenario(args):
data = _delete(f'/scenario/{args.name}')
print(f"Withdrew scenario '{args.name}': {data['count']} routes withdrawn")
def cmd_churn(args):
"""
Cycle announce/withdraw on the 'churn' scenario to generate ip_rib_log
entries and populate stats_chg_* tables in OpenBMP.
"""
count = args.count
interval = args.interval
print(f"Starting churn: {count} cycles, {interval}s interval")
print("This will populate ip_rib_log and stats_chg_* tables in OpenBMP.")
print("Press Ctrl+C to stop.\n")
cycle = 0
try:
while count == 0 or cycle < count:
cycle += 1
print(f"Cycle {cycle}: announcing churn scenario...")
r = _post('/scenario/churn')
print(f" + {r['count']} routes announced")
time.sleep(interval)
print(f"Cycle {cycle}: withdrawing churn scenario...")
r = _delete('/scenario/churn')
print(f" - {r['count']} routes withdrawn")
time.sleep(interval)
print()
except KeyboardInterrupt:
print("\nChurn stopped. Withdrawing any active routes...")
_post('/withdraw/all')
print("Done.")
def main():
parser = argparse.ArgumentParser(
description='ExaBGP Route Injection CLI',
formatter_class=argparse.RawDescriptionHelpFormatter,
)
sub = parser.add_subparsers(dest='command')
sub.add_parser('status', help='Show API health and peer states')
sub.add_parser('routes', help='List active announced routes')
sub.add_parser('scenarios', help='List available scenarios')
sub.add_parser('withdraw-all', help='Withdraw all active routes')
p = sub.add_parser('announce', help='Announce one or more prefixes')
p.add_argument('prefixes', nargs='+')
p.add_argument('--as-path', nargs='+', default=[], metavar='ASN')
p.add_argument('--community', nargs='+', default=[], metavar='COMM')
p.add_argument('--med', type=int, default=None)
p.add_argument('--next-hop', default='self', metavar='IP')
p = sub.add_parser('withdraw', help='Withdraw one or more prefixes')
p.add_argument('prefixes', nargs='+')
p = sub.add_parser('scenario', help='Load a named scenario')
p.add_argument('name')
p = sub.add_parser('withdraw-scenario', help='Withdraw a named scenario')
p.add_argument('name')
p = sub.add_parser('churn', help='Cycle announce/withdraw to populate ip_rib_log')
p.add_argument('--count', type=int, default=0, metavar='N',
help='Number of cycles (0 = infinite)')
p.add_argument('--interval', type=float, default=30.0, metavar='SEC',
help='Seconds between announce and withdraw (default: 30)')
args = parser.parse_args()
cmds = {
'status': cmd_status,
'routes': cmd_routes,
'scenarios': cmd_scenarios,
'announce': cmd_announce,
'withdraw': cmd_withdraw,
'withdraw-all': cmd_withdraw_all,
'scenario': cmd_scenario,
'withdraw-scenario': cmd_withdraw_scenario,
'churn': cmd_churn,
}
if not args.command:
parser.print_help()
sys.exit(1)
try:
cmds[args.command](args)
except requests.exceptions.ConnectionError:
print(f"ERROR: Cannot connect to ExaBGP API at {API}")
print("Is the exabgp container running? docker compose logs exabgp")
sys.exit(1)
except requests.exceptions.HTTPError as e:
print(f"ERROR: {e}")
sys.exit(1)
if __name__ == '__main__':
main()

172
exabgp/iosxr_bgp_config.md Normal file
View File

@ -0,0 +1,172 @@
# IOS-XR BGP Config for ExaBGP Peering
Apply to **both CORE routers** (`CML-R9K-CORE-01` @ 10.100.0.100 and
`CML-R9K-CORE-02` @ 10.100.0.200).
Credentials: `ssh user@<mgmt-ip>` password `cisco`
---
## Route Policy (apply once per router)
```
route-policy EXABGP_IN
pass
end-policy
route-policy EXABGP_OUT
drop
end-policy
```
---
## BGP Neighbor Block
```
router bgp 65020
neighbor 10.40.40.202
remote-as 65100
description ExaBGP-Route-Injector
ebgp-multihop 5
update-source MgmtEth0/RP0/CPU0/0
!
address-family ipv4 unicast
route-policy EXABGP_IN in
route-policy EXABGP_OUT out
next-hop-self
!
address-family ipv6 unicast
route-policy EXABGP_IN in
route-policy EXABGP_OUT out
next-hop-self
!
!
!
```
### Key config notes
| Knob | Why |
|------|-----|
| `remote-as 65100` | ExaBGP presents as AS 65100 (eBGP to your AS 65020 mesh) |
| `ebgp-multihop 5` | Host (10.40.40.202) and router (10.100.0.x) are different subnets |
| `update-source MgmtEth0/RP0/CPU0/0` | Use management interface for the TCP session |
| `next-hop-self` | Replace ExaBGP's next-hop (10.40.40.202) with the CORE router's loopback when reflecting into iBGP — ensures other routers can resolve the next-hop via ISIS |
| `EXABGP_OUT` drops | Prevent the lab from advertising its own prefixes back to ExaBGP |
---
## Verification Commands
```
show bgp neighbors 10.40.40.202
show bgp neighbors 10.40.40.202 received routes
show bgp summary
show route 1.1.1.0/24
show bgp 1.1.1.0/24
```
After loading the `internet_sample` scenario you should see ~94 new
prefixes in the BGP table and they should propagate to all 9 routers
via the iBGP mesh.
---
## NETCONF push (alternative to CLI)
With NETCONF already enabled, you can push this config programmatically:
```bash
pip install ncclient
python3 - <<'EOF'
from ncclient import manager
ROUTERS = [
{'host': '10.100.0.100', 'description': 'CML-R9K-CORE-01'},
{'host': '10.100.0.200', 'description': 'CML-R9K-CORE-02'},
]
POLICY_XML = """
<config>
<routing-policy xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-policy-repository-cfg">
<route-policies>
<route-policy>
<route-policy-name>EXABGP_IN</route-policy-name>
<rpl-route-policy>route-policy EXABGP_IN&#10; pass&#10;end-policy</rpl-route-policy>
</route-policy>
<route-policy>
<route-policy-name>EXABGP_OUT</route-policy-name>
<rpl-route-policy>route-policy EXABGP_OUT&#10; drop&#10;end-policy</rpl-route-policy>
</route-policy>
</route-policies>
</routing-policy>
<bgp xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ipv4-bgp-cfg">
<instance>
<instance-name>default</instance-name>
<instance-as>
<as>0</as>
<four-byte-as>
<as>65020</as>
<bgp-running/>
<default-vrf>
<bgp-entity>
<neighbors>
<neighbor>
<neighbor-address>10.40.40.202</neighbor-address>
<remote-as>
<as-xx>0</as-xx>
<as-yy>65100</as-yy>
</remote-as>
<description>ExaBGP-Route-Injector</description>
<ebgp-multihop>
<max-hop-count>5</max-hop-count>
</ebgp-multihop>
<update-in-filtering>
<enable/>
</update-in-filtering>
<neighbor-afs>
<neighbor-af>
<af-name>ipv4-unicast</af-name>
<activate/>
<route-policy-in>EXABGP_IN</route-policy-in>
<route-policy-out>EXABGP_OUT</route-policy-out>
<next-hop-self>true</next-hop-self>
</neighbor-af>
<neighbor-af>
<af-name>ipv6-unicast</af-name>
<activate/>
<route-policy-in>EXABGP_IN</route-policy-in>
<route-policy-out>EXABGP_OUT</route-policy-out>
<next-hop-self>true</next-hop-self>
</neighbor-af>
</neighbor-afs>
</neighbor>
</neighbors>
</bgp-entity>
</default-vrf>
</four-byte-as>
</instance-as>
</instance>
</bgp>
</config>
"""
for router in ROUTERS:
print(f"Configuring {router['description']} ({router['host']})...")
with manager.connect(
host=router['host'],
port=830,
username='user',
password='cisco',
hostkey_verify=False,
device_params={'name': 'iosxr'},
) as m:
m.edit_config(target='candidate', config=POLICY_XML)
m.commit()
print(f" Done.")
print("All routers configured.")
EOF
```

View File

@ -0,0 +1,315 @@
"""
BGP Route Injection Scenarios
Each scenario is a dict with:
description: str
routes: list of route dicts
Route dict keys:
prefix (required) e.g. "1.1.1.0/24"
next_hop default "self"
as_path list of ASNs, e.g. [65100, 1299, 15169]
communities list of strings, e.g. ["65100:100"]
med int, optional
local_pref int, optional
Well-known transit ASNs used in AS paths:
174 Cogent
701 Verizon / MCI
1299 Telia
2914 NTT
3257 GTT
3356 Lumen / Level3
6461 Zayo
6762 Sparkle / Telecom Italia
7018 AT&T
"""
# ---------------------------------------------------------------------------
# Helper to build route dicts quickly
# ---------------------------------------------------------------------------
def _r(prefix, as_path, communities=None, med=None, local_pref=None):
return {
'prefix': prefix,
'next_hop': 'self',
'as_path': as_path,
'communities': communities or [],
'med': med,
'local_pref': local_pref,
}
# ---------------------------------------------------------------------------
# Scenario: internet_sample
# Partial internet table — realistic mix of prefix lengths and AS paths.
# Prefixes are real public ranges with synthetic (but plausible) AS paths.
# ---------------------------------------------------------------------------
_INTERNET_V4 = [
# Cloudflare
_r('1.1.1.0/24', [65100, 174, 13335]),
_r('1.0.0.1/32', [65100, 3356, 13335]),
_r('104.16.0.0/13', [65100, 1299, 13335]),
_r('104.24.0.0/14', [65100, 6461, 13335]),
_r('162.158.0.0/15', [65100, 7018, 13335]),
_r('172.64.0.0/13', [65100, 2914, 13335]),
_r('198.41.128.0/17', [65100, 3257, 13335]),
# Google / Alphabet
_r('8.8.8.0/24', [65100, 3356, 15169]),
_r('8.8.4.0/24', [65100, 1299, 15169]),
_r('8.34.208.0/20', [65100, 6762, 15169]),
_r('34.0.0.0/15', [65100, 701, 15169]),
_r('35.190.0.0/17', [65100, 2914, 15169]),
_r('64.233.160.0/19', [65100, 3356, 15169]),
_r('66.102.0.0/20', [65100, 7018, 15169]),
_r('74.125.0.0/16', [65100, 174, 15169]),
_r('142.250.0.0/15', [65100, 3257, 15169]),
_r('172.217.0.0/16', [65100, 6461, 15169]),
_r('216.58.192.0/19', [65100, 1299, 15169]),
# Amazon AWS
_r('3.0.0.0/15', [65100, 3356, 16509]),
_r('13.32.0.0/15', [65100, 1299, 16509]),
_r('52.0.0.0/14', [65100, 6461, 16509]),
_r('52.84.0.0/15', [65100, 2914, 16509]),
_r('54.64.0.0/13', [65100, 701, 16509]),
_r('54.144.0.0/12', [65100, 174, 16509]),
_r('54.160.0.0/13', [65100, 3257, 16509]),
_r('99.77.128.0/18', [65100, 7018, 16509]),
_r('205.251.192.0/18',[65100, 3356, 16509]),
# Microsoft Azure
_r('13.64.0.0/11', [65100, 1299, 8075]),
_r('20.0.0.0/14', [65100, 6762, 8075]),
_r('20.33.0.0/16', [65100, 3356, 8075]),
_r('40.64.0.0/10', [65100, 2914, 8075]),
_r('52.224.0.0/11', [65100, 701, 8075]),
_r('104.40.0.0/13', [65100, 174, 8075]),
_r('168.61.0.0/16', [65100, 7018, 8075]),
# Akamai
_r('23.0.0.0/12', [65100, 3356, 20940]),
_r('23.32.0.0/11', [65100, 1299, 20940]),
_r('23.192.0.0/11', [65100, 6461, 20940]),
_r('92.122.0.0/15', [65100, 2914, 20940]),
_r('95.100.0.0/15', [65100, 3257, 20940]),
_r('184.24.0.0/13', [65100, 7018, 20940]),
# Fastly CDN
_r('23.235.32.0/20', [65100, 174, 54113]),
_r('103.244.50.0/24', [65100, 3356, 54113]),
_r('151.101.0.0/16', [65100, 1299, 54113]),
_r('157.52.192.0/18', [65100, 6461, 54113]),
_r('185.31.16.0/22', [65100, 2914, 54113]),
_r('199.27.72.0/21', [65100, 701, 54113]),
# Twitter / X
_r('104.244.42.0/24', [65100, 3356, 13414]),
_r('192.133.76.0/22', [65100, 1299, 13414]),
# Meta / Facebook
_r('31.13.24.0/21', [65100, 174, 32934]),
_r('31.13.64.0/18', [65100, 6762, 32934]),
_r('66.220.144.0/20', [65100, 7018, 32934]),
_r('69.63.176.0/20', [65100, 2914, 32934]),
_r('69.171.224.0/19', [65100, 3257, 32934]),
_r('157.240.0.0/17', [65100, 3356, 32934]),
_r('185.89.218.0/23', [65100, 701, 32934]),
_r('204.15.20.0/22', [65100, 1299, 32934]),
# Apple
_r('17.0.0.0/8', [65100, 1299, 714]),
_r('17.172.224.0/19', [65100, 6461, 714]),
_r('17.178.96.0/19', [65100, 2914, 714]),
_r('192.35.50.0/24', [65100, 3356, 714]),
# Comcast
_r('50.18.0.0/16', [65100, 7018, 7922]),
_r('73.0.0.0/8', [65100, 174, 7922]),
_r('96.0.0.0/11', [65100, 3257, 7922]),
# Verizon
_r('70.0.0.0/11', [65100, 3356, 701]),
_r('98.0.0.0/10', [65100, 1299, 701]),
_r('174.0.0.0/12', [65100, 6461, 701]),
# Generic transit destinations for AS path variety
_r('5.0.0.0/16', [65100, 1299, 6762, 34984]),
_r('45.86.0.0/16', [65100, 3257, 9002, 51847]),
_r('80.64.0.0/18', [65100, 174, 1239, 34224]),
_r('82.112.0.0/15', [65100, 6461, 5400, 12322]),
_r('89.0.0.0/17', [65100, 2914, 3491, 8551]),
_r('91.108.4.0/22', [65100, 701, 9002, 42831]),
_r('141.0.0.0/16', [65100, 7018, 1239, 6830]),
_r('185.0.0.0/22', [65100, 3356, 5400, 44946]),
_r('195.0.0.0/21', [65100, 1299, 3491, 30781]),
_r('212.0.0.0/16', [65100, 6762, 9002, 3301]),
_r('217.0.0.0/20', [65100, 174, 1239, 25160]),
]
_INTERNET_V6 = [
_r('2001:4860::/32', [65100, 3356, 15169]), # Google
_r('2001:4860:4860::/48', [65100, 1299, 15169]),
_r('2606:4700::/32', [65100, 174, 13335]), # Cloudflare
_r('2606:4700:4700::/48', [65100, 3356, 13335]),
_r('2400:cb00::/32', [65100, 2914, 13335]),
_r('2620:0:2d0::/48', [65100, 701, 2906]), # Netflix
_r('2600::/23', [65100, 6461, 16509]), # Amazon
_r('2a00:1450::/32', [65100, 1299, 15169]), # Google EU
_r('2001:8d8::/32', [65100, 3257, 20940]), # Akamai
_r('2620:1ec::/36', [65100, 7018, 8075]), # Microsoft
_r('2a03:2880::/32', [65100, 3356, 32934]), # Meta
_r('2001:df0::/32', [65100, 2914, 4837]), # China Unicom
_r('2001:500::/30', [65100, 174, 3356]), # ARIN
_r('2001:db8::/32', [65100, 1299, 65001]), # Documentation (RFC 3849)
]
# ---------------------------------------------------------------------------
# Scenario: churn
# 30 prefixes designed to be announced then withdrawn repeatedly.
# Load with /scenario/churn, withdraw with DELETE /scenario/churn.
# Run announce→withdraw→announce cycles to populate ip_rib_log.
# ---------------------------------------------------------------------------
_CHURN_PREFIXES = [
'198.51.100.0/24', # RFC 5737 documentation space
'198.51.101.0/24',
'198.51.102.0/24',
'198.51.103.0/24',
'198.51.104.0/24',
'198.51.105.0/24',
'198.51.106.0/24',
'198.51.107.0/24',
'198.51.108.0/24',
'198.51.109.0/24',
'203.0.113.0/24', # RFC 5737 documentation space
'203.0.113.1/32',
'203.0.113.2/32',
'203.0.113.3/32',
'203.0.113.4/32',
'100.64.0.0/24', # RFC 6598 shared address space
'100.64.1.0/24',
'100.64.2.0/24',
'100.64.3.0/24',
'100.64.4.0/24',
'192.0.2.0/24', # RFC 5737
'192.0.2.128/25',
'192.0.2.0/25',
'192.0.3.0/24',
'192.0.4.0/24',
'192.0.5.0/24',
'192.0.6.0/24',
'192.0.7.0/24',
'192.0.8.0/24',
'192.0.9.0/24',
]
_CHURN_ROUTES = [
_r(p, [65100, 65200], communities=['65100:200'])
for p in _CHURN_PREFIXES
]
# ---------------------------------------------------------------------------
# Scenario: blackhole
# Prefixes with RTBH (Remotely Triggered Black Hole) community.
# Community 65100:666 signals black-hole intent.
# Also includes the well-known BLACKHOLE community (65535:666).
# ---------------------------------------------------------------------------
_BLACKHOLE_ROUTES = [
_r('192.0.2.1/32', [65100], communities=['65100:666', '65535:666']),
_r('192.0.2.2/32', [65100], communities=['65100:666', '65535:666']),
_r('192.0.2.3/32', [65100], communities=['65100:666', '65535:666']),
_r('198.51.100.1/32',[65100], communities=['65100:666', '65535:666']),
_r('198.51.100.2/32',[65100], communities=['65100:666', '65535:666']),
]
# ---------------------------------------------------------------------------
# Scenario: anycast
# Same three prefixes announced with different AS paths and MEDs —
# simulates anycast competition (best-path selection testing).
# ---------------------------------------------------------------------------
_ANYCAST_ROUTES = [
# Anycast prefix 1 — two paths, different MED
_r('192.0.2.0/24', [65100, 65300], med=100),
# Anycast prefix 2 — longer AS path
_r('198.51.100.0/24', [65100, 65300, 65400], med=200),
# Anycast prefix 3 — shorter AS path, preferred
_r('203.0.113.0/24', [65100, 65200], med=50),
]
# ---------------------------------------------------------------------------
# Scenario: full_table
# 500+ prefixes simulating a large partial internet table.
# Built by expanding internet_sample with synthetic /24s.
# ---------------------------------------------------------------------------
def _gen_full_table():
routes = list(_INTERNET_V4) + list(_INTERNET_V6)
# Add synthetic /24 blocks from 100.x.x.0/24 space (RFC 6598)
transit_paths = [
[65100, 1299, 7922],
[65100, 3356, 16509],
[65100, 174, 15169],
[65100, 6461, 32934],
[65100, 2914, 8075],
[65100, 7018, 20940],
[65100, 1299, 54113],
[65100, 3356, 13335],
]
for i in range(100, 200):
for j in range(0, 256, 8):
path = transit_paths[((i - 100) + (j // 8)) % len(transit_paths)]
origin = 64512 + ((i * 32 + j // 8) % 1023)
routes.append(_r(f'100.{i}.{j}.0/24', path + [origin]))
return routes
# ---------------------------------------------------------------------------
# Scenario: lab_prefixes
# Mimics realistic enterprise/SP routes your lab routers would see.
# Useful for testing policy: communities, local-pref, AS path filtering.
# ---------------------------------------------------------------------------
_LAB_ROUTES = [
# Customer routes (shorter AS path, higher local-pref via community)
_r('10.200.0.0/24', [65100, 65500], communities=['65100:100'], local_pref=200),
_r('10.200.1.0/24', [65100, 65500], communities=['65100:100'], local_pref=200),
_r('10.200.2.0/24', [65100, 65500], communities=['65100:100'], local_pref=200),
# Peer routes (medium preference)
_r('10.201.0.0/22', [65100, 65600], communities=['65100:200'], local_pref=150),
_r('10.201.4.0/22', [65100, 65600], communities=['65100:200'], local_pref=150),
# Transit routes (longer path, lower preference)
_r('10.202.0.0/20', [65100, 1299, 65700], communities=['65100:300'], local_pref=100),
_r('10.202.16.0/20', [65100, 3356, 65700], communities=['65100:300'], local_pref=100),
# Default route
_r('0.0.0.0/0', [65100, 3356], communities=['65100:400']),
]
# ---------------------------------------------------------------------------
# Registry
# ---------------------------------------------------------------------------
SCENARIOS = {
'internet_sample': {
'description': 'Partial internet table (~80 IPv4 + 14 IPv6 prefixes with realistic AS paths)',
'routes': _INTERNET_V4 + _INTERNET_V6,
},
'churn': {
'description': '30 RFC documentation prefixes for announce/withdraw churn testing',
'routes': _CHURN_ROUTES,
},
'blackhole': {
'description': '5 /32 prefixes with RTBH community (65100:666 + 65535:666)',
'routes': _BLACKHOLE_ROUTES,
},
'anycast': {
'description': '3 prefixes with varying AS paths and MEDs for best-path testing',
'routes': _ANYCAST_ROUTES,
},
'full_table': {
'description': '500+ prefixes simulating a large partial internet table',
'routes': _gen_full_table(),
},
'lab_prefixes': {
'description': 'Enterprise/SP-style routes with communities and local-pref for policy testing',
'routes': _LAB_ROUTES,
},
}

67
exabgp/startup.sh Normal file
View File

@ -0,0 +1,67 @@
#!/bin/bash
set -e
LOCAL_IP=${EXABGP_LOCAL_IP:-10.40.40.202}
LOCAL_AS=${EXABGP_LOCAL_AS:-65100}
PEER_AS=${EXABGP_PEER_AS:-65020}
PEER_1=${EXABGP_PEER_1:-10.100.0.100}
PEER_2=${EXABGP_PEER_2:-10.100.0.200}
API_PORT=${EXABGP_API_PORT:-5050}
echo "================================================================"
echo " ExaBGP Route Injector"
echo " Local: ${LOCAL_IP} AS${LOCAL_AS}"
echo " Peers: ${PEER_1}, ${PEER_2} (AS${PEER_AS})"
echo " API: http://0.0.0.0:${API_PORT}"
echo "================================================================"
# Generate ExaBGP 5.x env file — ExaBGP looks here based on pip install prefix
mkdir -p /usr/local/etc/exabgp
exabgp env > /usr/local/etc/exabgp/exabgp.env
sed -i 's/drop = true/drop = false/' /usr/local/etc/exabgp/exabgp.env
sed -i 's/cli = true/cli = false/' /usr/local/etc/exabgp/exabgp.env
sed -i "s/destination = 'stdout'/destination = 'stderr'/" /usr/local/etc/exabgp/exabgp.env
# Generate exabgp.conf from environment
cat > /tmp/exabgp.conf << EOF
process api {
run /usr/local/bin/python3 /exabgp/api/server.py;
encoder text;
}
neighbor ${PEER_1} {
router-id ${LOCAL_IP};
local-address ${LOCAL_IP};
local-as ${LOCAL_AS};
peer-as ${PEER_AS};
description "CML-R9K-CORE-01";
hold-time 90;
family {
ipv4 unicast;
}
api {
processes [ api ];
}
}
neighbor ${PEER_2} {
router-id ${LOCAL_IP};
local-address ${LOCAL_IP};
local-as ${LOCAL_AS};
peer-as ${PEER_AS};
description "CML-R9K-CORE-02";
hold-time 90;
family {
ipv4 unicast;
}
api {
processes [ api ];
}
}
EOF
exec exabgp server /tmp/exabgp.conf

6
obmp-grafana/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.DS_Store
.idea
*.log
*.pyc
*.tgz
*.gz

26
obmp-grafana/LICENSE Normal file
View File

@ -0,0 +1,26 @@
Copyright 2021 Cisco Systems, Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

12
obmp-grafana/README.md Normal file
View File

@ -0,0 +1,12 @@
# OpenBMP Grafana Integration
Grafana can be used with the OpenBMP PostgreSQL backend to visualize BGP data and statistics.
## Install/Run Grafana
Install/run grafana. See [grafana in openbmp compose](https://github.com/OpenBMP/obmp-docker/blob/main/docker-compose.yml) for
details on how you can run the Grafana container.
## Grafana Provisioning
This repo is structured to support [Grafana Provisioning](https://grafana.com/docs/grafana/latest/administration/provisioning/).
For the most part, this repo can be cloned directly in to the ```/etc/grafana/provisioning``` directory.

View File

@ -0,0 +1,237 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 1,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 3,
"w": 24,
"x": 0,
"y": 0
},
"id": 6,
"links": [],
"options": {
"content": "# OpenBMP\n\n*Select a dashboard*",
"mode": "markdown"
},
"pluginVersion": "8.5.4",
"type": "text"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 18,
"w": 4,
"x": 0,
"y": 3
},
"id": 7,
"links": [],
"options": {
"maxItems": 41,
"query": "",
"showHeadings": true,
"showRecentlyViewed": false,
"showSearch": true,
"showStarred": false,
"tags": [
"obmp-tops"
]
},
"pluginVersion": "8.5.4",
"tags": [],
"title": "Tops",
"type": "dashlist"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 18,
"w": 5,
"x": 4,
"y": 3
},
"id": 8,
"links": [],
"options": {
"maxItems": 41,
"query": "",
"showHeadings": true,
"showRecentlyViewed": false,
"showSearch": true,
"showStarred": false,
"tags": [
"obmp-base"
]
},
"pluginVersion": "8.5.4",
"tags": [],
"title": "Base",
"type": "dashlist"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 18,
"w": 5,
"x": 9,
"y": 3
},
"id": 4,
"links": [],
"options": {
"maxItems": 41,
"query": "",
"showHeadings": true,
"showRecentlyViewed": false,
"showSearch": true,
"showStarred": false,
"tags": [
"obmp-history"
]
},
"pluginVersion": "8.5.4",
"tags": [],
"title": "Prefix History",
"type": "dashlist"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 18,
"w": 5,
"x": 14,
"y": 3
},
"id": 9,
"links": [],
"options": {
"maxItems": 41,
"query": "",
"showHeadings": true,
"showRecentlyViewed": false,
"showSearch": true,
"showStarred": false,
"tags": [
"obmp-l3vpn"
]
},
"pluginVersion": "8.5.4",
"tags": [],
"title": "L3VPN",
"type": "dashlist"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 18,
"w": 5,
"x": 19,
"y": 3
},
"id": 3,
"links": [],
"options": {
"maxItems": 41,
"query": "",
"showHeadings": true,
"showRecentlyViewed": false,
"showSearch": true,
"showStarred": false,
"tags": [
"obmp-linkstate"
]
},
"pluginVersion": "8.5.4",
"tags": [],
"title": "Link State",
"type": "dashlist"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "OBMP-Home",
"uid": "obmp-home",
"version": 1,
"weekStart": ""
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,506 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 4,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "up"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "light-green",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "down"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "light-red",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 11,
"w": 4,
"x": 0,
"y": 0
},
"id": 3,
"links": [],
"maxDataPoints": 3,
"options": {
"displayLabels": [],
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "bottom",
"values": [
"value",
"percent"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n count(distinct router_hash_id) as value,\n r.state as metric\nFROM routers r\n JOIN bgp_peers p on (r.hash_id = p.router_hash_id)\n group by r.state\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Router Status",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 11,
"w": 20,
"x": 4,
"y": 0
},
"id": 1,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "8.5.4",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select max(r.timestamp) as timestamp,r.name,max(ip_address) as ip_address,max(r.state) as state,\n count(*) as peers,max(description) as description, CASE WHEN max(r.state) = 'up' THEN 1 ELSE 0 END as stateBool\n from routers r\n JOIN bgp_peers p on (r.hash_id = p.router_hash_id)\n GROUP BY r.name;",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Routers",
"type": "table"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "up"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "light-green",
"mode": "fixed"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "down"
},
"properties": [
{
"id": "color",
"value": {
"fixedColor": "light-red",
"mode": "fixed"
}
}
]
}
]
},
"gridPos": {
"h": 7,
"w": 4,
"x": 0,
"y": 11
},
"id": 4,
"links": [],
"maxDataPoints": 3,
"options": {
"displayLabels": [],
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "bottom",
"sortBy": "Value",
"sortDesc": true,
"values": [
"value",
"percent"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"last"
],
"fields": "",
"values": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "8.3.4",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n state as metric,\n count(*) value\nFROM bgp_peers\ngroup by metric",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Peer Status",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 14,
"w": 20,
"x": 4,
"y": 11
},
"id": 2,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": [
{
"desc": true,
"displayName": "IPv4 Prefixes"
}
]
},
"pluginVersion": "8.5.4",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": " SELECT\n max(RouterName) as \"RouterName\",\n max(PeerName) as \"PeerName\",\n max(PeerIP) as \"PeerIP\",\n max(PeerASN) as \"PeerASN\",\n max(peer_state) as \"State\",\n max(LastModified) as \"LastModified\",\n max(v4_prefixes) as \"IPv4 Prefixes\",\n max(v6_prefixes) as \"IPv6 Prefixes\",\n CASE WHEN max(peer_state) = 'up' THEN 1 ELSE 0 END as stateBool\nFROM v_peers p\n LEFT JOIN stats_peer_rib s ON (p.peer_hash_id = s.peer_hash_id\n AND s.interval_time >= now() - interval '20 minutes')\nGROUP BY p.peer_hash_id;\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Peers",
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-base"
],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "utc",
"title": "Inventory",
"uid": "inventory",
"version": 3,
"weekStart": ""
}

View File

@ -0,0 +1,910 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 5,
"iteration": 1654877090626,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"uid": "obmp-postgres"
},
"gridPos": {
"h": 3,
"w": 12,
"x": 0,
"y": 0
},
"id": 15,
"links": [],
"options": {
"content": "# Looking Glass\n\n> Enter an IP address with or without bit length. The longest matched prefix will be used. Specify the length to find exact match or best aggregate.",
"mode": "markdown"
},
"pluginVersion": "8.5.4",
"type": "text"
},
{
"circleMaxSize": "15",
"circleMinSize": 2,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"decimals": 0,
"esMetric": "Count",
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"hideEmpty": false,
"hideZero": false,
"id": 17,
"initialZoom": "1",
"locationData": "table",
"mapCenter": "(0°, 0°)",
"mapCenterLatitude": 0,
"mapCenterLongitude": 0,
"maxDataPoints": 1,
"mouseWheelZoom": false,
"showLegend": false,
"stickyLabels": false,
"tableQueryOptions": {
"geohashField": "geohash",
"labelField": "name",
"latitudeField": "latitude",
"longitudeField": "longitude",
"metricField": "value",
"queryType": "coordinates"
},
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n 10 as value, latitude, longitude, stateprov as name\nFROM geo_ip\nWHERE\n ip && '$input'\nORDER BY ip desc limit 1",
"refId": "A",
"select": [
[
{
"params": [
"latitude"
],
"type": "column"
}
]
],
"table": "v_ip_routes_geo",
"timeColumn": "lastmodified",
"timeColumnType": "timestamp",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"thresholds": "0,10",
"title": "Prefix Location",
"type": "grafana-worldmap-panel",
"unitPlural": "",
"unitSingle": "",
"valueName": "current"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"description": "Prefix found in router's RIB.",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 5,
"w": 6,
"x": 0,
"y": 3
},
"id": 9,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value",
"percent"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n floor(extract(epoch from max(r.timestamp))) as time,\n CASE WHEN v.router_hash_id is null THEN 'Not in Router RIB' ELSE 'In Router Rib' END as metric,\n 1 as value\nFROM routers r\n left join (select distinct router_hash_id\n from v_ip_routes \n where prefix = '$prefix'\n and iswithdrawn = false group by router_hash_id) v \n on (r.hash_id = v.router_hash_id)\nWHERE r.state = 'up'\nGROUP BY r.hash_id,v.router_hash_id\norder by time\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Router Visibility",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"description": "Prefix found in peer RIB's",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 5,
"w": 6,
"x": 6,
"y": 3
},
"id": 10,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value",
"percent"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n floor(extract(epoch from max(p.timestamp))) as time,\n CASE WHEN v.peer_hash_id is null THEN 'Not in Peers RIB' ELSE 'In Peer RIB' END as metric,\n 1 as value\nFROM bgp_peers p\n left join (select peer_hash_id,isipv4\n from v_ip_routes \n where prefix = '$prefix' and prefix != '0.0.0.0/0'\n and iswithdrawn = false group by peer_hash_id,isipv4) v \n on (p.hash_id = v.peer_hash_id)\nWHERE p.isipv4 = CASE WHEN family('$prefix') = 4 THEN true ELSE false END\n AND p.state = 'up'\nGROUP BY p.hash_id,v.peer_hash_id,p.isipv4\norder by time\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Peer Visibility",
"type": "piechart"
},
{
"columns": [],
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fontSize": "100%",
"gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 8
},
"id": 12,
"links": [],
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"align": "auto",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "date"
},
{
"alias": "",
"align": "auto",
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"mappingType": 1,
"pattern": "raw_output",
"preserveFormat": true,
"sanitize": false,
"thresholds": [],
"type": "string",
"unit": "short"
},
{
"alias": "",
"align": "auto",
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "string",
"unit": "short"
}
],
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select distinct origin_as,i.as_name,org_id,org_name,remarks,address,city,state_prov,country,raw_output,source\n from ip_rib r LEFT JOIN info_asn i ON (i.asn = r.origin_as)\n where r.prefix = '$prefix' \n and origin_as > 0\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "ASN Info",
"transform": "table",
"type": "table-old"
},
{
"columns": [],
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fontSize": "100%",
"gridPos": {
"h": 4,
"w": 24,
"x": 0,
"y": 14
},
"id": 13,
"links": [],
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"align": "auto",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "date"
},
{
"alias": "",
"align": "auto",
"colorMode": "cell",
"colors": [
"#cca300",
"#e24d42",
"#9ac48a"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"mappingType": 1,
"pattern": "irr_origin_as",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "none"
},
{
"alias": "",
"align": "auto",
"colorMode": "cell",
"colors": [
"#cca300",
"#e24d42",
"#9ac48a"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"mappingType": 1,
"pattern": "rpki_origin_as",
"thresholds": [
"0",
"1"
],
"type": "number",
"unit": "none"
},
{
"alias": "",
"align": "auto",
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "string",
"unit": "short"
}
],
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select distinct r.origin_as as recv_origin_as,\n CASE WHEN g.rpki_origin_as is null THEN 0 ELSE g.rpki_origin_as END as rpki_origin_as,\n CASE WHEN i.origin_as is null THEN 0 ELSE i.origin_as END as irr_origin_as,\n i.descr,i.source\n from ip_rib r \n LEFT JOIN info_route i ON (i.prefix = r.prefix)\n LEFT JOIN global_ip_rib g ON (g.prefix = r.prefix)\n where r.prefix = '$prefix'\n and r.origin_as > 0\n AND r.peer_hash_id in ($peer_hash)\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefix Info",
"transform": "table",
"type": "table-old"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "locale"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "displayName",
"value": "Time"
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "prefix"
},
"properties": [
{
"id": "displayName",
"value": "Prefix"
},
{
"id": "unit",
"value": "short"
},
{
"id": "decimals",
"value": 2
},
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "Prefix History ",
"url": "/d/prefix-hist/prefix-history-by-prefix?orgId=1&var-prefix=${__value.text}&var-input=${__value.text}"
}
]
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "origin_as"
},
"properties": [
{
"id": "displayName",
"value": "Origin"
},
{
"id": "unit",
"value": "none"
},
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "ASN View",
"url": "d/asnview-agg/asn-view?orgId=1&var-asn_num=${__value.text}"
}
]
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "iswithdrawn"
},
"properties": [
{
"id": "displayName",
"value": "Withdrawn"
},
{
"id": "unit",
"value": "bool"
},
{
"id": "custom.displayMode",
"value": "color-background-solid"
},
{
"id": "custom.align",
"value": "auto"
},
{
"id": "color",
"value": {
"mode": "continuous-GrYlRd"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "Time"
},
"properties": [
{
"id": "custom.width",
"value": 194
}
]
}
]
},
"gridPos": {
"h": 23,
"w": 24,
"x": 0,
"y": 18
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "8.5.4",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select distinct ip.*, \n \tFIRST_VALUE(geo_ip.city) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as city,\n \tFIRST_VALUE(geo_ip.stateprov) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as stateprov,\n \tFIRST_VALUE(geo_ip.country) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as country,\n ls.local_router_name\n\tFROM (SELECT lastmodified,peername,prefix,\n \tiswithdrawn,origin_as,med,localpref,nh,as_path,communities\n from v_ip_routes\n \t\twhere prefix && '$input' and prefixlen <= 32 AND prefixlen > 0\n \t\t AND peer_hash_id in ($peer_hash)\n \t\tlimit 2000\n \t) ip\n\t\tLEFT JOIN geo_ip on (geo_ip.ip >>= ip.prefix AND geo_ip.ip != '0.0.0.0/0')\n LEFT JOIN v_ls_prefixes ls ON (ls.prefix >>= ip.nh and length(ls.local_router_name) > 0)",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Looking Glass",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-base"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "17.44.224.0/22",
"value": "17.44.224.0/22"
},
"hide": 0,
"label": "Prefix/IP",
"name": "input",
"options": [
{
"selected": false,
"text": "3.235.73.1",
"value": "3.235.73.1"
}
],
"query": "17.44.224.0/22",
"queryValue": "50.227.215.188",
"skipUrlSync": false,
"type": "textbox"
},
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from routers where state = 'up'",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select name as __text, hash_id as __value from routers where state = 'up'",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash)",
"hide": 0,
"includeAll": true,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": false,
"text": "17.44.224.0/22",
"value": "17.44.224.0/22"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select prefix from ip_rib \nwhere prefix >>= '$input' and peer_hash_id in ($peer_hash) \norder by prefix desc limit 1",
"hide": 2,
"includeAll": false,
"multi": false,
"name": "prefix",
"options": [],
"query": "select prefix from ip_rib \nwhere prefix >>= '$input' and peer_hash_id in ($peer_hash) \norder by prefix desc limit 1",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Looking Glass",
"uid": "lookingglass",
"version": 4,
"weekStart": ""
}

View File

@ -0,0 +1,644 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 7,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"links": [],
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 11,
"x": 0,
"y": 0
},
"id": 1,
"links": [],
"options": {
"legend": {
"calcs": [
"mean",
"max",
"sum"
],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "8.0.5",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n $__timeGroup(interval_time, $__interval) as time,\n sum(updates) as updates, sum(withdraws) as withdraws\nFROM stats_chg_byasn s\nWHERE $__timeFilter(interval_time)\n AND s.origin_as = [[origin_as]]\n AND s.peer_hash_id in ($peer_hash)\n\ngroup by time\nORDER BY time ASC\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefix Advertisements & Withdrawals",
"type": "timeseries"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": true,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 13,
"x": 11,
"y": 0
},
"id": 2,
"links": [],
"options": {
"legend": {
"calcs": [
"mean",
"max",
"sum"
],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "8.0.5",
"targets": [
{
"alias": "",
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n $__timeGroup(interval_time, $__interval) as time,\n sum(updates) as updates, sum(withdraws) as withdraws,\n left(PeerName,32) as metric\nFROM stats_chg_byasn l\n JOIN v_peers p ON (l.peer_hash_id = p.peer_hash_id)\nWHERE $__timeFilter(interval_time)\n AND l.origin_as = [[origin_as]]\n AND l.peer_hash_id in ($peer_hash)\n\nGROUP BY peername,time\nORDER BY time ASC\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Changes by Peer",
"type": "timeseries"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.width",
"value": 201
}
]
},
{
"matcher": {
"id": "byName",
"options": "origin_as"
},
"properties": [
{
"id": "custom.width",
"value": 118
}
]
},
{
"matcher": {
"id": "byName",
"options": "localpref"
},
"properties": [
{
"id": "custom.width",
"value": 76
}
]
},
{
"matcher": {
"id": "byName",
"options": "communities"
},
"properties": [
{
"id": "custom.width",
"value": 525
}
]
},
{
"matcher": {
"id": "byName",
"options": "as_path"
},
"properties": [
{
"id": "custom.width",
"value": 252
}
]
},
{
"matcher": {
"id": "byName",
"options": "med"
},
"properties": [
{
"id": "custom.width",
"value": 87
}
]
},
{
"matcher": {
"id": "byName",
"options": "nh"
},
"properties": [
{
"id": "custom.width",
"value": 136
}
]
},
{
"matcher": {
"id": "byName",
"options": "prefix"
},
"properties": [
{
"id": "custom.width",
"value": 206
}
]
},
{
"matcher": {
"id": "byName",
"options": "event"
},
"properties": [
{
"id": "custom.width",
"value": 113
}
]
},
{
"matcher": {
"id": "byName",
"options": "routername"
},
"properties": [
{
"id": "custom.width",
"value": 142
}
]
},
{
"matcher": {
"id": "byName",
"options": "peername"
},
"properties": [
{
"id": "custom.width",
"value": 283
}
]
}
]
},
"gridPos": {
"h": 20,
"w": 24,
"x": 0,
"y": 7
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "9.1.7",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": " select lastmodified,event,routername,peername,prefix,nh,\n origin_as,localpref,med,as_path,communities\n from v_ip_routes_history \n where $__timeFilter(lastmodified)\n AND origin_as = [[origin_as]]\n AND peer_hash_id in ($peer_hash)\n\n order by lastmodified desc,id desc\n limit $limit;",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefix History",
"type": "table"
}
],
"refresh": "",
"schemaVersion": 37,
"style": "dark",
"tags": [
"obmp-history"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "16509",
"value": "16509"
},
"hide": 0,
"label": "Origin ASN",
"name": "origin_as",
"options": [
{
"selected": true,
"text": "0",
"value": "0"
}
],
"query": "0",
"skipUrlSync": false,
"type": "textbox"
},
{
"current": {
"selected": false,
"text": "1000",
"value": "1000"
},
"hide": 0,
"includeAll": false,
"label": "Limit",
"multi": false,
"name": "limit",
"options": [
{
"selected": true,
"text": "1000",
"value": "1000"
},
{
"selected": false,
"text": "5000",
"value": "5000"
},
{
"selected": false,
"text": "10000",
"value": "10000"
}
],
"query": "1000,5000,10000",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from routers",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select name as __text, hash_id as __value from routers",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) ",
"hide": 0,
"includeAll": true,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) ",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
}
]
},
"time": {
"from": "now-24h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Prefix History (by ASN)",
"uid": "prefix-hist-asn",
"version": 2,
"weekStart": ""
}

View File

@ -0,0 +1,376 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 8,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "custom.width",
"value": 214
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
}
]
},
{
"matcher": {
"id": "byName",
"options": "localpref"
},
"properties": [
{
"id": "custom.width",
"value": 107
}
]
},
{
"matcher": {
"id": "byName",
"options": "med"
},
"properties": [
{
"id": "custom.width",
"value": 79
}
]
},
{
"matcher": {
"id": "byName",
"options": "nh"
},
"properties": [
{
"id": "custom.width",
"value": 122
}
]
},
{
"matcher": {
"id": "byName",
"options": "origin_as"
},
"properties": [
{
"id": "custom.width",
"value": 112
}
]
},
{
"matcher": {
"id": "byName",
"options": "prefix"
},
"properties": [
{
"id": "custom.width",
"value": 148
}
]
},
{
"matcher": {
"id": "byName",
"options": "routername"
},
"properties": [
{
"id": "custom.width",
"value": 216
}
]
},
{
"matcher": {
"id": "byName",
"options": "event"
},
"properties": [
{
"id": "custom.width",
"value": 112
}
]
},
{
"matcher": {
"id": "byName",
"options": "peername"
},
"properties": [
{
"id": "custom.width",
"value": 310
}
]
}
]
},
"gridPos": {
"h": 23,
"w": 23,
"x": 0,
"y": 0
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "9.1.7",
"targets": [
{
"alias": "",
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": " select lastmodified,event,routername,peername,prefix,\n origin_as,nh,localpref,med,as_path,communities \n from v_ip_routes_history \n where $__timeFilter(lastmodified)\n AND peer_hash_id in ($peer_hash)\n AND communities && '{$community}'\n order by lastmodified desc,id desc\n limit $limit;",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefix History",
"type": "table"
}
],
"schemaVersion": 37,
"style": "dark",
"tags": [
"obmp-history"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "13445:1000",
"value": "13445:1000"
},
"hide": 0,
"includeAll": false,
"label": "Community",
"multi": false,
"name": "community",
"options": [
{
"selected": true,
"text": "13445:1000",
"value": "13445:1000"
}
],
"query": "13445:1000",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from routers",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select name as __text, hash_id as __value from routers",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash)",
"hide": 0,
"includeAll": true,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": false,
"text": "1000",
"value": "1000"
},
"hide": 0,
"includeAll": false,
"label": "Limit",
"multi": false,
"name": "limit",
"options": [
{
"selected": true,
"text": "1000",
"value": "1000"
},
{
"selected": false,
"text": "5000",
"value": "5000"
},
{
"selected": false,
"text": "10000",
"value": "10000"
}
],
"query": "1000, 5000, 10000",
"skipUrlSync": false,
"type": "custom"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Prefix History (by Community)",
"uid": "prefix-hist-comm",
"version": 2,
"weekStart": ""
}

View File

@ -0,0 +1,677 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"description": "",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 9,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.width",
"value": 224
}
]
}
]
},
"gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 0
},
"id": 5,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "9.1.7",
"targets": [
{
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select lastmodified,CASE WHEN iswithdrawn THEN 'Withdrawn' ELSE 'Active' END as state,routername,peername,prefix,prefixlen,\n origin_as,med,localpref,nh,as_path,communities \n from v_ip_routes \n where peer_hash_id in ($peer_hash) \n ${prefix_clause:raw}\n limit $limit\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Current RIB State",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"type": "table"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"decimals": 0,
"fieldConfig": {
"defaults": {
"links": []
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 7,
"w": 11,
"x": 0,
"y": 6
},
"hiddenSeries": false,
"id": 1,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": true,
"min": false,
"show": true,
"total": true,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "9.1.7",
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "",
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n interval_time as time,\n sum(updates) as updates, sum(withdraws) as withdraws\nFROM stats_chg_byprefix s\nWHERE $__timeFilter(interval_time)\n AND peer_hash_id in ($peer_hash)\n ${prefix_clause:raw}\n\ngroup by interval_time\nORDER BY interval_time ASC\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"thresholds": [],
"timeRegions": [],
"title": "Prefix Advertisements & Withdrawals",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:289",
"format": "none",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:290",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"decimals": 0,
"fieldConfig": {
"defaults": {
"links": []
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 7,
"w": 13,
"x": 11,
"y": 6
},
"hiddenSeries": false,
"id": 2,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": true,
"min": false,
"rightSide": true,
"show": true,
"sort": "total",
"sortDesc": true,
"total": true,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "9.1.7",
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "",
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n interval_time as time,\n sum(updates) + sum(withdraws) as value,\n left(PeerName,32) as metric\nFROM stats_chg_byprefix s\n JOIN v_peers p ON (s.peer_hash_id = p.peer_hash_id)\nWHERE $__timeFilter(interval_time)\n AND s.peer_hash_id in ($peer_hash)\n ${prefix_clause:raw}\n\nGROUP BY s.interval_time,peername\nORDER BY interval_time ASC\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"thresholds": [],
"timeRegions": [],
"title": "Changes by Peer",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:346",
"decimals": 0,
"format": "none",
"label": "",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:347",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "displayName",
"value": "Last Modified"
}
]
},
{
"matcher": {
"id": "byName",
"options": "Last Modified"
},
"properties": [
{
"id": "custom.width",
"value": 208
}
]
},
{
"matcher": {
"id": "byName",
"options": "communities"
},
"properties": [
{
"id": "custom.width",
"value": 402
}
]
}
]
},
"gridPos": {
"h": 20,
"w": 24,
"x": 0,
"y": 13
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": [
{
"desc": true,
"displayName": "Last Modified"
}
]
},
"pluginVersion": "9.1.7",
"targets": [
{
"alias": "",
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": " select lastmodified,event,routername,peername,prefix,nh,\n origin_as,as_path,communities,localpref,med\n from v_ip_routes_history \n where $__timeFilter(lastmodified)\n AND peer_hash_id in ($peer_hash)\n ${prefix_clause:raw}\n \n order by lastmodified desc,id desc\n limit $limit;",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefix History",
"type": "table"
}
],
"refresh": "",
"schemaVersion": 37,
"style": "dark",
"tags": [
"obmp-history"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from routers\n",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select name as __text, hash_id as __value from routers\n",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) ",
"hide": 0,
"includeAll": true,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) ",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": false,
"text": "1000",
"value": "1000"
},
"hide": 0,
"includeAll": false,
"label": "Limit",
"multi": false,
"name": "limit",
"options": [
{
"selected": true,
"text": "1000",
"value": "1000"
},
{
"selected": false,
"text": "5000",
"value": "5000"
},
{
"selected": false,
"text": "10000",
"value": "10000"
}
],
"query": "1000,5000,10000",
"queryValue": "",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": false,
"text": "187.249.2.0/24",
"value": "187.249.2.0/24"
},
"hide": 0,
"label": "Prefix",
"name": "input",
"options": [
{
"selected": true,
"text": "187.249.2.0/24",
"value": "187.249.2.0/24"
}
],
"query": "187.249.2.0/24",
"queryValue": "67.211.53.0/24",
"skipUrlSync": false,
"type": "textbox"
},
{
"current": {
"selected": false,
"text": "AND prefix = '187.249.2.0/24'",
"value": "AND prefix = '187.249.2.0/24'"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select CASE WHEN '$input' != '-' THEN 'AND prefix = ''' || (select prefix from global_ip_rib where prefix >>= (CASE WHEN '$input' != '-' THEN '$input' ELSE '0/0' END)::inet order by prefix desc limit 1)::text || '''' ELSE '' END;",
"hide": 2,
"includeAll": false,
"multi": false,
"name": "prefix_clause",
"options": [],
"query": "select CASE WHEN '$input' != '-' THEN 'AND prefix = ''' || (select prefix from global_ip_rib where prefix >>= (CASE WHEN '$input' != '-' THEN '$input' ELSE '0/0' END)::inet order by prefix desc limit 1)::text || '''' ELSE '' END;",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
}
]
},
"time": {
"from": "now-3h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Prefix History (by Prefix)",
"uid": "prefix-hist",
"version": 2,
"weekStart": ""
}

View File

@ -0,0 +1,780 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 19,
"iteration": 1654877653557,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"description": "Prefix found in router's RIB.",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 5,
"w": 6,
"x": 0,
"y": 0
},
"id": 9,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value",
"percent"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n floor(extract(epoch from max(r.timestamp))) as time,\n CASE WHEN v.router_hash_id is null THEN 'Not in Router RIB' ELSE 'In Router Rib' END as metric,\n 1 as value\nFROM routers r\n left join (select distinct router_hash_id\n from v_l3vpn_routes\n where prefix = '$prefix'\n and ('$rd' = '-' OR rd = '$rd')\n and iswithdrawn = false group by router_hash_id) v \n on (r.hash_id = v.router_hash_id)\nWHERE r.state = 'up'\nGROUP BY r.hash_id,v.router_hash_id\norder by time\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Router Visibility",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"description": "Prefix found in peer RIB's",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 5,
"w": 6,
"x": 6,
"y": 0
},
"id": 10,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value",
"percent"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n floor(extract(epoch from max(p.timestamp))) as time,\n CASE WHEN v.peer_hash_id is null THEN 'Not in Peers RIB' ELSE 'In Peer RIB' END as metric,\n 1 as value\nFROM bgp_peers p\n left join (select peer_hash_id,isipv4\n from l3vpn_rib \n where prefix = '$prefix' and prefix != '0.0.0.0/0'\n AND ('$rd' = '-' OR rd = '$rd')\n and iswithdrawn = false group by peer_hash_id,isipv4) v \n on (p.hash_id = v.peer_hash_id)\nWHERE p.isipv4 = CASE WHEN family('$prefix') = 4 THEN true ELSE false END\n AND p.state = 'up'\nGROUP BY p.hash_id,v.peer_hash_id,p.isipv4\norder by time\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Peer Visibility",
"type": "piechart"
},
{
"circleMaxSize": "15",
"circleMinSize": 2,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"decimals": 0,
"esMetric": "Count",
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"hideEmpty": false,
"hideZero": false,
"id": 17,
"initialZoom": "1",
"locationData": "table",
"mapCenter": "(0°, 0°)",
"mapCenterLatitude": 0,
"mapCenterLongitude": 0,
"maxDataPoints": 1,
"mouseWheelZoom": false,
"showLegend": false,
"stickyLabels": false,
"tableQueryOptions": {
"geohashField": "geohash",
"labelField": "name",
"latitudeField": "latitude",
"longitudeField": "longitude",
"metricField": "value",
"queryType": "coordinates"
},
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n 10 as value, latitude, longitude, stateprov as name\nFROM geo_ip\nWHERE\n ip && '$input'\nORDER BY ip desc limit 1",
"refId": "A",
"select": [
[
{
"params": [
"latitude"
],
"type": "column"
}
]
],
"table": "v_ip_routes_geo",
"timeColumn": "lastmodified",
"timeColumnType": "timestamp",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"thresholds": "0,10",
"title": "Prefix Location",
"type": "grafana-worldmap-panel",
"unitPlural": "",
"unitSingle": "",
"valueName": "current"
},
{
"columns": [],
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fontSize": "100%",
"gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 8
},
"id": 12,
"links": [],
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"align": "auto",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "date"
},
{
"alias": "",
"align": "auto",
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"mappingType": 1,
"pattern": "raw_output",
"preserveFormat": true,
"sanitize": false,
"thresholds": [],
"type": "string",
"unit": "short"
},
{
"alias": "",
"align": "auto",
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "string",
"unit": "short"
}
],
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select distinct origin_as,i.as_name,org_id,org_name,remarks,address,city,state_prov,country,raw_output,source\n from l3vpn_rib r LEFT JOIN info_asn i ON (i.asn = r.origin_as)\n where r.prefix = '$prefix'\n and ('$rd' = '-' OR rd = '$rd')\n and origin_as > 0\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "ASN Info",
"transform": "table",
"type": "table-old"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "locale"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "displayName",
"value": "Time"
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "prefix"
},
"properties": [
{
"id": "displayName",
"value": "Prefix"
},
{
"id": "unit",
"value": "short"
},
{
"id": "decimals",
"value": 2
},
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "Prefix History ",
"url": "/d/l3vpn-prefix-hist/prefix-history-by-prefix-l3vpn?orgId=1&var-input=${__value.text}&var-rd=$rd"
}
]
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "origin_as"
},
"properties": [
{
"id": "displayName",
"value": "Origin"
},
{
"id": "unit",
"value": "none"
},
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "ASN View",
"url": "/grafana/d/asnview/asn-view?orgId=1&var-asn_num=${__value.text}"
}
]
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "iswithdrawn"
},
"properties": [
{
"id": "displayName",
"value": "Withdrawn"
},
{
"id": "unit",
"value": "bool"
},
{
"id": "custom.displayMode",
"value": "color-background-solid"
},
{
"id": "custom.align",
"value": "auto"
},
{
"id": "color",
"value": {
"mode": "continuous-GrYlRd"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "Time"
},
"properties": [
{
"id": "custom.width",
"value": 194
}
]
}
]
},
"gridPos": {
"h": 23,
"w": 24,
"x": 0,
"y": 14
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "8.5.4",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select distinct ip.*, \n \tFIRST_VALUE(geo_ip.city) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as city,\n \tFIRST_VALUE(geo_ip.stateprov) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as stateprov,\n \tFIRST_VALUE(geo_ip.country) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as country,\n ls.local_router_name\n\tFROM (SELECT lastmodified,peername,rd,prefix,\n \tiswithdrawn,origin_as,med,localpref,nh,as_path,extcommunities,communities,largecommunities\n from v_l3vpn_routes\n \t\twhere prefix && '$input' \n \t\t AND peer_hash_id in ($peer_hash)\n \t\t AND ('$rd' = '-' OR rd = '$rd')\n \t\tlimit 2000\n \t) ip\n\t\tLEFT JOIN geo_ip on (geo_ip.ip >>= ip.prefix AND geo_ip.ip != '0.0.0.0/0')\n LEFT JOIN v_ls_prefixes ls ON (ls.prefix >>= ip.nh and length(ls.local_router_name) > 0)",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Looking Glass",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-l3vpn"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "80.0.0.2",
"value": "80.0.0.2"
},
"hide": 0,
"label": "Prefix/IP",
"name": "input",
"options": [
{
"selected": true,
"text": "80.0.0.2",
"value": "80.0.0.2"
}
],
"query": "80.0.0.2",
"queryValue": "50.227.215.188",
"skipUrlSync": false,
"type": "textbox"
},
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from routers where state = 'up'",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select name as __text, hash_id as __value from routers where state = 'up'",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) and recvcapabilities like '% afi=1 safi=128 %';",
"hide": 0,
"includeAll": true,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) and recvcapabilities like '% afi=1 safi=128 %';",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"isNone": true,
"selected": false,
"text": "None",
"value": ""
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select prefix from l3vpn_rib \nwhere prefix >>= '$input' and peer_hash_id in ($peer_hash) and ('$rd' = '-' OR rd = '$rd')\norder by prefix desc limit 1",
"hide": 2,
"includeAll": false,
"multi": false,
"name": "prefix",
"options": [],
"query": "select prefix from l3vpn_rib \nwhere prefix >>= '$input' and peer_hash_id in ($peer_hash) and ('$rd' = '-' OR rd = '$rd')\norder by prefix desc limit 1",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
},
{
"description": "RD in the format of N:N. Set to - for all.",
"hide": 2,
"label": "RD",
"name": "rd",
"query": "-",
"skipUrlSync": false,
"type": "constant"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Looking Glass - L3VPN",
"uid": "jiQW6VB7k",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,745 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"description": "",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 20,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.width",
"value": 224
}
]
}
]
},
"gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 0
},
"id": 5,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "9.1.7",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select lastmodified,CASE WHEN iswithdrawn THEN 'Withdrawn' ELSE 'Active' END as state,routername,peername,prefix,prefixlen,\n origin_as,med,localpref,nh,as_path,communities \n from v_l3vpn_routes \n where peer_hash_id in ($peer_hash) \n ${prefix_clause:raw}\n limit $limit\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Current RIB State",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"type": "table"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"decimals": 0,
"fieldConfig": {
"defaults": {
"links": []
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 7,
"w": 12,
"x": 0,
"y": 6
},
"hiddenSeries": false,
"id": 1,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": true,
"min": false,
"rightSide": true,
"show": true,
"total": true,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "9.1.7",
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n interval_time as time,\n sum(updates) as updates, sum(withdraws) as withdraws\nFROM stats_l3vpn_chg_byprefix s\nWHERE $__timeFilter(interval_time)\n AND peer_hash_id in ($peer_hash)\n ${prefix_clause:raw}\n\ngroup by interval_time\nORDER BY interval_time ASC\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"thresholds": [],
"timeRegions": [],
"title": "Prefix Advertisements & Withdrawals",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:289",
"format": "none",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:290",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"decimals": 0,
"fieldConfig": {
"defaults": {
"links": []
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 7,
"w": 12,
"x": 12,
"y": 6
},
"hiddenSeries": false,
"id": 2,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": true,
"min": false,
"rightSide": true,
"show": true,
"sort": "total",
"sortDesc": true,
"total": true,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "9.1.7",
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n interval_time as time,\n sum(updates) + sum(withdraws) as value,\n left(PeerName,32) as metric\nFROM stats_l3vpn_chg_byprefix s\n JOIN v_peers p ON (s.peer_hash_id = p.peer_hash_id)\nWHERE $__timeFilter(interval_time)\n AND s.peer_hash_id in ($peer_hash)\n ${prefix_clause:raw}\n\nGROUP BY s.interval_time,peername\nORDER BY interval_time ASC\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"thresholds": [],
"timeRegions": [],
"title": "Changes by Peer",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:346",
"decimals": 0,
"format": "none",
"label": "",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:347",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "displayName",
"value": "Last Modified"
}
]
},
{
"matcher": {
"id": "byName",
"options": "Last Modified"
},
"properties": [
{
"id": "custom.width",
"value": 208
}
]
},
{
"matcher": {
"id": "byName",
"options": "event"
},
"properties": [
{
"id": "mappings",
"value": [
{
"options": {
"Advertised": {
"color": "semi-dark-green",
"index": 0
},
"Withdrawn": {
"color": "semi-dark-red",
"index": 1
}
},
"type": "value"
}
]
},
{
"id": "custom.displayMode",
"value": "color-background-solid"
}
]
}
]
},
"gridPos": {
"h": 20,
"w": 24,
"x": 0,
"y": 13
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": [
{
"desc": true,
"displayName": "Last Modified"
}
]
},
"pluginVersion": "9.1.7",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": " select lastmodified,event,routername,peername,prefix,nh,\n origin_as,localpref,med,as_path,extcommunities,communities,largecommunities\n from v_l3vpn_routes_history \n where $__timeFilter(lastmodified)\n AND peer_hash_id in ($peer_hash)\n ${prefix_clause:raw}\n \n order by lastmodified desc,id desc\n limit $limit;",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefix History",
"type": "table"
}
],
"refresh": "",
"schemaVersion": 37,
"style": "dark",
"tags": [
"obmp-l3vpn"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select routername as __text, router_hash_id as __value from v_peers where recvcapabilities like '% afi=1 safi=128 %';\n",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select routername as __text, router_hash_id as __value from v_peers where recvcapabilities like '% afi=1 safi=128 %';\n",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) and recvcapabilities like '% afi=1 safi=128 %';",
"hide": 0,
"includeAll": true,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) and recvcapabilities like '% afi=1 safi=128 %';",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": false,
"text": "1000",
"value": "1000"
},
"hide": 0,
"includeAll": false,
"label": "Limit",
"multi": false,
"name": "limit",
"options": [
{
"selected": true,
"text": "1000",
"value": "1000"
},
{
"selected": false,
"text": "3000",
"value": "3000"
},
{
"selected": false,
"text": "5000",
"value": "5000"
},
{
"selected": false,
"text": "8000",
"value": "8000"
},
{
"selected": false,
"text": "10000",
"value": "10000"
}
],
"query": "1000,3000,5000,8000,10000",
"queryValue": "",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": false,
"text": "100.100.100.100",
"value": "100.100.100.100"
},
"hide": 0,
"label": "Prefix",
"name": "input",
"options": [
{
"selected": true,
"text": "100.100.100.100",
"value": "100.100.100.100"
}
],
"query": "100.100.100.100",
"queryValue": "67.211.53.0/24",
"skipUrlSync": false,
"type": "textbox"
},
{
"current": {
"selected": false,
"text": "",
"value": ""
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select CASE WHEN '$input' != '-' THEN 'AND prefix = ''' || (\n select prefix from l3vpn_rib \n where peer_hash_id in ($peer_hash) \n AND ('$rd' = '-' OR rd = '$rd')\n AND prefix >>= (CASE WHEN '$input' != '-' THEN '$input' ELSE '0/0' END)::inet order by prefix desc limit 1)::text || ''''\n ELSE '' END;",
"hide": 2,
"includeAll": false,
"multi": false,
"name": "prefix_clause",
"options": [],
"query": "select CASE WHEN '$input' != '-' THEN 'AND prefix = ''' || (\n select prefix from l3vpn_rib \n where peer_hash_id in ($peer_hash) \n AND ('$rd' = '-' OR rd = '$rd')\n AND prefix >>= (CASE WHEN '$input' != '-' THEN '$input' ELSE '0/0' END)::inet order by prefix desc limit 1)::text || ''''\n ELSE '' END;",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
},
{
"current": {
"selected": false,
"text": "-",
"value": "-"
},
"description": "RD in the format of N:N. Set to - for all.",
"hide": 0,
"includeAll": false,
"label": "RD",
"multi": false,
"name": "rd",
"options": [
{
"selected": true,
"text": "-",
"value": "-"
}
],
"query": "-",
"skipUrlSync": false,
"type": "custom"
}
]
},
"time": {
"from": "now-3h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Prefix History (by Prefix) L3VPN",
"uid": "l3vpn-prefix-hist",
"version": 2,
"weekStart": ""
}

View File

@ -0,0 +1,702 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 21,
"iteration": 1654877634754,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"axisSoftMin": 0,
"fillOpacity": 80,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineWidth": 1,
"scaleDistribution": {
"type": "linear"
}
},
"decimals": 0,
"displayName": "Routes",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 11,
"x": 0,
"y": 0
},
"id": 5,
"options": {
"barRadius": 0,
"barWidth": 0.97,
"groupWidth": 0.7,
"legend": {
"calcs": [
"sum"
],
"displayMode": "table",
"placement": "bottom"
},
"orientation": "auto",
"showValue": "always",
"stacking": "none",
"tooltip": {
"mode": "single",
"sort": "none"
},
"xTickLabelRotation": 0,
"xTickLabelSpacing": 0
},
"pluginVersion": "8.3.4",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select\n count(*) as count,\n rd\n from l3vpn_rib\n where\n peer_hash_id in ($peer_hash)\n and ('$rd' = '-' or rd = '$rd')\n and iswithdrawn = false\n group by rd\n",
"refId": "A",
"select": [
[
{
"params": [
"latitude"
],
"type": "column"
}
]
],
"table": "v_ip_routes_geo",
"timeColumn": "lastmodified",
"timeColumnType": "timestamp",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Routes Advertised/Active",
"type": "barchart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"axisSoftMin": 0,
"fillOpacity": 80,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineWidth": 1,
"scaleDistribution": {
"type": "linear"
}
},
"decimals": 0,
"displayName": "Routes",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "semi-dark-orange",
"value": null
}
]
},
"unit": "none"
},
"overrides": [
{
"__systemRef": "hideSeriesFrom",
"matcher": {
"id": "byNames",
"options": {
"mode": "exclude",
"names": [
"count"
],
"prefix": "All except:",
"readOnly": true
}
},
"properties": [
{
"id": "custom.hideFrom",
"value": {
"legend": false,
"tooltip": false,
"viz": true
}
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 11,
"y": 0
},
"id": 6,
"options": {
"barRadius": 0,
"barWidth": 0.97,
"groupWidth": 0.7,
"legend": {
"calcs": [
"sum"
],
"displayMode": "table",
"placement": "bottom"
},
"orientation": "auto",
"showValue": "always",
"stacking": "none",
"tooltip": {
"mode": "single",
"sort": "none"
},
"xTickLabelRotation": 0,
"xTickLabelSpacing": 0
},
"pluginVersion": "8.3.4",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select\n count(*) as count,\n rd\n from l3vpn_rib\n where\n peer_hash_id in ($peer_hash)\n and ('$rd' = '-' OR rd = '$rd')\n and iswithdrawn = true\n group by rd\n",
"refId": "A",
"select": [
[
{
"params": [
"latitude"
],
"type": "column"
}
]
],
"table": "v_ip_routes_geo",
"timeColumn": "lastmodified",
"timeColumnType": "timestamp",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Routes Withdrawn/Inactive",
"type": "barchart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "locale"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "displayName",
"value": "Time"
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "prefix"
},
"properties": [
{
"id": "displayName",
"value": "Prefix"
},
{
"id": "unit",
"value": "short"
},
{
"id": "decimals",
"value": 2
},
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "Prefix History ",
"url": "/d/l3vpn-prefix-hist/prefix-history-by-prefix-l3vpn?orgId=1&var-limit=$limit&var-input=${__value.text}&var-rd=$rd"
}
]
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "origin_as"
},
"properties": [
{
"id": "displayName",
"value": "Origin"
},
{
"id": "unit",
"value": "none"
},
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "ASN View",
"url": "/grafana/d/asnview/asn-view?orgId=1&var-asn_num=${__value.text}"
}
]
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "iswithdrawn"
},
"properties": [
{
"id": "displayName",
"value": "Withdrawn"
},
{
"id": "unit",
"value": "bool"
},
{
"id": "custom.displayMode",
"value": "color-background-solid"
},
{
"id": "custom.align",
"value": "auto"
},
{
"id": "color",
"value": {
"mode": "continuous-GrYlRd"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "Time"
},
"properties": [
{
"id": "custom.width",
"value": 194
}
]
}
]
},
"gridPos": {
"h": 23,
"w": 24,
"x": 0,
"y": 8
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "8.5.4",
"targets": [
{
"alias": "",
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select distinct ip.*, \n \tFIRST_VALUE(geo_ip.city) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as city,\n \tFIRST_VALUE(geo_ip.stateprov) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as stateprov,\n \tFIRST_VALUE(geo_ip.country) OVER (PARTITION BY ip.prefix ORDER BY geo_ip.ip DESC) as country,\n ls.local_router_name\n\tFROM (SELECT lastmodified,peername,rd,prefix,\n \tiswithdrawn,origin_as,med,localpref,nh,as_path,communities,extcommunities\n from v_l3vpn_routes\n \t\twhere \n \t\t peer_hash_id in ($peer_hash)\n \t\t AND ('$rd' = '-' OR rd = '$rd')\n \t\t AND (iswithdrawn in ($state))\n \t\tlimit $limit\n \t) ip\n\t\tLEFT JOIN geo_ip on (geo_ip.ip >>= ip.prefix AND geo_ip.ip != '0.0.0.0/0')\n LEFT JOIN v_ls_prefixes ls ON (ls.prefix >>= ip.nh and length(ls.local_router_name) > 0)",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Looking Glass (RD = $rd)",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-l3vpn"
],
"templating": {
"list": [
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select routername as __text, router_hash_id as __value from v_peers where router_state = 'up' and recvcapabilities like '% afi=1 safi=128 %';",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select routername as __text, router_hash_id as __value from v_peers where router_state = 'up' and recvcapabilities like '% afi=1 safi=128 %';",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"isNone": true,
"selected": false,
"text": "None",
"value": ""
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) and recvcapabilities like '% afi=1 safi=128 %';",
"hide": 0,
"includeAll": false,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash) and recvcapabilities like '% afi=1 safi=128 %';",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": true,
"text": "-",
"value": "-"
},
"description": "RD in the format of N:N. Set to - for all.",
"hide": 0,
"includeAll": false,
"label": "RD",
"multi": false,
"name": "rd",
"options": [
{
"selected": true,
"text": "-",
"value": "-"
}
],
"query": "-",
"queryValue": "203:20",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": true,
"text": "1000",
"value": "1000"
},
"hide": 0,
"includeAll": false,
"label": "Limit",
"multi": false,
"name": "limit",
"options": [
{
"selected": true,
"text": "1000",
"value": "1000"
},
{
"selected": false,
"text": "3000",
"value": "3000"
},
{
"selected": false,
"text": "5000",
"value": "5000"
},
{
"selected": false,
"text": "8000",
"value": "8000"
},
{
"selected": false,
"text": "10000",
"value": "10000"
}
],
"query": "1000,3000,5000,8000,10000",
"queryValue": "",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": true,
"text": [
"Advertised"
],
"value": [
"False"
]
},
"hide": 0,
"includeAll": true,
"multi": true,
"name": "state",
"options": [
{
"selected": false,
"text": "All",
"value": "$__all"
},
{
"selected": true,
"text": "Advertised",
"value": "False"
},
{
"selected": false,
"text": "Withdrawn",
"value": "True"
}
],
"query": "Advertised : False, Withdrawn : True",
"queryValue": "",
"skipUrlSync": false,
"type": "custom"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "L3VPN RIB Browser",
"uid": "v-cdzIBnz",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,324 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 14,
"iteration": 1654877691622,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 6,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "always",
"spanNulls": true,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"decimals": 0,
"links": [],
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 0
},
"id": 4,
"options": {
"legend": {
"calcs": [
"sum"
],
"displayMode": "table",
"placement": "right"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "8.0.5",
"targets": [
{
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n $__timeGroup(timestamp, $__interval) as time,\n count(*) as count,\n CASE WHEN iswithdrawn THEN 'WITHDRAWN' ELSE 'ACTIVE' END as metric\nFROM\n ls_links_log\nWHERE\n $__timeFilter(timestamp)\n AND peer_hash_id = '$peer_hash'\nGROUP BY time,metric\nORDER BY time\n\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Link Changes",
"type": "timeseries"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "seq"
},
"properties": [
{
"id": "unit",
"value": "locale"
}
]
},
{
"matcher": {
"id": "byName",
"options": "timestamp"
},
"properties": [
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
}
]
},
{
"matcher": {
"id": "byName",
"options": "state"
},
"properties": [
{
"id": "custom.displayMode",
"value": "color-background-solid"
},
{
"id": "mappings",
"value": [
{
"options": {
"ACTIVE": {
"color": "semi-dark-green",
"index": 0
},
"WITHDRAWN": {
"color": "semi-dark-red",
"index": 1
}
},
"type": "value"
}
]
}
]
}
]
},
"gridPos": {
"h": 14,
"w": 24,
"x": 0,
"y": 8
},
"id": 2,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "8.5.4",
"targets": [
{
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n l.timestamp,\n l.seq,ln.name as LocalNode, rn.name as RemoteNode, l.mt_id,l.igp_metric,CASE WHEN l.iswithdrawn THEN 'WITHDRAWN' ELSE 'ACTIVE' END as state\nFROM\n ls_links_log l JOIN ls_nodes ln ON (l.local_node_hash_id = ln.hash_id and l.peer_hash_id = ln.peer_hash_id) \n JOIN ls_nodes rn ON (l.remote_node_hash_id = rn.hash_id and rn.peer_hash_id = l.peer_hash_id)\nWHERE\n $__timeFilter(l.timestamp)\n AND l.peer_hash_id = '$peer_hash'\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Link History",
"type": "table"
}
],
"refresh": false,
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-linkstate"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "yyz01-wxbb-crt01-lo0.webex.com",
"value": "367c22e4-57d9-2328-654b-96ea750e0267"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0",
"hide": 0,
"includeAll": false,
"label": "BGP Peer",
"multi": false,
"name": "peer_hash",
"options": [],
"query": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "LS Link History",
"uid": "-r7gAlyZk",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,479 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 15,
"iteration": 1654877712696,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 7,
"x": 0,
"y": 0
},
"id": 4,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value",
"percent"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select floor(extract(epoch from max(timestamp))) as time,\n count(*) as value, CASE WHEN iswithdrawn THEN 'WITHDRAWN' ELSE 'ACTIVE' END as metric\nfrom ls_links\nwhere local_node_hash_id = '$local_node_hash_id'\n AND peer_hash_id = '$peer_hash'\ngroup by iswithdrawn\norder by time\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Link States",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 6,
"x": 7,
"y": 0
},
"id": 6,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select floor(extract(epoch from max(timestamp))) as time,\n count(*) as value, CASE WHEN mt_id = 2 THEN 'IPv6' ELSE 'IPv4' END as metric\nfrom ls_links\nwhere local_node_hash_id = '$local_node_hash_id'\n AND peer_hash_id = '$peer_hash'\ngroup by mt_id\norder by time\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Links by Type",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "timestamp"
},
"properties": [
{
"id": "displayName",
"value": "Time"
},
{
"id": "unit",
"value": "short"
},
{
"id": "decimals",
"value": 2
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "seq"
},
"properties": [
{
"id": "unit",
"value": "locale"
}
]
},
{
"matcher": {
"id": "byName",
"options": "state"
},
"properties": [
{
"id": "custom.displayMode",
"value": "color-background-solid"
},
{
"id": "mappings",
"value": [
{
"options": {
"ACTIVE": {
"color": "semi-dark-green",
"index": 0
},
"WITHDRAWN": {
"color": "semi-dark-red",
"index": 1
}
},
"type": "value"
}
]
}
]
}
]
},
"gridPos": {
"h": 14,
"w": 24,
"x": 0,
"y": 7
},
"id": 2,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "8.5.4",
"targets": [
{
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT state,local_router_name,local_igp_routerid,remote_router_name,remote_igp_routerid,mt_id,igp_metric,protocol, timestamp, seq\n FROM v_ls_links\n WHERE local_node_hash_id = '$local_node_hash_id'\n AND peer_hash_id = '$peer_hash'",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "$local_node_name Links",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"transparent": true,
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-linkstate"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "yyz01-wxbb-crt01-lo0.webex.com",
"value": "367c22e4-57d9-2328-654b-96ea750e0267"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0\n ",
"hide": 0,
"includeAll": false,
"label": "BGP Peer",
"multi": false,
"name": "peer_hash",
"options": [],
"query": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0\n ",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": false,
"text": "AMS10-WXBB-CRT02",
"value": "1ed1da6b-6f57-57aa-92f5-edda59049e9a"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from ls_nodes where peer_hash_id = '$peer_hash' and not igp_router_id ~ '\\..[1-9A-F]00$'",
"hide": 0,
"includeAll": false,
"label": "ISIS Node",
"multi": false,
"name": "local_node_hash_id",
"options": [],
"query": "select name as __text, hash_id as __value from ls_nodes where peer_hash_id = '$peer_hash' and not igp_router_id ~ '\\..[1-9A-F]00$'",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": false,
"text": "AMS10-WXBB-CRT02",
"value": "AMS10-WXBB-CRT02"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name from ls_nodes where hash_id = '$local_node_hash_id' and peer_hash_id = '$peer_hash'",
"hide": 2,
"includeAll": false,
"multi": false,
"name": "local_node_name",
"options": [],
"query": "select name from ls_nodes where hash_id = '$local_node_hash_id' and peer_hash_id = '$peer_hash'",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "LS Links",
"uid": "MPqNG_sWz",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,511 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 16,
"iteration": 1654877745288,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [
{
"options": {
"match": "null",
"result": {
"text": "N/A"
}
},
"type": "special"
}
],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 3,
"x": 0,
"y": 0
},
"id": 6,
"links": [],
"maxDataPoints": 100,
"options": {
"colorMode": "background",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "horizontal",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"text": {},
"textMode": "auto"
},
"pluginVersion": "8.5.4",
"targets": [
{
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT count(*)\n FROM ls_nodes where peer_hash_id = '$peer_hash';",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Total Nodes",
"type": "stat"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 7,
"x": 3,
"y": 0
},
"id": 8,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select floor(extract(epoch from max(timestamp))) as time,\n count(*) as count, \n CASE WHEN iswithdrawn THEN 'WITHDRAWN' ELSE 'ACTIVE' END as metric\nfrom ls_links\nwhere peer_hash_id = '$peer_hash'\ngroup by iswithdrawn\norder by time\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Link States",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 7,
"x": 10,
"y": 0
},
"id": 9,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "right",
"values": [
"value"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"sum"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select floor(extract(epoch from max(timestamp))) as time,\n count(*) as count, \n CASE WHEN mt_id = 2 THEN 'IPv6' ELSE 'IPv4' END as metric\nfrom ls_links \nwhere peer_hash_id = '$peer_hash'\ngroup by metric\norder by time\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Links by Type",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "timestamp"
},
"properties": [
{
"id": "displayName",
"value": "Time"
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "state"
},
"properties": [
{
"id": "mappings",
"value": [
{
"options": {
"ACTIVE": {
"color": "semi-dark-green",
"index": 0
},
"WITHDRAWN": {
"color": "semi-dark-red",
"index": 1
}
},
"type": "value"
}
]
},
{
"id": "custom.displayMode",
"value": "color-background-solid"
}
]
}
]
},
"gridPos": {
"h": 13,
"w": 24,
"x": 0,
"y": 6
},
"id": 4,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "8.5.4",
"targets": [
{
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT state, nodename, routerid, protocol, timestamp, seq\n FROM v_ls_nodes\n where peer_hash_id = '$peer_hash'\n\n ",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Backbone ISIS Nodes",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"type": "table"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 2,
"w": 24,
"x": 0,
"y": 19
},
"id": 2,
"options": {
"content": "\n\n",
"mode": "markdown"
},
"pluginVersion": "8.5.4",
"type": "text"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-linkstate"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "yyz01-wxbb-crt01-lo0.webex.com",
"value": "367c22e4-57d9-2328-654b-96ea750e0267"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0\n",
"hide": 0,
"includeAll": false,
"label": "BGP Peer",
"multi": false,
"name": "peer_hash",
"options": [],
"query": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0\n",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "LS Nodes",
"uid": "dzdSWlyWz",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,377 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 17,
"iteration": 1654877763755,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"decimals": 0,
"mappings": [],
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 7,
"w": 7,
"x": 0,
"y": 0
},
"id": 4,
"links": [],
"maxDataPoints": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "table",
"placement": "bottom",
"values": [
"value"
]
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select floor(extract(epoch from max(timestamp))) as time,\n count(*) as value, CASE WHEN mt_id = 2 THEN 'IPv6' ELSE 'IPv4' END as metric\nfrom v_ls_prefixes\nwhere local_node_hash_id = '$local_node_hash_id'\n and peer_hash_id = '$peer_hash'\ngroup by mt_id\n",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefixes Total by Type",
"type": "piechart"
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"decimals": 0,
"displayName": "",
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "none"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "timestamp"
},
"properties": [
{
"id": "displayName",
"value": "Time"
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
},
{
"id": "custom.align"
}
]
},
{
"matcher": {
"id": "byName",
"options": "state"
},
"properties": [
{
"id": "custom.displayMode",
"value": "color-background-solid"
},
{
"id": "mappings",
"value": [
{
"options": {
"ACTIVE": {
"color": "semi-dark-green",
"index": 0
},
"WITHDRAWN": {
"color": "semi-dark-red",
"index": 1
}
},
"type": "value"
}
]
}
]
}
]
},
"gridPos": {
"h": 22,
"w": 23,
"x": 0,
"y": 7
},
"id": 2,
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "8.5.4",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT state, mt_id, prefix, metric, protocol, timestamp\n FROM v_ls_prefixes\n WHERE local_node_hash_id = '$local_node_hash_id'\n AND peer_hash_id = '$peer_hash'",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "$local_node_name Prefixes",
"transformations": [
{
"id": "merge",
"options": {
"reducers": []
}
}
],
"type": "table"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-linkstate"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "yyz01-wxbb-crt01-lo0.webex.com",
"value": "367c22e4-57d9-2328-654b-96ea750e0267"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0",
"hide": 0,
"includeAll": false,
"label": "BGP Peer",
"multi": false,
"name": "peer_hash",
"options": [],
"query": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": false,
"text": "BLR03-WXBB-CRT01",
"value": "4275c83a-8d03-5361-d890-0b2bf4ad1b91"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from ls_nodes where peer_hash_id = '$peer_hash' AND not igp_router_id ~ '\\..[1-9A-F]00$'",
"hide": 0,
"includeAll": false,
"label": "ISIS Node",
"multi": false,
"name": "local_node_hash_id",
"options": [],
"query": "select name as __text, hash_id as __value from ls_nodes where peer_hash_id = '$peer_hash' AND not igp_router_id ~ '\\..[1-9A-F]00$'",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"current": {
"selected": false,
"text": "BLR03-WXBB-CRT01",
"value": "BLR03-WXBB-CRT01"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name from ls_nodes where hash_id = '$local_node_hash_id' and peer_hash_id = '$peer_hash'",
"hide": 2,
"includeAll": false,
"multi": false,
"name": "local_node_name",
"options": [],
"query": "select name from ls_nodes where hash_id = '$local_node_hash_id' and peer_hash_id = '$peer_hash'",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "LS Prefixes",
"uid": "iEcqtlyWk",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,216 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 23,
"iteration": 1654877522167,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"gridPos": {
"h": 28,
"w": 23,
"x": 0,
"y": 0
},
"id": 2,
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select local_node_hash_id as id,\n CASE WHEN max(local_router_name) = '' THEN max(local_igp_routerid) ELSE max(local_router_name) END as title,\n max(local_igp_routerid) as detail__routerid\n from v_ls_links\n where peer_hash_id = '$peer_hash'\n and local_igp_routerid like '%.0000' and remote_igp_routerid like '%.0000'\n and igp_metric < 16000000\n and state in ($state)\n and (local_node_hash_id = '$local_node_hash' or remote_node_hash_id = '$local_node_hash')\n group by local_node_hash_id\n order by title;",
"refId": " nodes",
"select": [
[
{
"params": [
"amr_rx_hbhloss_pct"
],
"type": "column"
}
]
],
"table": "as_path_metrics",
"timeColumn": "start_timestamp",
"timeColumnType": "timestamp",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
},
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "select local_node_hash_id || '->' || remote_node_hash_id as id,\n local_node_hash_id as source,\n remote_node_hash_id as target,\n max(igp_metric)::int as mainstat,\n max(state) as secondarystat,\n max(remote_router_name) as detail__remote\n from v_ls_links\n where peer_hash_id = '$peer_hash'\n and local_igp_routerid like '%.0000' and remote_igp_routerid like '%.0000'\n and igp_metric < 16000000\n and state in ($state)\n and (local_node_hash_id = '$local_node_hash' or remote_node_hash_id = '$local_node_hash')\ngroup by local_node_hash_id,remote_node_hash_id;\n ",
"refId": "edges",
"select": [
[
{
"params": [
"amr_rx_hbhloss_pct"
],
"type": "column"
}
]
],
"table": "as_path_metrics",
"timeColumn": "start_timestamp",
"timeColumnType": "timestamp",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Topology",
"type": "nodeGraph"
}
],
"schemaVersion": 36,
"style": "dark",
"tags": [
"obmp-linkstate"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "yyz01-wxbb-crt01-lo0.webex.com",
"value": "367c22e4-57d9-2328-654b-96ea750e0267"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0",
"hide": 0,
"includeAll": false,
"label": "BGP Peer",
"multi": false,
"name": "peer_hash",
"options": [],
"query": "SELECT __text,__value FROM (\n select peername as __text, peer_hash_id as __value, count(*) as count\n from v_ls_nodes\n group by peername,peer_hash_id) d\nwhere count > 0",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
},
{
"current": {
"selected": true,
"text": "Active",
"value": "ACTIVE"
},
"hide": 0,
"includeAll": true,
"label": "State",
"multi": false,
"name": "state",
"options": [
{
"selected": false,
"text": "All",
"value": "$__all"
},
{
"selected": false,
"text": "Inactive",
"value": "WITHDRAWN"
},
{
"selected": true,
"text": "Active",
"value": "ACTIVE"
}
],
"query": "Inactive : WITHDRAWN, Active : ACTIVE",
"queryValue": "",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": false,
"text": "NRT02-WXBB-CRT01",
"value": "3e96d517-e4b8-7264-1479-2814e9691f10"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select local_router_name as __text, local_node_hash_id as __value \nfrom v_ls_links\nwhere peer_hash_id = '$peer_hash'\n and local_igp_routerid like '%.0000'\n and igp_metric < 16000000\n and state in ($state)\ngroup by local_router_name,local_node_hash_id",
"hide": 0,
"includeAll": false,
"label": "Node",
"multi": false,
"name": "local_node_hash",
"options": [],
"query": "select local_router_name as __text, local_node_hash_id as __value \nfrom v_ls_links\nwhere peer_hash_id = '$peer_hash'\n and local_igp_routerid like '%.0000'\n and igp_metric < 16000000\n and state in ($state)\ngroup by local_router_name,local_node_hash_id",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "LinkState Topology",
"uid": "SNOLrQlnz",
"version": 3,
"weekStart": ""
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,125 @@
apiVersion: 1
providers:
# <string> an unique provider name. Required
- name: 'OpenBMP'
# <int> Org id. Default to 1
orgId: 1
# <string> name of the dashboard folder.
folder: ''
# <string> folder UID. will be automatically generated if not specified
folderUid: ''
# <string> provider type. Default to 'file'
type: file
# <bool> disable dashboard deletion
disableDeletion: false
# <int> how often Grafana will scan for changed dashboards
updateIntervalSeconds: 30
# <bool> allow updating provisioned dashboards from the UI
allowUiUpdates: true
options:
# <string, required> path to dashboard files on disk. Required when using the 'file' type
path: /var/lib/grafana/dashboards/General
# <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: false
# <string> an unique provider name. Required
- name: 'OpenBMP-Base'
# <int> Org id. Default to 1
orgId: 1
# <string> name of the dashboard folder.
folder: 'OBMP-Base'
# <string> folder UID. will be automatically generated if not specified
folderUid: '1001'
# <string> provider type. Default to 'file'
type: file
# <bool> disable dashboard deletion
disableDeletion: false
# <int> how often Grafana will scan for changed dashboards
updateIntervalSeconds: 30
# <bool> allow updating provisioned dashboards from the UI
allowUiUpdates: true
options:
# <string, required> path to dashboard files on disk. Required when using the 'file' type
path: /var/lib/grafana/dashboards/obmp/Base-1001
# <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: false
- name: 'OpenBMP-History'
# <int> Org id. Default to 1
orgId: 1
# <string> name of the dashboard folder.
folder: 'OBMP-History'
# <string> folder UID. will be automatically generated if not specified
folderUid: '1002'
# <string> provider type. Default to 'file'
type: file
# <bool> disable dashboard deletion
disableDeletion: false
# <int> how often Grafana will scan for changed dashboards
updateIntervalSeconds: 30
# <bool> allow updating provisioned dashboards from the UI
allowUiUpdates: true
options:
# <string, required> path to dashboard files on disk. Required when using the 'file' type
path: /var/lib/grafana/dashboards/obmp/History-1002
# <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: false
- name: 'OpenBMP-Tops'
# <int> Org id. Default to 1
orgId: 1
# <string> name of the dashboard folder.
folder: 'OBMP-Tops'
# <string> folder UID. will be automatically generated if not specified
folderUid: '1003'
# <string> provider type. Default to 'file'
type: file
# <bool> disable dashboard deletion
disableDeletion: false
# <int> how often Grafana will scan for changed dashboards
updateIntervalSeconds: 30
# <bool> allow updating provisioned dashboards from the UI
allowUiUpdates: true
options:
# <string, required> path to dashboard files on disk. Required when using the 'file' type
path: /var/lib/grafana/dashboards/obmp/Tops-1003
# <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: false
- name: 'OpenBMP-LinkState'
# <int> Org id. Default to 1
orgId: 1
# <string> name of the dashboard folder.
folder: 'OBMP-LinkState'
# <string> folder UID. will be automatically generated if not specified
folderUid: '1004'
# <string> provider type. Default to 'file'
type: file
# <bool> disable dashboard deletion
disableDeletion: false
# <int> how often Grafana will scan for changed dashboards
updateIntervalSeconds: 30
# <bool> allow updating provisioned dashboards from the UI
allowUiUpdates: true
options:
# <string, required> path to dashboard files on disk. Required when using the 'file' type
path: /var/lib/grafana/dashboards/obmp/LinkState-1004
# <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: false
- name: 'OpenBMP-L3VPN'
# <int> Org id. Default to 1
orgId: 1
# <string> name of the dashboard folder.
folder: 'OBMP-L3VPN'
# <string> folder UID. will be automatically generated if not specified
folderUid: '1005'
# <string> provider type. Default to 'file'
type: file
# <bool> disable dashboard deletion
disableDeletion: false
# <int> how often Grafana will scan for changed dashboards
updateIntervalSeconds: 30
# <bool> allow updating provisioned dashboards from the UI
allowUiUpdates: true
options:
# <string, required> path to dashboard files on disk. Required when using the 'file' type
path: /var/lib/grafana/dashboards/obmp/L3VPN-1005
# <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: false

View File

@ -0,0 +1,48 @@
# config file version
apiVersion: 1
# list of datasources that should be deleted from the database
#deleteDatasources:
# - name: PostgreSQL
# orgId: 1
# list of datasources to insert/update depending
# whats available in the database
datasources:
# <string, required> name of the datasource. Required
- name: PostgreSQL
uid: obmp_postgres
# <string, required> datasource type. Required
type: postgres
# <string, required> access mode. direct or proxy. Required
access: direct
# <int> org id. will default to orgId 1 if not specified
orgId: 1
# <string> url
url: obmp-psql:5432
# <string> database user, if used
user: openbmp
# <string> database name, if used
database: openbmp
# <bool> mark as default datasource. Max one per org
isDefault: true
secureJsonData:
password: openbmp
# <map> fields that will be converted to json and stored in json_data
jsonData:
tlsAuth: false
tlsAuthWithCACert: false
postgresVersion: 1200
sslmode: "require"
timescaledb: true
maxOpenConns: 6
maxIdleConns: 1
connMaxLifetime: 3600
# <string> json object of data that will be encrypted.
#secureJsonData:
version: 1
# <bool> allow users to edit datasources from the UI.
editable: true