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

Add a test case to validate FEC histogram #14661

Merged
merged 24 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fd3ec05
Add a test case to validate FEC histogram
vvolam Sep 18, 2024
4f9a801
Fix pre-commit issue
vvolam Sep 19, 2024
70edba5
Bin errors must be ZERO for bin>=7
vvolam Sep 19, 2024
0d71d91
Add a speed check for supported speeds
vvolam Sep 25, 2024
0d47916
Add a log when skipping
vvolam Sep 26, 2024
f3fda4e
Take 3 samples before deciding bin error counters are increasing
vvolam Oct 9, 2024
5e18761
fix pre-commit errors
vvolam Oct 9, 2024
093e6cb
Minor change
vvolam Oct 9, 2024
4538a8f
Modularize the test definition for more clarity
vvolam Oct 10, 2024
463b46f
Minor change
vvolam Oct 10, 2024
bca5039
Remove check for sfp presence
vvolam Oct 18, 2024
f7abf5a
Use some library functions
vvolam Oct 25, 2024
3ffaf5c
Minor pre-commit fix
vvolam Oct 28, 2024
3d71217
Merge remote-tracking branch 'public/master' into fec-histogram
vvolam Nov 8, 2024
e16879b
Fail the test if critical bins are non-zero
vvolam Nov 10, 2024
6d6a89b
Remote time import which is unused
vvolam Nov 10, 2024
960979e
skip for broadcom ASICS
vvolam Nov 25, 2024
2e06a28
Merge remote-tracking branch 'public/master' into fec-histogram
vvolam Jan 8, 2025
10ff09b
Merge remote-tracking branch 'public/master' into fec-histogram
vvolam Jan 10, 2025
6dc6fe6
Address review comments
vvolam Jan 9, 2025
c51ef53
Check for fec_hist only once
vvolam Jan 10, 2025
dc53a7a
Address review comments
vvolam Jan 10, 2025
0147d7a
Merge remote-tracking branch 'public/master' into fec-histogram
vvolam Jan 22, 2025
d21bae9
Enable test_verify_fec_histogram test on Arista 7060x6 platforms
vvolam Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions tests/common/platform/interface_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,44 @@ def get_dpu_npu_ports_from_hwsku(duthost):
dpu_npu_port_list.append(intf)
logging.info(f"DPU NPU ports in hwsku.json are {dpu_npu_port_list}")
return dpu_npu_port_list


def get_fec_eligible_interfaces(duthost, supported_speeds):
"""
Get interfaces that are operationally up, SFP present and have supported speeds.

Args:
duthost: The device under test.
supported_speeds (list): A list of supported speeds for validation.

Returns:
interfaces (list): A list of interface names with SFP present, oper status up
and speed in supported_speeds.
"""
logging.info("Get output of 'show interface status'")
intf_status = duthost.show_and_parse("show interface status")
logging.info("Interface status: {intf_status}")
vvolam marked this conversation as resolved.
Show resolved Hide resolved

logging.info("Get output of 'sudo sfpshow presence'")
sfp_presence_output = duthost.show_and_parse("sudo sfpshow presence")
logging.info("SFP presence: {sfp_presence_output}")
vvolam marked this conversation as resolved.
Show resolved Hide resolved

sfp_presence_dict = {entry['port']: entry.get('presence', '').lower() for entry in sfp_presence_output}

interfaces = []
for intf in intf_status:
vvolam marked this conversation as resolved.
Show resolved Hide resolved
intf_name = intf['interface']
presence = sfp_presence_dict.get(intf_name, '')

if presence != "present":
continue

oper = intf.get('oper', '').lower()
speed = intf.get('speed', '')

if oper == "up" and speed in supported_speeds:
interfaces.append(intf_name)
else:
logging.info(f"Skip for {intf_name}: oper_state:{oper} speed:{speed}")

return interfaces
111 changes: 79 additions & 32 deletions tests/platform_tests/test_intf_fec.py
vvolam marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import logging
import pytest
import time

from tests.common.helpers.assertions import pytest_assert
from tests.common.utilities import skip_release, wait_until
from tests.common.platform.interface_utils import get_fec_eligible_interfaces

