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" : "Interface utilization metrics collected via gNMI streaming telemetry from IOS-XR routers. Shows byte rates, packet rates, and top interfaces by traffic volume." ,
"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"
} ,
{
"current" : { } ,
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"definition" : "from(bucket: \"telemetry\")\n |> range(start: -1h)\n |> filter(fn: (r) => r._measurement == \"interface_counters\")\n |> filter(fn: (r) => r.source =~ /${router:regex}/)\n |> keep(columns: [\"name\"])\n |> distinct(column: \"name\")\n |> sort()" ,
"hide" : 0 ,
"includeAll" : true ,
"label" : "Interface" ,
"multi" : true ,
"name" : "interface" ,
"options" : [ ] ,
"query" : "from(bucket: \"telemetry\")\n |> range(start: -1h)\n |> filter(fn: (r) => r._measurement == \"interface_counters\")\n |> filter(fn: (r) => r.source =~ /${router:regex}/)\n |> keep(columns: [\"name\"])\n |> distinct(column: \"name\")\n |> sort()" ,
"refresh" : 2 ,
"regex" : "" ,
"type" : "query"
}
]
} ,
"panels" : [
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"description" : "Rate of bytes received and sent per interface, computed as the derivative of cumulative counters. Unit: bytes per second." ,
"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" : 0 } ,
"id" : 1 ,
"options" : { "legend" : { "calcs" : [ "mean" , "max" ] , "displayMode" : "table" , "placement" : "bottom" } , "tooltip" : { "mode" : "multi" , "sort" : "desc" } } ,
"targets" : [
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
2026-05-15 14:22:58 -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.name =~ /${interface:regex}/)\n |> filter(fn: (r) => r._field == \"in-octets\" or r._field == \"out-octets\")\n |> toFloat()\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" : "Input/Output Bytes Rate" ,
"type" : "timeseries"
} ,
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"description" : "Rate of packets received and sent per interface, computed as the derivative of cumulative counters. Unit: packets per second." ,
"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" : "pps"
}
} ,
"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-05-15 14:22:58 -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.name =~ /${interface:regex}/)\n |> filter(fn: (r) => r._field == \"in-pkts\" or r._field == \"out-pkts\")\n |> toFloat()\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" : "Input/Output Packets Rate" ,
"type" : "timeseries"
} ,
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"description" : "Top interfaces ranked by total bytes (received + sent) over the selected time range." ,
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "palette-classic" } ,
"custom" : { "axisBorderShow" : false , "axisCenteredZero" : false , "axisLabel" : "" , "axisPlacement" : "auto" , "fillOpacity" : 80 , "gradientMode" : "none" , "hideFrom" : { "legend" : false , "tooltip" : false , "viz" : false } , "lineWidth" : 1 , "scaleDistribution" : { "type" : "linear" } , "thresholdsStyle" : { "mode" : "off" } } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } ] } ,
"unit" : "decbytes"
}
} ,
"gridPos" : { "h" : 10 , "w" : 24 , "x" : 0 , "y" : 20 } ,
"id" : 3 ,
"options" : { "barRadius" : 0 , "barWidth" : 0.6 , "fullHighlight" : false , "groupWidth" : 0.7 , "legend" : { "calcs" : [ ] , "displayMode" : "list" , "placement" : "bottom" } , "orientation" : "horizontal" , "showValue" : "auto" , "stacking" : "none" , "tooltip" : { "mode" : "single" , "sort" : "none" } , "xTickLabelRotation" : 0 } ,
"targets" : [
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
2026-05-15 14:22:58 -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.name =~ /${interface:regex}/)\n |> filter(fn: (r) => r._field == \"in-octets\" or r._field == \"out-octets\")\n |> toFloat()\n |> derivative(unit: 1s, nonNegative: true)\n |> group(columns: [\"source\", \"name\", \"_field\"])\n |> sum()\n |> group(columns: [\"source\", \"name\"])\n |> sum()\n |> group()\n |> sort(columns: [\"_value\"], desc: true)\n |> limit(n: 20)" ,
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" : "Top Interfaces by Traffic" ,
"type" : "barchart"
} ,
{
"datasource" : { "type" : "datasource" , "uid" : "grafana" } ,
"gridPos" : { "h" : 4 , "w" : 24 , "x" : 0 , "y" : 30 } ,
"id" : 4 ,
"options" : {
"code" : { "language" : "plaintext" , "showLineNumbers" : false , "showMiniMap" : false } ,
2026-03-06 16:19:16 -07:00
"content" : "## Interface Utilization Dashboard\n\nThis dashboard displays real-time interface utilization metrics collected via **gNMI streaming telemetry** from IOS-XR routers.\n\n- **Data source:** InfluxDB (Telegraf gNMI input plugin)\n- **YANG model:** OpenConfig (`openconfig-interfaces`)\n- **Subscription path:** `/interfaces/interface/state/counters`\n- **Sample interval:** 10 seconds\n\nUse the **Router** and **Interface** template variables at the top to filter the view." ,
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
"mode" : "markdown"
} ,
"title" : "About" ,
"type" : "text"
}
] ,
"schemaVersion" : 39 ,
"style" : "dark" ,
"tags" : [ "obmp-telemetry" ] ,
"time" : { "from" : "now-1h" , "to" : "now" } ,
"timepicker" : { } ,
"timezone" : "browser" ,
"title" : "Interface Utilization" ,
"uid" : "obmp-telem-01" ,
"version" : 1
}