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>
2026-03-05 14:46:37 -07:00
{
"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 ,
2026-05-18 20:55:03 -07:00
"id" : null ,
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>
2026-03-05 14:46:37 -07:00
"iteration" : 1654877090626 ,
2026-05-18 20:55:03 -07:00
"links" : [
{ "asDropdown" : true , "icon" : "external link" , "includeVars" : true , "keepTime" : true , "tags" : [ "obmp-nav" ] , "title" : "OBMP Dashboards" , "type" : "dashboards" }
] ,
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>
2026-03-05 14:46:37 -07:00
"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"
} ,
{
"datasource" : {
"type" : "postgres" ,
"uid" : "obmp_postgres"
} ,
2026-05-18 20:55:03 -07:00
"description" : "Geolocation of the matched prefix (from the geo_ip table)." ,
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "thresholds" } ,
"custom" : { "hideFrom" : { "legend" : false , "tooltip" : false , "viz" : false } } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } ] }
} ,
"overrides" : [ ]
} ,
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>
2026-03-05 14:46:37 -07:00
"gridPos" : {
"h" : 8 ,
"w" : 12 ,
"x" : 12 ,
"y" : 0
} ,
"id" : 17 ,
2026-05-18 20:55:03 -07:00
"options" : {
"basemap" : { "config" : { } , "name" : "Layer 0" , "type" : "default" } ,
"controls" : { "mouseWheelZoom" : false , "showAttribution" : true , "showDebug" : false , "showMeasure" : false , "showScale" : false , "showZoom" : true } ,
"layers" : [
{
"config" : {
"showLegend" : false ,
"style" : {
"color" : { "fixed" : "red" } ,
"opacity" : 0.7 ,
"rotation" : { "fixed" : 0 , "max" : 360 , "min" : -360 , "mode" : "mod" } ,
"size" : { "fixed" : 8 , "max" : 15 , "min" : 2 } ,
"symbol" : { "fixed" : "img/icons/marker/circle.svg" , "mode" : "fixed" } ,
"textConfig" : { "fontSize" : 12 , "offsetX" : 0 , "offsetY" : 0 , "textAlign" : "center" , "textBaseline" : "middle" }
}
} ,
"location" : { "latitude" : "latitude" , "longitude" : "longitude" , "mode" : "coords" } ,
"name" : "Prefix Location" ,
"tooltip" : true ,
"type" : "markers"
}
] ,
"tooltip" : { "mode" : "details" } ,
"view" : { "allLayers" : true , "id" : "zero" , "lat" : 0 , "lon" : 0 , "zoom" : 1 }
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>
2026-03-05 14:46:37 -07:00
} ,
2026-05-18 20:55:03 -07:00
"pluginVersion" : "9.1.7" ,
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>
2026-03-05 14:46:37 -07:00
"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"
}
]
}
] ,
"title" : "Prefix Location" ,
2026-05-18 20:55:03 -07:00
"type" : "geomap"
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>
2026-03-05 14:46:37 -07:00
} ,
{
"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"
} ,
{
"datasource" : {
"type" : "postgres" ,
"uid" : "obmp_postgres"
} ,
2026-05-18 20:55:03 -07:00
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "thresholds" } ,
"custom" : { "align" : "auto" , "displayMode" : "auto" , "inspect" : false } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } ] }
} ,
"overrides" : [ ]
} ,
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>
2026-03-05 14:46:37 -07:00
"gridPos" : {
"h" : 6 ,
"w" : 24 ,
"x" : 0 ,
"y" : 8
} ,
"id" : 12 ,
"links" : [ ] ,
2026-05-18 20:55:03 -07:00
"options" : {
"footer" : { "countRows" : false , "fields" : "" , "reducer" : [ "sum" ] , "show" : false } ,
"showHeader" : true
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>
2026-03-05 14:46:37 -07:00
} ,
"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" ,
2026-05-18 20:55:03 -07:00
"type" : "table"
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>
2026-03-05 14:46:37 -07:00
} ,
{
"datasource" : {
"type" : "postgres" ,
"uid" : "obmp_postgres"
} ,
2026-05-18 20:55:03 -07:00
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "thresholds" } ,
"custom" : { "align" : "auto" , "displayMode" : "auto" , "inspect" : false } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } ] }
} ,
"overrides" : [ ]
} ,
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>
2026-03-05 14:46:37 -07:00
"gridPos" : {
"h" : 4 ,
"w" : 24 ,
"x" : 0 ,
"y" : 14
} ,
"id" : 13 ,
"links" : [ ] ,
2026-05-18 20:55:03 -07:00
"options" : {
"footer" : { "countRows" : false , "fields" : "" , "reducer" : [ "sum" ] , "show" : false } ,
"showHeader" : true
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>
2026-03-05 14:46:37 -07:00
} ,
"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" ,
2026-05-18 20:55:03 -07:00
"type" : "table"
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>
2026-03-05 14:46:37 -07:00
} ,
{
"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" : [
2026-05-18 20:55:03 -07:00
"obmp" ,
"obmp-nav" ,
"operations"
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>
2026-03-05 14:46:37 -07:00
] ,
"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" : ""
}