diff --git a/tests/bgp/test_frr_config_check.py b/tests/bgp/test_frr_config_check.py index 0dd46abc888..4235ff84fb0 100644 --- a/tests/bgp/test_frr_config_check.py +++ b/tests/bgp/test_frr_config_check.py @@ -10,7 +10,7 @@ from tests.common.helpers.assertions import pytest_assert pytestmark = [ - pytest.mark.topology('t0', 't1', 'lma', 'uma'), + pytest.mark.topology('t0', 't1', 't1-lag', 't1-8-lag', 'lma', 'uma'), pytest.mark.disable_loganalyzer, ] @@ -35,14 +35,30 @@ } -def parse_frr_config_file(duthost, config_file): +def _frontend_asic_indexes(duthost): + if duthost.is_multi_asic: + return duthost.get_frontend_asic_ids() + return [None] + + +def _bgp_container_name(duthost, asic_index): + if not duthost.is_multi_asic: + return "bgp" + return "bgp{}".format(asic_index) + + +def parse_frr_config_file(duthost, config_file, asic_index=None): """ Parse FRR configuration file and extract meaningful configuration lines """ config_lines = [] try: - # Read the configuration file - cmd = "sudo cat /etc/sonic/frr/{}".format(config_file) + if duthost.is_multi_asic: + cmd = "docker exec {} cat /etc/frr/{}".format( + _bgp_container_name(duthost, asic_index), config_file + ) + else: + cmd = "sudo cat /etc/sonic/frr/{}".format(config_file) result = duthost.shell(cmd) for line in result['stdout_lines']: @@ -57,12 +73,15 @@ def parse_frr_config_file(duthost, config_file): return config_lines -def parse_vtysh_running_config(duthost): +def parse_vtysh_running_config(duthost, asic_index=None): """ Get running configuration from vtysh and parse it """ try: - result = duthost.shell('vtysh -c "show running-config"') + if duthost.is_multi_asic: + result = duthost.asic_instance(asic_index).run_vtysh('-c "show running-config"') + else: + result = duthost.shell('vtysh -c "show running-config"') running_config = result['stdout'] return running_config except Exception as e: @@ -104,14 +123,15 @@ def is_config_in_running(config_line, running_config): return False -def verify_frr_config_in_running(duthost, config_file, running_config): +def verify_frr_config_in_running(duthost, config_file, running_config, asic_index=None): """ Verify that configurations in config file are present in running configuration """ - logger.info("Verifying FRR config file: {}".format(config_file)) + asic_label = "asic{}".format(asic_index) if duthost.is_multi_asic else "default" + logger.info("Verifying FRR config file {} on {}".format(config_file, asic_label)) # Get configuration lines from file - config_lines = parse_frr_config_file(duthost, config_file) + config_lines = parse_frr_config_file(duthost, config_file, asic_index) logger.info("Parsed {} lines from config file {}".format(len(config_lines), config_file)) logger.debug("Configuration lines: {}".format(config_lines)) @@ -162,13 +182,18 @@ def verify_frr_config_in_running(duthost, config_file, running_config): return missing_configs -def get_frr_config_files(duthost): +def get_frr_config_files(duthost, asic_index=None): """ Get list of FRR config files from /etc/sonic/frr directory """ config_files = [] try: - result = duthost.shell("ls /etc/sonic/frr") + if duthost.is_multi_asic: + result = duthost.shell( + "docker exec {} ls /etc/frr".format(_bgp_container_name(duthost, asic_index)) + ) + else: + result = duthost.shell("ls /etc/sonic/frr") for file in result['stdout_lines']: file = file.strip() if file in SONIC_FRR_CONFIG_FILES: @@ -355,6 +380,21 @@ def _verify_config_file_forward(config_content, running_config): return missing +def _collect_missing_frr_configs(duthost): + missing_configs = {} + for asic_index in _frontend_asic_indexes(duthost): + asic_label = "asic{}".format(asic_index) if duthost.is_multi_asic else "default" + running_config = parse_vtysh_running_config(duthost, asic_index) + frr_config_files = get_frr_config_files(duthost, asic_index) + for config_file in frr_config_files: + missing = verify_frr_config_in_running( + duthost, config_file, running_config, asic_index + ) + if missing: + missing_configs.setdefault(asic_label, {})[config_file] = missing + return missing_configs + + def test_frr_config_check(duthosts, enum_rand_one_per_hwsku_frontend_hostname, get_function_completeness_level): """ Test FRR configuration consistency @@ -374,30 +414,16 @@ def test_frr_config_check(duthosts, enum_rand_one_per_hwsku_frontend_hostname, g num_iterations = ITERATION_LEVEL_MAP[normalized_level] logger.info('Completeness level: {}, setting iterations to: {}'.format(normalized_level, num_iterations)) - # FRR config files to check - ['bgpd.conf', 'staticd.conf', 'zebra.conf', 'vtysh.conf'] - frr_config_files = get_frr_config_files(duthost) - logger.info("FRR config files to check: {}".format(frr_config_files)) - - # Get current FRR running configuration (once) - logger.info("Getting FRR running configuration") - running_config = parse_vtysh_running_config(duthost) - # logger.debug("Running configuration: {}".format(running_config)) - # Initial configuration verification logger.info("Verifying initial FRR configuration consistency") - initial_missing_configs = {} - - for config_file in frr_config_files: - missing_configs = verify_frr_config_in_running(duthost, config_file, running_config) - logger.info("Missing configurations in {}: {}".format(config_file, missing_configs)) - if missing_configs: - initial_missing_configs[config_file] = missing_configs + initial_missing_configs = _collect_missing_frr_configs(duthost) # Log initial results if initial_missing_configs: logger.warning("Initial check - Found missing configurations:") - for config_file, missing in initial_missing_configs.items(): - logger.warning("File {}: {}".format(config_file, missing)) + for asic_label, missing_by_file in initial_missing_configs.items(): + for config_file, missing in missing_by_file.items(): + logger.warning("{} file {}: {}".format(asic_label, config_file, missing)) else: logger.info("Initial check - All configurations are present in running config") @@ -416,20 +442,14 @@ def test_frr_config_check(duthosts, enum_rand_one_per_hwsku_frontend_hostname, g except Exception as e: pytest.fail("Iteration {}: Config reload failed: {}".format(iteration, str(e))) - # Get running configuration again after reload - logger.info("Iteration {}: Getting FRR running configuration after reload".format(iteration)) - post_reload_running_config = parse_vtysh_running_config(duthost) - # Verify configuration after reload logger.info("Iteration {}: Verifying FRR configuration after config reload".format(iteration)) - post_reload_missing_configs = {} - - for config_file in frr_config_files: - missing_configs = verify_frr_config_in_running(duthost, config_file, post_reload_running_config) - if missing_configs: - post_reload_missing_configs[config_file] = missing_configs - logger.warning("Iteration {}: Missing configs in {}: {}".format( - iteration, config_file, missing_configs)) + post_reload_missing_configs = _collect_missing_frr_configs(duthost) + if post_reload_missing_configs: + for asic_label, missing_by_file in post_reload_missing_configs.items(): + for config_file, missing_configs in missing_by_file.items(): + logger.warning("Iteration {}: Missing configs on {} in {}: {}".format( + iteration, asic_label, config_file, missing_configs)) # Compare with initial results logger.info("Iteration {}: Comparing with initial configuration check".format(iteration)) @@ -443,8 +463,10 @@ def test_frr_config_check(duthosts, enum_rand_one_per_hwsku_frontend_hostname, g # Final verification for this iteration if post_reload_missing_configs: logger.error("Iteration {}: Found missing configurations:".format(iteration)) - for config_file, missing in post_reload_missing_configs.items(): - logger.error("Iteration {}: File {}: {}".format(iteration, config_file, missing)) + for asic_label, missing_by_file in post_reload_missing_configs.items(): + for config_file, missing in missing_by_file.items(): + logger.error("Iteration {}: {} file {}: {}".format( + iteration, asic_label, config_file, missing)) # Fail immediately when configuration inconsistency is detected pytest.fail("Iteration {}: FRR configuration inconsistency detected after config reload".format(iteration)) diff --git a/tests/common/plugins/conditional_mark/tests_mark_conditions_vs_t1_multiasic.yaml b/tests/common/plugins/conditional_mark/tests_mark_conditions_vs_t1_multiasic.yaml index a658c4c3c67..b6f78cd8fa7 100644 --- a/tests/common/plugins/conditional_mark/tests_mark_conditions_vs_t1_multiasic.yaml +++ b/tests/common/plugins/conditional_mark/tests_mark_conditions_vs_t1_multiasic.yaml @@ -48,11 +48,6 @@ bgp/test_bgpmon.py: conditions: - asic_type in ['vs'] and 't1-8-lag' in topo_name reason: This test case either cannot pass or should be skipped on virtual chassis -bgp/test_frr_config_check.py: - skip: - conditions: - - asic_type in ['vs'] and 't1-8-lag' in topo_name - reason: This test case either cannot pass or should be skipped on virtual chassis bgp/test_traffic_shift.py: skip: conditions: