diff --git a/config/muxcable.py b/config/muxcable.py index a009c6fe4f..d7d672a930 100644 --- a/config/muxcable.py +++ b/config/muxcable.py @@ -277,14 +277,52 @@ def lookup_statedb_and_update_configdb(db, per_npu_statedb, config_db, port, sta port_status_dict[port_name] = 'OK' def update_configdb_pck_loss_data(config_db, port, val): + fvs = {} configdb_state = get_value_for_key_in_config_tbl(config_db, port, "state", "MUX_CABLE") + fvs["state"] = configdb_state ipv4_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv4", "MUX_CABLE") + fvs["server_ipv4"] = ipv4_value ipv6_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv6", "MUX_CABLE") + fvs["server_ipv6"] = ipv6_value + soc_ipv4_value = get_optional_value_for_key_in_config_tbl(config_db, port, "soc_ipv4", "MUX_CABLE") + if soc_ipv4_value is not None: + fvs["soc_ipv4"] = soc_ipv4_value + cable_type = get_optional_value_for_key_in_config_tbl(config_db, port, "cable_type", "MUX_CABLE") + if cable_type is not None: + fvs["cable_type"] = cable_type + prober_type_val = get_optional_value_for_key_in_config_tbl(config_db, port, "prober_type", "MUX_CABLE") + if prober_type_val is not None: + fvs["prober_type"] = prober_type_val + fvs["pck_loss_data_reset"] = val try: - config_db.set_entry("MUX_CABLE", port, {"state": configdb_state, - "server_ipv4": ipv4_value, "server_ipv6": ipv6_value, - "pck_loss_data_reset": val}) + config_db.set_entry("MUX_CABLE", port, fvs) + except ValueError as e: + ctx = click.get_current_context() + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + +def update_configdb_prober_type(config_db, port, val): + fvs = {} + configdb_state = get_value_for_key_in_config_tbl(config_db, port, "state", "MUX_CABLE") + fvs["state"] = configdb_state + ipv4_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv4", "MUX_CABLE") + fvs["server_ipv4"] = ipv4_value + ipv6_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv6", "MUX_CABLE") + fvs["server_ipv6"] = ipv6_value + soc_ipv4_value = get_optional_value_for_key_in_config_tbl(config_db, port, "soc_ipv4", "MUX_CABLE") + if soc_ipv4_value is not None: + fvs["soc_ipv4"] = soc_ipv4_value + cable_type = get_optional_value_for_key_in_config_tbl(config_db, port, "cable_type", "MUX_CABLE") + if cable_type is not None: + fvs["cable_type"] = cable_type + pck_loss_data = get_optional_value_for_key_in_config_tbl(config_db, port, "pck_loss_data_reset", "MUX_CABLE") + if pck_loss_data is not None: + fvs["pck_loss_data_reset"] = pck_loss_data + + fvs["prober_type"] = val + try: + config_db.set_entry("MUX_CABLE", port, fvs) except ValueError as e: ctx = click.get_current_context() ctx.fail("Invalid ConfigDB. Error: {}".format(e)) @@ -381,6 +419,73 @@ def mode(db, state, port, json_output): sys.exit(CONFIG_SUCCESSFUL) +# 'muxcable' command ("config muxcable probertype hardware/software ") +@muxcable.command() +@click.argument('probertype', metavar='', required=True, type=click.Choice(["hardware", "software"])) +@click.argument('port', metavar='', required=True, default=None) +@clicommon.pass_db +def probertype(db, probertype, port): + """Config muxcable probertype""" + + port = platform_sfputil_helper.get_interface_name(port, db) + + port_table_keys = {} + y_cable_asic_table_keys = {} + per_npu_configdb = {} + per_npu_statedb = {} + + # Getting all front asic namespace and correspding config and state DB connector + + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + # replace these with correct macros + per_npu_configdb[asic_id] = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + per_npu_configdb[asic_id].connect() + per_npu_statedb[asic_id] = SonicV2Connector(use_unix_socket_path=True, namespace=namespace) + per_npu_statedb[asic_id].connect(per_npu_statedb[asic_id].STATE_DB) + + port_table_keys[asic_id] = per_npu_statedb[asic_id].keys( + per_npu_statedb[asic_id].STATE_DB, 'MUX_CABLE_TABLE|*') + + if port is not None and port != "all": + + asic_index = None + if platform_sfputil is not None: + asic_index = platform_sfputil.get_asic_id_for_logical_port(port) + if asic_index is None: + # TODO this import is only for unit test purposes, and should be removed once sonic_platform_base + # is fully mocked + import sonic_platform_base.sonic_sfp.sfputilhelper + asic_index = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper().get_asic_id_for_logical_port(port) + if asic_index is None: + click.echo("Got invalid asic index for port {}, cant retreive mux status".format(port)) + sys.exit(CONFIG_FAIL) + + if per_npu_statedb[asic_index] is not None: + y_cable_asic_table_keys = port_table_keys[asic_index] + logical_key = "MUX_CABLE_TABLE|{}".format(port) + if logical_key in y_cable_asic_table_keys: + update_configdb_prober_type(per_npu_configdb[asic_index], port, probertype) + sys.exit(CONFIG_SUCCESSFUL) + else: + click.echo("this is not a valid port {} present on mux_cable".format(port)) + sys.exit(CONFIG_FAIL) + else: + click.echo("there is not a valid asic asic-{} table for this asic_index".format(asic_index)) + sys.exit(CONFIG_FAIL) + + elif port == "all" and port is not None: + + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + for key in port_table_keys[asic_id]: + logical_port = key.split("|")[1] + update_configdb_prober_type(per_npu_configdb[asic_id], logical_port, probertype) + + sys.exit(CONFIG_SUCCESSFUL) + + # 'muxcable' command ("config muxcable kill-radv ") @muxcable.command(short_help="Kill radv service when it is meant to be stopped, so no good-bye packet is sent for ceasing To Be an Advertising Interface") @click.argument('knob', metavar='', required=True, type=click.Choice(["enable", "disable"])) @@ -396,8 +501,7 @@ def kill_radv(db, knob): mux_lmgrd_cfg_tbl = config_db.get_table("MUX_LINKMGR") config_db.mod_entry("MUX_LINKMGR", "SERVICE_MGMT", {"kill_radv": "True" if knob == "enable" else "False"}) - - #'muxcable' command ("config muxcable packetloss reset ") +# 'muxcable' command ("config muxcable packetloss reset ") @muxcable.command() @click.argument('action', metavar='', required=True, type=click.Choice(["reset"])) @click.argument('port', metavar='', required=True, default=None) diff --git a/show/muxcable.py b/show/muxcable.py index cf8403dfce..964d729ca4 100644 --- a/show/muxcable.py +++ b/show/muxcable.py @@ -550,7 +550,7 @@ def create_table_dump_per_port_status(db, print_data, muxcable_info_dict, muxcab print_data.append(print_port_data) -def create_table_dump_per_port_config(db ,print_data, per_npu_configdb, asic_id, port, is_dualtor_active_active): +def create_table_dump_per_port_config(db, print_data, per_npu_configdb, asic_id, port): port_list = [] port_name = platform_sfputil_helper.get_interface_alias(port, db) @@ -564,17 +564,25 @@ def create_table_dump_per_port_config(db ,print_data, per_npu_configdb, asic_id, cable_type = get_optional_value_for_key_in_config_tbl(per_npu_configdb[asic_id], port, "cable_type", "MUX_CABLE") if cable_type is not None: port_list.append(cable_type) + else: + port_list.append("") soc_ipv4_value = get_optional_value_for_key_in_config_tbl(per_npu_configdb[asic_id], port, "soc_ipv4", "MUX_CABLE") if soc_ipv4_value is not None: port_list.append(soc_ipv4_value) - is_dualtor_active_active[0] = True + else: + port_list.append("") soc_ipv6_value = get_optional_value_for_key_in_config_tbl(per_npu_configdb[asic_id], port, "soc_ipv6", "MUX_CABLE") if soc_ipv6_value is not None: - if cable_type is None: - port_list.append("") - if soc_ipv4_value is None: - port_list.append("") port_list.append(soc_ipv6_value) + else: + port_list.append("") + prober_type_value = get_optional_value_for_key_in_config_tbl(per_npu_configdb[asic_id], + port, "prober_type", "MUX_CABLE") + if prober_type_value is not None: + port_list.append(prober_type_value) + else: + port_list.append("software") + print_data.append(port_list) @@ -597,6 +605,11 @@ def create_json_dump_per_port_config(db, port_status_dict, per_npu_configdb, asi soc_ipv6_value = get_optional_value_for_key_in_config_tbl(per_npu_configdb[asic_id], port, "soc_ipv6", "MUX_CABLE") if soc_ipv6_value is not None: port_status_dict["MUX_CABLE"]["PORTS"][port_name]["SERVER"]["soc_ipv6"] = soc_ipv6_value + prober_type_value = get_optional_value_for_key_in_config_tbl(per_npu_configdb[asic_id], + port, "prober_type", "MUX_CABLE") + if prober_type_value is not None: + port_status_dict["MUX_CABLE"]["PORTS"][port_name]["SERVER"]["prober_type"] = prober_type_value + def get_tunnel_route_per_port(db, port_tunnel_route, per_npu_configdb, per_npu_appl_db, per_npu_asic_db, asic_id, port): @@ -861,10 +874,8 @@ def config(db, port, json_output): else: print_data = [] print_peer_tor = [] - is_dualtor_active_active = [False] - - create_table_dump_per_port_config(db, print_data, per_npu_configdb, asic_id, port, is_dualtor_active_active) + create_table_dump_per_port_config(db, print_data, per_npu_configdb, asic_id, port) headers = ['SWITCH_NAME', 'PEER_TOR'] peer_tor_data = [] @@ -872,10 +883,7 @@ def config(db, port, json_output): peer_tor_data.append(peer_switch_value) print_peer_tor.append(peer_tor_data) click.echo(tabulate(print_peer_tor, headers=headers)) - if is_dualtor_active_active[0]: - headers = ['port', 'state', 'ipv4', 'ipv6', 'cable_type', 'soc_ipv4', 'soc_ipv6'] - else: - headers = ['port', 'state', 'ipv4', 'ipv6'] + headers = ['port', 'state', 'ipv4', 'ipv6', 'cable_type', 'soc_ipv4', 'soc_ipv6', 'prober_type'] click.echo(tabulate(print_data, headers=headers)) sys.exit(CONFIG_SUCCESSFUL) @@ -911,12 +919,11 @@ def config(db, port, json_output): else: print_data = [] print_peer_tor = [] - is_dualtor_active_active = [False] for namespace in namespaces: asic_id = multi_asic.get_asic_index_from_namespace(namespace) for port in natsorted(port_mux_tbl_keys[asic_id]): - create_table_dump_per_port_config(db, print_data, per_npu_configdb, asic_id, port, is_dualtor_active_active) + create_table_dump_per_port_config(db, print_data, per_npu_configdb, asic_id, port) headers = ['SWITCH_NAME', 'PEER_TOR'] peer_tor_data = [] @@ -924,10 +931,7 @@ def config(db, port, json_output): peer_tor_data.append(peer_switch_value) print_peer_tor.append(peer_tor_data) click.echo(tabulate(print_peer_tor, headers=headers)) - if is_dualtor_active_active[0]: - headers = ['port', 'state', 'ipv4', 'ipv6', 'cable_type', 'soc_ipv4', 'soc_ipv6'] - else: - headers = ['port', 'state', 'ipv4', 'ipv6'] + headers = ['port', 'state', 'ipv4', 'ipv6', 'cable_type', 'soc_ipv4', 'soc_ipv6', 'prober_type'] click.echo(tabulate(print_data, headers=headers)) sys.exit(CONFIG_SUCCESSFUL) diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index 9716ed434d..d1f1c46f3d 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -1942,12 +1942,14 @@ }, "MUX_CABLE|Ethernet4": { "state": "auto", + "prober_type": "software", "server_ipv4": "10.3.1.1", "server_ipv6": "e801::46", "soc_ipv6": "e801::47" }, "MUX_CABLE|Ethernet8": { "state": "active", + "prober_type": "hardware", "server_ipv4": "10.4.1.1", "server_ipv6": "e802::46" }, diff --git a/tests/muxcable_test.py b/tests/muxcable_test.py index 13eefef960..d78a429495 100644 --- a/tests/muxcable_test.py +++ b/tests/muxcable_test.py @@ -143,30 +143,30 @@ SWITCH_NAME PEER_TOR ------------- ---------- sonic-switch 10.2.2.2 -port state ipv4 ipv6 cable_type soc_ipv4 soc_ipv6 ----------- ------- -------- -------- -------------- ---------- ---------- -Ethernet0 active 10.2.1.1 e800::46 -Ethernet4 auto 10.3.1.1 e801::46 e801::47 -Ethernet8 active 10.4.1.1 e802::46 -Ethernet12 active 10.4.1.1 e802::46 -Ethernet16 standby 10.1.1.1 fc00::75 active-standby -Ethernet28 manual 10.1.1.1 fc00::75 -Ethernet32 auto 10.1.1.1 fc00::75 active-active 10.1.1.2 fc00::76 +port state ipv4 ipv6 cable_type soc_ipv4 soc_ipv6 prober_type +---------- ------- -------- -------- -------------- ---------- ---------- ------------- +Ethernet0 active 10.2.1.1 e800::46 software +Ethernet4 auto 10.3.1.1 e801::46 e801::47 software +Ethernet8 active 10.4.1.1 e802::46 hardware +Ethernet12 active 10.4.1.1 e802::46 software +Ethernet16 standby 10.1.1.1 fc00::75 active-standby software +Ethernet28 manual 10.1.1.1 fc00::75 software +Ethernet32 auto 10.1.1.1 fc00::75 active-active 10.1.1.2 fc00::76 software """ tabular_data_config_output_expected_alias = """\ SWITCH_NAME PEER_TOR ------------- ---------- sonic-switch 10.2.2.2 -port state ipv4 ipv6 cable_type soc_ipv4 soc_ipv6 ------- ------- -------- -------- -------------- ---------- ---------- -etp1 active 10.2.1.1 e800::46 -etp2 auto 10.3.1.1 e801::46 e801::47 -etp3 active 10.4.1.1 e802::46 -etp4 active 10.4.1.1 e802::46 -etp5 standby 10.1.1.1 fc00::75 active-standby -etp8 manual 10.1.1.1 fc00::75 -etp9 auto 10.1.1.1 fc00::75 active-active 10.1.1.2 fc00::76 +port state ipv4 ipv6 cable_type soc_ipv4 soc_ipv6 prober_type +------ ------- -------- -------- -------------- ---------- ---------- ------------- +etp1 active 10.2.1.1 e800::46 software +etp2 auto 10.3.1.1 e801::46 e801::47 software +etp3 active 10.4.1.1 e802::46 hardware +etp4 active 10.4.1.1 e802::46 software +etp5 standby 10.1.1.1 fc00::75 active-standby software +etp8 manual 10.1.1.1 fc00::75 software +etp9 auto 10.1.1.1 fc00::75 active-active 10.1.1.2 fc00::76 software """ json_data_status_config_output_expected = """\ @@ -186,14 +186,16 @@ "SERVER": { "IPv4": "10.3.1.1", "IPv6": "e801::46", - "soc_ipv6": "e801::47" + "soc_ipv6": "e801::47", + "prober_type": "software" } }, "Ethernet8": { "STATE": "active", "SERVER": { "IPv4": "10.4.1.1", - "IPv6": "e802::46" + "IPv6": "e802::46", + "prober_type": "hardware" } }, "Ethernet12": { @@ -250,14 +252,16 @@ "SERVER": { "IPv4": "10.3.1.1", "IPv6": "e801::46", - "soc_ipv6": "e801::47" + "soc_ipv6": "e801::47", + "prober_type": "software" } }, "etp3": { "STATE": "active", "SERVER": { "IPv4": "10.4.1.1", - "IPv6": "e802::46" + "IPv6": "e802::46", + "prober_type": "hardware" } }, "etp4": { @@ -722,7 +726,6 @@ def test_muxcable_status_config(self): db = Db() result = runner.invoke(show.cli.commands["muxcable"].commands["config"], obj=db) - assert result.exit_code == 0 assert result.output == tabular_data_config_output_expected @@ -1049,6 +1052,51 @@ def test_config_muxcable_tabular_port_with_incorrect_port(self): assert result.exit_code == 1 + def test_config_muxcable_probertype_hardware_Ethernet0(self): + runner = CliRunner() + db = Db() + + with mock.patch('sonic_platform_base.sonic_sfp.sfputilhelper') as patched_util: + patched_util.SfpUtilHelper.return_value.get_asic_id_for_logical_port.return_value = 0 + result = runner.invoke(config.config.commands["muxcable"].commands["probertype"], [ + "hardware", "Ethernet0"], obj=db) + + assert result.exit_code == 0 + + def test_config_muxcable_probertype_hardware_all(self): + runner = CliRunner() + db = Db() + + with mock.patch('sonic_platform_base.sonic_sfp.sfputilhelper') as patched_util: + patched_util.SfpUtilHelper.return_value.get_asic_id_for_logical_port.return_value = 0 + result = runner.invoke(config.config.commands["muxcable"].commands["probertype"], [ + "hardware", "all"], obj=db) + + assert result.exit_code == 0 + + def test_config_muxcable_probertype_hardware_incorrect_index(self): + runner = CliRunner() + db = Db() + + with mock.patch('sonic_platform_base.sonic_sfp.sfputilhelper') as patched_util: + patched_util.SfpUtilHelper.return_value.get_asic_id_for_logical_port.return_value = 2 + result = runner.invoke(config.config.commands["muxcable"].commands["probertype"], [ + "hardware", "Ethernet0"], obj=db) + + assert result.exit_code == 1 + + def test_config_muxcable_probertype_hardware_incorrect_port(self): + runner = CliRunner() + db = Db() + + with mock.patch('sonic_platform_base.sonic_sfp.sfputilhelper') as patched_util: + patched_util.SfpUtilHelper.return_value.get_asic_id_for_logical_port.return_value = 0 + result = runner.invoke(config.config.commands["muxcable"].commands["probertype"], [ + "hardware", "Ethernet33"], obj=db) + + assert result.exit_code == 1 + + def test_config_muxcable_packetloss_reset_Ethernet0(self): runner = CliRunner() db = Db()