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

[show][interface][counters] Add proposal and changes for fec-histogram for interface counters fec-histogram subcommand #3519

Merged
merged 12 commits into from
Sep 10, 2024
34 changes: 34 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4806,6 +4806,7 @@ Optional argument "-p" specify a period (in seconds) with which to gather counte
show interfaces counters errors
show interfaces counters rates
show interfaces counters rif [-p|--period <period>] [-i <interface_name>]
show interfaces counters fec-histogram [-i <interface_name>]
```

- Example:
Expand Down Expand Up @@ -4923,6 +4924,39 @@ Optionally, you can specify a period (in seconds) with which to gather counters
admin@sonic:~$ sonic-clear rifcounters
```

The "fec-histogram" subcommand is used to display the fec histogram for the port.

When data is transmitted, it's broken down into units called codewords. FEC algorithms add extra data to each codeword that can be used to detect and correct errors in transmission.
In a FEC histogram, "bins" represent ranges of errors or specific categories of errors. For instance, Bin0 might represent codewords with no errors, while Bin1 could represent codewords with a single bit error, and so on. The histogram shows how many codewords fell into each bin. A high number in the higher bins might indicate a problem with the transmission link, such as signal degradation.

- Example:
```
admin@str-s6000-acs-11:/usr/bin$ show interface counters fec-histogram -i <PORT>

Symbol Errors Per Codeword Codewords
-------------------------- ---------
BIN0: 1000000
BIN1: 900000
BIN2: 800000
BIN3: 700000
BIN4: 600000
BIN5: 500000
BIN6: 400000
BIN7: 300000
BIN8: 0
BIN9: 0
BIN10: 0
BIN11: 0
BIN12: 0
BIN13: 0
BIN14: 0
BIN15: 0

```




**show interfaces description**

This command displays the key fields of the interfaces such as Operational Status, Administrative Status, Alias and Description.
Expand Down
70 changes: 70 additions & 0 deletions show/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

HWSKU_JSON = 'hwsku.json'

REDIS_HOSTIP = "127.0.0.1"

# Read given JSON file
def readJsonFile(fileName):
try:
Expand Down Expand Up @@ -646,6 +648,74 @@ def fec_stats(verbose, period, namespace, display):

clicommon.run_command(cmd, display_cmd=verbose)


def get_port_oid_mapping():
''' Returns dictionary of all ports interfaces and their OIDs. '''
db = SonicV2Connector(host=REDIS_HOSTIP)
db.connect(db.COUNTERS_DB)

port_oid_map = db.get_all(db.COUNTERS_DB, 'COUNTERS_PORT_NAME_MAP')

db.close(db.COUNTERS_DB)

return port_oid_map


def fetch_fec_histogram(port_oid_map, target_port):
''' Fetch and display FEC histogram for the given port. '''
asic_db = SonicV2Connector(host=REDIS_HOSTIP)
asic_db.connect(asic_db.ASIC_DB)

config_db = ConfigDBConnector()
config_db.connect()

counter_db = SonicV2Connector(host=REDIS_HOSTIP)
counter_db.connect(counter_db.COUNTERS_DB)

if target_port not in port_oid_map:
click.echo('Port {} not found in COUNTERS_PORT_NAME_MAP'.format(target_port), err=True)
raise click.Abort()

port_oid = port_oid_map[target_port]
asic_db_kvp = counter_db.get_all(counter_db.COUNTERS_DB, 'COUNTERS:{}'.format(port_oid))

if asic_db_kvp is not None:

fec_errors = {f'BIN{i}': asic_db_kvp.get
(f'SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S{i}', '0') for i in range(16)}

# Prepare the data for tabulation
table_data = [(bin_label, error_value) for bin_label, error_value in fec_errors.items()]

# Define headers
headers = ["Symbol Errors Per Codeword", "Codewords"]

# Print FEC histogram using tabulate
click.echo(tabulate(table_data, headers=headers))
else:
click.echo('No kvp found in ASIC DB for port {}, exiting'.format(target_port), err=True)
raise click.Abort()

asic_db.close(asic_db.ASIC_DB)
config_db.close(config_db.CONFIG_DB)
counter_db.close(counter_db.COUNTERS_DB)


# 'fec-histogram' subcommand ("show interfaces counters fec-histogram")
@counters.command('fec-histogram')
@multi_asic_util.multi_asic_click_options
@click.argument('interfacename', required=True)
def fec_histogram(interfacename, namespace, display):
"""Show interface counters fec-histogram"""
port_oid_map = get_port_oid_mapping()

# Try to convert interface name from alias
interfacename = try_convert_interfacename_from_alias(click.get_current_context(), interfacename)

# Fetch and display the FEC histogram
fetch_fec_histogram(port_oid_map, interfacename)


# 'rates' subcommand ("show interfaces counters rates")
@counters.command()
@click.option('-p', '--period')
Expand Down
18 changes: 17 additions & 1 deletion tests/mock_tables/counters_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,23 @@
"SAI_PORT_STAT_ETHER_STATS_JABBERS": "0",
"SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "130402",
"SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "3",
"SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "4"
"SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "4",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S0": "1000000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S1": "900000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S2": "800000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S3": "700000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S4": "600000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S5": "500000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S6": "400000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S7": "300000",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S8": "0",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S9": "0",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S10": "0",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S11": "0",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S12": "0",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S13": "0",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S14": "0",
"SAI_PORT_STAT_IF_IN_FEC_CODEWORD_ERRORS_S15": "0"
},
"COUNTERS:oid:0x1000000000013": {
"SAI_PORT_STAT_IF_IN_UCAST_PKTS": "4",
Expand Down
30 changes: 30 additions & 0 deletions tests/portstat_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@
Ethernet8 N/A 100,317 0 0
"""

intf_fec_counters_fec_hist = """\
Symbol Errors Per Codeword Codewords
---------------------------- -----------
BIN0 1000000
BIN1 900000
BIN2 800000
BIN3 700000
BIN4 600000
BIN5 500000
BIN6 400000
BIN7 300000
BIN8 0
BIN9 0
BIN10 0
BIN11 0
BIN12 0
BIN13 0
BIN14 0
BIN15 0
"""

intf_fec_counters_period = """\
The rates are calculated within 3 seconds period
IFACE STATE FEC_CORR FEC_UNCORR FEC_SYMBOL_ERR
Expand Down Expand Up @@ -337,6 +358,15 @@ def test_show_intf_fec_counters(self):
assert return_code == 0
assert result == intf_fec_counters

def test_show_intf_counters_fec_histogram(self):
runner = CliRunner()
result = runner.invoke(
show.cli.commands["interfaces"].commands["counters"].commands["fec-histogram"], ["Ethernet0"])
print(result.exit_code)
print(result.output)
assert result.exit_code == 0
assert result.output == intf_fec_counters_fec_hist

def test_show_intf_fec_counters_period(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["fec-stats"],
Expand Down
Loading