Skip to content

Commit 0ce6a25

Browse files
authored
[show][config] cli support for firmware upgrade on Y-Cable (sonic-net#1528)
Summary: This PR provides the support for adding CLI commands for activatie, download, upgrade firmware on the Y-cable In particular these Cli commands are supported: sudo config muxcable firmware download Ethernet0 sudo config muxcable firmware rollback Ethernet0 sudo config muxcable firmware download ~/AEC_WYOMING_B52Yb0_MS_0.6_20201218.bin Ethernet0 Signed-off-by: vaibhav-dahiya [email protected] What I did Added the support for firmware upgrade CLI on Y cable How I did it added the changes in sonic-utilities/show and sonic-utilities/config by changing the muxcable.py Signed-off-by: vaibhav-dahiya <[email protected]>
1 parent 9bbc25f commit 0ce6a25

File tree

3 files changed

+420
-0
lines changed

3 files changed

+420
-0
lines changed

config/muxcable.py

+231
Original file line numberDiff line numberDiff line change
@@ -631,3 +631,234 @@ def setswitchmode(state, port):
631631
if rc == False:
632632
click.echo("ERR: Unable to set switching mode one or more ports to {}".format(state))
633633
sys.exit(CONFIG_FAIL)
634+
635+
636+
def get_per_npu_statedb(per_npu_statedb, port_table_keys):
637+
638+
# Getting all front asic namespace and correspding config and state DB connector
639+
640+
namespaces = multi_asic.get_front_end_namespaces()
641+
for namespace in namespaces:
642+
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
643+
# replace these with correct macros
644+
per_npu_statedb[asic_id] = SonicV2Connector(use_unix_socket_path=True, namespace=namespace)
645+
per_npu_statedb[asic_id].connect(per_npu_statedb[asic_id].STATE_DB)
646+
647+
port_table_keys[asic_id] = per_npu_statedb[asic_id].keys(
648+
per_npu_statedb[asic_id].STATE_DB, 'MUX_CABLE_TABLE|*')
649+
650+
651+
def get_physical_port_list(port):
652+
653+
physical_port_list = []
654+
if platform_sfputil is not None:
655+
physical_port_list = platform_sfputil_helper.logical_port_name_to_physical_port_list(port)
656+
657+
asic_index = None
658+
if platform_sfputil is not None:
659+
asic_index = platform_sfputil_helper.get_asic_id_for_logical_port(port)
660+
if asic_index is None:
661+
# TODO this import is only for unit test purposes, and should be removed once sonic_platform_base
662+
# is fully mocked
663+
import sonic_platform_base.sonic_sfp.sfputilhelper
664+
asic_index = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper().get_asic_id_for_logical_port(port)
665+
if asic_index is None:
666+
click.echo("Got invalid asic index for port {}, cant retreive mux status".format(port))
667+
668+
if not isinstance(physical_port_list, list):
669+
click.echo(("ERR: Unable to locate physical port information for {}".format(port)))
670+
sys.exit(CONFIG_FAIL)
671+
672+
if len(physical_port_list) != 1:
673+
click.echo("ERR: Found multiple physical ports ({}) associated with {}".format(
674+
", ".join(physical_port_list), port))
675+
sys.exit(CONFIG_FAIL)
676+
677+
return (physical_port_list, asic_index)
678+
679+
680+
def perform_download_firmware(physical_port, fwfile, port):
681+
import sonic_y_cable.y_cable
682+
result = sonic_y_cable.y_cable.download_firmware(physical_port, fwfile)
683+
if result == sonic_y_cable.y_cable.FIRMWARE_DOWNLOAD_SUCCESS:
684+
click.echo("firmware download successful {}".format(port))
685+
return True
686+
else:
687+
click.echo("firmware download failure {}".format(port))
688+
return False
689+
690+
691+
def perform_activate_firmware(physical_port, port):
692+
import sonic_y_cable.y_cable
693+
result = sonic_y_cable.y_cable.activate_firmware(physical_port)
694+
if result == sonic_y_cable.y_cable.FIRMWARE_ACTIVATE_SUCCESS:
695+
click.echo("firmware activate successful for {}".format(port))
696+
return True
697+
else:
698+
click.echo("firmware activate failure for {}".format(port))
699+
return False
700+
701+
702+
def perform_rollback_firmware(physical_port, port):
703+
import sonic_y_cable.y_cable
704+
result = sonic_y_cable.y_cable.rollback_firmware(physical_port)
705+
if result == sonic_y_cable.y_cable.FIRMWARE_ROLLBACK_SUCCESS:
706+
click.echo("firmware rollback successful {}".format(port))
707+
return True
708+
else:
709+
click.echo("firmware rollback failure {}".format(port))
710+
return False
711+
712+
713+
@muxcable.group(cls=clicommon.AbbreviationGroup)
714+
def firmware():
715+
"""Configure muxcable firmware command"""
716+
pass
717+
718+
719+
@firmware.command()
720+
@click.argument('fwfile', metavar='<firmware_file>', required=True)
721+
@click.argument('port', metavar='<port_name>', required=True, default=None)
722+
def download(fwfile, port):
723+
"""Config muxcable firmware download"""
724+
725+
per_npu_statedb = {}
726+
y_cable_asic_table_keys = {}
727+
port_table_keys = {}
728+
729+
get_per_npu_statedb(per_npu_statedb, port_table_keys)
730+
731+
if port is not None and port != "all":
732+
733+
physical_port_list = []
734+
physical_port_list, asic_index = get_physical_port_list(port)
735+
physical_port = physical_port_list[0]
736+
if per_npu_statedb[asic_index] is not None:
737+
y_cable_asic_table_keys = port_table_keys[asic_index]
738+
logical_key = "MUX_CABLE_TABLE|{}".format(port)
739+
if logical_key in y_cable_asic_table_keys:
740+
perform_download_firmware(physical_port, fwfile, port)
741+
742+
else:
743+
click.echo("this is not a valid port present on mux_cable".format(port))
744+
sys.exit(CONFIG_FAIL)
745+
else:
746+
click.echo("there is not a valid asic table for this asic_index".format(asic_index))
747+
sys.exit(CONFIG_FAIL)
748+
749+
elif port == "all" and port is not None:
750+
751+
rc = CONFIG_SUCCESSFUL
752+
for namespace in namespaces:
753+
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
754+
for key in port_table_keys[asic_id]:
755+
port = key.split("|")[1]
756+
757+
physical_port_list = []
758+
(physical_port_list, asic_index) = get_physical_port_list(port)
759+
760+
physical_port = physical_port_list[0]
761+
762+
status = perform_download_firmware(physical_port, fwfile, port)
763+
764+
if status is not True:
765+
rc = CONFIG_FAIL
766+
767+
sys.exit(rc)
768+
769+
770+
@firmware.command()
771+
@click.argument('port', metavar='<port_name>', required=True, default=None)
772+
def activate(port):
773+
"""Config muxcable firmware activate"""
774+
775+
per_npu_statedb = {}
776+
y_cable_asic_table_keys = {}
777+
port_table_keys = {}
778+
779+
get_per_npu_statedb(per_npu_statedb, port_table_keys)
780+
781+
if port is not None and port != "all":
782+
783+
physical_port_list = []
784+
(physical_port_list, asic_index) = get_physical_port_list(port)
785+
physical_port = physical_port_list[0]
786+
if per_npu_statedb[asic_index] is not None:
787+
y_cable_asic_table_keys = port_table_keys[asic_index]
788+
logical_key = "MUX_CABLE_TABLE|{}".format(port)
789+
if logical_key in y_cable_asic_table_keys:
790+
perform_activate_firmware(physical_port, port)
791+
792+
else:
793+
click.echo("this is not a valid port present on mux_cable".format(port))
794+
sys.exit(CONFIG_FAIL)
795+
else:
796+
click.echo("there is not a valid asic table for this asic_index".format(asic_index))
797+
sys.exit(CONFIG_FAIL)
798+
799+
elif port == "all" and port is not None:
800+
801+
rc = CONFIG_SUCCESSFUL
802+
for namespace in namespaces:
803+
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
804+
for key in port_table_keys[asic_id]:
805+
port = key.split("|")[1]
806+
807+
physical_port_list = []
808+
809+
(physical_port_list, asic_index) = get_physical_port_list(port)
810+
physical_port = physical_port_list[0]
811+
status = perform_activate_firmware(physical_port, port)
812+
813+
if status is not True:
814+
rc = CONFIG_FAIL
815+
816+
sys.exit(rc)
817+
818+
819+
@firmware.command()
820+
@click.argument('port', metavar='<port_name>', required=True, default=None)
821+
def rollback(port):
822+
"""Config muxcable firmware rollback"""
823+
824+
port_table_keys = {}
825+
y_cable_asic_table_keys = {}
826+
per_npu_statedb = {}
827+
828+
get_per_npu_statedb(per_npu_statedb, port_table_keys)
829+
830+
if port is not None and port != "all":
831+
832+
physical_port_list = []
833+
(physical_port_list, asic_index) = get_physical_port_list(port)
834+
physical_port = physical_port_list[0]
835+
if per_npu_statedb[asic_index] is not None:
836+
y_cable_asic_table_keys = port_table_keys[asic_index]
837+
logical_key = "MUX_CABLE_TABLE|{}".format(port)
838+
if logical_key in y_cable_asic_table_keys:
839+
perform_rollback_firmware(physical_port, port)
840+
841+
else:
842+
click.echo("this is not a valid port present on mux_cable".format(port))
843+
sys.exit(CONFIG_FAIL)
844+
else:
845+
click.echo("there is not a valid asic table for this asic_index".format(asic_index))
846+
sys.exit(CONFIG_FAIL)
847+
848+
elif port == "all" and port is not None:
849+
850+
rc = CONFIG_SUCCESSFUL
851+
for namespace in namespaces:
852+
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
853+
for key in port_table_keys[asic_id]:
854+
port = key.split("|")[1]
855+
856+
physical_port_list = []
857+
(physical_port_list, asic_index) = get_physical_port_list(port)
858+
physical_port = physical_port_list[0]
859+
status = perform_rollback_firmware(physical_port, port)
860+
861+
if status is not True:
862+
rc = CONFIG_FAIL
863+
864+
sys.exit(rc)

show/muxcable.py

+105
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from natsort import natsorted
99
from sonic_py_common import multi_asic
1010
from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector
11+
from swsscommon import swsscommon
1112
from tabulate import tabulate
1213
from utilities_common import platform_sfputil_helper
1314

@@ -820,3 +821,107 @@ def switchmode(port):
820821
click.echo(tabulate(body, headers=headers))
821822
if rc == False:
822823
sys.exit(EXIT_FAIL)
824+
825+
826+
def get_firmware_dict(physical_port, target, side, mux_info_dict):
827+
828+
import sonic_y_cable.y_cable
829+
result = sonic_y_cable.y_cable.get_firmware_version(physical_port, target)
830+
831+
if result is not None and isinstance(result, dict):
832+
mux_info_dict[("version_{}_active".format(side))] = result.get("version_active", None)
833+
mux_info_dict[("version_{}_inactive".format(side))] = result.get("version_inactive", None)
834+
mux_info_dict[("version_{}_next".format(side))] = result.get("version_next", None)
835+
836+
else:
837+
mux_info_dict[("version_{}_active".format(side))] = "N/A"
838+
mux_info_dict[("version_{}_inactive".format(side))] = "N/A"
839+
mux_info_dict[("version_{}_next".format(side))] = "N/A"
840+
841+
842+
@muxcable.group(cls=clicommon.AbbreviationGroup)
843+
def firmware():
844+
"""Show muxcable firmware command"""
845+
pass
846+
847+
848+
@firmware.command()
849+
@click.argument('port', metavar='<port_name>', required=True, default=None)
850+
def version(port):
851+
"""Show muxcable firmware version"""
852+
853+
port_table_keys = {}
854+
y_cable_asic_table_keys = {}
855+
per_npu_statedb = {}
856+
physical_port_list = []
857+
858+
# Getting all front asic namespace and correspding config and state DB connector
859+
860+
namespaces = multi_asic.get_front_end_namespaces()
861+
for namespace in namespaces:
862+
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
863+
# replace these with correct macros
864+
per_npu_statedb[asic_id] = swsscommon.SonicV2Connector(use_unix_socket_path=True, namespace=namespace)
865+
per_npu_statedb[asic_id].connect(per_npu_statedb[asic_id].STATE_DB)
866+
867+
port_table_keys[asic_id] = per_npu_statedb[asic_id].keys(
868+
per_npu_statedb[asic_id].STATE_DB, 'MUX_CABLE_TABLE|*')
869+
870+
if port is not None:
871+
872+
logical_port_list = platform_sfputil_helper.get_logical_list()
873+
874+
if port not in logical_port_list:
875+
click.echo(("ERR: Not a valid logical port for muxcable firmware {}".format(port)))
876+
sys.exit(CONFIG_FAIL)
877+
878+
asic_index = None
879+
if platform_sfputil is not None:
880+
asic_index = platform_sfputil_helper.get_asic_id_for_logical_port(port)
881+
if asic_index is None:
882+
# TODO this import is only for unit test purposes, and should be removed once sonic_platform_base
883+
# is fully mocked
884+
import sonic_platform_base.sonic_sfp.sfputilhelper
885+
asic_index = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper().get_asic_id_for_logical_port(port)
886+
if asic_index is None:
887+
click.echo("Got invalid asic index for port {}, cant retreive mux status".format(port))
888+
889+
if platform_sfputil is not None:
890+
physical_port_list = platform_sfputil_helper.logical_port_name_to_physical_port_list(port)
891+
892+
if not isinstance(physical_port_list, list):
893+
click.echo(("ERR: Unable to locate physical port information for {}".format(port)))
894+
sys.exit(CONFIG_FAIL)
895+
896+
if len(physical_port_list) != 1:
897+
click.echo("ERR: Found multiple physical ports ({}) associated with {}".format(
898+
", ".join(physical_port_list), port))
899+
sys.exit(CONFIG_FAIL)
900+
901+
mux_info_dict = {}
902+
physical_port = physical_port_list[0]
903+
if per_npu_statedb[asic_index] is not None:
904+
y_cable_asic_table_keys = port_table_keys[asic_index]
905+
logical_key = "MUX_CABLE_TABLE|{}".format(port)
906+
import sonic_y_cable.y_cable
907+
read_side = sonic_y_cable.y_cable.check_read_side(physical_port)
908+
if logical_key in y_cable_asic_table_keys:
909+
if read_side == 1:
910+
get_firmware_dict(physical_port, 1, "self", mux_info_dict)
911+
get_firmware_dict(physical_port, 2, "peer", mux_info_dict)
912+
get_firmware_dict(physical_port, 0, "nic", mux_info_dict)
913+
click.echo("{}".format(json.dumps(mux_info_dict, indent=4)))
914+
elif read_side == 2:
915+
get_firmware_dict(physical_port, 2, "self", mux_info_dict)
916+
get_firmware_dict(physical_port, 1, "peer", mux_info_dict)
917+
get_firmware_dict(physical_port, 0, "nic", mux_info_dict)
918+
click.echo("{}".format(json.dumps(mux_info_dict, indent=4)))
919+
else:
920+
click.echo("Did not get a valid read_side for muxcable".format(port))
921+
sys.exit(CONFIG_FAIL)
922+
923+
else:
924+
click.echo("this is not a valid port present on mux_cable".format(port))
925+
sys.exit(CONFIG_FAIL)
926+
else:
927+
click.echo("there is not a valid asic table for this asic_index".format(asic_index))

0 commit comments

Comments
 (0)