Skip to content

Commit 9f3efaf

Browse files
authored
Merge pull request #188 from mssonicbld/sonicbld/202503-merge
```<br>* b0ff18c - (HEAD -> 202503) Merge branch '202412' of https://github.com/Azure/sonic-utilities.msft into 202503 (2025-06-18) [Sonic Automation] * afa6c14 - (base/202412) Skip checking offload flags for static routes/sids in route check and add check_sids (#187) (2025-06-17) [mssonicbld]<br>```
2 parents 65162ab + b0ff18c commit 9f3efaf

2 files changed

Lines changed: 511 additions & 197 deletions

File tree

scripts/route_check.py

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,52 @@ def get_asicdb_routes(namespace):
329329
return (selector, subs, sorted(rt))
330330

331331

332+
def get_appdb_sids(namespace):
333+
"""
334+
helper to read SIDs table from APPL-DB.
335+
:return list of sorted SIDs with prefix ensured
336+
"""
337+
db = swsscommon.DBConnector(APPL_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace)
338+
print_message(syslog.LOG_DEBUG, "APPL DB connected for sids")
339+
tbl = swsscommon.Table(db, 'SRV6_MY_SID_TABLE')
340+
keys = tbl.getKeys()
341+
342+
sids = sorted(keys)
343+
print_message(syslog.LOG_DEBUG, json.dumps({"APPL_MY_SID_TABLE": sids}, indent=4))
344+
return sids
345+
346+
347+
def get_asicdb_sids(namespace):
348+
"""
349+
helper to read SIDs table from APPL-DB.
350+
:return list of sorted SIDs with prefix ensured
351+
"""
352+
db = swsscommon.DBConnector(ASIC_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace)
353+
print_message(syslog.LOG_DEBUG, "ASIC DB connected for sids")
354+
tbl = swsscommon.Table(db, ASIC_TABLE_NAME)
355+
keys = tbl.getKeys()
356+
357+
sids = []
358+
for k in keys:
359+
content = k.split(":", 1)
360+
if content[0] != 'SAI_OBJECT_TYPE_MY_SID_ENTRY':
361+
continue
362+
sid_info = json.loads(content[1])
363+
sid_entry = ":".join([
364+
sid_info.get("locator_block_len", "0"),
365+
sid_info.get("locator_node_len", "0"),
366+
sid_info.get("function_len", "0"),
367+
sid_info.get("args_len", "0"),
368+
sid_info.get("sid")
369+
])
370+
371+
sids.append(sid_entry)
372+
373+
sids = sorted(sids)
374+
print_message(syslog.LOG_DEBUG, json.dumps({"ASIC_MY_SID_TABLE": sids}, indent=4))
375+
return sids
376+
377+
332378
def is_suppress_fib_pending_enabled(namespace):
333379
"""
334380
Returns True if FIB suppression is enabled, False otherwise
@@ -575,7 +621,7 @@ def check_frr_pending_routes(namespace):
575621

576622
for _, entries in frr_routes.items():
577623
for entry in entries:
578-
if entry['protocol'] in ('connected', 'kernel'):
624+
if entry['protocol'] in ('connected', 'kernel', 'static'):
579625
continue
580626

581627
# TODO: Also handle VRF routes. Currently this script does not check for VRF routes so it would be incorrect for us
@@ -839,6 +885,74 @@ def check_routes(namespace):
839885
print_message(syslog.LOG_INFO, "All good!")
840886
return 0, None
841887

888+
889+
def check_sids_for_namespace(namespace):
890+
"""
891+
Process a Single Namespace for SIDs consistency check:
892+
Read APPL-DB & ASIC-DB, the relevant tables for SID checking.
893+
Checkout SIDs in ASIC-DB to match APPL-DB. Compared to check_routes,
894+
this function does not wait for subscriber updates, as SIDs are not
895+
expected to change frequently.
896+
897+
:return (0, None) on sucess, else (-1, results) where results holds
898+
the unjustifiable entries.
899+
"""
900+
901+
results = {}
902+
sid_appl_miss = []
903+
sid_asic_miss = []
904+
905+
sids_asic = get_asicdb_sids(namespace)
906+
907+
sids_appl = get_appdb_sids(namespace)
908+
909+
# Diff APPL-DB SIDs & ASIC-DB SIDs
910+
sid_appl_miss, sid_asic_miss = diff_sorted_lists(sids_appl, sids_asic)
911+
912+
if sid_appl_miss:
913+
results["missed_APPL_MY_SID_TABLE_entries"] = sid_appl_miss
914+
915+
if sid_asic_miss:
916+
results["missed_ASIC_MY_SID_TABLE_entries"] = sid_asic_miss
917+
918+
return results
919+
920+
921+
def check_sids(namespace):
922+
"""
923+
Main function to parallelize SID checks across all namespaces.
924+
"""
925+
namespace_list = []
926+
if namespace is not multi_asic.DEFAULT_NAMESPACE and namespace in multi_asic.get_namespace_list():
927+
namespace_list.append(namespace)
928+
else:
929+
namespace_list = multi_asic.get_namespace_list()
930+
print_message(syslog.LOG_INFO, "Checking SIDs for namespaces: ", namespace_list)
931+
932+
results = {}
933+
934+
# Use ThreadPoolExecutor to parallelize the check for each namespace
935+
with concurrent.futures.ThreadPoolExecutor() as executor:
936+
futures = {executor.submit(check_sids_for_namespace, ns): ns for ns in namespace_list}
937+
938+
for future in concurrent.futures.as_completed(futures):
939+
ns = futures[future]
940+
try:
941+
result = future.result()
942+
if result:
943+
results[ns] = result
944+
except Exception as e:
945+
print_message(syslog.LOG_ERR, "Error processing namespace {}: {}".format(ns, e))
946+
return -1, results
947+
948+
if results:
949+
print_message(syslog.LOG_WARNING, "SIDs Check Failure results: {", json.dumps(results, indent=4), "}")
950+
return -1, results
951+
else:
952+
print_message(syslog.LOG_INFO, "All good!")
953+
return 0, None
954+
955+
842956
def main():
843957
"""
844958
main entry point, which mainly parses the args and call check_routes
@@ -884,9 +998,22 @@ def main():
884998

885999
while True:
8861000
signal.alarm(TIMEOUT_SECONDS)
887-
ret, res= check_routes(namespace)
888-
print_message(syslog.LOG_DEBUG, "ret={}, res={}".format(ret, res))
1001+
ret1, res1 = check_routes(namespace)
1002+
print_message(syslog.LOG_DEBUG, "check_routes: ret={}, res={}".format(ret1, res1))
1003+
ret2, res2 = check_sids(namespace)
1004+
print_message(syslog.LOG_DEBUG, "check_sids: ret={}, res={}".format(ret2, res2))
8891005
signal.alarm(0)
1006+
if ret1 < 0 or ret2 < 0:
1007+
ret = -1
1008+
else:
1009+
ret = 0
1010+
1011+
if res1 is not None or res2 is not None:
1012+
res = dict()
1013+
res.update(res1 if res1 else {})
1014+
res.update(res2 if res2 else {})
1015+
else:
1016+
res = None
8901017

8911018
if interval:
8921019
time.sleep(interval)

0 commit comments

Comments
 (0)