{
  "__inputs": [
    {
      "name": "DS_PROMETHEUS",
      "label": "Prometheus",
      "description": "",
      "type": "datasource",
      "pluginId": "prometheus",
      "pluginName": "Prometheus"
    }
  ],
  "__requires": [
    {
      "type": "grafana",
      "id": "grafana",
      "name": "Grafana",
      "version": "10.0.0"
    },
    {
      "type": "datasource",
      "id": "prometheus",
      "name": "Prometheus",
      "version": "1.0.0"
    },
    {
      "type": "panel",
      "id": "timeseries",
      "name": "Time series",
      "version": ""
    },
    {
      "type": "panel",
      "id": "stat",
      "name": "Stat",
      "version": ""
    }
  ],
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": {
          "type": "grafana",
          "uid": "-- Grafana --"
        },
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "fiscalYearStartMonth": 0,
  "graphTooltip": 1,
  "id": null,
  "links": [],
  "liveNow": false,
  "panels": [
    {
      "id": 1,
      "type": "row",
      "title": "Overview",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 0
      },
      "panels": []
    },
    {
      "id": 2,
      "type": "stat",
      "title": "Active attacks",
      "description": "Attacks currently in progress (kapkan_engine_active_attacks).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 0,
        "y": 1
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "color": {
            "mode": "thresholds"
          },
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 1
              }
            ]
          }
        },
        "overrides": []
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "colorMode": "value",
        "graphMode": "area",
        "textMode": "auto",
        "justifyMode": "auto",
        "orientation": "auto"
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_engine_active_attacks",
          "refId": "A",
          "legendFormat": "",
          "instant": true,
          "range": false
        }
      ]
    },
    {
      "id": 3,
      "type": "stat",
      "title": "Tracked hosts",
      "description": "Destination hosts in the sliding window (kapkan_engine_tracked_hosts).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 6,
        "y": 1
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "color": {
            "mode": "thresholds"
          },
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "text",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "colorMode": "value",
        "graphMode": "area",
        "textMode": "auto",
        "justifyMode": "auto",
        "orientation": "auto"
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_engine_tracked_hosts",
          "refId": "A",
          "legendFormat": "",
          "instant": true,
          "range": false
        }
      ]
    },
    {
      "id": 4,
      "type": "stat",
      "title": "Announced routes (real)",
      "description": "Blackhole routes actually announced (mode=real). Peer-enforced rungs only (blackhole/divert/flowspec) \u2014 bans on the local dataplane rung are in kapkan_mitigate_dataplane_bans.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 12,
        "y": 1
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "color": {
            "mode": "thresholds"
          },
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "orange",
                "value": 1
              }
            ]
          }
        },
        "overrides": []
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "colorMode": "value",
        "graphMode": "area",
        "textMode": "auto",
        "justifyMode": "auto",
        "orientation": "auto"
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum(kapkan_mitigate_announced_routes{mode=\"real\"})",
          "refId": "A",
          "legendFormat": "",
          "instant": true,
          "range": false
        }
      ]
    },
    {
      "id": 5,
      "type": "stat",
      "title": "FlowSpec rules (real)",
      "description": "FlowSpec rules actually announced (mode=real). Watch against your upstream's FlowSpec limit.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 4,
        "w": 6,
        "x": 18,
        "y": 1
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "color": {
            "mode": "thresholds"
          },
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "orange",
                "value": 1
              }
            ]
          }
        },
        "overrides": []
      },
      "options": {
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "colorMode": "value",
        "graphMode": "area",
        "textMode": "auto",
        "justifyMode": "auto",
        "orientation": "auto"
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum(kapkan_mitigate_flowspec_rules{mode=\"real\"})",
          "refId": "A",
          "legendFormat": "",
          "instant": true,
          "range": false
        }
      ]
    },
    {
      "id": 6,
      "type": "row",
      "title": "Ingestion",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 5
      },
      "panels": []
    },
    {
      "id": 7,
      "type": "timeseries",
      "title": "Flow records / sec by protocol",
      "description": "Normalized flow records produced (kapkan_ingest_flows_total).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 6
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (proto) (rate(kapkan_ingest_flows_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{proto}}"
        }
      ]
    },
    {
      "id": 8,
      "type": "timeseries",
      "title": "Telemetry datagrams / sec by protocol",
      "description": "UDP telemetry datagrams received (kapkan_ingest_packets_total).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 6
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (proto) (rate(kapkan_ingest_packets_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{proto}}"
        }
      ]
    },
    {
      "id": 9,
      "type": "timeseries",
      "title": "Decode errors / sec by protocol",
      "description": "Datagrams that failed to decode (kapkan_ingest_decode_errors_total).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 14
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (proto) (rate(kapkan_ingest_decode_errors_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{proto}}"
        }
      ]
    },
    {
      "id": 10,
      "type": "timeseries",
      "title": "Dropped flows / sec (engine queue full)",
      "description": "Flows dropped because the engine input queue was full (kapkan_ingest_dropped_flows_total).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 14
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "rate(kapkan_ingest_dropped_flows_total[$__rate_interval])",
          "refId": "A",
          "legendFormat": "dropped"
        }
      ]
    },
    {
      "id": 11,
      "type": "row",
      "title": "Detection / Engine",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 22
      },
      "panels": []
    },
    {
      "id": 12,
      "type": "timeseries",
      "title": "Active attacks",
      "description": "Attacks currently in progress (kapkan_engine_active_attacks).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 7,
        "w": 8,
        "x": 0,
        "y": 23
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_engine_active_attacks",
          "refId": "A",
          "legendFormat": "active"
        }
      ]
    },
    {
      "id": 13,
      "type": "timeseries",
      "title": "Attacks started / sec",
      "description": "AttackStarted events (kapkan_engine_attacks_total).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 7,
        "w": 8,
        "x": 8,
        "y": 23
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "rate(kapkan_engine_attacks_total[$__rate_interval])",
          "refId": "A",
          "legendFormat": "started"
        }
      ]
    },
    {
      "id": 14,
      "type": "timeseries",
      "title": "Tracked hosts",
      "description": "Destination hosts tracked (kapkan_engine_tracked_hosts).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 7,
        "w": 8,
        "x": 16,
        "y": 23
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_engine_tracked_hosts",
          "refId": "A",
          "legendFormat": "hosts"
        }
      ]
    },
    {
      "id": 15,
      "type": "timeseries",
      "title": "Hot-path processing latency (quantiles)",
      "description": "Per-batch flow processing latency (kapkan_engine_process_latency_seconds).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 7,
        "w": 24,
        "x": 0,
        "y": 30
      },
      "fieldConfig": {
        "defaults": {
          "unit": "s",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "histogram_quantile(0.50, sum by (le) (rate(kapkan_engine_process_latency_seconds_bucket[$__rate_interval])))",
          "refId": "A",
          "legendFormat": "p50"
        },
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "histogram_quantile(0.95, sum by (le) (rate(kapkan_engine_process_latency_seconds_bucket[$__rate_interval])))",
          "refId": "B",
          "legendFormat": "p95"
        },
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "histogram_quantile(0.99, sum by (le) (rate(kapkan_engine_process_latency_seconds_bucket[$__rate_interval])))",
          "refId": "C",
          "legendFormat": "p99"
        }
      ]
    },
    {
      "id": 16,
      "type": "row",
      "title": "Mitigation",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 37
      },
      "panels": []
    },
    {
      "id": 17,
      "type": "timeseries",
      "title": "Announced routes by mode",
      "description": "Blackhole routes announced, real vs dry_run (kapkan_mitigate_announced_routes). Counts only rungs that ask a peer to enforce something; the local dataplane rung announces nothing and is graphed separately.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 38
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_mitigate_announced_routes",
          "refId": "A",
          "legendFormat": "{{mode}}"
        }
      ]
    },
    {
      "id": 18,
      "type": "timeseries",
      "title": "FlowSpec rules by mode",
      "description": "FlowSpec rules announced, real vs dry_run (kapkan_mitigate_flowspec_rules).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 38
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_mitigate_flowspec_rules",
          "refId": "A",
          "legendFormat": "{{mode}}"
        }
      ]
    },
    {
      "id": 19,
      "type": "timeseries",
      "title": "Bans rejected / sec by reason",
      "description": "Bans refused by a safety guard (kapkan_mitigate_bans_rejected_total). Climbing blast_radius_* means containment is firing.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 46
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (reason) (rate(kapkan_mitigate_bans_rejected_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{reason}}"
        }
      ]
    },
    {
      "id": 20,
      "type": "timeseries",
      "title": "Mitigation fallbacks / sec (from to)",
      "description": "Announces that degraded to a fallback method (kapkan_mitigate_fallback_total). A non-zero from=flowspec series flags upstreams that ignore FlowSpec.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 46
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (from, to) (rate(kapkan_mitigate_fallback_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{from}} \u2192 {{to}}"
        }
      ]
    },
    {
      "id": 32,
      "type": "timeseries",
      "title": "Data-plane bans by mode",
      "description": "Bans enforced by this host's own XDP data plane rather than by an upstream, real vs dry_run (kapkan_mitigate_dataplane_bans). These announce nothing to any peer and keep filtering through a BGP outage, which is why they are absent from announced routes.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 54
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_mitigate_dataplane_bans",
          "refId": "A",
          "legendFormat": "{{mode}}"
        }
      ]
    },
    {
      "id": 33,
      "type": "timeseries",
      "title": "Data-plane rules by mode (mitigator)",
      "description": "Rules the mitigator believes it installed, attributed to the bans that own them, real vs dry_run (kapkan_mitigate_dataplane_rules). A ban contributes 1 rule for a cleanly classified single-vector attack and up to 8 for a mixed or unclassified one. Watch it against dataplane.limits.max_dynamic_rules. In real mode it should track the dynamic half of 'Rules in kernel by mode' \u2014 compare them, never sum them. In dry_run mode the two diverge by design: nothing is installed, so this reports intent while the measured gauge stays at zero.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 54
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_mitigate_dataplane_rules",
          "refId": "A",
          "legendFormat": "{{mode}}"
        }
      ]
    },
    {
      "id": 24,
      "type": "row",
      "title": "Data plane",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 62
      },
      "panels": []
    },
    {
      "id": 25,
      "type": "timeseries",
      "title": "Packets / sec by XDP verdict",
      "description": "Terminal XDP verdicts (kapkan_dataplane_packets_total). Stacked, so the total height is packets through the datapath: observation counters such as dryrun_would_drop are a SEPARATE metric (kapkan_dataplane_observations_total) precisely so this sum does not double-count them.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 63
      },
      "fieldConfig": {
        "defaults": {
          "unit": "pps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 30,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto",
            "stacking": {
              "mode": "normal",
              "group": "A"
            }
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (verdict) (rate(kapkan_dataplane_packets_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{verdict}}"
        }
      ]
    },
    {
      "id": 26,
      "type": "timeseries",
      "title": "Rules in kernel by mode (measured total)",
      "description": "All rules the kernel is actually running \u2014 config statics plus the mitigator's dynamic rules \u2014 real vs dry_run (kapkan_dataplane_rules). dry_run is read back from the datapath, not from the config file: an adopted pin set can be running the previous process's flag. In real mode its dynamic half should track 'Data-plane rules by mode (mitigator)', and a lasting gap there means a withdraw failed or the kernel expired rules under a still-active ban. Under dry_run nothing is installed, so the dynamic half is zero by design.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 63
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_dataplane_rules",
          "refId": "A",
          "legendFormat": "{{mode}}"
        }
      ]
    },
    {
      "id": 27,
      "type": "timeseries",
      "title": "XDP attachment by interface and mode",
      "description": "1 = the program is attached to this interface in this mode (kapkan_dataplane_xdp_mode). BOTH series read 0 for an interface that is not filtering at all, which is the distinction between 'on the generic path' and 'not protected'. mode=generic costs roughly 10x the per-packet CPU of native.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 7,
        "w": 8,
        "x": 0,
        "y": 71
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 0,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_dataplane_xdp_mode",
          "refId": "A",
          "legendFormat": "{{interface}} / {{mode}}"
        }
      ]
    },
    {
      "id": 28,
      "type": "timeseries",
      "title": "Attach errors / sec by interface",
      "description": "Failed XDP attach attempts including watcher retries (kapkan_dataplane_attach_errors_total). Rising WITH kapkan_dataplane_degraded = a NIC that will not take the program; rising WITHOUT it = a flapping link that is being recovered, which no single scrape would ever show.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 7,
        "w": 8,
        "x": 8,
        "y": 71
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (interface) (rate(kapkan_dataplane_attach_errors_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{interface}}"
        }
      ]
    },
    {
      "id": 29,
      "type": "timeseries",
      "title": "Policy generation",
      "description": "The live half of the double-buffered policy (kapkan_dataplane_policy_generation). The VALUE is uninteresting; the SLOPE is the alert. Each flip walks the policy map under the lock that also serialises rule installs, so a generation climbing every second means something is republishing static policy in a loop.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 7,
        "w": 8,
        "x": 16,
        "y": 71
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 0,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "kapkan_dataplane_policy_generation",
          "refId": "A",
          "legendFormat": "generation"
        }
      ]
    },
    {
      "id": 30,
      "type": "timeseries",
      "title": "Policy apply time (quantiles)",
      "description": "Time to build and publish one generation of static policy (kapkan_dataplane_policy_apply_seconds). This span holds the Manager lock, and that lock is what a rule install waits on \u2014 so this panel answers 'could a config reload have delayed mitigating an attack?'.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 78
      },
      "fieldConfig": {
        "defaults": {
          "unit": "s",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "histogram_quantile(0.50, sum by (le) (rate(kapkan_dataplane_policy_apply_seconds_bucket[$__rate_interval])))",
          "refId": "A",
          "legendFormat": "p50"
        },
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "histogram_quantile(0.95, sum by (le) (rate(kapkan_dataplane_policy_apply_seconds_bucket[$__rate_interval])))",
          "refId": "B",
          "legendFormat": "p95"
        },
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "histogram_quantile(0.99, sum by (le) (rate(kapkan_dataplane_policy_apply_seconds_bucket[$__rate_interval])))",
          "refId": "C",
          "legendFormat": "p99"
        }
      ]
    },
    {
      "id": 31,
      "type": "timeseries",
      "title": "BPF map entries (as created)",
      "description": "max_entries of each map after dataplane.limits were applied (kapkan_dataplane_map_entries). This is the feedback loop for sizing: the maps are charged to the unit's memory cgroup in one step at load, so an operator who lowers max_ratelimit_sources should SEE the result here rather than infer it. Pair with kapkan_dataplane_map_bytes for the footprint.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 78
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 0,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "topk(8, kapkan_dataplane_map_entries)",
          "refId": "A",
          "legendFormat": "{{map}}"
        }
      ]
    },
    {
      "id": 21,
      "type": "row",
      "title": "Notifications & Storage",
      "collapsed": false,
      "gridPos": {
        "h": 1,
        "w": 24,
        "x": 0,
        "y": 86
      },
      "panels": []
    },
    {
      "id": 22,
      "type": "timeseries",
      "title": "Notifications / sec by channel and result",
      "description": "Notification attempts (kapkan_notify_notifications_total).",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 87
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (channel, result) (rate(kapkan_notify_notifications_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{channel}} {{result}}"
        }
      ]
    },
    {
      "id": 23,
      "type": "timeseries",
      "title": "Storage rows / sec by table and result",
      "description": "Rows handed to ClickHouse storage (kapkan_storage_rows_total). result=dropped means the bounded queue was full.",
      "datasource": {
        "type": "prometheus",
        "uid": "${DS_PROMETHEUS}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 87
      },
      "fieldConfig": {
        "defaults": {
          "unit": "cps",
          "custom": {
            "drawStyle": "line",
            "lineInterpolation": "linear",
            "fillOpacity": 12,
            "showPoints": "never",
            "lineWidth": 1,
            "axisPlacement": "auto"
          },
          "color": {
            "mode": "palette-classic"
          }
        },
        "overrides": []
      },
      "options": {
        "legend": {
          "displayMode": "list",
          "placement": "bottom",
          "calcs": []
        },
        "tooltip": {
          "mode": "multi",
          "sort": "desc"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "expr": "sum by (table, result) (rate(kapkan_storage_rows_total[$__rate_interval]))",
          "refId": "A",
          "legendFormat": "{{table}} {{result}}"
        }
      ]
    }
  ],
  "refresh": "30s",
  "schemaVersion": 39,
  "style": "dark",
  "tags": [
    "kapkan",
    "ddos",
    "mitigation"
  ],
  "templating": {
    "list": []
  },
  "time": {
    "from": "now-6h",
    "to": "now"
  },
  "timepicker": {},
  "timezone": "",
  "title": "Kapkan \u2014 Overview",
  "uid": "kapkan-overview",
  "version": 2,
  "weekStart": ""
}
