[Mellanox] Implement new platform API for SONiC physical entity mib extension (#5645)

In order to support SONiC physical entity mib extension, a few new platform API are added to sonic-platform-common, this PR is to provide an mellanox platform implementation for those new APIs.
This commit is contained in:
Junchao-Mellanox 2020-11-17 10:56:03 +08:00 committed by GitHub
parent ced11615a4
commit b595a6eadf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 144 additions and 35 deletions

View File

@ -104,7 +104,7 @@ class Chassis(ChassisBase):
drawer = drawer_ctor(drawer_index, fan_data) drawer = drawer_ctor(drawer_index, fan_data)
self._fan_drawer_list.append(drawer) self._fan_drawer_list.append(drawer)
for index in range(fan_num_per_drawer): for index in range(fan_num_per_drawer):
fan = Fan(fan_index, drawer) fan = Fan(fan_index, drawer, index + 1)
fan_index += 1 fan_index += 1
drawer._fan_list.append(fan) drawer._fan_list.append(fan)
self._fan_list.append(fan) self._fan_list.append(fan)
@ -130,18 +130,19 @@ class Chassis(ChassisBase):
for index in range(self.PORT_START, self.PORT_END + 1): for index in range(self.PORT_START, self.PORT_END + 1):
if index in range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1): if index in range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1):
sfp_module = SFP(index, 'QSFP', self.sdk_handle) sfp_module = SFP(index, 'QSFP', self.sdk_handle, self.platform_name)
else: else:
sfp_module = SFP(index, 'SFP', self.sdk_handle) sfp_module = SFP(index, 'SFP', self.sdk_handle, self.platform_name)
self._sfp_list.append(sfp_module) self._sfp_list.append(sfp_module)
self.sfp_module_initialized = True self.sfp_module_initialized = True
def initialize_thermals(self): def initialize_thermals(self):
from sonic_platform.thermal import initialize_thermals from sonic_platform.thermal import initialize_chassis_thermals
# Initialize thermals # Initialize thermals
initialize_thermals(self.platform_name, self._thermal_list, self._psu_list) initialize_chassis_thermals(self.platform_name, self._thermal_list)
def initialize_eeprom(self): def initialize_eeprom(self):
@ -514,3 +515,20 @@ class Chassis(ChassisBase):
specified. specified.
""" """
return None if not Chassis._led else Chassis._led.get_status() return None if not Chassis._led else Chassis._led.get_status()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False

View File

@ -37,14 +37,16 @@ class Fan(FanBase):
PSU_FAN_SPEED = ['0x3c', '0x3c', '0x3c', '0x3c', '0x3c', PSU_FAN_SPEED = ['0x3c', '0x3c', '0x3c', '0x3c', '0x3c',
'0x3c', '0x3c', '0x46', '0x50', '0x5a', '0x64'] '0x3c', '0x3c', '0x46', '0x50', '0x5a', '0x64']
def __init__(self, fan_index, fan_drawer, psu_fan = False): def __init__(self, fan_index, fan_drawer, position, psu_fan = False, psu=None):
super(Fan, self).__init__() super(Fan, self).__init__()
# API index is starting from 0, Mellanox platform index is starting from 1 # API index is starting from 0, Mellanox platform index is starting from 1
self.index = fan_index + 1 self.index = fan_index + 1
self.fan_drawer = fan_drawer self.fan_drawer = fan_drawer
self.position = position
self.is_psu_fan = psu_fan self.is_psu_fan = psu_fan
self.psu = psu
if self.fan_drawer: if self.fan_drawer:
self.led = ComponentFaultyIndicator(self.fan_drawer.get_led()) self.led = ComponentFaultyIndicator(self.fan_drawer.get_led())
elif self.is_psu_fan: elif self.is_psu_fan:
@ -123,13 +125,8 @@ class Fan(FanBase):
Returns: Returns:
bool: True if fan is present, False if not bool: True if fan is present, False if not
""" """
status = 0
if self.is_psu_fan: if self.is_psu_fan:
if os.path.exists(os.path.join(FAN_PATH, self.fan_presence_path)): return self.psu.get_presence() and self.psu.get_powergood_status() and os.path.exists(os.path.join(FAN_PATH, self.fan_presence_path))
status = 1
else:
status = 0
return status == 1
else: else:
return self.fan_drawer.get_presence() return self.fan_drawer.get_presence()
@ -254,6 +251,22 @@ class Fan(FanBase):
# The tolerance value is fixed as 50% for all the Mellanox platform # The tolerance value is fixed as 50% for all the Mellanox platform
return 50 return 50
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device
Returns:
integer: The 1-based relative physical position in parent device
"""
return self.position
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
@classmethod @classmethod
def set_cooling_level(cls, level, cur_state): def set_cooling_level(cls, level, cur_state):
""" """
@ -288,3 +301,4 @@ class Fan(FanBase):
except (ValueError, IOError) as e: except (ValueError, IOError) as e:
raise RuntimeError("Failed to get cooling level - {}".format(e)) raise RuntimeError("Failed to get cooling level - {}".format(e))

View File

@ -84,6 +84,22 @@ class MellanoxFanDrawer(FanDrawerBase):
""" """
return self._led.get_status() return self._led.get_status()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device
Returns:
integer: The 1-based relative physical position in parent device
"""
return self._index
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return self._fan_data['hot_swappable']
class RealDrawer(MellanoxFanDrawer): class RealDrawer(MellanoxFanDrawer):
def __init__(self, index, fan_data): def __init__(self, index, fan_data):

