Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 10 commits into from
Nov 17, 2020
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 @@ -36,14 +36,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 @@ -125,13 +127,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 @@ -291,6 +288,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 @@ -329,3 +342,4 @@ def get_cooling_level(cls):
except (ValueError, IOError) as e:
raise RuntimeError("Failed to get cooling level - {}".format(e))


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