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 error and drop counters collected via gNMI streaming telemetry. Helps identify interfaces with packet loss or physical layer issues." ,
"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" : "Interface error counters over time: input errors, output errors, and CRC errors. A rising trend indicates physical or configuration issues." ,
"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" : "yellow" , "value" : 1 } , { "color" : "red" , "value" : 100 } ] } ,
"unit" : "short"
}
} ,
"gridPos" : { "h" : 10 , "w" : 24 , "x" : 0 , "y" : 0 } ,
"id" : 1 ,
"options" : { "legend" : { "calcs" : [ "mean" , "max" , "last" ] , "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-errors\" or r._field == \"out-errors\" or r._field == \"in-fcs-errors\")\n |> toFloat()\n |> derivative(unit: 1s, nonNegative: true)" ,
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 Errors" ,
"type" : "timeseries"
} ,
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"description" : "Interface drop counters over time: input drops and output drops. Drops indicate congestion or queue overflow." ,
"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" : "yellow" , "value" : 1 } , { "color" : "red" , "value" : 100 } ] } ,
"unit" : "short"
}
} ,
"gridPos" : { "h" : 10 , "w" : 24 , "x" : 0 , "y" : 10 } ,
"id" : 2 ,
"options" : { "legend" : { "calcs" : [ "mean" , "max" , "last" ] , "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-discards\" or r._field == \"out-discards\")\n |> toFloat()\n |> derivative(unit: 1s, nonNegative: true)" ,
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 Drops" ,
"type" : "timeseries"
} ,
{
"datasource" : { "type" : "influxdb" , "uid" : "obmp_influxdb" } ,
"description" : "Summary table showing the latest error and drop counter values per interface. Useful for quickly identifying problematic interfaces." ,
"fieldConfig" : {
"defaults" : {
"color" : { "mode" : "thresholds" } ,
"custom" : { "align" : "auto" , "displayMode" : "auto" , "filterable" : true , "inspect" : true } ,
"mappings" : [ ] ,
"thresholds" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } , { "color" : "yellow" , "value" : 1 } , { "color" : "red" , "value" : 100 } ] }
} ,
"overrides" : [
2026-03-06 16:19:16 -07:00
{ "matcher" : { "id" : "byName" , "options" : "in-errors" } , "properties" : [ { "id" : "custom.displayMode" , "value" : "color-background-solid" } , { "id" : "thresholds" , "value" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } , { "color" : "yellow" , "value" : 1 } , { "color" : "red" , "value" : 100 } ] } } ] } ,
{ "matcher" : { "id" : "byName" , "options" : "out-errors" } , "properties" : [ { "id" : "custom.displayMode" , "value" : "color-background-solid" } , { "id" : "thresholds" , "value" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } , { "color" : "yellow" , "value" : 1 } , { "color" : "red" , "value" : 100 } ] } } ] } ,
{ "matcher" : { "id" : "byName" , "options" : "in-discards" } , "properties" : [ { "id" : "custom.displayMode" , "value" : "color-background-solid" } , { "id" : "thresholds" , "value" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } , { "color" : "yellow" , "value" : 1 } , { "color" : "red" , "value" : 100 } ] } } ] } ,
{ "matcher" : { "id" : "byName" , "options" : "out-discards" } , "properties" : [ { "id" : "custom.displayMode" , "value" : "color-background-solid" } , { "id" : "thresholds" , "value" : { "mode" : "absolute" , "steps" : [ { "color" : "green" , "value" : null } , { "color" : "yellow" , "value" : 1 } , { "color" : "red" , "value" : 100 } ] } } ] }
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
]
} ,
"gridPos" : { "h" : 12 , "w" : 24 , "x" : 0 , "y" : 20 } ,
"id" : 3 ,
2026-03-06 16:19:16 -07:00
"options" : { "footer" : { "fields" : "" , "reducer" : [ "sum" ] , "show" : false } , "showHeader" : true , "sortBy" : [ { "desc" : true , "displayName" : "in-errors" } ] } ,
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
"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-errors\" or r._field == \"out-errors\" or r._field == \"in-fcs-errors\" or r._field == \"in-discards\" or r._field == \"out-discards\")\n |> toFloat()\n |> last()\n |> pivot(rowKey: [\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\")\n |> keep(columns: [\"source\", \"name\", \"in-errors\", \"out-errors\", \"in-fcs-errors\", \"in-discards\", \"out-discards\"])\n |> sort(columns: [\"in-errors\"], desc: true)" ,
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" : "Error Summary Table" ,
"type" : "table"
}
] ,
"schemaVersion" : 39 ,
"style" : "dark" ,
"tags" : [ "obmp-telemetry" ] ,
"time" : { "from" : "now-1h" , "to" : "now" } ,
"timepicker" : { } ,
"timezone" : "browser" ,
"title" : "Interface Errors & Drops" ,
"uid" : "obmp-telem-02" ,
"version" : 1
}