def __init__(self): self._api_common = Common() # Init cpld reg path self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE) self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE) # Set default value self._disable() self.armed = False self.timeout = self._gettimeout()
def __init__(self): ChassisBase.__init__(self) self.CHASSIS_CONFIG = 'chassis.json' self.THERMAL_CONFIG = 'thermal.json' self.SFP_CONFIG = 'sfp.json' self.PSU_CONFIG = 'psu.json' self.FAN_CONFIG = 'fan.json' self.COMPONENT_CONFIG = 'component.json' self.SFP_STATUS_INSERTED = "1" self.SFP_STATUS_REMOVED = "0" self.port_dict = {} self.enable_read = "i2cset -f -y 2 0x35 0x2a 0x01" self.disable_read = "i2cset -f -y 2 0x35 0x2a 0x00" self.enable_write = "i2cset -f -y 2 0x35 0x2b 0x00" self.disable_write = "i2cset -f -y 2 0x35 0x2b 0x01" self.enable_erase = "i2cset -f -y 2 0x35 0x2c 0x01" self.disable_erase = "i2cset -f -y 2 0x35 0x2c 0x00" self.read_value = "i2cget -f -y 2 0x35 0x25" self.write_value = "i2cset -f -y 2 0x35 0x21 0x0a" self.set_sys_led_cmd = "i2cset -f -y 2 0x33 0xb2 " self.get_sys_led_cmd = "i2cget -f -y 2 0x33 0xb2" self.led_status = "red" # Initialize SFP list # sfp.py will read eeprom contents and retrive the eeprom data. # It will also provide support sfp controls like reset and setting # low power mode. # We pass the eeprom path and sfp control path from chassis.py # So that sfp.py implementation can be generic to all platforms for index in range(PORT_START, PORTS_IN_BLOCK): sfp_node = Sfp(index) self._sfp_list.append(sfp_node) if sfp_node.get_presence(): self.port_dict[index] = self.SFP_STATUS_INSERTED else: self.port_dict[index] = self.SFP_STATUS_REMOVED self._api_common = Common() config_path = self._api_common.get_config_path(self.CHASSIS_CONFIG) self._config = self._api_common.load_json_file(config_path) self.__initialize_eeprom() if self._api_common.is_host(): self.__initialize_fan() self.__initialize_psu() self.__initialize_thermals() else: self.__initialize_components()
def __init__(self, sfp_list): self.num_sfp = len(sfp_list) self._api_common = Common() self._initialize_interrupts()
class SfpEvent: ''' Listen to insert/remove sfp events ''' PORT_INFO_DIR = 'SFF' PATH_INT_SYSFS = "{0}/{port_name}/{type_prefix}_isr_flags" PATH_INTMASK_SYSFS = "{0}/{port_name}/{type_prefix}_isr_mask" PATH_PRS_SYSFS = "{0}/{port_name}/{prs_file_name}" PRESENT_EN = 0x01 def __init__(self, sfp_list): self.num_sfp = len(sfp_list) self._api_common = Common() self._initialize_interrupts() def _initialize_interrupts(self): sfp_info_obj = {} port_info_path = os.path.join(PLATFORM_PATH, SWITCH_BRD_PLATFORM, self.PORT_INFO_DIR) for index in range(self.num_sfp): port_num = index + 1 if port_num <= 32: port_name = "QSFP{}".format(port_num) port_type = "qsfp" sysfs_prs_file = "{}_modprs".format(port_type) else: port_name = "SFP{}".format(port_num - 32) port_type = "sfp" sysfs_prs_file = "{}_modabs".format(port_type) sfp_info_obj[index] = {} sfp_info_obj[index][ 'intmask_sysfs'] = self.PATH_INTMASK_SYSFS.format( port_info_path, port_name=port_name, type_prefix=port_type) sfp_info_obj[index]['int_sysfs'] = self.PATH_INT_SYSFS.format( port_info_path, port_name=port_name, type_prefix=port_type) sfp_info_obj[index]['prs_sysfs'] = self.PATH_PRS_SYSFS.format( port_info_path, port_name=port_name, prs_file_name=sysfs_prs_file) self._api_common.write_txt_file( sfp_info_obj[index]["intmask_sysfs"], hex(self.PRESENT_EN)) self.sfp_info_obj = sfp_info_obj def _is_port_device_present(self, port_idx): prs_path = self.sfp_info_obj[port_idx]["prs_sysfs"] is_present = 1 - int(self._api_common.read_txt_file(prs_path)) return is_present def _update_port_event_object(self, interrup_devices, port_dict): for port_idx in interrup_devices: device_id = str(port_idx + 1) port_dict[device_id] = str(self._is_port_device_present(port_idx)) return port_dict def _clear_event_flag(self, path): self._api_common.write_txt_file(path, hex(0xff)) time.sleep(0.1) self._api_common.write_txt_file(path, hex(0x0)) def _check_all_port_interrupt_event(self): interrupt_devices = {} for i in range(self.num_sfp): int_sysfs = self.sfp_info_obj[i]["int_sysfs"] interrupt_flags = self._api_common.read_txt_file(int_sysfs) if interrupt_flags != '0x00': interrupt_devices[i] = 1 self._clear_event_flag(int_sysfs) return interrupt_devices def get_event(self, timeout): sleep_time = min(timeout, POLL_INTERVAL) if timeout != 0 else POLL_INTERVAL start_milli_time = int(round(time.time() * 1000)) int_sfp = {} while True: chk_sfp = self._check_all_port_interrupt_event() int_sfp = self._update_port_event_object( chk_sfp, int_sfp) if chk_sfp else int_sfp current_milli_time = int(round(time.time() * 1000)) if (int_sfp) or \ (timeout != 0 and current_milli_time - start_milli_time > timeout): break time.sleep(sleep_time) change_dict = dict() change_dict['sfp'] = int_sfp return True, change_dict
class Watchdog(WatchdogBase): def __init__(self): WatchdogBase.__init__(self) self._api_common = Common() # Init cpld reg path self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE) self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE) # Set default value self._disable() self.armed = False self.timeout = self._gettimeout() def _enable(self): """ Turn on the watchdog timer """ # echo 0xA181 0x1 > /sys/devices/platform/baseboard/setreg enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD) return self._api_common.write_txt_file(self.setreg_path, enable_val) def _disable(self): """ Turn off the watchdog timer """ # echo 0xA181 0x0 > /sys/devices/platform/baseboard/setreg disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD) return self._api_common.write_txt_file(self.setreg_path, disable_val) def _keepalive(self): """ Keep alive watchdog timer """ # echo 0xA185 0x1 > /sys/devices/platform/baseboard/setreg enable_val = '{} {}'.format(WDT_KEEP_ALVIVE_REG, ENABLE_CMD) return self._api_common.write_txt_file(self.setreg_path, enable_val) def _get_level_hex(self, sub_hex): sub_hex_str = sub_hex.replace("x", "0") return hex(int(sub_hex_str, 16)) def _seconds_to_lmh_hex(self, seconds): ms = seconds * 1000 # calculate timeout in ms format hex_str = hex(ms) l = self._get_level_hex(hex_str[-2:]) m = self._get_level_hex(hex_str[-4:-2]) h = self._get_level_hex(hex_str[-6:-4]) return (l, m, h) def _settimeout(self, seconds): """ Set watchdog timer timeout @param seconds - timeout in seconds @return is the actual set timeout """ # max = 0xffffff = 16777.215 seconds (l, m, h) = self._seconds_to_lmh_hex(seconds) set_h_val = '{} {}'.format(WDT_TIMER_H_BIT_REG, h) set_m_val = '{} {}'.format(WDT_TIMER_M_BIT_REG, m) set_l_val = '{} {}'.format(WDT_TIMER_L_BIT_REG, l) self._api_common.write_txt_file(self.setreg_path, set_h_val) # set high bit self._api_common.write_txt_file(self.setreg_path, set_m_val) # set med bit self._api_common.write_txt_file(self.setreg_path, set_l_val) # set low bit return seconds def _gettimeout(self): """ Get watchdog timeout @return watchdog timeout """ h_bit = self._api_common.get_reg(self.getreg_path, WDT_TIMER_H_BIT_REG) m_bit = self._api_common.get_reg(self.getreg_path, WDT_TIMER_M_BIT_REG) l_bit = self._api_common.get_reg(self.getreg_path, WDT_TIMER_L_BIT_REG) hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:]) ms = int(hex_time, 16) return int(float(ms) / 1000) ################################################################# def arm(self, seconds): """ Arm the hardware watchdog with a timeout of <seconds> seconds. If the watchdog is currently armed, calling this function will simply reset the timer to the provided value. If the underlying hardware does not support the value provided in <seconds>, this method should arm the watchdog with the *next greater* available value. Returns: An integer specifying the *actual* number of seconds the watchdog was armed with. On failure returns -1. """ ret = WDT_COMMON_ERROR if seconds < 0: return ret try: if self.timeout != seconds: self.timeout = self._settimeout(seconds) if self.armed: self._keepalive() else: self._enable() self.armed = True ret = self.timeout self.arm_timestamp = time.time() except IOError as e: pass return ret def disarm(self): """ Disarm the hardware watchdog Returns: A boolean, True if watchdog is disarmed successfully, False if not """ disarmed = False if self.is_armed(): try: self._disable() self.armed = False disarmed = True except IOError: pass return disarmed def is_armed(self): """ Retrieves the armed state of the hardware watchdog. Returns: A boolean, True if watchdog is armed, False if not """ return self.armed def get_remaining_time(self): """ If the watchdog is armed, retrieve the number of seconds remaining on the watchdog timer Returns: An integer specifying the number of seconds remaining on thei watchdog timer. If the watchdog is not armed, returns -1. """ return int(self.timeout - (time.time() - self.arm_timestamp)) if self.armed else WDT_COMMON_ERROR
class Chassis(ChassisBase): """ Ruijie B6510-48VS8CQ Platform-specific Chassis class """ def __init__(self): ChassisBase.__init__(self) self.CHASSIS_CONFIG = 'chassis.json' self.THERMAL_CONFIG = 'thermal.json' self.SFP_CONFIG = 'sfp.json' self.PSU_CONFIG = 'psu.json' self.FAN_CONFIG = 'fan.json' self.COMPONENT_CONFIG = 'component.json' self.SFP_STATUS_INSERTED = "1" self.SFP_STATUS_REMOVED = "0" self.port_dict = {} self.enable_read = "i2cset -f -y 2 0x35 0x2a 0x01" self.disable_read = "i2cset -f -y 2 0x35 0x2a 0x00" self.enable_write = "i2cset -f -y 2 0x35 0x2b 0x00" self.disable_write = "i2cset -f -y 2 0x35 0x2b 0x01" self.enable_erase = "i2cset -f -y 2 0x35 0x2c 0x01" self.disable_erase = "i2cset -f -y 2 0x35 0x2c 0x00" self.read_value = "i2cget -f -y 2 0x35 0x25" self.write_value = "i2cset -f -y 2 0x35 0x21 0x0a" self.set_sys_led_cmd = "i2cset -f -y 2 0x33 0xb2 " self.get_sys_led_cmd = "i2cget -f -y 2 0x33 0xb2" self.led_status = "red" # Initialize SFP list # sfp.py will read eeprom contents and retrive the eeprom data. # It will also provide support sfp controls like reset and setting # low power mode. # We pass the eeprom path and sfp control path from chassis.py # So that sfp.py implementation can be generic to all platforms for index in range(PORT_START, PORTS_IN_BLOCK): sfp_node = Sfp(index) self._sfp_list.append(sfp_node) if sfp_node.get_presence(): self.port_dict[index] = self.SFP_STATUS_INSERTED else: self.port_dict[index] = self.SFP_STATUS_REMOVED self._api_common = Common() config_path = self._api_common.get_config_path(self.CHASSIS_CONFIG) self._config = self._api_common.load_json_file(config_path) self.__initialize_eeprom() if self._api_common.is_host(): self.__initialize_fan() self.__initialize_psu() self.__initialize_thermals() else: self.__initialize_components() def __initialize_fan(self): from sonic_platform.fan import Fan from sonic_platform.fan_drawer import FanDrawer fan_config_path = self._api_common.get_config_path(self.FAN_CONFIG) self.fan_config = self._api_common.load_json_file( fan_config_path)["fans"] if self.fan_config: drawer_fan_list = [] for index in range(0, len(self.fan_config)): fan = Fan(index, config=self.fan_config[index]) self._fan_list.append(fan) drawer_fan_list.append(fan) fan_drawer = FanDrawer(0, fan_list=drawer_fan_list) self._fan_drawer_list.append(fan_drawer) def __initialize_psu(self): from sonic_platform.psu import Psu psu_config_path = self._api_common.get_config_path(self.PSU_CONFIG) self.psu_config = self._api_common.load_json_file( psu_config_path)["psus"] if self.psu_config: for index in range(0, len(self.psu_config)): psu = Psu(index, config=self.psu_config[index]) self._psu_list.append(psu) def __initialize_thermals(self): from sonic_platform.thermal import Thermal thermal_config_path = self._api_common.get_config_path( self.THERMAL_CONFIG) self.thermal_config = self._api_common.load_json_file( thermal_config_path)['thermals'] if self.thermal_config: for index in range(0, len(self.thermal_config)): thermal = Thermal(index, config=self.thermal_config[index]) self._thermal_list.append(thermal) def __initialize_eeprom(self): from sonic_platform.eeprom import Eeprom self._eeprom = Eeprom(config=self._config["eeprom"]) def __initialize_components(self): from sonic_platform.component import Component component_config_path = self._api_common.get_config_path( self.COMPONENT_CONFIG) self.component_config = self._api_common.load_json_file( component_config_path)['components'] if self.component_config: for index in range(0, len(self.component_config)): component = Component(index, config=self.component_config[index]) self._component_list.append(component) def _init_standard_config(self, conflist, class_name, objlist): for conf in conflist: obj = globals()[class_name](conf.get("name"), config=conf) objlist.append(obj) def _init_by_hal(self, hal_interface): self.hal_interface = hal_interface self.hal_interface.get_fans() def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self._eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the chassis Returns: bool: True if chassis is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self._eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self._eeprom.serial_str() def get_status(self): """ Retrieves the operational status of the chassis Returns: bool: A boolean value, True if chassis is operating properly False if not """ return True def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.base_mac_addr() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.system_eeprom_info() def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ try: is_power_loss = False # enable read subprocess.getstatusoutput(self.disable_write) subprocess.getstatusoutput(self.enable_read) ret, log = subprocess.getstatusoutput(self.read_value) if ret == 0 and "0x0a" in log: is_power_loss = True # erase i2c and e2 subprocess.getstatusoutput(self.enable_erase) time.sleep(1) subprocess.getstatusoutput(self.disable_erase) # clear data subprocess.getstatusoutput(self.enable_write) subprocess.getstatusoutput(self.disable_read) subprocess.getstatusoutput(self.disable_write) subprocess.getstatusoutput(self.enable_read) # enable write and set data subprocess.getstatusoutput(self.enable_write) subprocess.getstatusoutput(self.disable_read) subprocess.getstatusoutput(self.write_value) if is_power_loss: return (self.REBOOT_CAUSE_POWER_LOSS, None) except Exception as e: logger.error(str(e)) return (self.REBOOT_CAUSE_NON_HARDWARE, None) def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level Args: timeout: Timeout in milliseconds (optional). If timeout == 0, this method will block until a change is detected. Returns: (bool, dict): - True if call successful, False if not; - A nested dictionary where key is a device type, value is a dictionary with key:value pairs in the format of {'device_id':'device_event'}, where device_id is the device ID for this device and device_event, status='1' represents device inserted, status='0' represents device removed. Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} indicates that fan 0 has been removed, fan 2 has been inserted and sfp 11 has been removed. Specifically for SFP event, besides SFP plug in and plug out, there are some other error event could be raised from SFP, when these error happened, SFP eeprom will not be avalaible, XCVRD shall stop to read eeprom before SFP recovered from error status. status='2' I2C bus stuck, status='3' Bad eeprom, status='4' Unsupported cable, status='5' High Temperature, status='6' Bad cable. """ change_event_dict = {"fan": {}, "sfp": {}} sfp_status, sfp_change_dict = self.get_transceiver_change_event( timeout) change_event_dict["sfp"] = sfp_change_dict if sfp_status is True: return True, change_event_dict return False, {} def get_transceiver_change_event(self, timeout=0): start_time = time.time() currernt_port_dict = {} forever = False if timeout == 0: forever = True elif timeout > 0: timeout = timeout / float(1000) # Convert to secs else: print("get_transceiver_change_event:Invalid timeout value", timeout) return False, {} end_time = start_time + timeout if start_time > end_time: print( "get_transceiver_change_event:" "time wrap / invalid timeout value", timeout, ) return False, {} # Time wrap or possibly incorrect timeout while timeout >= 0: # Check for OIR events and return updated port_dict for index in range(PORT_START, PORTS_IN_BLOCK): if self._sfp_list[index].get_presence(): currernt_port_dict[index] = self.SFP_STATUS_INSERTED else: currernt_port_dict[index] = self.SFP_STATUS_REMOVED if currernt_port_dict == self.port_dict: if forever: time.sleep(1) else: timeout = end_time - time.time() if timeout >= 1: time.sleep(1) # We poll at 1 second granularity else: if timeout > 0: time.sleep(timeout) return True, {} else: # Update reg value self.port_dict = currernt_port_dict print(self.port_dict) return True, self.port_dict print("get_transceiver_change_event: Should not reach here.") return False, {} def get_all_components(self): return self._component_list def get_all_fans(self): return self._fan_list def get_all_psus(self): return self._psu_list def get_all_thermals(self): return self._thermal_list def get_supervisor_slot(self): """ Retrieves the physical-slot of the supervisor-module in the modular chassis. On the supervisor or line-card modules, it will return the physical-slot of the supervisor-module. On the fixed-platforms, the API can be ignored. Users of the API can catch the exception and return a default ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. Returns: An integer, the vendor specific physical slot identifier of the supervisor module in the modular-chassis. """ return 0 def get_my_slot(self): """ Retrieves the physical-slot of this module in the modular chassis. On the supervisor, it will return the physical-slot of the supervisor module. On the linecard, it will return the physical-slot of the linecard module where this instance of SONiC is running. On the fixed-platforms, the API can be ignored. Users of the API can catch the exception and return a default ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. Returns: An integer, the vendor specific physical slot identifier of this module in the modular-chassis. """ return 0 def is_modular_chassis(self): """ Retrieves whether the sonic instance is part of modular chassis Returns: A bool value, should return False by default or for fixed-platforms. Should return True for supervisor-cards, line-cards etc running as part of modular-chassis. """ return True def init_midplane_switch(self): """ Initializes the midplane functionality of the modular chassis. For example, any validation of midplane, populating any lookup tables etc can be done here. The expectation is that the required kernel modules, ip-address assignment etc are done before the pmon, database dockers are up. Returns: A bool value, should return True if the midplane initialized successfully. """ return True def get_module_index(self, module_name): """ Retrieves module index from the module name Args: module_name: A string, prefixed by SUPERVISOR, LINE-CARD or FABRIC-CARD Ex. SUPERVISOR0, LINE-CARD1, FABRIC-CARD5 Returns: An integer, the index of the ModuleBase object in the module_list """ return 0 def set_status_led(self, color): """ Sets the state of the system LED Args: color: A string representing the color with which to set the system LED Returns: bool: True if system LED state is set successfully, False if not """ colors = {"amber": "0x00", "red": "0x02", "green": "0x04"} regval = colors.get(color, None) if regval is None: print("Invaild color input.") return False ret, log = subprocess.getstatusoutput(self.set_sys_led_cmd + regval) if ret != 0: print("Cannot execute %s" % self.set_sys_led_cmd + regval) return False self.led_status = color return True def get_status_led(self): """ Gets the state of the system LED Returns: A string, one of the valid LED color strings which could be vendor specified. """ ret, log = subprocess.getstatusoutput(self.get_sys_led_cmd) if ret != 0: print("Cannot execute %s" % self.get_sys_led_cmd) return False colors = {"0x00": "amber", "0x02": "red", "0x04": "green"} color = colors.get(log, None) if color is None: return "Unknown color status" self.led_status = color return self.led_status