{ "annotations": { "list": [ { "builtIn": 1, "datasource": { "type": "datasource", "uid": "grafana" }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "target": { "limit": 100, "matchAny": false, "tags": [], "type": "dashboard" }, "type": "dashboard" } ] }, "description": "Compare Route Reflector Loc-RIB tables via BMP Adj-RIB-In. Surfaces missing prefixes, attribute differences, and per-client consistency between two RRs.", "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" } ], "panels": [ { "datasource": { "type": "datasource", "uid": "grafana" }, "gridPos": { "h": 5, "w": 24, "x": 0, "y": 0 }, "id": 1, "options": { "content": "## Route Reflector Loc-RIB Diff\n\nCompares the RIB tables of two Route Reflectors via BMP. Select your two RRs using the **RR1** and **RR2** dropdowns above.\n\n**What this shows:**\n- **Summary stats** \u2014 prefix counts and diff totals\n- **Missing prefixes** \u2014 routes present on one RR but not the other (expected for each RR's own locally-originated routes)\n- **Attribute differences** \u2014 same prefix on both RRs but with different next-hop, AS path, or other attributes (indicates different best-path selection)\n- **Per-client consistency** \u2014 route counts each client sends to each RR (should be identical in a healthy RR cluster)", "mode": "markdown" }, "title": "RR Loc-RIB Diff \u2014 Overview", "type": "text" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Total active (non-withdrawn) prefixes on RR1", "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 || '/' || r.prefix_len) 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 = '$rr1' AND r.iswithdrawn = false", "refId": "A" } ], "title": "$rr1 Prefixes", "type": "stat" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Total active (non-withdrawn) prefixes on RR2", "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 || '/' || r.prefix_len) 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 = '$rr2' AND r.iswithdrawn = false", "refId": "A" } ], "title": "$rr2 Prefixes", "type": "stat" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Prefixes present on RR1 but missing from RR2", "fieldConfig": { "defaults": { "color": { "fixedColor": "orange", "mode": "fixed" }, "thresholds": { "mode": "absolute", "steps": [ { "color": "orange", "value": null }, { "color": "red", "value": 1 } ] } }, "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(*) AS \"only_rr1\"\nFROM (\n SELECT DISTINCT r1.prefix, r1.prefix_len\n FROM ip_rib r1\n JOIN bgp_peers p1 ON p1.hash_id = r1.peer_hash_id\n JOIN routers rt1 ON rt1.hash_id = p1.router_hash_id\n WHERE rt1.name = '$rr1' AND r1.iswithdrawn = false\n EXCEPT\n SELECT DISTINCT r2.prefix, r2.prefix_len\n FROM ip_rib r2\n JOIN bgp_peers p2 ON p2.hash_id = r2.peer_hash_id\n JOIN routers rt2 ON rt2.hash_id = p2.router_hash_id\n WHERE rt2.name = '$rr2' AND r2.iswithdrawn = false\n) sub", "refId": "A" } ], "title": "Only on $rr1", "type": "stat" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Prefixes present on RR2 but missing from RR1", "fieldConfig": { "defaults": { "color": { "fixedColor": "orange", "mode": "fixed" }, "thresholds": { "mode": "absolute", "steps": [ { "color": "orange", "value": null }, { "color": "red", "value": 1 } ] } }, "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(*) AS \"only_rr2\"\nFROM (\n SELECT DISTINCT r2.prefix, r2.prefix_len\n FROM ip_rib r2\n JOIN bgp_peers p2 ON p2.hash_id = r2.peer_hash_id\n JOIN routers rt2 ON rt2.hash_id = p2.router_hash_id\n WHERE rt2.name = '$rr2' AND r2.iswithdrawn = false\n EXCEPT\n SELECT DISTINCT r1.prefix, r1.prefix_len\n FROM ip_rib r1\n JOIN bgp_peers p1 ON p1.hash_id = r1.peer_hash_id\n JOIN routers rt1 ON rt1.hash_id = p1.router_hash_id\n WHERE rt1.name = '$rr1' AND r1.iswithdrawn = false\n) sub", "refId": "A" } ], "title": "Only on $rr2", "type": "stat" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Prefixes present on both RRs but with different best-path attributes (next-hop, AS path, MED, or local-pref)", "fieldConfig": { "defaults": { "color": { "fixedColor": "yellow", "mode": "fixed" }, "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "yellow", "value": 1 }, { "color": "red", "value": 10 } ] } }, "overrides": [] }, "gridPos": { "h": 4, "w": 4, "x": 16, "y": 5 }, "id": 14, "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": "WITH c1 AS (\n SELECT DISTINCT ON (r.prefix, r.prefix_len)\n r.prefix, r.prefix_len, ba.next_hop, ba.as_path,\n COALESCE(ba.local_pref, 0) AS lp, COALESCE(ba.med, 0) AS med\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 WHERE rt.name = '$rr1' AND r.iswithdrawn = false\n ORDER BY r.prefix, r.prefix_len, ba.local_pref DESC NULLS LAST\n),\nc2 AS (\n SELECT DISTINCT ON (r.prefix, r.prefix_len)\n r.prefix, r.prefix_len, ba.next_hop, ba.as_path,\n COALESCE(ba.local_pref, 0) AS lp, COALESCE(ba.med, 0) AS med\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 WHERE rt.name = '$rr2' AND r.iswithdrawn = false\n ORDER BY r.prefix, r.prefix_len, ba.local_pref DESC NULLS LAST\n)\nSELECT COUNT(*) AS \"attr_diffs\"\nFROM c1 JOIN c2 ON c1.prefix = c2.prefix AND c1.prefix_len = c2.prefix_len\nWHERE c1.next_hop != c2.next_hop OR c1.as_path != c2.as_path\n OR c1.lp != c2.lp OR c1.med != c2.med", "refId": "A" } ], "title": "Attribute Diffs", "type": "stat" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Total RIB entries (including multiple paths per prefix) on each RR", "fieldConfig": { "defaults": { "color": { "fixedColor": "purple", "mode": "fixed" }, "thresholds": { "mode": "absolute", "steps": [ { "color": "purple", "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\n SUM(CASE WHEN rt.name = '$rr1' THEN 1 ELSE 0 END) AS \"RR1 Total Paths\",\n SUM(CASE WHEN rt.name = '$rr2' THEN 1 ELSE 0 END) AS \"RR2 Total Paths\"\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 IN ('$rr1', '$rr2') AND r.iswithdrawn = false", "refId": "A" } ], "title": "Total RIB Paths", "type": "stat" }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 9 }, "id": 20, "title": "Missing Prefixes", "type": "row" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Prefixes present on RR1 but NOT on RR2. Expected: RR2's own locally-originated routes won't appear here (they're on RR2 only). Unexpected entries indicate a convergence or session issue.", "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": "Learned From" }, "properties": [ { "id": "custom.width", "value": 130 } ] }, { "matcher": { "id": "byName", "options": "Origin AS" }, "properties": [ { "id": "custom.width", "value": 90 } ] }, { "matcher": { "id": "byName", "options": "Next Hop" }, "properties": [ { "id": "custom.width", "value": 140 } ] } ] }, "gridPos": { "h": 10, "w": 12, "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": "SELECT DISTINCT ON (r1.prefix, r1.prefix_len)\n r1.prefix::text AS \"Prefix\",\n ba.origin_as AS \"Origin AS\",\n ba.next_hop::text AS \"Next Hop\",\n ba.as_path::text AS \"AS Path\",\n p1.peer_addr::text AS \"Learned From\"\nFROM ip_rib r1\nJOIN bgp_peers p1 ON p1.hash_id = r1.peer_hash_id\nJOIN routers rt1 ON rt1.hash_id = p1.router_hash_id\nJOIN base_attrs ba ON ba.hash_id = r1.base_attr_hash_id\nWHERE rt1.name = '$rr1' AND r1.iswithdrawn = false\n AND NOT EXISTS (\n SELECT 1 FROM ip_rib r2\n JOIN bgp_peers p2 ON p2.hash_id = r2.peer_hash_id\n JOIN routers rt2 ON rt2.hash_id = p2.router_hash_id\n WHERE rt2.name = '$rr2'\n AND r2.prefix = r1.prefix AND r2.prefix_len = r1.prefix_len\n AND r2.iswithdrawn = false\n )\nORDER BY r1.prefix, r1.prefix_len, ba.local_pref DESC NULLS LAST", "refId": "A" } ], "title": "Prefixes Only on $rr1", "type": "table" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Prefixes present on RR2 but NOT on RR1. Expected: RR1's own locally-originated routes won't appear here. Unexpected entries indicate a convergence or session issue.", "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": "Learned From" }, "properties": [ { "id": "custom.width", "value": 130 } ] }, { "matcher": { "id": "byName", "options": "Origin AS" }, "properties": [ { "id": "custom.width", "value": 90 } ] }, { "matcher": { "id": "byName", "options": "Next Hop" }, "properties": [ { "id": "custom.width", "value": 140 } ] } ] }, "gridPos": { "h": 10, "w": 12, "x": 12, "y": 10 }, "id": 22, "options": { "footer": { "fields": "", "reducer": [ "count" ], "show": true }, "showHeader": true, "sortBy": [ { "desc": false, "displayName": "Prefix" } ] }, "targets": [ { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "format": "table", "rawSql": "SELECT DISTINCT ON (r2.prefix, r2.prefix_len)\n r2.prefix::text AS \"Prefix\",\n ba.origin_as AS \"Origin AS\",\n ba.next_hop::text AS \"Next Hop\",\n ba.as_path::text AS \"AS Path\",\n p2.peer_addr::text AS \"Learned From\"\nFROM ip_rib r2\nJOIN bgp_peers p2 ON p2.hash_id = r2.peer_hash_id\nJOIN routers rt2 ON rt2.hash_id = p2.router_hash_id\nJOIN base_attrs ba ON ba.hash_id = r2.base_attr_hash_id\nWHERE rt2.name = '$rr2' AND r2.iswithdrawn = false\n AND NOT EXISTS (\n SELECT 1 FROM ip_rib r1\n JOIN bgp_peers p1 ON p1.hash_id = r1.peer_hash_id\n JOIN routers rt1 ON rt1.hash_id = p1.router_hash_id\n WHERE rt1.name = '$rr1'\n AND r1.prefix = r2.prefix AND r1.prefix_len = r2.prefix_len\n AND r1.iswithdrawn = false\n )\nORDER BY r2.prefix, r2.prefix_len, ba.local_pref DESC NULLS LAST", "refId": "A" } ], "title": "Prefixes Only on $rr2", "type": "table" }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 20 }, "id": 30, "title": "Attribute Differences (Same Prefix, Different Best Path)", "type": "row" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Prefixes present on both RRs but where the selected best path differs in next-hop, AS path, local-pref, or MED. This is normal for multi-homed link subnets where each RR selects a different best path based on router-id tiebreaker. Filter by address family using the AFI 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": "RR1 Next Hop" }, "properties": [ { "id": "custom.displayMode", "value": "color-text" }, { "id": "color", "value": { "mode": "fixed", "fixedColor": "blue" } } ] }, { "matcher": { "id": "byName", "options": "RR2 Next Hop" }, "properties": [ { "id": "custom.displayMode", "value": "color-text" }, { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] }, { "matcher": { "id": "byName", "options": "Diff Type" }, "properties": [ { "id": "custom.displayMode", "value": "color-background" }, { "id": "color", "value": { "mode": "thresholds" } }, { "id": "thresholds", "value": { "mode": "absolute", "steps": [ { "color": "yellow", "value": null } ] } } ] } ] }, "gridPos": { "h": 12, "w": 24, "x": 0, "y": 21 }, "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 c1 AS (\n SELECT DISTINCT ON (r.prefix, r.prefix_len)\n r.prefix, r.prefix_len, r.isipv4,\n ba.next_hop, ba.as_path, ba.origin_as,\n COALESCE(ba.local_pref, 0) AS lp, COALESCE(ba.med, 0) AS med,\n ba.community_list, p.peer_addr AS learned_from\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 WHERE rt.name = '$rr1' AND r.iswithdrawn = false\n ORDER BY r.prefix, r.prefix_len, ba.local_pref DESC NULLS LAST\n),\nc2 AS (\n SELECT DISTINCT ON (r.prefix, r.prefix_len)\n r.prefix, r.prefix_len, r.isipv4,\n ba.next_hop, ba.as_path, ba.origin_as,\n COALESCE(ba.local_pref, 0) AS lp, COALESCE(ba.med, 0) AS med,\n ba.community_list, p.peer_addr AS learned_from\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 WHERE rt.name = '$rr2' AND r.iswithdrawn = false\n ORDER BY r.prefix, r.prefix_len, ba.local_pref DESC NULLS LAST\n)\nSELECT\n c1.prefix::text AS \"Prefix\",\n CASE WHEN c1.isipv4 THEN 'IPv4' ELSE 'IPv6' END AS \"AFI\",\n c1.next_hop::text AS \"RR1 Next Hop\",\n c2.next_hop::text AS \"RR2 Next Hop\",\n c1.as_path::text AS \"RR1 AS Path\",\n c2.as_path::text AS \"RR2 AS Path\",\n c1.lp AS \"RR1 LP\",\n c2.lp AS \"RR2 LP\",\n c1.med AS \"RR1 MED\",\n c2.med AS \"RR2 MED\",\n CASE\n WHEN c1.next_hop != c2.next_hop AND c1.as_path != c2.as_path THEN 'NH+ASPath'\n WHEN c1.next_hop != c2.next_hop THEN 'Next-Hop'\n WHEN c1.as_path != c2.as_path THEN 'AS Path'\n WHEN c1.lp != c2.lp THEN 'Local-Pref'\n WHEN c1.med != c2.med THEN 'MED'\n ELSE 'Other'\n END AS \"Diff Type\"\nFROM c1 JOIN c2 ON c1.prefix = c2.prefix AND c1.prefix_len = c2.prefix_len\nWHERE (c1.next_hop != c2.next_hop OR c1.as_path != c2.as_path\n OR c1.lp != c2.lp OR c1.med != c2.med)\n AND ('$afi' = 'All' OR ('$afi' = 'IPv4' AND c1.isipv4 = true) OR ('$afi' = 'IPv6' AND c1.isipv4 = false))\nORDER BY c1.prefix", "refId": "A" } ], "title": "Attribute Differences \u2014 $rr1 vs $rr2", "type": "table" }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 33 }, "id": 40, "title": "Per-Client Consistency", "type": "row" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Route counts each RR client sends to each RR. In a healthy cluster, every client should send the same number of routes to both RRs. Mismatches indicate session issues, policy differences, or BMP reporting gaps.", "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": "Delta" }, "properties": [ { "id": "custom.displayMode", "value": "color-background" }, { "id": "color", "value": { "mode": "thresholds" } }, { "id": "thresholds", "value": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "yellow", "value": 1 }, { "color": "red", "value": 5 } ] } } ] }, { "matcher": { "id": "byName", "options": "Status" }, "properties": [ { "id": "custom.displayMode", "value": "color-background" }, { "id": "mappings", "value": [ { "options": { "Match": { "color": "green", "index": 0, "text": "Match" }, "MISMATCH": { "color": "red", "index": 1, "text": "MISMATCH" } }, "type": "value" } ] } ] } ] }, "gridPos": { "h": 10, "w": 12, "x": 0, "y": 34 }, "id": 41, "options": { "footer": { "fields": "", "reducer": [ "sum" ], "show": false }, "showHeader": true, "sortBy": [ { "desc": true, "displayName": "Delta" } ] }, "targets": [ { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "format": "table", "rawSql": "WITH rr1_peers AS (\n SELECT p.peer_addr, p.hash_id\n FROM bgp_peers p\n JOIN routers rt ON rt.hash_id = p.router_hash_id\n WHERE rt.name = '$rr1'\n),\nrr2_peers AS (\n SELECT p.peer_addr, p.hash_id\n FROM bgp_peers p\n JOIN routers rt ON rt.hash_id = p.router_hash_id\n WHERE rt.name = '$rr2'\n),\nrr1_counts AS (\n SELECT pp.peer_addr, COUNT(*) AS cnt\n FROM rr1_peers pp\n JOIN ip_rib r ON r.peer_hash_id = pp.hash_id AND r.iswithdrawn = false\n GROUP BY pp.peer_addr\n),\nrr2_counts AS (\n SELECT pp.peer_addr, COUNT(*) AS cnt\n FROM rr2_peers pp\n JOIN ip_rib r ON r.peer_hash_id = pp.hash_id AND r.iswithdrawn = false\n GROUP BY pp.peer_addr\n)\nSELECT\n COALESCE(c1.peer_addr, c2.peer_addr)::text AS \"Client\",\n COALESCE(c1.cnt, 0) AS \"Routes to RR1\",\n COALESCE(c2.cnt, 0) AS \"Routes to RR2\",\n ABS(COALESCE(c1.cnt, 0) - COALESCE(c2.cnt, 0)) AS \"Delta\",\n CASE WHEN COALESCE(c1.cnt, 0) = COALESCE(c2.cnt, 0) THEN 'Match' ELSE 'MISMATCH' END AS \"Status\"\nFROM rr1_counts c1\nFULL OUTER JOIN rr2_counts c2 ON c1.peer_addr = c2.peer_addr\nWHERE c1.peer_addr IS NOT NULL AND c2.peer_addr IS NOT NULL\nORDER BY ABS(COALESCE(c1.cnt, 0) - COALESCE(c2.cnt, 0)) DESC, COALESCE(c1.peer_addr, c2.peer_addr)", "refId": "A" } ], "title": "Per-Client Route Consistency", "type": "table" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "For clients with route count mismatches, shows which specific prefixes differ. Select a client from the Client dropdown to drill down.", "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": "Present On" }, "properties": [ { "id": "custom.displayMode", "value": "color-text" }, { "id": "color", "value": { "mode": "thresholds" } }, { "id": "thresholds", "value": { "mode": "absolute", "steps": [ { "color": "blue", "value": null } ] } } ] } ] }, "gridPos": { "h": 10, "w": 12, "x": 12, "y": 34 }, "id": 42, "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 rr1_client_routes AS (\n SELECT r.prefix, r.prefix_len\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 WHERE rt.name = '$rr1' AND p.peer_addr::text = '$client'\n AND r.iswithdrawn = false\n),\nrr2_client_routes AS (\n SELECT r.prefix, r.prefix_len\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 WHERE rt.name = '$rr2' AND p.peer_addr::text = '$client'\n AND r.iswithdrawn = false\n)\nSELECT r1.prefix::text AS \"Prefix\", 'RR1 only' AS \"Present On\"\nFROM rr1_client_routes r1\nWHERE NOT EXISTS (\n SELECT 1 FROM rr2_client_routes r2\n WHERE r2.prefix = r1.prefix AND r2.prefix_len = r1.prefix_len\n)\nUNION ALL\nSELECT r2.prefix::text AS \"Prefix\", 'RR2 only' AS \"Present On\"\nFROM rr2_client_routes r2\nWHERE NOT EXISTS (\n SELECT 1 FROM rr1_client_routes r1\n WHERE r1.prefix = r2.prefix AND r1.prefix_len = r2.prefix_len\n)\nORDER BY \"Prefix\"", "refId": "A" } ], "title": "Client Prefix Diff \u2014 $client", "type": "table" }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 44 }, "id": 50, "title": "Full RIB Comparison (All Paths)", "type": "row" }, { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Side-by-side view of all paths for a specific prefix on both RRs. Select a prefix from the Prefix dropdown to drill down.", "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": { "mode": "thresholds" } }, { "id": "thresholds", "value": { "mode": "absolute", "steps": [ { "color": "blue", "value": null } ] } } ] } ] }, "gridPos": { "h": 10, "w": 24, "x": 0, "y": 45 }, "id": 51, "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 ba.next_hop::text 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 ba.originator_id::text 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 ('$rr1', '$rr2')\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" }, { "type": "row", "id": 60, "title": "RR Next-Hop Sanity", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 55 }, "collapsed": false, "panels": [] }, { "type": "stat", "id": 61, "title": "Reflected Routes on RR Next-Hop", "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Reflected routes whose NEXT_HOP is an RR loopback while the route was originated by a different router \u2014 the next-hop-self-on-an-RR anti-pattern that pulls the RR into the data path. Should be 0.", "gridPos": { "h": 6, "w": 6, "x": 0, "y": 56 }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 1 } ] }, "unit": "short" }, "overrides": [] }, "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": "time_series", "refId": "A", "rawSql": "SELECT NOW() AS time, count(*) AS \"Anti-pattern Routes\"\nFROM ip_rib r\nJOIN base_attrs ba ON ba.hash_id = r.base_attr_hash_id\nWHERE r.iswithdrawn = false\n AND host(ba.next_hop) IN (${rr_loopbacks:singlequote})\n AND ba.originator_id IS NOT NULL AND host(ba.originator_id) <> host(ba.next_hop)" } ] }, { "type": "table", "id": 62, "title": "Reflected Routes Landing on an RR Next-Hop", "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "description": "Each row is a reflected route whose NEXT_HOP points at an RR loopback instead of the true originator \u2014 the RR has been pulled into the forwarding path (next-hop-self mis-applied on the client-facing side). Empty is healthy. Use this to validate RR behavior, e.g. during an IOS-XR to Junos RR migration.", "gridPos": { "h": 6, "w": 18, "x": 6, "y": 56 }, "fieldConfig": { "defaults": { "custom": { "align": "auto", "displayMode": "auto" } }, "overrides": [ { "matcher": { "id": "byName", "options": "Next-Hop (RR!)" }, "properties": [ { "id": "custom.displayMode", "value": "color-background" }, { "id": "color", "value": { "mode": "fixed", "fixedColor": "red" } } ] } ] }, "options": { "showHeader": true, "footer": { "show": false, "reducer": [ "sum" ], "fields": "" } }, "targets": [ { "datasource": { "type": "postgres", "uid": "obmp_postgres" }, "format": "table", "refId": "A", "rawSql": "SELECT\n r.prefix AS \"Prefix\",\n host(ba.next_hop) AS \"Next-Hop (RR!)\",\n host(ba.originator_id) AS \"True Originator\",\n COALESCE(rtr.name, p.peer_addr::text) AS \"Seen on Router\",\n COALESCE(NULLIF(p.name,''), p.peer_addr::text) AS \"Via Peer\",\n ba.origin_as AS \"Origin AS\"\nFROM ip_rib r\nJOIN base_attrs ba ON ba.hash_id = r.base_attr_hash_id\nJOIN bgp_peers p ON p.hash_id = r.peer_hash_id\nJOIN routers rtr ON rtr.hash_id = p.router_hash_id\nWHERE r.iswithdrawn = false\n AND host(ba.next_hop) IN (${rr_loopbacks:singlequote})\n AND ba.originator_id IS NOT NULL AND host(ba.originator_id) <> host(ba.next_hop)\nORDER BY r.prefix\nLIMIT 200" } ] } ], "refresh": "30s", "schemaVersion": 38, "tags": [ "openbmp", "rr-diff", "bgp", "obmp", "obmp-nav", "reference" ], "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": "RR1", "multi": false, "name": "rr1", "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": "RR2", "multi": false, "name": "rr2", "options": [], "query": "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 p.peer_addr::text FROM bgp_peers p JOIN routers rt ON rt.hash_id = p.router_hash_id WHERE rt.name IN ('$rr1', '$rr2') AND p.state = 'up' ORDER BY 1", "hide": 0, "includeAll": false, "label": "Client", "multi": false, "name": "client", "options": [], "query": "SELECT DISTINCT p.peer_addr::text FROM bgp_peers p JOIN routers rt ON rt.hash_id = p.router_hash_id WHERE rt.name IN ('$rr1', '$rr2') AND p.state = 'up' ORDER BY 1", "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 1, "type": "query" }, { "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 ('$rr1', '$rr2') 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 ('$rr1', '$rr2') AND r.iswithdrawn = false ORDER BY 1", "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 1, "type": "query" }, { "name": "rr_loopbacks", "type": "custom", "label": "RR Loopbacks", "description": "Loopback / BGP router-id addresses of your route reflectors. Edit this list for your environment.", "query": "10.10.255.0,10.10.255.20,10.11.255.0,10.11.255.20", "multi": true, "includeAll": true, "current": { "text": [ "All" ], "value": [ "$__all" ] }, "options": [ { "text": "All", "value": "$__all", "selected": true }, { "text": "10.10.255.0", "value": "10.10.255.0", "selected": false }, { "text": "10.10.255.20", "value": "10.10.255.20", "selected": false }, { "text": "10.11.255.0", "value": "10.11.255.0", "selected": false }, { "text": "10.11.255.20", "value": "10.11.255.20", "selected": false } ], "hide": 0 } ] }, "time": { "from": "now-6h", "to": "now" }, "timepicker": {}, "timezone": "", "title": "RR Loc-RIB Diff", "uid": "rr-locrib-diff", "version": 1 }