diff --git a/obmp-grafana/dashboards/obmp/History-1002/router_diff.json b/obmp-grafana/dashboards/obmp/History-1002/router_diff.json new file mode 100644 index 0000000..d6c7f26 --- /dev/null +++ b/obmp-grafana/dashboards/obmp/History-1002/router_diff.json @@ -0,0 +1,901 @@ +{ + "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": "Generic Router Diff. Compares the BGP routing tables (BMP Adj-RIB-In) of up to 4 selectable routers. Generalized from the 2-router RR Loc-RIB Diff dashboard. Router 1 and Router 2 are always compared; Router 3 and Router 4 are optional - set them to '-- none --' to compare just two.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "obmp-nav" + ], + "title": "OBMP Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "content": "## Router Diff\n\nCompares the BGP routing tables of up to **4 routers** via BMP (Adj-RIB-In). Select routers with the **Router 1-4** dropdowns. **Router 1** and **Router 2** are always compared; set **Router 3** / **Router 4** to `-- none --` to compare just two or three.\n\n- **Presence Matrix** — one row per prefix, one column per selected router, cell = best-path next-hop. Blank cell = prefix absent on that router.\n- **Divergence** — prefixes that are missing on some routers or whose best-path next-hop / AS-path disagree.\n- **Summary stats** — prefix count per router and total divergent prefixes.\n- **All Paths** — per-prefix drill-down across the selected routers (pick a prefix with the **Prefix** dropdown).", + "mode": "markdown" + }, + "title": "Router Diff — Overview", + "type": "text" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Active (non-withdrawn) prefixes on Router 1 for the selected AFI.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 5 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "SELECT COUNT(DISTINCT r.prefix::text) AS \"prefixes\"\nFROM ip_rib r\nJOIN bgp_peers p ON p.hash_id = r.peer_hash_id\nJOIN routers rt ON rt.hash_id = p.router_hash_id\nWHERE rt.name = '$router1' AND r.iswithdrawn = false\n AND ('$afi' = 'All' OR ('$afi' = 'IPv4' AND r.isipv4) OR ('$afi' = 'IPv6' AND NOT r.isipv4))", + "refId": "A" + } + ], + "title": "$router1 Prefixes", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Active (non-withdrawn) prefixes on Router 2 for the selected AFI.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "green", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 5 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "SELECT COUNT(DISTINCT r.prefix::text) AS \"prefixes\"\nFROM ip_rib r\nJOIN bgp_peers p ON p.hash_id = r.peer_hash_id\nJOIN routers rt ON rt.hash_id = p.router_hash_id\nWHERE rt.name = '$router2' AND r.iswithdrawn = false\n AND ('$afi' = 'All' OR ('$afi' = 'IPv4' AND r.isipv4) OR ('$afi' = 'IPv6' AND NOT r.isipv4))", + "refId": "A" + } + ], + "title": "$router2 Prefixes", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Active prefixes on Router 3 for the selected AFI. Shows 0 when Router 3 is set to '-- none --'.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "purple", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 5 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "SELECT COUNT(DISTINCT r.prefix::text) AS \"prefixes\"\nFROM ip_rib r\nJOIN bgp_peers p ON p.hash_id = r.peer_hash_id\nJOIN routers rt ON rt.hash_id = p.router_hash_id\nWHERE rt.name = '$router3' AND r.iswithdrawn = false\n AND ('$afi' = 'All' OR ('$afi' = 'IPv4' AND r.isipv4) OR ('$afi' = 'IPv6' AND NOT r.isipv4))", + "refId": "A" + } + ], + "title": "$router3 Prefixes", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Active prefixes on Router 4 for the selected AFI. Shows 0 when Router 4 is set to '-- none --'.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 5 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "SELECT COUNT(DISTINCT r.prefix::text) AS \"prefixes\"\nFROM ip_rib r\nJOIN bgp_peers p ON p.hash_id = r.peer_hash_id\nJOIN routers rt ON rt.hash_id = p.router_hash_id\nWHERE rt.name = '$router4' AND r.iswithdrawn = false\n AND ('$afi' = 'All' OR ('$afi' = 'IPv4' AND r.isipv4) OR ('$afi' = 'IPv6' AND NOT r.isipv4))", + "refId": "A" + } + ], + "title": "$router4 Prefixes", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Distinct prefixes that diverge across the selected routers — either missing on some routers or with a different best-path next-hop / AS-path.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "red", + "value": 25 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 5 + }, + "id": 14, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "WITH params AS (\n SELECT '$router1'::text AS r1, '$router2'::text AS r2,\n '$router3'::text AS r3, '$router4'::text AS r4, '$afi'::text AS afi\n),\nbp AS (\n SELECT DISTINCT ON (rt.name, r.prefix, r.prefix_len)\n rt.name AS rname, r.prefix, r.prefix_len, ba.next_hop, ba.as_path\n FROM ip_rib r\n JOIN bgp_peers p ON p.hash_id = r.peer_hash_id\n JOIN routers rt ON rt.hash_id = p.router_hash_id\n JOIN base_attrs ba ON ba.hash_id = r.base_attr_hash_id\n CROSS JOIN params\n WHERE r.iswithdrawn = false\n AND rt.name IN (params.r1, params.r2, params.r3, params.r4)\n AND (params.afi = 'All' OR (params.afi = 'IPv4' AND r.isipv4) OR (params.afi = 'IPv6' AND NOT r.isipv4))\n ORDER BY rt.name, r.prefix, r.prefix_len, ba.local_pref DESC NULLS LAST\n),\nagg AS (\n SELECT bp.prefix, bp.prefix_len,\n COUNT(DISTINCT bp.rname) AS present_on,\n COUNT(DISTINCT host(bp.next_hop)) AS nh_variants,\n COUNT(DISTINCT bp.as_path) AS path_variants\n FROM bp GROUP BY bp.prefix, bp.prefix_len\n),\nsel AS (\n SELECT COUNT(*) AS n FROM (\n SELECT t.v FROM params, unnest(ARRAY[params.r1, params.r2, params.r3, params.r4]) AS t(v)\n WHERE t.v <> '-- none --'\n ) s\n)\nSELECT COUNT(*) AS \"divergent\"\nFROM agg\nWHERE agg.present_on < (SELECT n FROM sel) OR agg.nh_variants > 1 OR agg.path_variants > 1", + "refId": "A" + } + ], + "title": "Divergent Prefixes", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Number of routers currently selected (Router 1-4, excluding any set to '-- none --').", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 5 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "SELECT COUNT(*) AS \"routers\"\nFROM (\n SELECT t.v\n FROM unnest(ARRAY['$router1','$router2','$router3','$router4']) AS t(v)\n WHERE t.v <> '-- none --'\n) s", + "refId": "A" + } + ], + "title": "Routers Selected", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 20, + "title": "Presence Matrix", + "type": "row" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "One row per prefix, one column per selected router. Each cell shows the best-path next-hop on that router; a blank cell means the prefix is absent there. Columns for routers set to '-- none --' are headed '-- none --' and stay empty. Filter by AFI with the dropdown.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": true + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Prefix" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "AFI" + }, + "properties": [ + { + "id": "custom.width", + "value": 70 + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 21, + "options": { + "footer": { + "fields": "", + "reducer": [ + "count" + ], + "show": true + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Prefix" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "WITH params AS (\n SELECT '$router1'::text AS r1, '$router2'::text AS r2,\n '$router3'::text AS r3, '$router4'::text AS r4, '$afi'::text AS afi\n),\nbp AS (\n SELECT DISTINCT ON (rt.name, r.prefix, r.prefix_len)\n rt.name AS rname, r.prefix, r.prefix_len, r.isipv4, ba.next_hop\n FROM ip_rib r\n JOIN bgp_peers p ON p.hash_id = r.peer_hash_id\n JOIN routers rt ON rt.hash_id = p.router_hash_id\n JOIN base_attrs ba ON ba.hash_id = r.base_attr_hash_id\n CROSS JOIN params\n WHERE r.iswithdrawn = false\n AND rt.name IN (params.r1, params.r2, params.r3, params.r4)\n AND (params.afi = 'All' OR (params.afi = 'IPv4' AND r.isipv4) OR (params.afi = 'IPv6' AND NOT r.isipv4))\n ORDER BY rt.name, r.prefix, r.prefix_len, ba.local_pref DESC NULLS LAST\n)\nSELECT\n bp.prefix::text AS \"Prefix\",\n CASE WHEN bp.isipv4 THEN 'IPv4' ELSE 'IPv6' END AS \"AFI\",\n MAX(CASE WHEN bp.rname = pr.r1 THEN host(bp.next_hop) END) AS \"$router1\",\n MAX(CASE WHEN bp.rname = pr.r2 THEN host(bp.next_hop) END) AS \"$router2\",\n MAX(CASE WHEN bp.rname = pr.r3 THEN host(bp.next_hop) END) AS \"$router3\",\n MAX(CASE WHEN bp.rname = pr.r4 THEN host(bp.next_hop) END) AS \"$router4\"\nFROM bp CROSS JOIN params pr\nGROUP BY bp.prefix, bp.prefix_len, bp.isipv4, pr.r1, pr.r2, pr.r3, pr.r4\nORDER BY \"Prefix\"", + "refId": "A" + } + ], + "title": "Prefix Presence Matrix (cell = best-path next-hop)", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 30, + "title": "Divergence", + "type": "row" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Prefixes where the selected routers disagree: either the prefix is present on some routers but not all, or the best-path next-hop / AS-path differs between routers. 'Present On' counts how many selected routers carry the prefix; 'Selected' is the total selected router count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": true + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Divergence" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "AS-Path differs": { + "color": "orange", + "index": 1 + }, + "Missing on some": { + "color": "red", + "index": 0 + }, + "NH + AS-Path differ": { + "color": "red", + "index": 3 + }, + "Next-Hop differs": { + "color": "yellow", + "index": 2 + } + }, + "type": "value" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Next-Hops" + }, + "properties": [ + { + "id": "custom.width", + "value": 320 + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 31, + "options": { + "footer": { + "fields": "", + "reducer": [ + "count" + ], + "show": true + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Prefix" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "WITH params AS (\n SELECT '$router1'::text AS r1, '$router2'::text AS r2,\n '$router3'::text AS r3, '$router4'::text AS r4, '$afi'::text AS afi\n),\nbp AS (\n SELECT DISTINCT ON (rt.name, r.prefix, r.prefix_len)\n rt.name AS rname, r.prefix, r.prefix_len, r.isipv4, ba.next_hop, ba.as_path\n FROM ip_rib r\n JOIN bgp_peers p ON p.hash_id = r.peer_hash_id\n JOIN routers rt ON rt.hash_id = p.router_hash_id\n JOIN base_attrs ba ON ba.hash_id = r.base_attr_hash_id\n CROSS JOIN params\n WHERE r.iswithdrawn = false\n AND rt.name IN (params.r1, params.r2, params.r3, params.r4)\n AND (params.afi = 'All' OR (params.afi = 'IPv4' AND r.isipv4) OR (params.afi = 'IPv6' AND NOT r.isipv4))\n ORDER BY rt.name, r.prefix, r.prefix_len, ba.local_pref DESC NULLS LAST\n),\nagg AS (\n SELECT bp.prefix, bp.prefix_len, bool_and(bp.isipv4) AS isipv4,\n COUNT(DISTINCT bp.rname) AS present_on,\n COUNT(DISTINCT host(bp.next_hop)) AS nh_variants,\n COUNT(DISTINCT bp.as_path) AS path_variants,\n string_agg(DISTINCT bp.rname || '=' || host(bp.next_hop), ', ' ORDER BY bp.rname || '=' || host(bp.next_hop)) AS nh_detail\n FROM bp GROUP BY bp.prefix, bp.prefix_len\n),\nsel AS (\n SELECT COUNT(*) AS n FROM (\n SELECT t.v FROM params, unnest(ARRAY[params.r1, params.r2, params.r3, params.r4]) AS t(v)\n WHERE t.v <> '-- none --'\n ) s\n)\nSELECT\n agg.prefix::text AS \"Prefix\",\n CASE WHEN agg.isipv4 THEN 'IPv4' ELSE 'IPv6' END AS \"AFI\",\n agg.present_on AS \"Present On\",\n (SELECT n FROM sel) AS \"Selected\",\n CASE\n WHEN agg.present_on < (SELECT n FROM sel) THEN 'Missing on some'\n WHEN agg.nh_variants > 1 AND agg.path_variants > 1 THEN 'NH + AS-Path differ'\n WHEN agg.nh_variants > 1 THEN 'Next-Hop differs'\n WHEN agg.path_variants > 1 THEN 'AS-Path differs'\n ELSE 'Consistent'\n END AS \"Divergence\",\n agg.nh_detail AS \"Next-Hops\"\nFROM agg\nWHERE agg.present_on < (SELECT n FROM sel) OR agg.nh_variants > 1 OR agg.path_variants > 1\nORDER BY \"Prefix\"", + "refId": "A" + } + ], + "title": "Divergent Prefixes — Detail", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 40, + "title": "Per-Prefix All Paths", + "type": "row" + }, + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "description": "Every path for the prefix chosen in the Prefix dropdown, across all selected routers. Use this to drill into a divergent prefix and see exactly which path each router holds and where it was learned from.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": true + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Router" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 41, + "options": { + "footer": { + "fields": "", + "reducer": [ + "count" + ], + "show": true + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Router" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "format": "table", + "rawSql": "SELECT\n rt.name AS \"Router\",\n p.peer_addr::text AS \"Learned From\",\n host(ba.next_hop) AS \"Next Hop\",\n ba.as_path::text AS \"AS Path\",\n ba.origin_as AS \"Origin AS\",\n COALESCE(ba.local_pref, 0) AS \"Local Pref\",\n COALESCE(ba.med, 0) AS \"MED\",\n ba.community_list::text AS \"Communities\",\n ba.cluster_list::text AS \"Cluster List\",\n host(ba.originator_id) AS \"Originator ID\",\n r.labels AS \"Labels\",\n r.timestamp AS \"Last Update\"\nFROM ip_rib r\nJOIN bgp_peers p ON p.hash_id = r.peer_hash_id\nJOIN routers rt ON rt.hash_id = p.router_hash_id\nJOIN base_attrs ba ON ba.hash_id = r.base_attr_hash_id\nWHERE rt.name IN ('$router1', '$router2', '$router3', '$router4')\n AND r.iswithdrawn = false\n AND r.prefix::text = '$prefix'\nORDER BY rt.name, p.peer_addr", + "refId": "A" + } + ], + "title": "All Paths for $prefix", + "type": "table" + } + ], + "refresh": "30s", + "schemaVersion": 36, + "tags": [ + "obmp", + "obmp-nav", + "bgp", + "diff" + ], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "definition": "SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "hide": 0, + "includeAll": false, + "label": "Router 1", + "multi": false, + "name": "router1", + "options": [], + "query": "SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "definition": "SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "hide": 0, + "includeAll": false, + "label": "Router 2", + "multi": false, + "name": "router2", + "options": [], + "query": "SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "definition": "SELECT '-- none --' AS name UNION ALL SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "description": "Optional third router. Select '-- none --' to compare only two routers.", + "hide": 0, + "includeAll": false, + "label": "Router 3", + "multi": false, + "name": "router3", + "options": [], + "query": "SELECT '-- none --' AS name UNION ALL SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "definition": "SELECT '-- none --' AS name UNION ALL SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "description": "Optional fourth router. Select '-- none --' to compare fewer routers.", + "hide": 0, + "includeAll": false, + "label": "Router 4", + "multi": false, + "name": "router4", + "options": [], + "query": "SELECT '-- none --' AS name UNION ALL SELECT name FROM routers WHERE state = 'up' ORDER BY name", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": { + "selected": true, + "text": "All", + "value": "All" + }, + "hide": 0, + "includeAll": false, + "label": "AFI", + "multi": false, + "name": "afi", + "options": [ + { + "selected": true, + "text": "All", + "value": "All" + }, + { + "selected": false, + "text": "IPv4", + "value": "IPv4" + }, + { + "selected": false, + "text": "IPv6", + "value": "IPv6" + } + ], + "query": "All,IPv4,IPv6", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "obmp_postgres" + }, + "definition": "SELECT DISTINCT r.prefix::text FROM ip_rib r JOIN bgp_peers p ON p.hash_id = r.peer_hash_id JOIN routers rt ON rt.hash_id = p.router_hash_id WHERE rt.name IN ('$router1', '$router2', '$router3', '$router4') AND r.iswithdrawn = false ORDER BY 1", + "hide": 0, + "includeAll": false, + "label": "Prefix", + "multi": false, + "name": "prefix", + "options": [], + "query": "SELECT DISTINCT r.prefix::text FROM ip_rib r JOIN bgp_peers p ON p.hash_id = r.peer_hash_id JOIN routers rt ON rt.hash_id = p.router_hash_id WHERE rt.name IN ('$router1', '$router2', '$router3', '$router4') AND r.iswithdrawn = false ORDER BY 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Router Diff", + "uid": "router-diff", + "version": 1 +}