View File

@ -103,7 +103,7 @@ class Psu(PsuBase):
# unplugable PSU has no FAN # unplugable PSU has no FAN
if self.psu_data['hot_swappable']: if self.psu_data['hot_swappable']:
fan = Fan(psu_index, None, True) fan = Fan(psu_index, None, 1, True, self)
self._fan_list.append(fan) self._fan_list.append(fan)
if self.psu_data['led_num'] == 1: if self.psu_data['led_num'] == 1:
@ -111,6 +111,10 @@ class Psu(PsuBase):
else: # 2010/2100 else: # 2010/2100
self.led = PsuLed(self.index) self.led = PsuLed(self.index)
# initialize thermal for PSU
from .thermal import initialize_psu_thermals
initialize_psu_thermals(platform, self._thermal_list, self.index, self.get_power_available_status)
def get_name(self): def get_name(self):
return self._name return self._name
@ -244,6 +248,22 @@ class Psu(PsuBase):
else: else:
return True, "" return True, ""
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device
Returns:
integer: The 1-based relative physical position in parent device
"""
return self.index
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return self.psu_data['hot_swappable']
@classmethod @classmethod
def get_shared_led(cls): def get_shared_led(cls):
if not cls.shared_led: if not cls.shared_led:

View File

@ -309,7 +309,8 @@ def deinitialize_sdk_handle(sdk_handle):
class SFP(SfpBase): class SFP(SfpBase):
"""Platform-specific SFP class""" """Platform-specific SFP class"""
def __init__(self, sfp_index, sfp_type, sdk_handle): def __init__(self, sfp_index, sfp_type, sdk_handle, platform):
SfpBase.__init__(self)
self.index = sfp_index + 1 self.index = sfp_index + 1
self.sfp_eeprom_path = "qsfp{}".format(self.index) self.sfp_eeprom_path = "qsfp{}".format(self.index)
self.sfp_status_path = "qsfp{}_status".format(self.index) self.sfp_status_path = "qsfp{}_status".format(self.index)
@ -319,7 +320,12 @@ class SFP(SfpBase):
self.sdk_handle = sdk_handle self.sdk_handle = sdk_handle
self.sdk_index = sfp_index self.sdk_index = sfp_index
# initialize SFP thermal list
from .thermal import initialize_sfp_thermals
initialize_sfp_thermals(platform, self._thermal_list, self.index)
def reinit(self): def reinit(self):
""" """
Re-initialize this SFP object when a new SFP inserted Re-initialize this SFP object when a new SFP inserted
:return: :return:
@ -2034,3 +2040,11 @@ class SFP(SfpBase):
False if not False if not
""" """
return NotImplementedError return NotImplementedError
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -113,12 +113,10 @@ thermal_name = {
} }
thermal_device_categories_all = [ thermal_device_categories_all = [
THERMAL_DEV_CATEGORY_CPU_CORE,
THERMAL_DEV_CATEGORY_CPU_PACK,
THERMAL_DEV_CATEGORY_MODULE,
THERMAL_DEV_CATEGORY_PSU,
THERMAL_DEV_CATEGORY_AMBIENT, THERMAL_DEV_CATEGORY_AMBIENT,
THERMAL_DEV_CATEGORY_GEARBOX THERMAL_DEV_CATEGORY_CPU_PACK,
THERMAL_DEV_CATEGORY_CPU_CORE,
THERMAL_DEV_CATEGORY_GEARBOX,
] ]
thermal_device_categories_singleton = [ thermal_device_categories_singleton = [
@ -305,18 +303,34 @@ thermal_profile_list = [
} }
] ]
def initialize_psu_thermals(platform, thermal_list, psu_index, dependency):
tp_index = platform_dict_thermal[platform]
thermal_profile = thermal_profile_list[tp_index]
_, count = thermal_profile[THERMAL_DEV_CATEGORY_PSU]
if count == 0:
return
thermal = Thermal(THERMAL_DEV_CATEGORY_PSU, psu_index, True, 1, dependency)
thermal_list.append(thermal)
def initialize_thermals(platform, thermal_list, psu_list):
def initialize_sfp_thermals(platform, thermal_list, sfp_index):
thermal = Thermal(THERMAL_DEV_CATEGORY_MODULE, sfp_index, True, 1)
thermal_list.append(thermal)
def initialize_chassis_thermals(platform, thermal_list):
# create thermal objects for all categories of sensors # create thermal objects for all categories of sensors
tp_index = platform_dict_thermal[platform] tp_index = platform_dict_thermal[platform]
thermal_profile = thermal_profile_list[tp_index] thermal_profile = thermal_profile_list[tp_index]
Thermal.thermal_profile = thermal_profile Thermal.thermal_profile = thermal_profile
position = 1
for category in thermal_device_categories_all: for category in thermal_device_categories_all:
if category == THERMAL_DEV_CATEGORY_AMBIENT: if category == THERMAL_DEV_CATEGORY_AMBIENT:
count, ambient_list = thermal_profile[category] count, ambient_list = thermal_profile[category]
for ambient in ambient_list: for ambient in ambient_list:
thermal = Thermal(category, ambient, True) thermal = Thermal(category, ambient, True, position)
thermal_list.append(thermal) thermal_list.append(thermal),
position += 1
else: else:
start, count = 0, 0 start, count = 0, 0
if category in thermal_profile: if category in thermal_profile:
@ -324,17 +338,14 @@ def initialize_thermals(platform, thermal_list, psu_list):
if count == 0: if count == 0:
continue continue
if count == 1: if count == 1:
thermal = Thermal(category, 0, False) thermal = Thermal(category, 0, False, position)
thermal_list.append(thermal)
else:
if category == THERMAL_DEV_CATEGORY_PSU:
for index in range(count):
thermal = Thermal(category, start + index, True, psu_list[index].get_power_available_status)
thermal_list.append(thermal) thermal_list.append(thermal)
position += 1
else: else:
for index in range(count): for index in range(count):
thermal = Thermal(category, start + index, True) thermal = Thermal(category, start + index, True, position)
thermal_list.append(thermal) thermal_list.append(thermal)
position += 1
@ -342,7 +353,7 @@ class Thermal(ThermalBase):
thermal_profile = None thermal_profile = None
thermal_algorithm_status = False thermal_algorithm_status = False
def __init__(self, category, index, has_index, dependency = None): def __init__(self, category, index, has_index, position, dependency = None):
""" """
index should be a string for category ambient and int for other categories index should be a string for category ambient and int for other categories
""" """
@ -357,6 +368,7 @@ class Thermal(ThermalBase):
self.index = 0 self.index = 0
self.category = category self.category = category
self.position = position
self.temperature = self._get_file_from_api(THERMAL_API_GET_TEMPERATURE) self.temperature = self._get_file_from_api(THERMAL_API_GET_TEMPERATURE)
self.high_threshold = self._get_file_from_api(THERMAL_API_GET_HIGH_THRESHOLD) self.high_threshold = self._get_file_from_api(THERMAL_API_GET_HIGH_THRESHOLD)
self.high_critical_threshold = self._get_file_from_api(THERMAL_API_GET_HIGH_CRITICAL_THRESHOLD) self.high_critical_threshold = self._get_file_from_api(THERMAL_API_GET_HIGH_CRITICAL_THRESHOLD)
@ -480,6 +492,21 @@ class Thermal(ThermalBase):
return None return None
return value_float / 1000.0 return value_float / 1000.0
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device
Returns:
integer: The 1-based relative physical position in parent device
"""
return self.position
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
@classmethod @classmethod
def _write_generic_file(cls, filename, content): def _write_generic_file(cls, filename, content):

