Skip to content

Commit

Permalink
[Mellanox] Implement new platform API for SONiC physical entity mib e…
Browse files Browse the repository at this point in the history
…xtension (#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.
  • Loading branch information
Junchao-Mellanox authored Nov 17, 2020
1 parent ced1161 commit b595a6e
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 35 deletions.
28 changes: 23 additions & 5 deletions platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def initialize_fan(self):
drawer = drawer_ctor(drawer_index, fan_data)
self._fan_drawer_list.append(drawer)
for index in range(fan_num_per_drawer):
fan = Fan(fan_index, drawer)
fan = Fan(fan_index, drawer, index + 1)
fan_index += 1
drawer._fan_list.append(fan)
self._fan_list.append(fan)
Expand All @@ -130,18 +130,19 @@ def initialize_sfp(self):

for index in range(self.PORT_START, self.PORT_END + 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:
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_module_initialized = True


def initialize_thermals(self):
from sonic_platform.thermal import initialize_thermals
from sonic_platform.thermal import initialize_chassis_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):
Expand Down Expand Up @@ -514,3 +515,20 @@ def get_status_led(self):
specified.
"""
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
28 changes: 21 additions & 7 deletions platform/mellanox/mlnx-platform-api/sonic_platform/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ class Fan(FanBase):
PSU_FAN_SPEED = ['0x3c', '0x3c', '0x3c', '0x3c', '0x3c',
'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__()

# API index is starting from 0, Mellanox platform index is starting from 1
self.index = fan_index + 1
self.fan_drawer = fan_drawer
self.position = position

self.is_psu_fan = psu_fan
self.psu = psu
if self.fan_drawer:
self.led = ComponentFaultyIndicator(self.fan_drawer.get_led())
elif self.is_psu_fan:
Expand Down Expand Up @@ -123,13 +125,8 @@ def get_presence(self):
Returns:
bool: True if fan is present, False if not
"""
status = 0
if self.is_psu_fan:
if os.path.exists(os.path.join(FAN_PATH, self.fan_presence_path)):
status = 1
else:
status = 0
return status == 1
return self.psu.get_presence() and self.psu.get_powergood_status() and os.path.exists(os.path.join(FAN_PATH, self.fan_presence_path))
else:
return self.fan_drawer.get_presence()

Expand Down Expand Up @@ -254,6 +251,22 @@ def get_speed_tolerance(self):
# The tolerance value is fixed as 50% for all the Mellanox platform
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
def set_cooling_level(cls, level, cur_state):
"""
Expand Down Expand Up @@ -288,3 +301,4 @@ def get_cooling_level(cls):
except (ValueError, IOError) as e:
raise RuntimeError("Failed to get cooling level - {}".format(e))


16 changes: 16 additions & 0 deletions platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ def get_status_led(self):
"""
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):
def __init__(self, index, fan_data):
Expand Down
22 changes: 21 additions & 1 deletion platform/mellanox/mlnx-platform-api/sonic_platform/psu.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,18 @@ def __init__(self, psu_index, platform):

# unplugable PSU has no FAN
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)

if self.psu_data['led_num'] == 1:
self.led = ComponentFaultyIndicator(Psu.get_shared_led())
else: # 2010/2100
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):
return self._name
Expand Down Expand Up @@ -244,6 +248,22 @@ def get_power_available_status(self):
else:
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
def get_shared_led(cls):
if not cls.shared_led:
Expand Down
16 changes: 15 additions & 1 deletion platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ def deinitialize_sdk_handle(sdk_handle):
class SFP(SfpBase):
"""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.sfp_eeprom_path = "qsfp{}".format(self.index)
self.sfp_status_path = "qsfp{}_status".format(self.index)
Expand All @@ -319,7 +320,12 @@ def __init__(self, sfp_index, sfp_type, sdk_handle):
self.sdk_handle = sdk_handle
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):

"""
Re-initialize this SFP object when a new SFP inserted
:return:
Expand Down Expand Up @@ -2034,3 +2040,11 @@ def set_power_override(self, power_override, power_set):
False if not
"""
return NotImplementedError

def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True
63 changes: 45 additions & 18 deletions platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,10 @@
}

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_GEARBOX
THERMAL_DEV_CATEGORY_CPU_PACK,
THERMAL_DEV_CATEGORY_CPU_CORE,
THERMAL_DEV_CATEGORY_GEARBOX,
]

thermal_device_categories_singleton = [
Expand Down Expand Up @@ -305,44 +303,57 @@
}
]

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
tp_index = platform_dict_thermal[platform]
thermal_profile = thermal_profile_list[tp_index]
Thermal.thermal_profile = thermal_profile
position = 1
for category in thermal_device_categories_all:
if category == THERMAL_DEV_CATEGORY_AMBIENT:
count, ambient_list = thermal_profile[category]
for ambient in ambient_list:
thermal = Thermal(category, ambient, True)
thermal_list.append(thermal)
thermal = Thermal(category, ambient, True, position)
thermal_list.append(thermal),
position += 1
else:
start, count = 0, 0
if category in thermal_profile:
start, count = thermal_profile[category]
if count == 0:
continue
if count == 1:
thermal = Thermal(category, 0, False)
thermal = Thermal(category, 0, False, position)
thermal_list.append(thermal)
position += 1
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)
else:
for index in range(count):
thermal = Thermal(category, start + index, True)
thermal_list.append(thermal)
for index in range(count):
thermal = Thermal(category, start + index, True, position)
thermal_list.append(thermal)
position += 1



class Thermal(ThermalBase):
thermal_profile = None
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
"""
Expand All @@ -357,6 +368,7 @@ def __init__(self, category, index, has_index, dependency = None):
self.index = 0

self.category = category
self.position = position
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_critical_threshold = self._get_file_from_api(THERMAL_API_GET_HIGH_CRITICAL_THRESHOLD)
Expand Down Expand Up @@ -480,6 +492,21 @@ def get_high_critical_threshold(self):
return None
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
def _write_generic_file(cls, filename, content):
Expand Down
6 changes: 3 additions & 3 deletions platform/mellanox/mlnx-platform-api/tests/test_fan_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

def test_get_absence_fan_direction():
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)

assert not fan.is_psu_fan
Expand All @@ -31,8 +31,8 @@ def test_fan_drawer_set_status_led():
with pytest.raises(Exception):
fan_drawer.set_status_led(None, Fan.STATUS_LED_COLOR_RED)

fan1 = Fan(0, fan_drawer)
fan2 = Fan(1, fan_drawer)
fan1 = Fan(0, fan_drawer, 1)
fan2 = Fan(1, fan_drawer, 2)
fan_list = fan_drawer.get_all_fans()
fan_list.append(fan1)
fan_list.append(fan2)
Expand Down

0 comments on commit b595a6e

Please sign in to comment.