From 3c489ba5b6adb3ffae3ee5a8c68a969b41bdb6f3 Mon Sep 17 00:00:00 2001 From: Deepak Singhal <115033986+deepak-singhal0408@users.noreply.github.com> Date: Fri, 22 Mar 2024 16:02:50 -0700 Subject: [PATCH] Enhance route-check for multi-asic platforms (#3216) ### What I did Enhanced route_check.py script to cover multi-asic platforms. Accordingly enhanced the test files as well. MSFT ADO: 25416673 #### How I did it Enhanced the route_check.py script to take additional optional parameter(--n/namespace). Without this parameter, the check will be run on all asics in multi-asic platforms. Different connections to DBs are modified accordingly to connect to relevant ns dbs. Result will be encapsulated under different namespace. For single asic, results will be displayed under Default-Namespace(""). testData and the testfiles are enhanced accordinly. #### How to verify it 1. Verified that all pytest UT cases are passing. 2. Verified the route_check_test.sh script on single asic and multi-asic platforms. 3. Verified Monit routecheck outputs by simulating a failure scenario on both single asic and multi-asic platforms. output from Monit Check: **Single Asic:** xxx/usr/local/bin# monit status routecheck Monit 5.20.0 uptime: 1d 20h 32m Program 'routeCheck' status Status failed monitoring status Monitored monitoring mode active on reboot start last exit value 255 last output Failure results: {{ "": { "missed_ROUTE_TABLE_routes": [ "20c0:d9b8:99:80::/64" ] } }} Failed. Look at reported mismatches above add: { "": [] } del: { "": [] } data collected Tue, 12 Dec 2023 20:30:11 ''' **Multi Asic:** ''' /bin# monit status routecheck Monit 5.20.0 uptime: 1d 23h 51m Program 'routeCheck' status Status failed monitoring status Monitored monitoring mode active on reboot start last exit value 255 last output Failure results: {{ "asic0": { "missed_ROUTE_TABLE_routes": [ "1.0.0.0/16" ] }, "asic1": { "missed_ROUTE_TABLE_routes": [ "1.0.0.0/16" ] }, "asic2": { "missed_ROUTE_TABLE_routes": [ "1.0.0.0/16" ] } }} Failed. Look at reported mismatches above add: { "asic0": [], "asic1": [], "asic2": [] } del: { "asic0": [], "asic1": [], "asic2": [] } data collected Tue, 12 Dec 2023 23:54:23 ''' --- scripts/route_check.py | 220 +++--- scripts/route_check_test.sh | 125 +++- tests/route_check_test.py | 190 +++-- tests/route_check_test_data.py | 1182 +++++++++++++++++++++----------- 4 files changed, 1069 insertions(+), 648 deletions(-) diff --git a/scripts/route_check.py b/scripts/route_check.py index 4346d733fc..5349acd0af 100755 --- a/scripts/route_check.py +++ b/scripts/route_check.py @@ -50,6 +50,8 @@ from ipaddress import ip_network from swsscommon import swsscommon from utilities_common import chassis +from sonic_py_common import multi_asic +from utilities_common.general import load_db_config APPL_DB_NAME = 'APPL_DB' ASIC_DB_NAME = 'ASIC_DB' @@ -76,6 +78,8 @@ FRR_CHECK_RETRIES = 3 FRR_WAIT_TIME = 15 +REDIS_TIMEOUT_MSECS = 0 + class Level(Enum): ERR = 'ERR' INFO = 'INFO' @@ -276,12 +280,12 @@ def is_vrf(k): return k.startswith("Vrf") -def get_routes(): +def get_appdb_routes(namespace): """ helper to read route table from APPL-DB. :return list of sorted routes with prefix ensured """ - db = swsscommon.DBConnector(APPL_DB_NAME, 0) + db = swsscommon.DBConnector(APPL_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace) print_message(syslog.LOG_DEBUG, "APPL DB connected for routes") tbl = swsscommon.Table(db, 'ROUTE_TABLE') keys = tbl.getKeys() @@ -298,15 +302,15 @@ def get_routes(): return sorted(valid_rt) -def get_route_entries(): +def get_asicdb_routes(namespace): """ helper to read present route entries from ASIC-DB and as well initiate selector for ASIC-DB:ASIC-state updates. :return (selector, subscriber, ) """ - db = swsscommon.DBConnector(ASIC_DB_NAME, 0) + db = swsscommon.DBConnector(ASIC_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace) subs = swsscommon.SubscriberStateTable(db, ASIC_TABLE_NAME) - print_message(syslog.LOG_DEBUG, "ASIC DB connected") + print_message(syslog.LOG_DEBUG, "ASIC DB {} connected".format(namespace)) rt = [] while True: @@ -324,37 +328,42 @@ def get_route_entries(): return (selector, subs, sorted(rt)) -def is_suppress_fib_pending_enabled(): +def is_suppress_fib_pending_enabled(namespace): """ Returns True if FIB suppression is enabled, False otherwise """ - cfg_db = swsscommon.ConfigDBConnector() - cfg_db.connect() - + cfg_db = multi_asic.connect_config_db_for_ns(namespace) state = cfg_db.get_entry('DEVICE_METADATA', 'localhost').get('suppress-fib-pending') return state == 'enabled' -def get_frr_routes(): +def get_frr_routes(namespace): """ Read routes from zebra through CLI command :return frr routes dictionary """ + if namespace == multi_asic.DEFAULT_NAMESPACE: + v4_route_cmd = ['show', 'ip', 'route', 'json'] + v6_route_cmd = ['show', 'ipv6', 'route', 'json'] + else: + v4_route_cmd = ['show', 'ip', 'route', '-n', namespace, 'json'] + v6_route_cmd = ['show', 'ipv6', 'route', '-n', namespace, 'json'] - output = subprocess.check_output('show ip route json', shell=True) + output = subprocess.check_output(v4_route_cmd, text=True) routes = json.loads(output) - output = subprocess.check_output('show ipv6 route json', shell=True) + output = subprocess.check_output(v6_route_cmd, text=True) routes.update(json.loads(output)) + print_message(syslog.LOG_DEBUG, "FRR Routes: namespace={}, routes={}".format(namespace, routes)) return routes -def get_interfaces(): +def get_interfaces(namespace): """ helper to read interface table from APPL-DB. :return sorted list of IP addresses with added prefix """ - db = swsscommon.DBConnector(APPL_DB_NAME, 0) + db = swsscommon.DBConnector(APPL_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace) print_message(syslog.LOG_DEBUG, "APPL DB connected for interfaces") tbl = swsscommon.Table(db, 'INTF_TABLE') keys = tbl.getKeys() @@ -374,20 +383,20 @@ def get_interfaces(): return sorted(intf) -def filter_out_local_interfaces(keys): +def filter_out_local_interfaces(namespace, keys): """ helper to filter out local interfaces :param keys: APPL-DB:ROUTE_TABLE Routes to check. :return keys filtered out of local """ rt = [] - local_if_lst = {'eth0', 'docker0'} + local_if_lst = {'eth0', 'eth1', 'docker0'} #eth1 is added to skip route installed in AAPL_DB on packet-chassis local_if_lo = [r'tun0', r'lo', r'Loopback\d+'] chassis_local_intfs = chassis.get_chassis_local_interfaces() local_if_lst.update(set(chassis_local_intfs)) - db = swsscommon.DBConnector(APPL_DB_NAME, 0) + db = swsscommon.DBConnector(APPL_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace) tbl = swsscommon.Table(db, 'ROUTE_TABLE') for k in keys: @@ -407,20 +416,20 @@ def filter_out_local_interfaces(keys): return rt -def filter_out_voq_neigh_routes(keys): +def filter_out_voq_neigh_routes(namespace, keys): """ helper to filter out voq neigh routes. These are the routes statically added for the voq neighbors. We skip writing route entries in asic db for these. We filter out reporting error on all the host routes written on inband interface prefixed with "Ethernte-IB" - :param keys: APPL-DB:ROUTE_TABLE Routes to check. + :param namespace: Asic namespace, keys: APPL-DB:ROUTE_TABLE Routes to check. :return keys filtered out for voq neigh routes """ rt = [] local_if_re = [r'Ethernet-IB\d+'] - db = swsscommon.DBConnector(APPL_DB_NAME, 0) + db = swsscommon.DBConnector(APPL_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace) tbl = swsscommon.Table(db, 'ROUTE_TABLE') for k in keys: @@ -452,13 +461,13 @@ def filter_out_default_routes(lst): return upd -def filter_out_vnet_routes(routes): +def filter_out_vnet_routes(namespace, routes): """ Helper to filter out VNET routes :param routes: list of routes to filter :return filtered list of routes. """ - db = swsscommon.DBConnector('APPL_DB', 0) + db = swsscommon.DBConnector('APPL_DB', REDIS_TIMEOUT_MSECS, True, namespace) vnet_route_table = swsscommon.Table(db, 'VNET_ROUTE_TABLE') vnet_route_tunnel_table = swsscommon.Table(db, 'VNET_ROUTE_TUNNEL_TABLE') @@ -488,14 +497,14 @@ def is_dualtor(config_db): return subtype.lower() == 'dualtor' -def filter_out_standalone_tunnel_routes(routes): - config_db = swsscommon.ConfigDBConnector() - config_db.connect() +def filter_out_standalone_tunnel_routes(namespace, routes): + + config_db = multi_asic.connect_config_db_for_ns(namespace) if not is_dualtor(config_db): return routes - app_db = swsscommon.DBConnector('APPL_DB', 0) + app_db = swsscommon.DBConnector('APPL_DB', REDIS_TIMEOUT_MSECS, True, namespace) neigh_table = swsscommon.Table(app_db, 'NEIGH_TABLE') neigh_keys = neigh_table.getKeys() standalone_tunnel_route_ips = [] @@ -525,18 +534,17 @@ def filter_out_standalone_tunnel_routes(routes): return updated_routes -def check_frr_pending_routes(): +def check_frr_pending_routes(namespace): """ Check FRR routes for offload flag presence by executing "show ip route json" Returns a list of routes that have no offload flag. """ missed_rt = [] - retries = FRR_CHECK_RETRIES for i in range(retries): missed_rt = [] - frr_routes = get_frr_routes() + frr_routes = get_frr_routes(namespace) for _, entries in frr_routes.items(): for entry in entries: @@ -559,11 +567,11 @@ def check_frr_pending_routes(): break time.sleep(FRR_WAIT_TIME) - + print_message(syslog.LOG_DEBUG, "FRR missed routes: {}".format(missed_rt, indent=4)) return missed_rt -def mitigate_installed_not_offloaded_frr_routes(missed_frr_rt, rt_appl): +def mitigate_installed_not_offloaded_frr_routes(namespace, missed_frr_rt, rt_appl): """ Mitigate installed but not offloaded FRR routes. @@ -575,7 +583,7 @@ def mitigate_installed_not_offloaded_frr_routes(missed_frr_rt, rt_appl): All of the above mentioned cases must be considered as a bug, but even in that case we will report an error in the log but given that this script ensures the route is installed in the hardware it will automitigate such a bug. """ - db = swsscommon.DBConnector('APPL_STATE_DB', 0) + db = swsscommon.DBConnector('APPL_STATE_DB', REDIS_TIMEOUT_MSECS, True, namespace) response_producer = swsscommon.NotificationProducer(db, f'{APPL_DB_NAME}_{swsscommon.APP_ROUTE_TABLE_NAME}_RESPONSE_CHANNEL') for entry in [entry for entry in missed_frr_rt if entry['prefix'] in rt_appl]: fvs = swsscommon.FieldValuePairs([('err_str', 'SWSS_RC_SUCCESS'), ('protocol', entry['protocol'])]) @@ -598,7 +606,7 @@ def get_soc_ips(config_db): return soc_ips -def filter_out_soc_ip_routes(routes): +def filter_out_soc_ip_routes(namespace, routes): """ Ignore ASIC only routes for SOC IPs @@ -608,8 +616,7 @@ def filter_out_soc_ip_routes(routes): will use the kernel routing table), but still provide connectivity to any external traffic in case of a link issue (since this traffic will be forwarded by the ASIC). """ - config_db = swsscommon.ConfigDBConnector() - config_db.connect() + config_db = multi_asic.connect_config_db_for_ns(namespace) if not is_dualtor(config_db): return routes @@ -618,7 +625,7 @@ def filter_out_soc_ip_routes(routes): if not soc_ips: return routes - + updated_routes = [] for route in routes: if route not in soc_ips: @@ -627,9 +634,9 @@ def filter_out_soc_ip_routes(routes): return updated_routes -def get_vlan_neighbors(): +def get_vlan_neighbors(namespace): """Return a list of VLAN neighbors.""" - db = swsscommon.DBConnector(APPL_DB_NAME, 0) + db = swsscommon.DBConnector(APPL_DB_NAME, REDIS_TIMEOUT_MSECS, True, namespace) print_message(syslog.LOG_DEBUG, "APPL DB connected for neighbors") tbl = swsscommon.Table(db, 'NEIGH_TABLE') neigh_entries = tbl.getKeys() @@ -645,7 +652,7 @@ def get_vlan_neighbors(): return valid_neighs -def filter_out_vlan_neigh_route_miss(rt_appl_miss, rt_asic_miss): +def filter_out_vlan_neigh_route_miss(namespace, rt_appl_miss, rt_asic_miss): """Ignore any route miss for vlan neighbor IPs.""" def _filter_out_neigh_route(routes, neighs): @@ -658,12 +665,10 @@ def _filter_out_neigh_route(routes, neighs): updated_routes.append(route) return updated_routes, ignored_routes - config_db = swsscommon.ConfigDBConnector() - config_db.connect() + config_db = multi_asic.connect_config_db_for_ns(namespace) - print_message(syslog.LOG_DEBUG, "Ignore vlan neighbor route miss") if is_dualtor(config_db): - vlan_neighs = set(get_vlan_neighbors()) + vlan_neighs = set(get_vlan_neighbors(namespace)) rt_appl_miss, ignored_rt_appl_miss = _filter_out_neigh_route(rt_appl_miss, vlan_neighs) print_message(syslog.LOG_DEBUG, "Ignored appl route miss:", json.dumps(ignored_rt_appl_miss, indent=4)) rt_asic_miss, ignored_rt_asic_miss = _filter_out_neigh_route(rt_asic_miss, vlan_neighs) @@ -672,7 +677,7 @@ def _filter_out_neigh_route(routes, neighs): return rt_appl_miss, rt_asic_miss -def check_routes(): +def check_routes(namespace): """ The heart of this script which runs the checks. Read APPL-DB & ASIC-DB, the relevant tables for route checking. @@ -691,85 +696,102 @@ def check_routes(): :return (0, None) on sucess, else (-1, results) where results holds the unjustifiable entries. """ - intf_appl_miss = [] - rt_appl_miss = [] - rt_asic_miss = [] - rt_frr_miss = [] + namespace_list = [] + if namespace is not multi_asic.DEFAULT_NAMESPACE and namespace in multi_asic.get_namespace_list(): + namespace_list.append(namespace) + else: + namespace_list = multi_asic.get_namespace_list() + print_message(syslog.LOG_INFO, "Checking routes for namespaces: ", namespace_list) results = {} - adds = [] - deletes = [] + adds = {} + deletes = {} + for namespace in namespace_list: + intf_appl_miss = [] + rt_appl_miss = [] + rt_asic_miss = [] + rt_frr_miss = [] + adds[namespace] = [] + deletes[namespace] = [] + + selector, subs, rt_asic = get_asicdb_routes(namespace) - selector, subs, rt_asic = get_route_entries() + rt_appl = get_appdb_routes(namespace) + intf_appl = get_interfaces(namespace) - rt_appl = get_routes() - intf_appl = get_interfaces() + # Diff APPL-DB routes & ASIC-DB routes + rt_appl_miss, rt_asic_miss = diff_sorted_lists(rt_appl, rt_asic) - # Diff APPL-DB routes & ASIC-DB routes - rt_appl_miss, rt_asic_miss = diff_sorted_lists(rt_appl, rt_asic) + # Check missed ASIC routes against APPL-DB INTF_TABLE + _, rt_asic_miss = diff_sorted_lists(intf_appl, rt_asic_miss) + rt_asic_miss = filter_out_default_routes(rt_asic_miss) + rt_asic_miss = filter_out_vnet_routes(namespace, rt_asic_miss) + rt_asic_miss = filter_out_standalone_tunnel_routes(namespace, rt_asic_miss) + rt_asic_miss = filter_out_soc_ip_routes(namespace, rt_asic_miss) - # Check missed ASIC routes against APPL-DB INTF_TABLE - _, rt_asic_miss = diff_sorted_lists(intf_appl, rt_asic_miss) - rt_asic_miss = filter_out_default_routes(rt_asic_miss) - rt_asic_miss = filter_out_vnet_routes(rt_asic_miss) - rt_asic_miss = filter_out_standalone_tunnel_routes(rt_asic_miss) - rt_asic_miss = filter_out_soc_ip_routes(rt_asic_miss) - # Check APPL-DB INTF_TABLE with ASIC table route entries - intf_appl_miss, _ = diff_sorted_lists(intf_appl, rt_asic) + # Check APPL-DB INTF_TABLE with ASIC table route entries + intf_appl_miss, _ = diff_sorted_lists(intf_appl, rt_asic) - if rt_appl_miss: - rt_appl_miss = filter_out_local_interfaces(rt_appl_miss) + if rt_appl_miss: + rt_appl_miss = filter_out_local_interfaces(namespace, rt_appl_miss) - if rt_appl_miss: - rt_appl_miss = filter_out_voq_neigh_routes(rt_appl_miss) + if rt_appl_miss: + rt_appl_miss = filter_out_voq_neigh_routes(namespace, rt_appl_miss) - # NOTE: On dualtor environment, ignore any route miss for the - # neighbors learned from the vlan subnet. - if rt_appl_miss or rt_asic_miss: - rt_appl_miss, rt_asic_miss = filter_out_vlan_neigh_route_miss(rt_appl_miss, rt_asic_miss) + # NOTE: On dualtor environment, ignore any route miss for the + # neighbors learned from the vlan subnet. + if rt_appl_miss or rt_asic_miss: + rt_appl_miss, rt_asic_miss = filter_out_vlan_neigh_route_miss(namespace, rt_appl_miss, rt_asic_miss) - if rt_appl_miss or rt_asic_miss: - # Look for subscribe updates for a second - adds, deletes = get_subscribe_updates(selector, subs) + if rt_appl_miss or rt_asic_miss: + # Look for subscribe updates for a second + adds[namespace], deletes[namespace] = get_subscribe_updates(selector, subs) # Drop all those for which SET received - rt_appl_miss, _ = diff_sorted_lists(rt_appl_miss, adds) + rt_appl_miss, _ = diff_sorted_lists(rt_appl_miss, adds[namespace]) # Drop all those for which DEL received - rt_asic_miss, _ = diff_sorted_lists(rt_asic_miss, deletes) + rt_asic_miss, _ = diff_sorted_lists(rt_asic_miss, deletes[namespace]) - if rt_appl_miss: - results["missed_ROUTE_TABLE_routes"] = rt_appl_miss + if rt_appl_miss: + if namespace not in results: + results[namespace] = {} + results[namespace]["missed_ROUTE_TABLE_routes"] = rt_appl_miss - if intf_appl_miss: - results["missed_INTF_TABLE_entries"] = intf_appl_miss + if intf_appl_miss: + if namespace not in results: + results[namespace] = {} + results[namespace]["missed_INTF_TABLE_entries"] = intf_appl_miss - if rt_asic_miss: - results["Unaccounted_ROUTE_ENTRY_TABLE_entries"] = rt_asic_miss + if rt_asic_miss: + if namespace not in results: + results[namespace] = {} + results[namespace]["Unaccounted_ROUTE_ENTRY_TABLE_entries"] = rt_asic_miss - rt_frr_miss = check_frr_pending_routes() + rt_frr_miss = check_frr_pending_routes(namespace) - if rt_frr_miss: - results["missed_FRR_routes"] = rt_frr_miss + if rt_frr_miss: + if namespace not in results: + results[namespace] = {} + results[namespace]["missed_FRR_routes"] = rt_frr_miss + + if results: + if rt_frr_miss and not rt_appl_miss and not rt_asic_miss: + print_message(syslog.LOG_ERR, "Some routes are not set offloaded in FRR{} but all routes in APPL_DB and ASIC_DB are in sync".format(namespace)) + if is_suppress_fib_pending_enabled(namespace): + mitigate_installed_not_offloaded_frr_routes(namespace, rt_frr_miss, rt_appl) if results: print_message(syslog.LOG_WARNING, "Failure results: {", json.dumps(results, indent=4), "}") print_message(syslog.LOG_WARNING, "Failed. Look at reported mismatches above") print_message(syslog.LOG_WARNING, "add: ", json.dumps(adds, indent=4)) print_message(syslog.LOG_WARNING, "del: ", json.dumps(deletes, indent=4)) - - if rt_frr_miss and not rt_appl_miss and not rt_asic_miss: - print_message(syslog.LOG_ERR, "Some routes are not set offloaded in FRR but all routes in APPL_DB and ASIC_DB are in sync") - if is_suppress_fib_pending_enabled(): - mitigate_installed_not_offloaded_frr_routes(rt_frr_miss, rt_appl) - return -1, results else: print_message(syslog.LOG_INFO, "All good!") return 0, None - def main(): """ main entry point, which mainly parses the args and call check_routes @@ -782,8 +804,18 @@ def main(): parser.add_argument('-m', "--mode", type=Level, choices=list(Level), default='ERR') parser.add_argument("-i", "--interval", type=int, default=0, help="Scan interval in seconds") parser.add_argument("-s", "--log_to_syslog", action="store_true", default=True, help="Write message to syslog") + parser.add_argument('-n','--namespace', default=multi_asic.DEFAULT_NAMESPACE, help='Verify routes for this specific namespace') args = parser.parse_args() + namespace = args.namespace + if namespace is not multi_asic.DEFAULT_NAMESPACE and not multi_asic.is_multi_asic(): + print_message(syslog.LOG_ERR, "Namespace option is not valid for a single-ASIC device") + return -1, None + + if namespace is not multi_asic.DEFAULT_NAMESPACE and namespace not in multi_asic.get_namespace_list(): + print_message(syslog.LOG_ERR, "Namespace option is not valid. Choose one of {}".format(multi_asic.get_namespace_list())) + return -1, None + set_level(args.mode, args.log_to_syslog) if args.interval: @@ -797,10 +829,12 @@ def main(): interval = 1 signal.signal(signal.SIGALRM, handler) + load_db_config() while True: signal.alarm(TIMEOUT_SECONDS) - ret, res= check_routes() + ret, res= check_routes(namespace) + print_message(syslog.LOG_DEBUG, "ret={}, res={}".format(ret, res)) signal.alarm(0) if interval: diff --git a/scripts/route_check_test.sh b/scripts/route_check_test.sh index 989cbfae0b..b78351f7a6 100755 --- a/scripts/route_check_test.sh +++ b/scripts/route_check_test.sh @@ -2,36 +2,95 @@ # add a route, interface & route-entry to simulate error # -sonic-db-cli APPL_DB hmset "ROUTE_TABLE:20c0:d9b8:99:80::/64" "nexthop" "fc00::72,fc00::76,fc00::7a,fc00::7e" "ifname" "PortChannel01,PortChannel02,PortChannel03,PortChannel04" > /dev/null -sonic-db-cli ASIC_DB hmset "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"192.193.120.255/25\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000022\"}" "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" "oid:0x5000000000614" > /dev/null -sonic-db-cli APPL_DB hmset "INTF_TABLE:PortChannel01:10.0.0.99/31" "scope" "global" "family" "IPv4" > /dev/null - -echo "------" -echo "expect errors!" -echo "Running Route Check..." -./route_check.py -echo "return value: $?" - -sonic-db-cli APPL_DB del "ROUTE_TABLE:20c0:d9b8:99:80::/64" > /dev/null -sonic-db-cli ASIC_DB del "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"192.193.120.255/25\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000022\"}" > /dev/null -sonic-db-cli APPL_DB del "INTF_TABLE:PortChannel01:10.0.0.99/31" > /dev/null - -# add standalone tunnel route to simulate unreachable neighbor scenario on dual ToR -# in this scenario, we expect the route mismatch to be ignored -sonic-db-cli APPL_DB hmset "NEIGH_TABLE:Vlan1000:fc02:1000::99" "neigh" "00:00:00:00:00:00" "family" "IPv6" > /dev/null -sonic-db-cli ASIC_DB hmset 'ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"fc02:1000::99/128","switch_id":"oid:0x21000000000000","vr":"oid:0x300000000007c"}' "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" "oid:0x400000000167d" "SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION" "SAI_PACKET_ACTION_FORWARD" > /dev/null - -echo "------" -echo "expect success on dualtor, expect error on all other devices!" -echo "Running Route Check..." -./route_check.py -echo "return value: $?" - -sonic-db-cli APPL_DB del "NEIGH_TABLE:Vlan1000:fc02:1000::99" > /dev/null -sonic-db-cli ASIC_DB del 'ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"fc02:1000::99/128","switch_id":"oid:0x21000000000000","vr":"oid:0x300000000007c"}' > /dev/null - -echo "------" -echo "expect success!" -echo "Running Route Check..." -./route_check.py -echo "return value: $?" + +CONFIG_FILE="/etc/sonic/config_db.json" +if [ ! -e "$CONFIG_FILE" ]; then + echo "File $CONFIG_FILE not found. returning.." + exit 1 +fi + +# Extract platform and hwsku from DEVICE_METADATA using awk +platform=$(awk -F'"' '/"DEVICE_METADATA":/,/\}/{if(/"platform":/) print $4}' "$CONFIG_FILE") + +# Print the values +echo "Platform: $platform" + +PLATFORM_DIR="/usr/share/sonic/device/$platform" +if [ ! -d "$PLATFORM_DIR" ]; then + echo "Directory $PLATFORM_DIR not found. returning.." + exit 1 +fi + +ASIC_CONF_FILE="$PLATFORM_DIR/asic.conf" +echo "$ASIC_CONF_FILE" +num_asic=1 + +# Check if asic.conf exists +if [ -f "$ASIC_CONF_FILE" ]; then + if grep -q "^NUM_ASIC=" "$ASIC_CONF_FILE"; then + # Extract the value of NUM_ASIC into a local variable + num_asic=$(grep "^NUM_ASIC=" "$ASIC_CONF_FILE" | cut -d'=' -f2) + else + # Print a message if NUM_ASIC is not present + echo "NUM_ASIC not found.. returning.." + exit 1 + fi +fi + +echo "num_asic: $num_asic" + +if [ "$num_asic" -gt 1 ]; then + # test on asic0 + # add a route, interface & route-entry to simulate error + # + sonic-db-cli -n asic0 APPL_DB hmset "ROUTE_TABLE:20c0:d9b8:99:80::/64" "nexthop" "fc00::72,fc00::76,fc00::7a,fc00::7e" "ifname" "PortChannel01,PortChannel02,PortChannel03,PortChannel04" > /dev/null + sonic-db-cli -n asic0 ASIC_DB hmset "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"192.193.120.255/25\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000022\"}" "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" "oid:0x5000000000614" > /dev/null + sonic-db-cli -n asic0 APPL_DB hmset "INTF_TABLE:PortChannel01:10.0.0.99/31" "scope" "global" "family" "IPv4" > /dev/null + + echo "------" + echo "expect errors!" + echo "Running Route Check..." + ./route_check.py + echo "return value: $?" + + sonic-db-cli -n asic0 APPL_DB del "ROUTE_TABLE:20c0:d9b8:99:80::/64" > /dev/null + sonic-db-cli -n asic0 ASIC_DB del "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"192.193.120.255/25\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000022\"}" > /dev/null + sonic-db-cli -n asic0 APPL_DB del "INTF_TABLE:PortChannel01:10.0.0.99/31" > /dev/null + +else + # add a route, interface & route-entry to simulate error + # + sonic-db-cli APPL_DB hmset "ROUTE_TABLE:20c0:d9b8:99:80::/64" "nexthop" "fc00::72,fc00::76,fc00::7a,fc00::7e" "ifname" "PortChannel01,PortChannel02,PortChannel03,PortChannel04" > /dev/null + sonic-db-cli ASIC_DB hmset "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"192.193.120.255/25\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000022\"}" "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" "oid:0x5000000000614" > /dev/null + sonic-db-cli APPL_DB hmset "INTF_TABLE:PortChannel01:10.0.0.99/31" "scope" "global" "family" "IPv4" > /dev/null + + echo "------" + echo "expect errors!" + echo "Running Route Check..." + ./route_check.py + echo "return value: $?" + + sonic-db-cli APPL_DB del "ROUTE_TABLE:20c0:d9b8:99:80::/64" > /dev/null + sonic-db-cli ASIC_DB del "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"192.193.120.255/25\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000022\"}" > /dev/null + sonic-db-cli APPL_DB del "INTF_TABLE:PortChannel01:10.0.0.99/31" > /dev/null + + # add standalone tunnel route to simulate unreachable neighbor scenario on dual ToR + # in this scenario, we expect the route mismatch to be ignored + sonic-db-cli APPL_DB hmset "NEIGH_TABLE:Vlan1000:fc02:1000::99" "neigh" "00:00:00:00:00:00" "family" "IPv6" > /dev/null + sonic-db-cli ASIC_DB hmset 'ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"fc02:1000::99/128","switch_id":"oid:0x21000000000000","vr":"oid:0x300000000007c"}' "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" "oid:0x400000000167d" "SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION" "SAI_PACKET_ACTION_FORWARD" > /dev/null + + echo "------" + echo "expect success on dualtor, expect error on all other devices!" + echo "Running Route Check..." + ./route_check.py + echo "return value: $?" + + sonic-db-cli APPL_DB del "NEIGH_TABLE:Vlan1000:fc02:1000::99" > /dev/null + sonic-db-cli ASIC_DB del 'ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"fc02:1000::99/128","switch_id":"oid:0x21000000000000","vr":"oid:0x300000000007c"}' > /dev/null + + echo "------" + echo "expect success!" + echo "Running Route Check..." + ./route_check.py + echo "return value: $?" +fi diff --git a/tests/route_check_test.py b/tests/route_check_test.py index 3b38add9ff..820f062107 100644 --- a/tests/route_check_test.py +++ b/tests/route_check_test.py @@ -1,14 +1,17 @@ import copy from io import StringIO import json -import os import logging -import sys import syslog +import sys import time from sonic_py_common import device_info from unittest.mock import MagicMock, patch -from tests.route_check_test_data import APPL_DB, ARGS, ASIC_DB, CONFIG_DB, DEFAULT_CONFIG_DB, APPL_STATE_DB, DESCR, OP_DEL, OP_SET, PRE, RESULT, RET, TEST_DATA, UPD, FRR_ROUTES +from tests.route_check_test_data import ( + APPL_DB, MULTI_ASIC, NAMESPACE, DEFAULTNS, ARGS, ASIC_DB, CONFIG_DB, + DEFAULT_CONFIG_DB, APPL_STATE_DB, DESCR, OP_DEL, OP_SET, PRE, RESULT, RET, TEST_DATA, + UPD, FRR_ROUTES +) import pytest @@ -18,50 +21,37 @@ import route_check current_test_data = None - -tables_returned = {} selector_returned = None subscribers_returned = {} +db_conns = {} def set_test_case_data(ctdata): - """ - Setup global variables for each test case - """ - global current_test_data, tables_returned, selector_returned, subscribers_returned - + global current_test_data, db_conns, selector_returned, subscribers_returned current_test_data = ctdata - tables_returned = {} - selector_returned = None subscribers_returned = {} - def recursive_update(d, t): - assert (type(t) is dict) + assert type(t) is dict for k in t.keys(): if type(t[k]) is not dict: d.update(t) return - if k not in d: d[k] = {} recursive_update(d[k], t[k]) - class Table: - def __init__(self, db, tbl): self.db = db self.tbl = tbl - self.data = copy.deepcopy(self.get_val(current_test_data[PRE], [db, tbl])) - # print("Table:init: db={} tbl={} data={}".format(db, tbl, json.dumps(self.data, indent=4))) - + self.data = copy.deepcopy(self.get_val(current_test_data[PRE], [db["namespace"], db["name"], tbl])) def update(self): t = copy.deepcopy(self.get_val(current_test_data.get(UPD, {}), - [self.db, self.tbl, OP_SET])) + [self.db["namespace"], self.db["name"], self.tbl, OP_SET])) drop = copy.deepcopy(self.get_val(current_test_data.get(UPD, {}), - [self.db, self.tbl, OP_DEL])) + [self.db["namespace"], self.db["name"], self.tbl, OP_DEL])) if t: recursive_update(self.data, t) @@ -69,41 +59,41 @@ def update(self): self.data.pop(k, None) return (list(t.keys()), list(drop.keys())) - def get_val(self, d, keys): for k in keys: d = d[k] if k in d else {} return d - def getKeys(self): return list(self.data.keys()) - def get(self, key): ret = copy.deepcopy(self.data.get(key, {})) return (True, ret) - def hget(self, key, field): ret = copy.deepcopy(self.data.get(key, {}).get(field, {})) return True, ret +def conn_side_effect(arg, _1, _2, namespace): + return db_conns[namespace][arg] -db_conns = {"APPL_DB": APPL_DB, "ASIC_DB": ASIC_DB, "APPL_STATE_DB": APPL_STATE_DB } -def conn_side_effect(arg, _): - return db_conns[arg] - +def init_db_conns(namespaces): + for ns in namespaces: + db_conns[ns] = { + "APPL_DB": {"namespace": ns, "name": APPL_DB}, + "ASIC_DB": {"namespace": ns, "name": ASIC_DB}, + "APPL_STATE_DB": {"namespace": ns, "name": APPL_STATE_DB}, + "CONFIG_DB": ConfigDB(ns) + } def table_side_effect(db, tbl): - if not db in tables_returned: - tables_returned[db] = {} - if not tbl in tables_returned[db]: - tables_returned[db][tbl] = Table(db, tbl) - return tables_returned[db][tbl] + if not tbl in db.keys(): + db[tbl] = Table(db, tbl) + return db[tbl] -class mock_selector: +class MockSelector: TIMEOUT = 1 EMULATE_HANG = False @@ -111,21 +101,19 @@ def __init__(self): self.select_state = 0 self.select_cnt = 0 self.subs = None - # print("Mock Selector constructed") - + logger.debug("Mock Selector constructed") def addSelectable(self, subs): self.subs = subs return 0 - def select(self, timeout): # Toggle between good & timeout # state = self.select_state self.subs.update() - if mock_selector.EMULATE_HANG: + if MockSelector.EMULATE_HANG: time.sleep(60) if self.select_state == 0: @@ -136,29 +124,15 @@ def select(self, timeout): return (state, None) -class mock_db_conn: - def __init__(self, db): - self.db_name = None - for (k, v) in db_conns.items(): - if v == db: - self.db_name = k - assert self.db_name != None - - def getDbName(self): - return self.db_name - - -class mock_subscriber: +class MockSubscriber: def __init__(self, db, tbl): self.state = PRE self.db = db self.tbl = tbl - self.dbconn = mock_db_conn(db) self.mock_tbl = table_side_effect(self.db, self.tbl) self.set_keys = list(self.mock_tbl.data.keys()) self.del_keys = [] - def update(self): if self.state == PRE: s_keys, d_keys = self.mock_tbl.update() @@ -166,7 +140,6 @@ def update(self): self.del_keys += d_keys self.state = UPD - def pop(self): v = None if self.set_keys: @@ -180,61 +153,53 @@ def pop(self): k = "" op = "" - print("state={} k={} op={} v={}".format(self.state, k, op, str(v))) return (k, op, v) - - - def getDbConnector(self): - return self.dbconn - - - def getTableName(self): - return self.tbl - def subscriber_side_effect(db, tbl): global subscribers_returned - - key = "db_{}_tbl_{}".format(db, tbl) + key = "db_{}_{}_tbl_{}".format(db["namespace"], db["name"], tbl) if not key in subscribers_returned: - subscribers_returned[key] = mock_subscriber(db, tbl) + subscribers_returned[key] = MockSubscriber(db, tbl) return subscribers_returned[key] - def select_side_effect(): global selector_returned if not selector_returned: - selector_returned = mock_selector() + selector_returned = MockSelector() return selector_returned +def config_db_side_effect(namespace): + return db_conns[namespace]["CONFIG_DB"] -def table_side_effect(db, tbl): - if not db in tables_returned: - tables_returned[db] = {} - if not tbl in tables_returned[db]: - tables_returned[db][tbl] = Table(db, tbl) - return tables_returned[db][tbl] - +class ConfigDB: + def __init__(self, namespace): + self.namespace = namespace + self.name = CONFIG_DB + self.db = current_test_data.get(PRE, {}).get(namespace, {}).get(CONFIG_DB, DEFAULT_CONFIG_DB) if current_test_data is not None else DEFAULT_CONFIG_DB -def config_db_side_effect(table): - if CONFIG_DB not in current_test_data[PRE]: - return DEFAULT_CONFIG_DB[table] - if not CONFIG_DB in tables_returned: - tables_returned[CONFIG_DB] = {} - if not table in tables_returned[CONFIG_DB]: - tables_returned[CONFIG_DB][table] = current_test_data[PRE][CONFIG_DB].get(table, {}) - return tables_returned[CONFIG_DB][table] + def get_table(self, table): + return self.db.get(table, {}) + def get_entry(self, table, key): + return self.get_table(table).get(key, {}) def set_mock(mock_table, mock_conn, mock_sel, mock_subs, mock_config_db): mock_conn.side_effect = conn_side_effect mock_table.side_effect = table_side_effect mock_sel.side_effect = select_side_effect mock_subs.side_effect = subscriber_side_effect - mock_config_db.get_table = MagicMock(side_effect=config_db_side_effect) + mock_config_db.side_effect = config_db_side_effect class TestRouteCheck(object): + @staticmethod + def extract_namespace_from_args(args): + # args: ['show', 'ip', 'route', '-n', 'asic0', 'json'], + for i, arg in enumerate(args): + if arg == "-n" and i + 1 < len(args): + return args[i + 1] + return DEFAULTNS + def setup(self): pass @@ -246,21 +211,20 @@ def init(self): def force_hang(self): old_timeout = route_check.TIMEOUT_SECONDS route_check.TIMEOUT_SECONDS = 5 - mock_selector.EMULATE_HANG = True + MockSelector.EMULATE_HANG = True yield route_check.TIMEOUT_SECONDS = old_timeout - mock_selector.EMULATE_HANG = False + MockSelector.EMULATE_HANG = False @pytest.fixture def mock_dbs(self): - mock_config_db = MagicMock() with patch("route_check.swsscommon.DBConnector") as mock_conn, \ patch("route_check.swsscommon.Table") as mock_table, \ patch("route_check.swsscommon.Select") as mock_sel, \ patch("route_check.swsscommon.SubscriberStateTable") as mock_subs, \ - patch("route_check.swsscommon.ConfigDBConnector", return_value=mock_config_db), \ + patch("sonic_py_common.multi_asic.connect_config_db_for_ns") as mock_config_db, \ patch("route_check.swsscommon.NotificationProducer"): device_info.get_platform = MagicMock(return_value='unittest') set_mock(mock_table, mock_conn, mock_sel, mock_subs, mock_config_db) @@ -268,32 +232,40 @@ def mock_dbs(self): @pytest.mark.parametrize("test_num", TEST_DATA.keys()) def test_route_check(self, mock_dbs, test_num): + logger.debug("test_route_check: test_num={}".format(test_num)) self.init() ret = 0 - ct_data = TEST_DATA[test_num] set_test_case_data(ct_data) - logger.info("Running test case {}: {}".format(test_num, ct_data[DESCR])) + self.run_test(ct_data) + def run_test(self, ct_data): with patch('sys.argv', ct_data[ARGS].split()), \ - patch('route_check.subprocess.check_output') as mock_check_output: + patch('sonic_py_common.multi_asic.get_namespace_list', return_value= ct_data[NAMESPACE]), \ + patch('sonic_py_common.multi_asic.is_multi_asic', return_value= ct_data[MULTI_ASIC]), \ + patch('route_check.subprocess.check_output', side_effect=lambda *args, **kwargs: self.mock_check_output(ct_data, *args, **kwargs)), \ + patch('route_check.mitigate_installed_not_offloaded_frr_routes', side_effect=lambda *args, **kwargs: None), \ + patch('route_check.load_db_config', side_effect=lambda: init_db_conns(ct_data[NAMESPACE])): + + ret, res = route_check.main() + self.assert_results(ct_data, ret, res) - routes = ct_data.get(FRR_ROUTES, {}) + def mock_check_output(self, ct_data, *args, **kwargs): + ns = self.extract_namespace_from_args(args[0]) + routes = ct_data.get(FRR_ROUTES, {}).get(ns, {}) + return json.dumps(routes) - def side_effect(*args, **kwargs): - return json.dumps(routes) + def assert_results(self, ct_data, ret, res): + expect_ret = ct_data.get(RET, 0) + expect_res = ct_data.get(RESULT, None) - mock_check_output.side_effect = side_effect + if res: + logger.debug("res={}".format(json.dumps(res, indent=4))) + if expect_res: + logger.debug("expect_res={}".format(json.dumps(expect_res, indent=4))) - ret, res = route_check.main() - expect_ret = ct_data[RET] if RET in ct_data else 0 - expect_res = ct_data[RESULT] if RESULT in ct_data else None - if res: - print("res={}".format(json.dumps(res, indent=4))) - if expect_res: - print("expect_res={}".format(json.dumps(expect_res, indent=4))) - assert ret == expect_ret - assert res == expect_res + assert ret == expect_ret + assert res == expect_res def test_timeout(self, mock_dbs, force_hang): # Test timeout @@ -324,9 +296,11 @@ def test_logging(self): assert len(msg) == 5 def test_mitigate_routes(self, mock_dbs): + namespace = DEFAULTNS missed_frr_rt = [ { 'prefix': '192.168.0.1', 'protocol': 'bgp' } ] rt_appl = [ '192.168.0.1' ] + init_db_conns([namespace]) with patch('sys.stdout', new_callable=StringIO) as mock_stdout: - route_check.mitigate_installed_not_offloaded_frr_routes(missed_frr_rt, rt_appl) + route_check.mitigate_installed_not_offloaded_frr_routes(namespace, missed_frr_rt, rt_appl) # Verify that the stdout are suppressed in this function assert not mock_stdout.getvalue() diff --git a/tests/route_check_test_data.py b/tests/route_check_test_data.py index 9250c54ca9..50c6276f26 100644 --- a/tests/route_check_test_data.py +++ b/tests/route_check_test_data.py @@ -1,4 +1,6 @@ DESCR = "Description" +MULTI_ASIC = "multi_asic" +NAMESPACE = "namespace-list" ARGS = "args" RET = "return" APPL_DB = 0 @@ -9,6 +11,9 @@ UPD = "update" FRR_ROUTES = "frr-routes" RESULT = "res" +DEFAULTNS="" +ASIC0 = "asic0" +ASIC1 = "asic1" OP_SET = "SET" OP_DEL = "DEL" @@ -32,66 +37,76 @@ TEST_DATA = { "0": { DESCR: "basic good one", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -m INFO -i 1000", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "10.10.196.30/31" : { "ifname": "lo" } + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } } } } }, "1": { DESCR: "With updates", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -m DEBUG -i 1", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "10.10.196.30/31" : { "ifname": "lo" } + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.10.10/32" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.10.10/32" + RT_ENTRY_KEY_SUFFIX: {} + } } } }, UPD: { - ASIC_DB: { - RT_ENTRY_TABLE: { - OP_SET: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - }, - OP_DEL: { - RT_ENTRY_KEY_PREFIX + "10.10.10.10/32" + RT_ENTRY_KEY_SUFFIX: {} + DEFAULTNS: { + ASIC_DB: { + RT_ENTRY_TABLE: { + OP_SET: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + }, + OP_DEL: { + RT_ENTRY_KEY_PREFIX + "10.10.10.10/32" + RT_ENTRY_KEY_SUFFIX: {} + } } } } @@ -99,506 +114,845 @@ }, "2": { DESCR: "basic failure one", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -i 15", RET: -1, PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "10.10.196.30/31" : { "ifname": "lo" } + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:90.10.196.24/31": {}, + "PortChannel1023:9603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } }, - INTF_TABLE: { - "PortChannel1013:90.10.196.24/31": {}, - "PortChannel1023:9603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "20.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "20.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "20.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "3603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "20.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "20.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "20.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "3603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } } } }, RESULT: { - "missed_ROUTE_TABLE_routes": [ - "10.10.196.12/31", - "10.10.196.20/31" - ], - "missed_INTF_TABLE_entries": [ - "90.10.196.24/32", - "9603:10b0:503:df4::5d/128" - ], - "Unaccounted_ROUTE_ENTRY_TABLE_entries": [ - "20.10.196.12/31", - "20.10.196.20/31", - "20.10.196.24/32", - "3603:10b0:503:df4::5d/128" - ] + DEFAULTNS: { + "missed_ROUTE_TABLE_routes": [ + "10.10.196.12/31", + "10.10.196.20/31" + ], + "missed_INTF_TABLE_entries": [ + "90.10.196.24/32", + "9603:10b0:503:df4::5d/128" + ], + "Unaccounted_ROUTE_ENTRY_TABLE_entries": [ + "20.10.196.12/31", + "20.10.196.20/31", + "20.10.196.24/32", + "3603:10b0:503:df4::5d/128" + ] + } } }, "3": { DESCR: "basic good one with no args", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "10.10.196.30/31" : { "ifname": "lo" } + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } } } } }, "4": { DESCR: "Good one with routes on voq inband interface", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "10.10.196.30/31" : { "ifname": "lo" }, - "10.10.197.1" : { "ifname": "Ethernet-IB0", "nexthop": "0.0.0.0"}, - "2603:10b0:503:df5::1" : { "ifname": "Ethernet-IB0", "nexthop": "::"}, - "100.0.0.2/32" : { "ifname": "Ethernet-IB0", "nexthop": "0.0.0.0" }, - "2064:100::2/128" : { "ifname": "Ethernet-IB0", "nexthop": "::" }, - "101.0.0.0/24" : { "ifname": "Ethernet-IB0", "nexthop": "100.0.0.2"} + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" }, + "10.10.197.1" : { "ifname": "Ethernet-IB0", "nexthop": "0.0.0.0"}, + "2603:10b0:503:df5::1" : { "ifname": "Ethernet-IB0", "nexthop": "::"}, + "100.0.0.2/32" : { "ifname": "Ethernet-IB0", "nexthop": "0.0.0.0" }, + "2064:100::2/128" : { "ifname": "Ethernet-IB0", "nexthop": "::" }, + "101.0.0.0/24" : { "ifname": "Ethernet-IB0", "nexthop": "100.0.0.2"} + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {}, + "Ethernet-IB0:10.10.197.1/24": {}, + "Ethernet-IB0:2603:10b0:503:df5::1/64": {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {}, - "Ethernet-IB0:10.10.197.1/24": {}, - "Ethernet-IB0:2603:10b0:503:df5::1/64": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.197.1/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df5::1/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "101.0.0.0/24" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.197.1/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df5::1/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "101.0.0.0/24" + RT_ENTRY_KEY_SUFFIX: {} + } } } } }, "5": { DESCR: "local route with nexthop - fail", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -m INFO -i 1000", RET: -1, PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "10.10.196.30/31" : { "ifname": "lo", "nexthop": "100.0.0.2" } + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo", "nexthop": "100.0.0.2" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } } } }, RESULT: { - "missed_ROUTE_TABLE_routes": [ - "10.10.196.30/31" - ] + DEFAULTNS: { + "missed_ROUTE_TABLE_routes": [ + "10.10.196.30/31" + ] + } } }, "6": { DESCR: "Good one with VNET routes", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "10.10.196.30/31" : { "ifname": "lo" } - }, - VNET_ROUTE_TABLE: { - "Vnet1:30.1.10.0/24": { "ifname": "Vlan3001" }, - "Vnet1:50.1.1.0/24": { "ifname": "Vlan3001" }, - "Vnet1:50.2.2.0/24": { "ifname": "Vlan3001" } + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + VNET_ROUTE_TABLE: { + "Vnet1:30.1.10.0/24": { "ifname": "Vlan3001" }, + "Vnet1:50.1.1.0/24": { "ifname": "Vlan3001" }, + "Vnet1:50.2.2.0/24": { "ifname": "Vlan3001" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {}, + "Vlan3001": { "vnet_name": "Vnet1" }, + "Vlan3001:30.1.10.1/24": {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {}, - "Vlan3001": { "vnet_name": "Vnet1" }, - "Vlan3001:30.1.10.1/24": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "30.1.10.1/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "30.1.10.0/24" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "50.1.1.0/24" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "50.2.2.0/24" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "30.1.10.1/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "30.1.10.0/24" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "50.1.1.0/24" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "50.2.2.0/24" + RT_ENTRY_KEY_SUFFIX: {} + } } } } }, "7": { DESCR: "dualtor standalone tunnel route case", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check", PRE: { - CONFIG_DB: { - DEVICE_METADATA: { - LOCALHOST: {"subtype": "DualToR"} - } - }, - APPL_DB: { - NEIGH_TABLE: { - "Vlan1000:fc02:1000::99": { "neigh": "00:00:00:00:00:00", "family": "IPv6"} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "fc02:1000::99/128" + RT_ENTRY_KEY_SUFFIX: {}, + DEFAULTNS: { + CONFIG_DB: { + DEVICE_METADATA: { + LOCALHOST: {"subtype": "DualToR"} + } + }, + APPL_DB: { + NEIGH_TABLE: { + "Vlan1000:fc02:1000::99": { "neigh": "00:00:00:00:00:00", "family": "IPv6"} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "fc02:1000::99/128" + RT_ENTRY_KEY_SUFFIX: {}, + } } } } }, "8": { DESCR: "Good one with VRF routes", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "Vrf1:0.0.0.0/0" : { "ifname": "portchannel0" }, - "Vrf1:10.10.196.12/31" : { "ifname": "portchannel0" }, - "Vrf1:10.10.196.20/31" : { "ifname": "portchannel0" } + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "Vrf1:0.0.0.0/0" : { "ifname": "portchannel0" }, + "Vrf1:10.10.196.12/31" : { "ifname": "portchannel0" }, + "Vrf1:10.10.196.20/31" : { "ifname": "portchannel0" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } } } } }, "9": { DESCR: "SOC IPs on Libra ToRs should be ignored", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check", PRE: { - CONFIG_DB: { - DEVICE_METADATA: { - LOCALHOST: {"subtype": "DualToR"} - }, - MUX_CABLE: { - "Ethernet4": { - "cable_type": "active-active", - "server_ipv4": "192.168.0.2/32", - "server_ipv6": "fc02:1000::2/128", - "soc_ipv4": "192.168.0.3/32", - "soc_ipv6": "fc02:1000::3/128", - "state": "auto" + DEFAULTNS: { + CONFIG_DB: { + DEVICE_METADATA: { + LOCALHOST: {"subtype": "DualToR"} }, - } - }, - APPL_DB: { - ROUTE_TABLE: { - "192.168.0.2/32": {"ifname": "tun0"}, - "fc02:1000::2/128": {"ifname": "tun0"} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "192.168.0.2/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "fc02:1000::2/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "192.168.0.3/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "fc02:1000::3/128" + RT_ENTRY_KEY_SUFFIX: {} + MUX_CABLE: { + "Ethernet4": { + "cable_type": "active-active", + "server_ipv4": "192.168.0.2/32", + "server_ipv6": "fc02:1000::2/128", + "soc_ipv4": "192.168.0.3/32", + "soc_ipv6": "fc02:1000::3/128", + "state": "auto" + }, + } + }, + APPL_DB: { + ROUTE_TABLE: { + "192.168.0.2/32": {"ifname": "tun0"}, + "fc02:1000::2/128": {"ifname": "tun0"} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "192.168.0.2/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "fc02:1000::2/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "192.168.0.3/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "fc02:1000::3/128" + RT_ENTRY_KEY_SUFFIX: {} + } } } } }, "10": { DESCR: "basic good one, check FRR routes", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -m INFO -i 1000", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} - } }, }, FRR_ROUTES: { - "0.0.0.0/0": [ - { - "prefix": "0.0.0.0/0", - "vrfName": "default", - "protocol": "bgp", - "selected": True, - "offloaded": True, - }, - ], - "10.10.196.12/31": [ - { - "prefix": "10.10.196.12/31", - "vrfName": "default", - "protocol": "bgp", - "selected": True, - "offloaded": True, - }, - ], - "10.10.196.24/31": [ - { - "protocol": "connected", - "selected": True, - }, - ], + DEFAULTNS: { + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "vrfName": "default", + "protocol": "bgp", + "selected": True, + "offloaded": True, + }, + ], + "10.10.196.12/31": [ + { + "prefix": "10.10.196.12/31", + "vrfName": "default", + "protocol": "bgp", + "selected": True, + "offloaded": True, + }, + ], + "10.10.196.24/31": [ + { + "protocol": "connected", + "selected": True, + }, + ], + } }, }, "11": { DESCR: "failure test case, missing FRR routes", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -m INFO -i 1000", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} - } }, }, FRR_ROUTES: { - "0.0.0.0/0": [ - { - "prefix": "0.0.0.0/0", - "vrfName": "default", - "protocol": "bgp", - "selected": True, - "offloaded": True, - }, - ], - "10.10.196.12/31": [ - { - "prefix": "10.10.196.12/31", - "vrfName": "default", - "protocol": "bgp", - "selected": True, - }, - ], - "1.1.1.0/24": [ - { - "prefix": "1.1.1.0/24", - "vrfName": "default", - "protocol": "static", - "selected": True, - }, - ], - "10.10.196.24/31": [ - { - "protocol": "connected", - "selected": True, - }, - ], + DEFAULTNS: { + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "vrfName": "default", + "protocol": "bgp", + "selected": True, + "offloaded": True, + }, + ], + "10.10.196.12/31": [ + { + "prefix": "10.10.196.12/31", + "vrfName": "default", + "protocol": "bgp", + "selected": True, + }, + ], + "1.1.1.0/24": [ + { + "prefix": "1.1.1.0/24", + "vrfName": "default", + "protocol": "static", + "selected": True, + }, + ], + "10.10.196.24/31": [ + { + "protocol": "connected", + "selected": True, + }, + ], + }, }, RESULT: { - "missed_FRR_routes": [ - {"prefix": "10.10.196.12/31", "vrfName": "default", "protocol": "bgp", "selected": True}, - {"prefix": "1.1.1.0/24", "vrfName": "default", "protocol": "static", "selected": True}, - ], + DEFAULTNS: { + "missed_FRR_routes": [ + {"prefix": "10.10.196.12/31", "vrfName": "default", "protocol": "bgp", "selected": True}, + {"prefix": "1.1.1.0/24", "vrfName": "default", "protocol": "static", "selected": True}, + ], + }, }, RET: -1, }, "12": { DESCR: "skip bgp routes offloaded check, if not selected as best", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -m INFO -i 1000", PRE: { - APPL_DB: { - ROUTE_TABLE: { - "0.0.0.0/0" : { "ifname": "portchannel0" }, - "10.10.196.12/31" : { "ifname": "portchannel0" }, + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } }, - INTF_TABLE: { - "PortChannel1013:10.10.196.24/31": {}, - "PortChannel1023:2603:10b0:503:df4::5d/126": {}, - "PortChannel1024": {} - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} - } }, }, FRR_ROUTES: { - "0.0.0.0/0": [ - { - "prefix": "0.0.0.0/0", - "vrfName": "default", - "protocol": "bgp", - "selected": True, - "offloaded": True, - }, - ], - "10.10.196.12/31": [ - { - "prefix": "10.10.196.12/31", - "vrfName": "default", - "protocol": "bgp", - }, - ], - "10.10.196.24/31": [ - { - "protocol": "connected", - "selected": True, - }, - ], + DEFAULTNS: { + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "vrfName": "default", + "protocol": "bgp", + "selected": True, + "offloaded": True, + }, + ], + "10.10.196.12/31": [ + { + "prefix": "10.10.196.12/31", + "vrfName": "default", + "protocol": "bgp", + }, + ], + "10.10.196.24/31": [ + { + "protocol": "connected", + "selected": True, + }, + ], + }, }, }, "13": { DESCR: "basic good one with IPv6 address", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -m INFO -i 1000", PRE: { - APPL_DB: { - ROUTE_TABLE: { + DEFAULTNS: { + APPL_DB: { + ROUTE_TABLE: { + }, + INTF_TABLE: { + "PortChannel1013:2000:31:0:0::1/64": {}, + } }, - INTF_TABLE: { - "PortChannel1013:2000:31:0:0::1/64": {}, - } - }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "2000:31::1/128" + RT_ENTRY_KEY_SUFFIX: {}, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "2000:31::1/128" + RT_ENTRY_KEY_SUFFIX: {}, + } } } } }, "14": { DESCR: "dualtor ignore vlan neighbor route miss case", + MULTI_ASIC: False, + NAMESPACE: [''], ARGS: "route_check -i 15", RET: -1, PRE: { - CONFIG_DB: { - DEVICE_METADATA: { - LOCALHOST: {"subtype": "DualToR"} + DEFAULTNS: { + CONFIG_DB: { + DEVICE_METADATA: { + LOCALHOST: {"subtype": "DualToR"} + } + }, + APPL_DB: { + ROUTE_TABLE: { + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "192.168.0.101/32": { "ifname": "tun0" }, + "192.168.0.103/32": { "ifname": "tun0" }, + }, + INTF_TABLE: { + "PortChannel1013:90.10.196.24/31": {}, + "PortChannel1023:9603:10b0:503:df4::5d/126": {}, + }, + NEIGH_TABLE: { + "Vlan1000:192.168.0.100": {}, + "Vlan1000:192.168.0.101": {}, + "Vlan1000:192.168.0.102": {}, + "Vlan1000:192.168.0.103": {}, + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "20.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "20.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "20.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "192.168.0.101/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "192.168.0.102/32" + RT_ENTRY_KEY_SUFFIX: {}, + } } - }, - APPL_DB: { - ROUTE_TABLE: { - "10.10.196.12/31" : { "ifname": "portchannel0" }, - "10.10.196.20/31" : { "ifname": "portchannel0" }, - "192.168.0.101/32": { "ifname": "tun0" }, - "192.168.0.103/32": { "ifname": "tun0" }, + } + }, + RESULT: { + DEFAULTNS: { + "missed_ROUTE_TABLE_routes": [ + "10.10.196.12/31", + "10.10.196.20/31" + ], + "missed_INTF_TABLE_entries": [ + "90.10.196.24/32", + "9603:10b0:503:df4::5d/128" + ], + "Unaccounted_ROUTE_ENTRY_TABLE_entries": [ + "20.10.196.12/31", + "20.10.196.20/31", + "20.10.196.24/32", + ] + } + } + }, + "15": { + DESCR: "basic good one on multi-asic on a particular asic", + MULTI_ASIC: True, + NAMESPACE: ['asic0', 'asic1'], + ARGS: "route_check -n asic0 -m INFO -i 1000", + PRE: { + ASIC0: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } }, - INTF_TABLE: { - "PortChannel1013:90.10.196.24/31": {}, - "PortChannel1023:9603:10b0:503:df4::5d/126": {}, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } + } + } + } + }, + "16": { + DESCR: "basic good one on multi-asic on all asics", + MULTI_ASIC: True, + NAMESPACE: ['asic0', 'asic1'], + ARGS: "route_check -m INFO -i 1000", + PRE: { + ASIC0: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } }, - NEIGH_TABLE: { - "Vlan1000:192.168.0.100": {}, - "Vlan1000:192.168.0.101": {}, - "Vlan1000:192.168.0.102": {}, - "Vlan1000:192.168.0.103": {}, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } } }, - ASIC_DB: { - RT_ENTRY_TABLE: { - RT_ENTRY_KEY_PREFIX + "20.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "20.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "20.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "192.168.0.101/32" + RT_ENTRY_KEY_SUFFIX: {}, - RT_ENTRY_KEY_PREFIX + "192.168.0.102/32" + RT_ENTRY_KEY_SUFFIX: {}, + ASIC1: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } + } + }, + } + }, + "17": { + DESCR: "simple failure case on multi-asic on a particular asic", + MULTI_ASIC: True, + NAMESPACE: ['asic0', 'asic1'], + ARGS: "route_check -n asic0 -m INFO -i 1000", + PRE: { + ASIC0: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } } } }, RESULT: { - "missed_ROUTE_TABLE_routes": [ - "10.10.196.12/31", - "10.10.196.20/31" - ], - "missed_INTF_TABLE_entries": [ - "90.10.196.24/32", - "9603:10b0:503:df4::5d/128" - ], - "Unaccounted_ROUTE_ENTRY_TABLE_entries": [ - "20.10.196.12/31", - "20.10.196.20/31", - "20.10.196.24/32", - ] - } + ASIC0: { + "missed_ROUTE_TABLE_routes": [ + "10.10.196.12/31" + ], + } + }, + RET: -1, + }, + "18": { + DESCR: "simple failure case on multi-asic on all asics", + MULTI_ASIC: True, + NAMESPACE: ['asic0', 'asic1'], + ARGS: "route_check -m INFO -i 1000", + PRE: { + ASIC0: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } + } + }, + ASIC1: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.20/31" : { "ifname": "portchannel0" }, + "10.10.196.30/31" : { "ifname": "lo" } + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.20/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } + } + }, + }, + RESULT: { + ASIC0: { + "missed_ROUTE_TABLE_routes": [ + "10.10.196.12/31" + ], + }, + ASIC1: { + "Unaccounted_ROUTE_ENTRY_TABLE_entries": [ + "10.10.196.12/31" + ], + }, + }, + RET: -1, }, + "19": { + DESCR: "validate namespace input on multi-asic", + MULTI_ASIC: True, + NAMESPACE: ['asic0', 'asic1'], + ARGS: "route_check -n random -m INFO -i 1000", + RET: -1, + }, + "20": { + DESCR: "validate namespace input on single-asic", + MULTI_ASIC: False, + NAMESPACE: [''], + ARGS: "route_check -n random -m INFO -i 1000", + RET: -1, + }, + "21": { + DESCR: "multi-asic failure test case, missing FRR routes", + MULTI_ASIC: True, + NAMESPACE: ['asic0', 'asic1'], + ARGS: "route_check -n asic1 -m INFO -i 1000", + PRE: { + ASIC1: { + APPL_DB: { + ROUTE_TABLE: { + "0.0.0.0/0" : { "ifname": "portchannel0" }, + "10.10.196.12/31" : { "ifname": "portchannel0" }, + }, + INTF_TABLE: { + "PortChannel1013:10.10.196.24/31": {}, + "PortChannel1023:2603:10b0:503:df4::5d/126": {}, + "PortChannel1024": {} + } + }, + ASIC_DB: { + RT_ENTRY_TABLE: { + RT_ENTRY_KEY_PREFIX + "10.10.196.12/31" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "10.10.196.24/32" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "2603:10b0:503:df4::5d/128" + RT_ENTRY_KEY_SUFFIX: {}, + RT_ENTRY_KEY_PREFIX + "0.0.0.0/0" + RT_ENTRY_KEY_SUFFIX: {} + } + }, + }, + }, + FRR_ROUTES: { + ASIC1: { + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "vrfName": "default", + "protocol": "bgp", + "selected": True, + "offloaded": True, + }, + ], + "10.10.196.12/31": [ + { + "prefix": "10.10.196.12/31", + "vrfName": "default", + "protocol": "bgp", + "selected": True, + }, + ], + "10.10.196.24/31": [ + { + "protocol": "connected", + "selected": True, + }, + ], + }, + }, + RESULT: { + ASIC1: { + "missed_FRR_routes": [ + {"prefix": "10.10.196.12/31", "vrfName": "default", "protocol": "bgp", "selected": True} + ], + }, + }, + RET: -1, + }, + }