@@ -18,6 +18,7 @@ def list_tools():
1818 'asn_downstream_count' : ['asn' ],
1919 'asn_upstream_details' : ['asn' ],
2020 'asn_downstream_details' : ['asn' ],
21+ 'asn_upstream_connectivity' : ['asn' ],
2122 'asn_trend_24h' : ['asn' ],
2223 'asn_prefix_aggregates' : ['asn' ],
2324 'asn_advertised_prefixes' : ['asn' ],
@@ -54,6 +55,7 @@ def list_tools():
5455 'asn_downstream_count' : 'Count unique downstream ASNs directly after an ASN in paths' ,
5556 'asn_upstream_details' : 'List upstream ASNs and names for an ASN' ,
5657 'asn_downstream_details' : 'List downstream ASNs and names for an ASN' ,
58+ 'asn_upstream_connectivity' : 'Check connectivity to upstream ASNs (to Tier 1) for ASN' ,
5759 'asn_trend_24h' : '24h time series of prefix and coverage stats for ASN' ,
5860 'asn_prefix_aggregates' : 'List aggregate supernets for ASN-advertised prefixes' ,
5961 'asn_advertised_prefixes' : 'List prefixes with RPKI/IRR context for ASN' ,
@@ -199,6 +201,51 @@ def run_tool(name, params, db):
199201 """ )
200202 return _rows (db , q , {'asn' : asn })
201203
204+ if name == 'asn_upstream_connectivity' :
205+ asn = int (params ['asn' ])
206+ q = text ("""
207+ WITH target_paths AS (
208+ SELECT DISTINCT
209+ ba.as_path,
210+ ba.as_path_count
211+ FROM ip_rib r
212+ JOIN base_attrs ba ON r.base_attr_hash_id = ba.hash_id
213+ WHERE r.origin_as = :asn
214+ AND r.iswithdrawn = false
215+ AND ba.as_path_count > 0
216+ LIMIT 200
217+ ),
218+ tier1_list AS (
219+ -- Common Tier 1 ASNs
220+ SELECT unnest(ARRAY[
221+ 174, -- Cogent
222+ 1299, -- Telia/Arelion
223+ 2914, -- NTT
224+ 3257, -- GTT/Lumen
225+ 3320, -- Deutsche Telekom
226+ 3356, -- Lumen/Level3
227+ 5511, -- Orange
228+ 6453, -- Tata
229+ 6461, -- Zayo
230+ 6762, -- Telecom Italia
231+ 6830, -- Liberty Global
232+ 6939, -- Hurricane Electric
233+ 7018 -- AT&T
234+ ]::bigint[]) as asn
235+ )
236+ SELECT
237+ tp.as_path,
238+ tp.as_path_count,
239+ array_agg(DISTINCT t1.asn) as tier1_asns_in_path
240+ FROM target_paths tp
241+ CROSS JOIN tier1_list t1
242+ WHERE tp.as_path @> ARRAY[t1.asn] -- Check if path contains Tier 1
243+ GROUP BY tp.as_path, tp.as_path_count
244+ ORDER BY tp.as_path_count, tp.as_path
245+ LIMIT 50;
246+ """ )
247+ return _rows (db , q , {'asn' : asn })
248+
202249 if name == 'asn_trend_24h' :
203250 asn = int (params ['asn' ])
204251 from datetime import datetime , timedelta
0 commit comments