Add Phase 4: gNMI streaming telemetry and traffic generator
- gNMI integration: NETCONF script to enable gRPC on all 9 routers,
Telegraf container with gnmi input plugin, InfluxDB for time-series
storage, 3 Grafana telemetry dashboards (utilization, errors, combined)
- Traffic generator: Scapy-based dual-mode container (sender/responder)
with Flask API, RFC 2544 test suite (throughput, latency, frame-loss,
back-to-back), Vue 3 web UI with flow builder, test runner, real-time
stats monitor, and results export
- docker-compose.yml updated with influxdb, telegraf, traffic-gen,
traffic-gen-ui services
- Full documentation in DOCS.md sections 15-16
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:29:44 -07:00
{
"annotations" : { "list" : [ { "builtIn" : 1 , "datasource" : { "type" : "datasource" , "uid" : "grafana" } , "enable" : true , "hide" : true , "iconColor" : "rgba(0, 211, 255, 1)" , "name" : "Annotations & Alerts" , "type" : "dashboard" } ] } ,
"description" : "Combined view of BMP control-plane data (from PostgreSQL) and gNMI data-plane telemetry (from InfluxDB). Correlate BGP peer state with interface traffic patterns." ,
"editable" : true ,
"fiscalYearStartMonth" : 0 ,
"graphTooltip" : 1 ,
"id" : null ,
"links" : [ ] ,
"templating" : {
"list" : [
{
"current" : { } ,
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"definition" : "from(bucket: \"telemetry\")\n |> range(start: -1h)\n |> filter(fn: (r) => r._measurement == \"interface_counters\")\n |> keep(columns: [\"source\"])\n |> distinct(column: \"source\")\n |> sort()" ,
"hide" : 0 ,
"includeAll" : true ,
"label" : "Router" ,
"multi" : true ,
"name" : "router" ,
"options" : [ ] ,
"query" : "from(bucket: \"telemetry\")\n |> range(start: -1h)\n |> filter(fn: (r) => r._measurement == \"interface_counters\")\n |> keep(columns: [\"source\"])\n |> distinct(column: \"source\")\n |> sort()" ,
"refresh" : 2 ,
"regex" : "" ,
"type" : "query"
}
]
} ,
"panels" : [
{
"datasource" : { "type" : "postgres" , "uid" : "obmp_postgres" } ,
"description" : "Current BGP peer status from the OpenBMP PostgreSQL database. Shows peer address, name, and session state." ,
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "thresholds" } ,
"custom" : { "align" : "auto" , "displayMode" : "auto" , "filterable" : true , "inspect" : true } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } ] }
} ,
"overrides" : [
{ "matcher" : { "id" : "byName" , "options" : "state" } , "properties" : [ { "id" : "custom.displayMode" , "value" : "color-background-solid" } , { "id" : "mappings" , "value" : [ { "options" : { "down" : { "color" : "red" , "index" : 1 , "text" : "DOWN" } , "up" : { "color" : "green" , "index" : 0 , "text" : "UP" } } , "type" : "value" } ] } ] } ,
{ "matcher" : { "id" : "byName" , "options" : "peer_addr" } , "properties" : [ { "id" : "custom.width" , "value" : 160 } ] } ,
{ "matcher" : { "id" : "byName" , "options" : "name" } , "properties" : [ { "id" : "custom.width" , "value" : 200 } ] }
]
} ,
"gridPos" : { "h" : 10 , "w" : 24 , "x" : 0 , "y" : 0 } ,
"id" : 1 ,
"options" : { "footer" : { "fields" : "" , "reducer" : [ "sum" ] , "show" : false } , "showHeader" : true , "sortBy" : [ { "desc" : false , "displayName" : "state" } ] } ,
"targets" : [
{
"datasource" : { "type" : "postgres" , "uid" : "obmp_postgres" } ,
"format" : "table" ,
"rawSql" : "SELECT\n p.peer_addr,\n COALESCE(p.name, p.peer_addr::text) AS name,\n p.state,\n p.peer_as AS \"AS\",\n p.router_hash_id IS NOT NULL AS \"BMP Active\",\n p.timestamp AS \"Last State Change\"\nFROM bgp_peers p\nWHERE p.isprepolicy = true\nORDER BY p.state, p.peer_addr" ,
"refId" : "A"
}
] ,
"title" : "BGP Peer Status" ,
"type" : "table"
} ,
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"description" : "Interface traffic rates from gNMI streaming telemetry. Shows bytes per second for each interface across selected routers." ,
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "palette-classic" } ,
"custom" : { "axisBorderShow" : false , "axisCenteredZero" : false , "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" : false , "stacking" : { "group" : "A" , "mode" : "none" } , "thresholdsStyle" : { "mode" : "off" } } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } , { "color" : "red" , "value" : 80 } ] } ,
"unit" : "Bps"
}
} ,
"gridPos" : { "h" : 10 , "w" : 24 , "x" : 0 , "y" : 10 } ,
"id" : 2 ,
"options" : { "legend" : { "calcs" : [ "mean" , "max" ] , "displayMode" : "table" , "placement" : "bottom" } , "tooltip" : { "mode" : "multi" , "sort" : "desc" } } ,
"targets" : [
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
2026-03-06 16:19:16 -07:00
"query" : "from(bucket: \"telemetry\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"interface_counters\")\n |> filter(fn: (r) => r.source =~ /${router:regex}/)\n |> filter(fn: (r) => r._field == \"in-octets\" or r._field == \"out-octets\")\n |> derivative(unit: 1s, nonNegative: true)\n |> map(fn: (r) => ({r with _value: if r._value < 0.0 then 0.0 else r._value}))" ,
Add Phase 4: gNMI streaming telemetry and traffic generator
- gNMI integration: NETCONF script to enable gRPC on all 9 routers,
Telegraf container with gnmi input plugin, InfluxDB for time-series
storage, 3 Grafana telemetry dashboards (utilization, errors, combined)
- Traffic generator: Scapy-based dual-mode container (sender/responder)
with Flask API, RFC 2544 test suite (throughput, latency, frame-loss,
back-to-back), Vue 3 web UI with flow builder, test runner, real-time
stats monitor, and results export
- docker-compose.yml updated with influxdb, telegraf, traffic-gen,
traffic-gen-ui services
- Full documentation in DOCS.md sections 15-16
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:29:44 -07:00
"refId" : "A"
}
] ,
"title" : "Interface Traffic" ,
"type" : "timeseries"
} ,
{
"datasource" : { "type" : "postgres" , "uid" : "obmp_postgres" } ,
"description" : "BGP update activity over time from the OpenBMP PostgreSQL database. Shows peer event transitions and update counts for correlation with traffic patterns." ,
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "palette-classic" } ,
"custom" : { "axisBorderShow" : false , "axisCenteredZero" : false , "axisLabel" : "" , "axisPlacement" : "auto" , "barAlignment" : 0 , "drawStyle" : "bars" , "fillOpacity" : 50 , "gradientMode" : "none" , "hideFrom" : { "legend" : false , "tooltip" : false , "viz" : false } , "lineInterpolation" : "linear" , "lineWidth" : 1 , "pointSize" : 5 , "scaleDistribution" : { "type" : "linear" } , "showPoints" : "never" , "spanNulls" : false , "stacking" : { "group" : "A" , "mode" : "normal" } , "thresholdsStyle" : { "mode" : "off" } } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } ] } ,
"unit" : "short"
}
} ,
"gridPos" : { "h" : 10 , "w" : 24 , "x" : 0 , "y" : 20 } ,
"id" : 3 ,
"options" : { "legend" : { "calcs" : [ "sum" ] , "displayMode" : "table" , "placement" : "bottom" } , "tooltip" : { "mode" : "multi" , "sort" : "desc" } } ,
"targets" : [
{
"datasource" : { "type" : "postgres" , "uid" : "obmp_postgres" } ,
"format" : "time_series" ,
"rawSql" : "SELECT\n $__timeGroupAlias(e.timestamp, '1m'),\n COALESCE(p.name, p.peer_addr::text) AS metric,\n COUNT(*) AS \"value\"\nFROM peer_event_log e\nJOIN bgp_peers p ON p.hash_id = e.peer_hash_id\nWHERE $__timeFilter(e.timestamp)\nGROUP BY 1, 2\nORDER BY 1" ,
"refId" : "A"
}
] ,
"title" : "BGP Update Activity" ,
"type" : "timeseries"
} ,
{
"datasource" : { "type" : "datasource" , "uid" : "grafana" } ,
"gridPos" : { "h" : 6 , "w" : 24 , "x" : 0 , "y" : 30 } ,
"id" : 4 ,
"options" : {
"code" : { "language" : "plaintext" , "showLineNumbers" : false , "showMiniMap" : false } ,
"content" : "## Combined BMP + Telemetry View\n\nThis dashboard integrates two complementary data sources to provide a unified network monitoring view:\n\n### Control Plane (BMP via PostgreSQL)\n- **BGP Peer Status** -- Real-time BGP session state from BMP (OpenBMP)\n- **BGP Update Activity** -- Session transitions and update events from `peer_event_log`\n\n### Data Plane (gNMI via InfluxDB)\n- **Interface Traffic** -- Streaming telemetry byte rates collected via gNMI at 10-second intervals\n\n### Correlation Use Cases\n- A BGP peer flap (control plane) should correlate with a traffic shift on affected interfaces (data plane)\n- Sustained high interface utilization (data plane) may precede BGP session resets due to congestion\n- Compare the number of active BGP peers with interface traffic to validate routing convergence" ,
"mode" : "markdown"
} ,
"title" : "About" ,
"type" : "text"
}
] ,
"schemaVersion" : 39 ,
"style" : "dark" ,
"tags" : [ "obmp-telemetry" ] ,
"time" : { "from" : "now-1h" , "to" : "now" } ,
"timepicker" : { } ,
"timezone" : "browser" ,
"title" : "Combined BMP + Telemetry View" ,
"uid" : "obmp-telem-03" ,
"version" : 1
}