pytestmark = [
pytest.mark.disable_loganalyzer, # disable automatic loganalyzer
Expand Down Expand Up @@ -49,22 +51,14 @@ def test_verify_fec_oper_mode(duthosts, enum_rand_one_per_hwsku_frontend_hostnam
if "broadcom" in duthost.facts.get('platform_asic'):
pytest.skip("Skipping this test on platforms with Broadcom ASICs")

logging.info("Get output of '{}'".format("show interface status"))
intf_status = duthost.show_and_parse("show interface status")
# Get interfaces that are operationally up and have supported speeds.
interfaces = get_fec_eligible_interfaces(duthost, SUPPORTED_SPEEDS)

for intf in intf_status:
sfp_presence = duthost.show_and_parse("sudo sfpshow presence -p {}"
.format(intf['interface']))
if sfp_presence:
presence = sfp_presence[0].get('presence', '').lower()
oper = intf.get('oper', '').lower()
speed = intf.get('speed', '')

if presence == "present" and oper == "up" and speed in SUPPORTED_SPEEDS:
# Verify the FEC operational mode is valid
fec = get_fec_oper_mode(duthost, intf['interface'])
if fec == "n/a":
pytest.fail("FEC status is N/A for interface {}".format(intf['interface']))
for intf in interfaces:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vvolam some platforms like Arista 7060-x6 does not support fec operational mode yet. can you test there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prgeor yes, that's the reason this test is already skipped on broadcom platform which is at line 51.

# Verify the FEC operational mode is valid
fec = get_fec_oper_mode(duthost, intf)
if fec == "n/a":
pytest.fail("FEC status is N/A for interface {}".format(intf['interface']))


def test_config_fec_oper_mode(duthosts, enum_rand_one_per_hwsku_frontend_hostname,
Expand All @@ -78,21 +72,11 @@ def test_config_fec_oper_mode(duthosts, enum_rand_one_per_hwsku_frontend_hostnam
if "broadcom" in duthost.facts.get('platform_asic'):
vvolam marked this conversation as resolved.
Show resolved Hide resolved
pytest.skip("Skipping this test on platforms with Broadcom ASICs")

logging.info("Get output of '{}'".format("show interface status"))
intf_status = duthost.show_and_parse("show interface status")
# Get interfaces that are operationally up and have supported speeds.
interfaces = get_fec_eligible_interfaces(duthost, SUPPORTED_SPEEDS)

for intf in intf_status:
sfp_presence = duthost.show_and_parse("sudo sfpshow presence -p {}"
.format(intf['interface']))
if sfp_presence:
presence = sfp_presence[0].get('presence', '').lower()
oper = intf.get('oper', '').lower()
speed = intf.get('speed', '')

if presence == "not present" or oper != "up" or speed not in SUPPORTED_SPEEDS:
continue

fec_mode = get_fec_oper_mode(duthost, intf['interface'])
for intf in interfaces:
fec_mode = get_fec_oper_mode(duthost, intf)
if fec_mode == "n/a":
pytest.fail("FEC status is N/A for interface {}".format(intf['interface']))

Expand All @@ -102,7 +86,7 @@ def test_config_fec_oper_mode(duthosts, enum_rand_one_per_hwsku_frontend_hostnam
pytest_assert(wait_until(30, 2, 0, duthost.is_interface_status_up, intf["interface"]),
"Interface {} did not come up after configuring FEC mode".format(intf["interface"]))
# Verify the FEC operational mode is restored
post_fec = get_fec_oper_mode(duthost, intf['interface'])
post_fec = get_fec_oper_mode(duthost, intf)
if not (post_fec == fec_mode):
pytest.fail("FEC status is not restored for interface {}".format(intf['interface']))

Expand Down Expand Up @@ -149,7 +133,7 @@ def skip_ber_counters_test(intf_status: dict) -> bool:

for intf in intf_status:
intf_name = intf['iface']
speed = get_interface_speed(duthost, intf_name)
speed = duthost.get_speed(intf_name)
if speed not in SUPPORTED_SPEEDS:
continue

Expand All @@ -174,7 +158,7 @@ def skip_ber_counters_test(intf_status: dict) -> bool:
# Check for valid FEC correctable codeword errors > FEC symbol errors
if fec_symbol_err_int > fec_corr_int:
pytest.fail("FEC symbol errors:{} are higher than FEC correctable errors:{} for interface {}"
.format(intf_name, fec_symbol_err_int, fec_corr_int))
.format(fec_symbol_err_int, fec_corr_int, intf_name))

if skip_ber_counters_test(intf):
continue
Expand All @@ -189,3 +173,66 @@ def skip_ber_counters_test(intf_status: dict) -> bool:
pytest.fail("Pre-FEC and Post-FEC BER are not valid floats for interface {}, \
fec_pre_ber: {} fec_post_ber: {}"
.format(intf_name, fec_pre_ber, fec_post_ber))


def get_fec_histogram(duthost, intf_name):
"""
@Summary: Fetch FEC histogram for a given interface.
"""
try:
logging.info("Get output of 'show interfaces counters fec-histogram {}'".format(intf_name))
fec_hist = duthost.show_and_parse("show interfaces counters fec-histogram {}".format(intf_name))
except Exception as e:
logging.error("Failed to execute 'show interfaces counters fec-histogram {}': {}".format(intf_name, e))
pytest.skip("Command 'show interfaces counters fec-histogram {}' not found \
or failed: {}".format(intf_name, str(e)))
return None

logging.info("FEC histogram for interface {}: {}".format(intf_name, fec_hist))
return fec_hist


def validate_fec_histogram(duthost, intf_name):
"""
@Summary: Validate FEC histogram critical bins for any errors. Fail the test if bin value > 0
"""

fec_hist = get_fec_histogram(duthost, intf_name)
if not fec_hist:
vvolam marked this conversation as resolved.
Show resolved Hide resolved
pytest.fail("FEC histogram data not found or incomplete for interface {}".format(intf_name))

critical_bins = range(7, 16)
vvolam marked this conversation as resolved.
Show resolved Hide resolved
error_bins = []
for bin_index in critical_bins:
bin_value = int(fec_hist[bin_index].get('codewords', 0))
if bin_value > 0:
error_bins.append((bin_index, bin_value))

if error_bins:
error_messages = ["FEC histogram bin {} has errors for interface {}: {}".format(bin_index, intf_name, bin_value)
for bin_index, bin_value in error_bins]
logging.error("\n".join(error_messages))
return False

return True


def test_verify_fec_histogram(duthosts, enum_rand_one_per_hwsku_frontend_hostname,
enum_frontend_asic_index, conn_graph_facts):
"""
@Summary: Verify the FEC histogram is valid and check for errors
"""
duthost = duthosts[enum_rand_one_per_hwsku_frontend_hostname]

if "broadcom" in duthost.facts.get('platform_asic'):
if "7060x6" not in duthost.facts['platform']:
pytest.skip("Skipping this test on platforms with Broadcom ASICs")

# Get operationally up and interfaces with supported speeds
interfaces = get_fec_eligible_interfaces(duthost, SUPPORTED_SPEEDS)

for intf_name in interfaces:
for _ in range(3):
if not validate_fec_histogram(duthost, intf_name):
pytest.fail("FEC histogram validation failed for interface {}".format(intf_name))
time.sleep(10)
Loading