View File

@ -16,7 +16,7 @@ from sonic_platform.device_data import DEVICE_DATA
def test_get_absence_fan_direction(): def test_get_absence_fan_direction():
fan_drawer = RealDrawer(0, DEVICE_DATA['x86_64-mlnx_msn2700-r0']['fans']) fan_drawer = RealDrawer(0, DEVICE_DATA['x86_64-mlnx_msn2700-r0']['fans'])
fan = Fan(0, fan_drawer) fan = Fan(0, fan_drawer, 1)
fan_drawer.get_presence = MagicMock(return_value=False) fan_drawer.get_presence = MagicMock(return_value=False)
assert not fan.is_psu_fan assert not fan.is_psu_fan
@ -31,8 +31,8 @@ def test_fan_drawer_set_status_led():
with pytest.raises(Exception): with pytest.raises(Exception):
fan_drawer.set_status_led(None, Fan.STATUS_LED_COLOR_RED) fan_drawer.set_status_led(None, Fan.STATUS_LED_COLOR_RED)
fan1 = Fan(0, fan_drawer) fan1 = Fan(0, fan_drawer, 1)
fan2 = Fan(1, fan_drawer) fan2 = Fan(1, fan_drawer, 2)
fan_list = fan_drawer.get_all_fans() fan_list = fan_drawer.get_all_fans()
fan_list.append(fan1) fan_list.append(fan1)
fan_list.append(fan2) fan_list.append(fan2)