Skip to content

Commit

Permalink
[Mellanox] Skip the leftover hardware reboot cause in case of last bo…
Browse files Browse the repository at this point in the history
…ot is warm/fast reboot (sonic-net#13246)

- Why I did it
In case of warm/fast reboot, the hardware reboot cause will NOT be cleared because CPLD will not be touched in this flow. To not confuse the reboot cause determine logic, the leftover hardware reboot cause shall be skipped by the platform API, platform API will return the 'REBOOT_CAUSE_NON_HARDWARE' instead of the "hardware" reboot cause.

- How I did it
Check the proc cmdline to see whether the last reboot is a warm or fast reboot, if yes skip checking the leftover hardware reboot cause.

- How to verify it
a. Manual test:
    - Perform a power loss
    - Perform a warm/fast reboot
    - Check the reboot cause should be "warm-reboot" or "fast-reboot" instead of "power loss"
b. Run reboot cause related regression test.

Signed-off-by: Kebo Liu <[email protected]>
  • Loading branch information
keboliu authored and mssonicbld committed Jan 31, 2023
1 parent c579ff3 commit 8c750c0
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
25 changes: 25 additions & 0 deletions platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from .utils import extract_RJ45_ports_index
from . import utils
from .device_data import DeviceDataManager
import re
except ImportError as e:
raise ImportError (str(e) + "- required module not found")

Expand Down Expand Up @@ -61,6 +62,10 @@

REBOOT_CAUSE_FILE_LENGTH = 1

REBOOT_TYPE_KEXEC_FILE = "/proc/cmdline"
REBOOT_TYPE_KEXEC_PATTERN_WARM = ".*SONIC_BOOT_TYPE=(warm|fastfast).*"
REBOOT_TYPE_KEXEC_PATTERN_FAST = ".*SONIC_BOOT_TYPE=(fast|fast-reboot).*"

# Global logger class instance
logger = Logger()

Expand Down Expand Up @@ -736,6 +741,18 @@ def initialize_reboot_cause(self):
self.reboot_by_software = 'reset_sw_reset'
self.reboot_cause_initialized = True

def _parse_warmfast_reboot_from_proc_cmdline(self):
if os.path.isfile(REBOOT_TYPE_KEXEC_FILE):
with open(REBOOT_TYPE_KEXEC_FILE) as cause_file:
cause_file_kexec = cause_file.readline()
m = re.search(REBOOT_TYPE_KEXEC_PATTERN_WARM, cause_file_kexec)
if m and m.group(1):
return 'warm-reboot'
m = re.search(REBOOT_TYPE_KEXEC_PATTERN_FAST, cause_file_kexec)
if m and m.group(1):
return 'fast-reboot'
return None

def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Expand All @@ -748,6 +765,14 @@ def get_reboot_cause(self):
to pass a description of the reboot cause.
"""
#read reboot causes files in the following order

# To avoid the leftover hardware reboot cause confusing the reboot cause determine service
# Skip the hardware reboot cause check if warm/fast reboot cause found from cmdline
if utils.is_host():
reboot_cause = self._parse_warmfast_reboot_from_proc_cmdline()
if reboot_cause:
return self.REBOOT_CAUSE_NON_HARDWARE, ''

if not self.reboot_cause_initialized:
self.initialize_reboot_cause()

Expand Down
29 changes: 29 additions & 0 deletions platform/mellanox/mlnx-platform-api/tests/test_chassis.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,35 @@ def read_int_from_file(file_path, *args, **kwargs):
assert minor == value
mock_file_content[file_path] = 0

utils.is_host = mock.MagicMock(return_value=True)
chassis._parse_warmfast_reboot_from_proc_cmdline = mock.MagicMock(return_value='warm-reboot')
for key, value in chassis.reboot_major_cause_dict.items():
file_path = os.path.join(REBOOT_CAUSE_ROOT, key)
mock_file_content[file_path] = 1
major, minor = chassis.get_reboot_cause()
assert major == chassis.REBOOT_CAUSE_NON_HARDWARE
assert minor == ''
mock_file_content[file_path] = 0

for key, value in chassis.reboot_minor_cause_dict.items():
file_path = os.path.join(REBOOT_CAUSE_ROOT, key)
mock_file_content[file_path] = 1
major, minor = chassis.get_reboot_cause()
assert major == chassis.REBOOT_CAUSE_NON_HARDWARE
assert minor == value
mock_file_content[file_path] = 0

def test_parse_warmfast_reboot_from_proc_cmdline(self):
chassis = Chassis()
with mock.patch("builtins.open", mock.mock_open(read_data="SONIC_BOOT_TYPE=warm")):
assert chassis._parse_warmfast_reboot_from_proc_cmdline() == "warm-reboot"

with mock.patch("builtins.open", mock.mock_open(read_data="SONIC_BOOT_TYPE=fast")):
assert chassis._parse_warmfast_reboot_from_proc_cmdline() == "fast-reboot"

with mock.patch("builtins.open", mock.mock_open(read_data="SONIC_BOOT_TYPE=None")):
assert chassis._parse_warmfast_reboot_from_proc_cmdline() == None

def test_module(self):
from sonic_platform.chassis import ModularChassis
# Test get_num_modules, it should not create any SFP objects
Expand Down

0 comments on commit 8c750c0

Please sign in to comment.