From 4deb0dc790d5a8911508fbfe80382d7c04b975fc Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Wed, 29 Jul 2020 15:30:43 -0700 Subject: [PATCH 1/5] show interface counters for multi asic devices Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- scripts/portstat | 96 +++++++++++++++++++++++++++++++++++------------- show/main.py | 8 +++- 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/scripts/portstat b/scripts/portstat index 42757d3677..574bbd09d6 100644 --- a/scripts/portstat +++ b/scripts/portstat @@ -7,6 +7,8 @@ ##################################################################### import argparse +from ast import NodeTransformer + import cPickle as pickle import datetime import os.path @@ -17,8 +19,16 @@ import time from collections import namedtuple, OrderedDict from natsort import natsorted from tabulate import tabulate + +from sonic_py_common.multi_asic_device_info import connect_to_all_dbs_for_ns +from utilities_common.constants import DISPLAY_EXTERNAL +from utilities_common.constants import DISPLAY_ALL +from utilities_common.constants import PORT_OBJ from utilities_common.netstat import ns_diff, ns_brate, ns_prate, ns_util, table_as_json from utilities_common.intf_filter import parse_interface_in_filter +from utilities_common.multi_asic import MultiAsic +from utilities_common.multi_asic import run_on_all_asics + PORT_RATE = 40 @@ -62,11 +72,25 @@ PORT_STATE_UP = 'U' PORT_STATE_DOWN = 'D' PORT_STATE_DISABLED = 'X' + class Portstat(object): - def __init__(self): - self.db = swsssdk.SonicV2Connector(host='127.0.0.1') - self.db.connect(self.db.COUNTERS_DB) - self.db.connect(self.db.APPL_DB) + def __init__(self, namespace, display_option): + self.db = None + self.multi_asic = MultiAsic(display_option, namespace) + + def get_cnstat_dict(self): + self.cnstat_dict = OrderedDict() + self.cnstat_dict['time'] = datetime.datetime.now() + self.collect_stat() + return self.cnstat_dict + + @run_on_all_asics + def collect_stat(self): + """ + Collect the statisitics from all the asics present on the + device and store in a dict + """ + self.cnstat_dict.update(self.get_cnstat()) def get_cnstat(self): """ @@ -91,11 +115,14 @@ class Portstat(object): counter_port_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_PORT_NAME_MAP); # Build a dictionary of the stats cnstat_dict = OrderedDict() - cnstat_dict['time'] = datetime.datetime.now() if counter_port_name_map is None: return cnstat_dict for port in natsorted(counter_port_name_map): + port_name = port.split(":")[0] + if self.multi_asic.skip_display(PORT_OBJ, port_name): + continue cnstat_dict[port] = get_counters(counter_port_name_map[port]) + return cnstat_dict def get_port_speed(self, port_name): @@ -104,11 +131,12 @@ class Portstat(object): """ # Get speed from APPL_DB full_table_id = PORT_STATUS_TABLE_PREFIX + port_name - speed = self.db.get(self.db.APPL_DB, full_table_id, PORT_SPEED_FIELD) - if speed is None: - speed = PORT_RATE - else: - speed = int(speed)//1000 + speed = PORT_RATE + for ns in self.multi_asic.get_ns_list_based_on_options(): + self.db = connect_to_all_dbs_for_ns(ns) + speed = self.db.get(self.db.APPL_DB, full_table_id, PORT_SPEED_FIELD) + if speed is not None: + return int(speed)//1000 return speed def get_port_state(self, port_name): @@ -116,18 +144,23 @@ class Portstat(object): Get the port state """ full_table_id = PORT_STATUS_TABLE_PREFIX + port_name - admin_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_ADMIN_STATUS_FIELD) - oper_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_OPER_STATUS_FIELD) - if admin_state is None or oper_state is None: - return STATUS_NA - elif admin_state.upper() == PORT_STATUS_VALUE_DOWN: - return PORT_STATE_DISABLED - elif admin_state.upper() == PORT_STATUS_VALUE_UP and oper_state.upper() == PORT_STATUS_VALUE_UP: - return PORT_STATE_UP - elif admin_state.upper() == PORT_STATUS_VALUE_UP and oper_state.upper() == PORT_STATUS_VALUE_DOWN: - return PORT_STATE_DOWN - else: - return STATUS_NA + for ns in self.multi_asic.get_ns_list_based_on_options(): + self.db = connect_to_all_dbs_for_ns(ns) + admin_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_ADMIN_STATUS_FIELD) + oper_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_OPER_STATUS_FIELD) + + if admin_state is None or oper_state is None: + continue + if admin_state.upper() == PORT_STATUS_VALUE_DOWN: + return PORT_STATE_DISABLED + elif admin_state.upper() == PORT_STATUS_VALUE_UP and oper_state.upper() == PORT_STATUS_VALUE_UP: + return PORT_STATE_UP + elif admin_state.upper() == PORT_STATUS_VALUE_UP and oper_state.upper() == PORT_STATUS_VALUE_DOWN: + return PORT_STATE_DOWN + else: + return STATUS_NA + return STATUS_NA + def cnstat_print(self, cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only): """ @@ -171,6 +204,7 @@ class Portstat(object): else: print tabulate(table, header, tablefmt='simple', stralign='right') + def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, intf_list, use_json, print_all, errors_only, rates_only): """ Print the difference between two cnstat results. @@ -311,6 +345,8 @@ Examples: parser.add_argument('-t', '--tag', type=str, help='Save stats with name TAG', default=None) parser.add_argument('-p', '--period', type=int, help='Display stats over a specified period (in seconds).', default=0) parser.add_argument('-i', '--interface', type=str, help='Display stats for interface lists.', default=None) + parser.add_argument('-s','--show', default=DISPLAY_EXTERNAL, help='Display all interfaces or only external interfaces') + parser.add_argument('-n','--namespace', default=None, help='Display interfaces for specific namespace') args = parser.parse_args() save_fresh_stats = args.clear @@ -325,6 +361,9 @@ Examples: wait_time_in_seconds = args.period print_all = args.all intf_fs = args.interface + namespace = args.namespace + display_option = args.show + if tag_name is not None: cnstat_file = uid + "-" + tag_name else: @@ -358,9 +397,14 @@ Examples: intf_list = parse_interface_in_filter(intf_fs) - portstat = Portstat() - # The cnstat_dict just give an ordered dict of all output. - cnstat_dict = portstat.get_cnstat() + # When saving counters to the file, save counters + # for all ports(Internal and External) + if save_fresh_stats: + namespace = None + display_option = DISPLAY_ALL + + portstat = Portstat(namespace, display_option) + cnstat_dict = portstat.get_cnstat_dict() # Now decide what information to display if raw_stats: @@ -404,7 +448,7 @@ Examples: #wait for the specified time and then gather the new stats and output the difference. time.sleep(wait_time_in_seconds) print "The rates are calculated within %s seconds period" % wait_time_in_seconds - cnstat_new_dict = portstat.get_cnstat() + cnstat_new_dict = portstat.get_cnstat_dict() portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only) if __name__ == "__main__": diff --git a/show/main.py b/show/main.py index b670596466..eff0d9e3e3 100755 --- a/show/main.py +++ b/show/main.py @@ -21,6 +21,7 @@ from portconfig import get_child_ports import mlnx +from utilities_common.multi_asic import multi_asic_click_options # Global Variable PLATFORM_ROOT_PATH = "/usr/share/sonic/device" @@ -1059,9 +1060,10 @@ def status(interfacename, verbose): @click.option('-a', '--printall', is_flag=True) @click.option('-p', '--period') @click.option('-i', '--interface') +@multi_asic_click_options @click.option('--verbose', is_flag=True, help="Enable verbose output") @click.pass_context -def counters(ctx, verbose, period, interface, printall): +def counters(ctx, verbose, period, interface, printall, namespace, display): """Show interface counters""" if ctx.invoked_subcommand is None: @@ -1073,6 +1075,10 @@ def counters(ctx, verbose, period, interface, printall): cmd += " -p {}".format(period) if interface is not None: cmd += " -i {}".format(interface) + if namespace is not None: + cmd += " -n {}".format(namespace) + + cmd += " -s {}".format(display) run_command(cmd, display_cmd=verbose) From 7e69c2d08c84985e144534b2140732a809647f5d Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Tue, 18 Aug 2020 14:36:36 -0700 Subject: [PATCH 2/5] refactor to latest changes Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- scripts/portstat | 33 ++++++++++++++------------------- show/interfaces/__init__.py | 22 +++++++++++++++++++--- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/scripts/portstat b/scripts/portstat index 39716e9217..47abc699c8 100644 --- a/scripts/portstat +++ b/scripts/portstat @@ -7,28 +7,23 @@ ##################################################################### import argparse -from ast import NodeTransformer - import cPickle as pickle import datetime import os.path -import swsssdk import sys import time +from collections import OrderedDict, namedtuple + -from collections import namedtuple, OrderedDict from natsort import natsorted from tabulate import tabulate +from sonic_py_common import multi_asic -from sonic_py_common.multi_asic_device_info import connect_to_all_dbs_for_ns -from utilities_common.constants import DISPLAY_EXTERNAL -from utilities_common.constants import DISPLAY_ALL -from utilities_common.constants import PORT_OBJ -from utilities_common.netstat import ns_diff, ns_brate, ns_prate, ns_util, table_as_json +from utilities_common import constants from utilities_common.intf_filter import parse_interface_in_filter -from utilities_common.multi_asic import MultiAsic -from utilities_common.multi_asic import run_on_all_asics - +import utilities_common.multi_asic as multi_asic_util +from utilities_common.netstat import (ns_brate, ns_diff, ns_prate, ns_util, + table_as_json) PORT_RATE = 40 @@ -76,7 +71,7 @@ PORT_STATE_DISABLED = 'X' class Portstat(object): def __init__(self, namespace, display_option): self.db = None - self.multi_asic = MultiAsic(display_option, namespace) + self.multi_asic = multi_asic_util.MultiAsic(display_option, namespace) def get_cnstat_dict(self): self.cnstat_dict = OrderedDict() @@ -84,7 +79,7 @@ class Portstat(object): self.collect_stat() return self.cnstat_dict - @run_on_all_asics + @multi_asic_util.run_on_multi_asic def collect_stat(self): """ Collect the statisitics from all the asics present on the @@ -119,7 +114,7 @@ class Portstat(object): return cnstat_dict for port in natsorted(counter_port_name_map): port_name = port.split(":")[0] - if self.multi_asic.skip_display(PORT_OBJ, port_name): + if self.multi_asic.skip_display(constants.PORT_OBJ, port_name): continue cnstat_dict[port] = get_counters(counter_port_name_map[port]) @@ -133,7 +128,7 @@ class Portstat(object): full_table_id = PORT_STATUS_TABLE_PREFIX + port_name speed = PORT_RATE for ns in self.multi_asic.get_ns_list_based_on_options(): - self.db = connect_to_all_dbs_for_ns(ns) + self.db = multi_asic.connect_to_all_dbs_for_ns(ns) speed = self.db.get(self.db.APPL_DB, full_table_id, PORT_SPEED_FIELD) if speed is not None: return int(speed)//1000 @@ -145,7 +140,7 @@ class Portstat(object): """ full_table_id = PORT_STATUS_TABLE_PREFIX + port_name for ns in self.multi_asic.get_ns_list_based_on_options(): - self.db = connect_to_all_dbs_for_ns(ns) + self.db = multi_asic.connect_to_all_dbs_for_ns(ns) admin_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_ADMIN_STATUS_FIELD) oper_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_OPER_STATUS_FIELD) @@ -345,7 +340,7 @@ Examples: parser.add_argument('-t', '--tag', type=str, help='Save stats with name TAG', default=None) parser.add_argument('-p', '--period', type=int, help='Display stats over a specified period (in seconds).', default=0) parser.add_argument('-i', '--interface', type=str, help='Display stats for interface lists.', default=None) - parser.add_argument('-s','--show', default=DISPLAY_EXTERNAL, help='Display all interfaces or only external interfaces') + parser.add_argument('-s','--show', default=constants.DISPLAY_EXTERNAL, help='Display all interfaces or only external interfaces') parser.add_argument('-n','--namespace', default=None, help='Display interfaces for specific namespace') args = parser.parse_args() @@ -401,7 +396,7 @@ Examples: # for all ports(Internal and External) if save_fresh_stats: namespace = None - display_option = DISPLAY_ALL + display_option = constants.DISPLAY_ALL portstat = Portstat(namespace, display_option) cnstat_dict = portstat.get_cnstat_dict() diff --git a/show/interfaces/__init__.py b/show/interfaces/__init__.py index b2d1c17936..14b824d17c 100644 --- a/show/interfaces/__init__.py +++ b/show/interfaces/__init__.py @@ -5,6 +5,7 @@ from tabulate import tabulate import utilities_common.cli as clicommon +import utilities_common.multi_asic as multi_asic_util import portchannel def try_convert_interfacename_from_alias(ctx, db, interfacename): @@ -330,9 +331,10 @@ def presence(db, interfacename, verbose): @click.option('-a', '--printall', is_flag=True) @click.option('-p', '--period') @click.option('-i', '--interface') +@multi_asic_util.multi_asic_click_options @click.option('--verbose', is_flag=True, help="Enable verbose output") @click.pass_context -def counters(ctx, verbose, period, interface, printall): +def counters(ctx, verbose, period, interface, printall, namespace, display): """Show interface counters""" if ctx.invoked_subcommand is None: @@ -344,29 +346,43 @@ def counters(ctx, verbose, period, interface, printall): cmd += " -p {}".format(period) if interface is not None: cmd += " -i {}".format(interface) + else: + cmd += " -s {}".format(display) + if namespace is not None: + cmd += " -n {}".format(namespace) clicommon.run_command(cmd, display_cmd=verbose) # 'errors' subcommand ("show interfaces counters errors") @counters.command() @click.option('-p', '--period') +@multi_asic_util.multi_asic_click_options @click.option('--verbose', is_flag=True, help="Enable verbose output") -def errors(verbose, period): +def errors(verbose, period, namespace, display): """Show interface counters errors""" cmd = "portstat -e" if period is not None: cmd += " -p {}".format(period) + + cmd += " -s {}".format(display) + if namespace is not None: + cmd += " -n {}".format(namespace) + clicommon.run_command(cmd, display_cmd=verbose) # 'rates' subcommand ("show interfaces counters rates") @counters.command() @click.option('-p', '--period') +@multi_asic_util.multi_asic_click_options @click.option('--verbose', is_flag=True, help="Enable verbose output") -def rates(verbose, period): +def rates(verbose, period, namespace, display): """Show interface counters rates""" cmd = "portstat -R" if period is not None: cmd += " -p {}".format(period) + cmd += " -s {}".format(display) + if namespace is not None: + cmd += " -n {}".format(namespace) clicommon.run_command(cmd, display_cmd=verbose) # 'counters' subcommand ("show interfaces counters rif") From 0e18118c15f7e3bc63059bc021b4caaa2a826cf9 Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Fri, 21 Aug 2020 18:10:11 -0700 Subject: [PATCH 3/5] sort imports Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- show/main.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/show/main.py b/show/main.py index 41179dafe8..147554259a 100755 --- a/show/main.py +++ b/show/main.py @@ -1,29 +1,28 @@ #! /usr/bin/python -u +import ipaddress import json -import netaddr -import netifaces import os import re import subprocess import sys -import ipaddress +import netifaces +from pkg_resources import parse_version import click + +import feature +import interfaces +import mlnx +import netaddr +import vlan from natsort import natsorted -from pkg_resources import parse_version from sonic_py_common import device_info -from swsssdk import ConfigDBConnector -from swsssdk import SonicV2Connector +from swsssdk import ConfigDBConnector, SonicV2Connector from tabulate import tabulate -from utilities_common.db import Db import utilities_common.cli as clicommon - -import mlnx +from utilities_common.db import Db from utilities_common.multi_asic import multi_asic_click_options -import feature -import interfaces -import vlan # Global Variables PLATFORM_JSON = 'platform.json' From 17cdd635bbe7cb0cfe4c6be7f5885b75d801d295 Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Thu, 27 Aug 2020 23:48:09 -0700 Subject: [PATCH 4/5] Add Unit Tests Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- scripts/portstat | 16 +- tests/mock_tables/asic0/counters_db.json | 24 ++ tests/mock_tables/asic1/counters_db.json | 198 +++++++++++ tests/mock_tables/counters_db.json | 18 + tests/pfcstat_test.py | 53 ++- tests/portstat_test.py | 400 +++++++++++++++++++++++ 6 files changed, 693 insertions(+), 16 deletions(-) mode change 100644 => 100755 scripts/portstat create mode 100644 tests/mock_tables/asic1/counters_db.json create mode 100644 tests/portstat_test.py diff --git a/scripts/portstat b/scripts/portstat old mode 100644 new mode 100755 index 47abc699c8..1fe00af2cc --- a/scripts/portstat +++ b/scripts/portstat @@ -25,6 +25,21 @@ import utilities_common.multi_asic as multi_asic_util from utilities_common.netstat import (ns_brate, ns_diff, ns_prate, ns_util, table_as_json) +# mock the redis for unit test purposes # +try: + if os.environ["UTILITIES_UNIT_TESTING"] == "2": + modules_path = os.path.join(os.path.dirname(__file__), "..") + tests_path = os.path.join(modules_path, "tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, tests_path) + import mock_tables.dbconnector + if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic": + import mock_tables.mock_multi_asic + mock_tables.dbconnector.load_namespace_config() + +except KeyError: + pass + PORT_RATE = 40 NStats = namedtuple("NStats", "rx_ok, rx_err, rx_drop, rx_ovr, tx_ok,\ @@ -117,7 +132,6 @@ class Portstat(object): if self.multi_asic.skip_display(constants.PORT_OBJ, port_name): continue cnstat_dict[port] = get_counters(counter_port_name_map[port]) - return cnstat_dict def get_port_speed(self, port_name): diff --git a/tests/mock_tables/asic0/counters_db.json b/tests/mock_tables/asic0/counters_db.json index 38d5e445d7..307c8a2337 100644 --- a/tests/mock_tables/asic0/counters_db.json +++ b/tests/mock_tables/asic0/counters_db.json @@ -120,6 +120,12 @@ "Packets": "1001" }, "COUNTERS:oid:0x1000000000002": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "8", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "800", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "10", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "1000", "SAI_PORT_STAT_IF_IN_ERRORS": "10", "SAI_PORT_STAT_IF_IN_DISCARDS": "100", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80", @@ -142,6 +148,12 @@ "SAI_PORT_STAT_PFC_7_TX_PKTS": "207" }, "COUNTERS:oid:0x1000000000004": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "4", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "400", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "40", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "4000", "SAI_PORT_STAT_IF_IN_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", @@ -164,6 +176,12 @@ "SAI_PORT_STAT_PFC_7_TX_PKTS": "407" }, "COUNTERS:oid:0x1000000000006": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "6", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "600", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "60", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "6000", "SAI_PORT_STAT_IF_IN_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", @@ -186,6 +204,12 @@ "SAI_PORT_STAT_PFC_7_TX_PKTS": "607" }, "COUNTERS:oid:0x1000000000008": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "8", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "800", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "80", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "8000", "SAI_PORT_STAT_IF_IN_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", diff --git a/tests/mock_tables/asic1/counters_db.json b/tests/mock_tables/asic1/counters_db.json new file mode 100644 index 0000000000..1fed0f6f1e --- /dev/null +++ b/tests/mock_tables/asic1/counters_db.json @@ -0,0 +1,198 @@ +{ + "COUNTERS:oid:0x60000000005a3": { + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0" + }, + "COUNTERS:oid:0x60000000005a1": { + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_OCTETS": "608985", + "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS": "883", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0" + }, + "COUNTERS:oid:0x600000000065f": { + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_OCTETS": "1128", + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS": "2", + "SAI_ROUTER_INTERFACE_STAT_IN_OCTETS": "3", + "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS": "4", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS": "5", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "6", + "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "754", + "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "8" + }, + "COUNTERS:oid:0x60000000005a2": { + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_OCTETS": "608985", + "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS": "883", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0" + }, + "COUNTERS:oid:0x600000000063c": { + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0" + }, + "COUNTERS:oid:0x600000000063d": { + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_IN_OCTETS": "608985", + "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS": "883", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", + "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0" + }, + "COUNTERS_RIF_NAME_MAP": { + "Ethernet20": "oid:0x600000000065f", + "PortChannel0001": "oid:0x60000000005a1", + "PortChannel0002": "oid:0x60000000005a2", + "PortChannel0003": "oid:0x600000000063c", + "PortChannel0004": "oid:0x600000000063d", + "Vlan1000": "oid:0x60000000005a3" + }, + "COUNTERS_RIF_TYPE_MAP": { + "oid:0x60000000005a1": "SAI_ROUTER_INTERFACE_TYPE_PORT", + "oid:0x60000000005a2": "SAI_ROUTER_INTERFACE_TYPE_PORT", + "oid:0x60000000005a3": "SAI_ROUTER_INTERFACE_TYPE_VLAN", + "oid:0x600000000063c": "SAI_ROUTER_INTERFACE_TYPE_PORT", + "oid:0x600000000063d": "SAI_ROUTER_INTERFACE_TYPE_PORT", + "oid:0x600000000065f": "SAI_ROUTER_INTERFACE_TYPE_PORT" + }, + "COUNTERS:DATAACL:DEFAULT_RULE": { + "Bytes": "1", + "Packets": "2" + }, + "COUNTERS:DATAACL:RULE_1": { + "Bytes": "100", + "Packets": "101" + }, + "COUNTERS:DATAACL:RULE_2": { + "Bytes": "200", + "Packets": "201" + }, + "COUNTERS:DATAACL:RULE_3": { + "Bytes": "300", + "Packets": "301" + }, + "COUNTERS:DATAACL:RULE_4": { + "Bytes": "400", + "Packets": "401" + }, + "COUNTERS:DATAACL:RULE_05": { + "Bytes": "0", + "Packets": "0" + }, + "COUNTERS:EVERFLOW:RULE_6": { + "Bytes": "600", + "Packets": "601" + }, + "COUNTERS:DATAACL:RULE_7":{ + "Bytes": "700", + "Packets": "701" + }, + "COUNTERS:EVERFLOW:RULE_08": { + "Bytes": "0", + "Packets": "0" + }, + "COUNTERS:DATAACL:RULE_9": { + "Bytes": "900", + "Packets": "901" + }, + "COUNTERS:DATAACL:RULE_10": { + "Bytes": "1000", + "Packets": "1001" + }, + "COUNTERS:oid:0x1000000000002": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "8", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "800", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "10", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "1000", + "SAI_PORT_STAT_IF_IN_ERRORS": "10", + "SAI_PORT_STAT_IF_IN_DISCARDS": "100", + "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80", + "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20", + "SAI_PORT_STAT_PFC_0_RX_PKTS": "20", + "SAI_PORT_STAT_PFC_1_RX_PKTS": "21", + "SAI_PORT_STAT_PFC_2_RX_PKTS": "22", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "23", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "24", + "SAI_PORT_STAT_PFC_5_RX_PKTS": "25", + "SAI_PORT_STAT_PFC_6_RX_PKTS": "26", + "SAI_PORT_STAT_PFC_7_RX_PKTS": "27", + "SAI_PORT_STAT_PFC_0_TX_PKTS": "400", + "SAI_PORT_STAT_PFC_1_TX_PKTS": "201", + "SAI_PORT_STAT_PFC_2_TX_PKTS": "202", + "SAI_PORT_STAT_PFC_3_TX_PKTS": "203", + "SAI_PORT_STAT_PFC_4_TX_PKTS": "204", + "SAI_PORT_STAT_PFC_5_TX_PKTS": "205", + "SAI_PORT_STAT_PFC_6_TX_PKTS": "206", + "SAI_PORT_STAT_PFC_7_TX_PKTS": "207" + }, + "COUNTERS:oid:0x1000000000004": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "4", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "400", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "40", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "4000", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", + "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", + "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100", + "SAI_PORT_STAT_PFC_0_RX_PKTS": "40", + "SAI_PORT_STAT_PFC_1_RX_PKTS": "41", + "SAI_PORT_STAT_PFC_2_RX_PKTS": "42", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "43", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "44", + "SAI_PORT_STAT_PFC_5_RX_PKTS": "45", + "SAI_PORT_STAT_PFC_6_RX_PKTS": "46", + "SAI_PORT_STAT_PFC_7_RX_PKTS": "47", + "SAI_PORT_STAT_PFC_0_TX_PKTS": "400", + "SAI_PORT_STAT_PFC_1_TX_PKTS": "401", + "SAI_PORT_STAT_PFC_2_TX_PKTS": "402", + "SAI_PORT_STAT_PFC_3_TX_PKTS": "403", + "SAI_PORT_STAT_PFC_4_TX_PKTS": "404", + "SAI_PORT_STAT_PFC_5_TX_PKTS": "405", + "SAI_PORT_STAT_PFC_6_TX_PKTS": "406", + "SAI_PORT_STAT_PFC_7_TX_PKTS": "407" + }, + "COUNTERS:oid:0x21000000000000": { + "SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000" + }, + "COUNTERS_PORT_NAME_MAP": { + "Ethernet-BP256": "oid:0x1000000000002", + "Ethernet-BP260": "oid:0x1000000000004" + }, + "COUNTERS_LAG_NAME_MAP": { + "PortChannel0001": "oid:0x60000000005a1", + "PortChannel0002": "oid:0x60000000005a2", + "PortChannel0003": "oid:0x600000000063c", + "PortChannel0004": "oid:0x600000000063d" + }, + "COUNTERS_DEBUG_NAME_PORT_STAT_MAP": { + "DEBUG_0": "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE", + "DEBUG_2": "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS" + }, + "COUNTERS_DEBUG_NAME_SWITCH_STAT_MAP": { + "DEBUG_1": "SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE" + } +} diff --git a/tests/mock_tables/counters_db.json b/tests/mock_tables/counters_db.json index 6468f74ded..2f28b344c5 100644 --- a/tests/mock_tables/counters_db.json +++ b/tests/mock_tables/counters_db.json @@ -120,6 +120,12 @@ "Packets": "1001" }, "COUNTERS:oid:0x1000000000002": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "8", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "800", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "10", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "1000", "SAI_PORT_STAT_IF_IN_ERRORS": "10", "SAI_PORT_STAT_IF_IN_DISCARDS": "100", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80", @@ -142,6 +148,12 @@ "SAI_PORT_STAT_PFC_7_TX_PKTS": "0" }, "COUNTERS:oid:0x1000000000004": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "4", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "400", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "40", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "4000", "SAI_PORT_STAT_IF_IN_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", @@ -164,6 +176,12 @@ "SAI_PORT_STAT_PFC_7_TX_PKTS": "407" }, "COUNTERS:oid:0x1000000000006": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "6", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "600", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "60", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "6000", "SAI_PORT_STAT_IF_IN_ERRORS": "100", "SAI_PORT_STAT_IF_IN_DISCARDS": "10", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "10", diff --git a/tests/pfcstat_test.py b/tests/pfcstat_test.py index ee5abc724d..943ad09f43 100644 --- a/tests/pfcstat_test.py +++ b/tests/pfcstat_test.py @@ -41,7 +41,7 @@ Ethernet8 0 0 0 0 0 0 0 0 """ -show_pfc_counters_all = """\ +show_pfc_counters_asic_all = """\ Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 ------------ ------ ------ ------ ------ ------ ------ ------ ------ Ethernet0 400 201 202 203 204 205 206 207 @@ -56,6 +56,25 @@ Ethernet-BP0 600 601 602 603 604 605 606 607 Ethernet-BP4 800 801 802 803 804 805 806 807 """ +show_pfc_counters_all = """\ + Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 +-------------- ------ ------ ------ ------ ------ ------ ------ ------ + Ethernet0 400 201 202 203 204 205 206 207 + Ethernet4 400 401 402 403 404 405 406 407 + Ethernet-BP0 600 601 602 603 604 605 606 607 + Ethernet-BP4 800 801 802 803 804 805 806 807 +Ethernet-BP256 400 201 202 203 204 205 206 207 +Ethernet-BP260 400 401 402 403 404 405 406 407 + + Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 +-------------- ------ ------ ------ ------ ------ ------ ------ ------ + Ethernet0 400 201 202 203 204 205 206 207 + Ethernet4 400 401 402 403 404 405 406 407 + Ethernet-BP0 600 601 602 603 604 605 606 607 + Ethernet-BP4 800 801 802 803 804 805 806 807 +Ethernet-BP256 400 201 202 203 204 205 206 207 +Ethernet-BP260 400 401 402 403 404 405 406 407 +""" show_pfc_counters_asic0_frontend = """\ Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 @@ -70,19 +89,23 @@ """ show_pfc_counters_msaic_output_diff = """\ - Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 ------------- ------ ------ ------ ------ ------ ------ ------ ------ - Ethernet0 0 0 0 0 0 0 0 0 - Ethernet4 0 0 0 0 0 0 0 0 -Ethernet-BP0 0 0 0 0 0 0 0 0 -Ethernet-BP4 0 0 0 0 0 0 0 0 - - Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 ------------- ------ ------ ------ ------ ------ ------ ------ ------ - Ethernet0 0 0 0 0 0 0 0 0 - Ethernet4 0 0 0 0 0 0 0 0 -Ethernet-BP0 0 0 0 0 0 0 0 0 -Ethernet-BP4 0 0 0 0 0 0 0 0 + Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 +-------------- ------ ------ ------ ------ ------ ------ ------ ------ + Ethernet0 0 0 0 0 0 0 0 0 + Ethernet4 0 0 0 0 0 0 0 0 + Ethernet-BP0 0 0 0 0 0 0 0 0 + Ethernet-BP4 0 0 0 0 0 0 0 0 +Ethernet-BP256 0 0 0 0 0 0 0 0 +Ethernet-BP260 0 0 0 0 0 0 0 0 + + Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7 +-------------- ------ ------ ------ ------ ------ ------ ------ ------ + Ethernet0 0 0 0 0 0 0 0 0 + Ethernet4 0 0 0 0 0 0 0 0 + Ethernet-BP0 0 0 0 0 0 0 0 0 + Ethernet-BP4 0 0 0 0 0 0 0 0 +Ethernet-BP256 0 0 0 0 0 0 0 0 +Ethernet-BP260 0 0 0 0 0 0 0 0 """ @@ -182,7 +205,7 @@ def test_pfc_counters_asic_all(self): 'pfcstat -n asic0 -s all' ) assert return_code == 0 - assert result == show_pfc_counters_all + assert result == show_pfc_counters_asic_all def test_pfc_clear(self): pfc_clear(show_pfc_counters_msaic_output_diff) diff --git a/tests/portstat_test.py b/tests/portstat_test.py new file mode 100644 index 0000000000..e39b542f74 --- /dev/null +++ b/tests/portstat_test.py @@ -0,0 +1,400 @@ +import os +import shutil + +from click.testing import CliRunner + +import clear.main as clear +import show.main as show +from utils import get_result_and_return_code + +root_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(root_path) +scripts_path = os.path.join(modules_path, "scripts") + +intf_counters_before_clear = """\ + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- +Ethernet0 D 8 N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A +Ethernet4 N/A 4 N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A +Ethernet8 N/A 6 N/A N/A 100 10 N/A 60 N/A N/A N/A N/A N/A +""" + +intf_counters_ethernet4 = """\ + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- +Ethernet4 N/A 4 N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A +""" + +intf_counters_all = """\ + IFACE STATE RX_OK RX_BPS RX_PPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS Tx_PPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- -------- --------- -------- -------- -------- ------- -------- -------- --------- -------- -------- -------- +Ethernet0 D 8 N/A N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A N/A +Ethernet4 N/A 4 N/A N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A N/A +Ethernet8 N/A 6 N/A N/A N/A 100 10 N/A 60 N/A N/A N/A N/A N/A N/A +""" + +intf_counters_period = """\ +The rates are calculated within 3 seconds period + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- +Ethernet0 D 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet4 N/A 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet8 N/A 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +""" + +intf_counter_after_clear = """\ + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- +Ethernet0 D 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet4 N/A 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet8 N/A 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A""" + +clear_counter = """\ +Cleared counters""" + +multi_asic_external_intf_counters = """\ + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- +Ethernet0 U 8 N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A +Ethernet4 U 4 N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A +""" + +multi_asic_all_intf_counters = """\ + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +-------------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- + Ethernet0 U 8 N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A + Ethernet4 U 4 N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A + Ethernet-BP0 U 6 N/A N/A 0 1000 N/A 60 N/A N/A N/A N/A N/A + Ethernet-BP4 U 8 N/A N/A 0 1000 N/A 80 N/A N/A N/A N/A N/A +Ethernet-BP256 U 8 N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A +Ethernet-BP260 U 4 N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A +""" +multi_asic_intf_counters_asic0 = """\ + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +------------ ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- + Ethernet0 U 8 N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A + Ethernet4 U 4 N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A +Ethernet-BP0 U 6 N/A N/A 0 1000 N/A 60 N/A N/A N/A N/A N/A +Ethernet-BP4 U 8 N/A N/A 0 1000 N/A 80 N/A N/A N/A N/A N/A +""" + +multi_asic_external_intf_counters_printall = """\ + IFACE STATE RX_OK RX_BPS RX_PPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS Tx_PPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- -------- --------- -------- -------- -------- ------- -------- -------- --------- -------- -------- -------- +Ethernet0 U 8 N/A N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A N/A +Ethernet4 U 4 N/A N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A N/A +""" + +multi_asic_intf_counters_printall = """\ + IFACE STATE RX_OK RX_BPS RX_PPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS Tx_PPS TX_UTIL TX_ERR TX_DRP TX_OVR +-------------- ------- ------- -------- -------- --------- -------- -------- -------- ------- -------- -------- --------- -------- -------- -------- + Ethernet0 U 8 N/A N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A N/A + Ethernet4 U 4 N/A N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A N/A + Ethernet-BP0 U 6 N/A N/A N/A 0 1000 N/A 60 N/A N/A N/A N/A N/A N/A + Ethernet-BP4 U 8 N/A N/A N/A 0 1000 N/A 80 N/A N/A N/A N/A N/A N/A +Ethernet-BP256 U 8 N/A N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A N/A +Ethernet-BP260 U 4 N/A N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A N/A +""" + +multi_asic_intf_counters_asic0_printall = """\ + IFACE STATE RX_OK RX_BPS RX_PPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS Tx_PPS TX_UTIL TX_ERR TX_DRP TX_OVR +------------ ------- ------- -------- -------- --------- -------- -------- -------- ------- -------- -------- --------- -------- -------- -------- + Ethernet0 U 8 N/A N/A N/A 10 100 N/A 10 N/A N/A N/A N/A N/A N/A + Ethernet4 U 4 N/A N/A N/A 0 1000 N/A 40 N/A N/A N/A N/A N/A N/A +Ethernet-BP0 U 6 N/A N/A N/A 0 1000 N/A 60 N/A N/A N/A N/A N/A N/A +Ethernet-BP4 U 8 N/A N/A N/A 0 1000 N/A 80 N/A N/A N/A N/A N/A N/A +""" +multi_asic_intf_counters_period = """\ +The rates are calculated within 3 seconds period + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +--------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- +Ethernet0 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +""" + +multi_asic_intf_counters_period_all = """\ +The rates are calculated within 3 seconds period + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +-------------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- + Ethernet0 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A + Ethernet4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A + Ethernet-BP0 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A + Ethernet-BP4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP256 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP260 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +""" + +multi_asic_intf_counter_period_asic_all = """\ +The rates are calculated within 3 seconds period + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +------------ ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- + Ethernet0 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A + Ethernet4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP0 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +""" + +mutli_asic_intf_counters_after_clear = """\ + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR +-------------- ------- ------- -------- --------- -------- -------- -------- ------- -------- --------- -------- -------- -------- + Ethernet0 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A + Ethernet4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A + Ethernet-BP0 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A + Ethernet-BP4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP256 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP260 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% N/A N/A N/A""" + +intf_invalid_asic_error = """ValueError: Unknown Namespace asic99""" + +TEST_PERIOD = 3 + + +def remove_tmp_cnstat_file(): + # remove the tmp portstat + uid = str(os.getuid()) + cnstat_dir = os.path.join(os.sep, "tmp", "portstat-{}".format(uid)) + shutil.rmtree(cnstat_dir, ignore_errors=True, onerror=None) + + +def verify_after_clear(output, expected_out): + lines = output.splitlines() + assert lines[0].startswith('Last cached time was') == True + # ignore the first line as it has time stamp and is diffcult to compare + new_output = '\n'.join(lines[1:]) + assert new_output == expected_out + + +class TestPortStat(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "2" + remove_tmp_cnstat_file() + + def test_show_intf_counters(self): + runner = CliRunner() + result = runner.invoke( + show.cli.commands["interfaces"].commands["counters"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == intf_counters_before_clear + + return_code, result = get_result_and_return_code('portstat') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == intf_counters_before_clear + + def test_show_intf_counters_ethernet4(self): + runner = CliRunner() + result = runner.invoke( + show.cli.commands["interfaces"].commands["counters"], ["-i Ethernet4"]) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == intf_counters_ethernet4 + + return_code, result = get_result_and_return_code( + 'portstat -i Ethernet4') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == intf_counters_ethernet4 + + def test_show_intf_counters_all(self): + runner = CliRunner() + result = runner.invoke( + show.cli.commands["interfaces"].commands["counters"], ["--printall"]) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == intf_counters_all + + return_code, result = get_result_and_return_code('portstat -a') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == intf_counters_all + + def test_show_intf_counters_period(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["counters"], [ + "-p {}".format(TEST_PERIOD)]) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == intf_counters_period + + return_code, result = get_result_and_return_code( + 'portstat -p {}'.format(TEST_PERIOD)) + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == intf_counters_period + + def test_clear_intf_counters(self): + runner = CliRunner() + result = runner.invoke(clear.cli.commands["counters"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output.rstrip() == clear_counter + + return_code, result = get_result_and_return_code('portstat -c') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result.rstrip() == clear_counter + + # check counters after clear + result = runner.invoke( + show.cli.commands["interfaces"].commands["counters"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + verify_after_clear(result.output, intf_counter_after_clear) + + return_code, result = get_result_and_return_code('portstat') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + verify_after_clear(result, intf_counter_after_clear) + + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join( + os.environ["PATH"].split(os.pathsep)[:-1]) + os.environ["UTILITIES_UNIT_TESTING"] = "0" + remove_tmp_cnstat_file() + + +class TestMultiAsicPortStat(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "2" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" + remove_tmp_cnstat_file() + + def test_multi_show_intf_counters(self): + return_code, result = get_result_and_return_code('portstat') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_external_intf_counters + + def test_multi_show_intf_counters_all(self): + return_code, result = get_result_and_return_code('portstat -s all') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_all_intf_counters + + def test_multi_show_intf_counters_asic(self): + return_code, result = get_result_and_return_code('portstat -n asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_external_intf_counters + + def test_multi_show_intf_counters_asic_all(self): + return_code, result = get_result_and_return_code( + 'portstat -n asic0 -s all') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_intf_counters_asic0 + + def test_multi_show_external_intf_counters_printall(self): + return_code, result = get_result_and_return_code('portstat -a') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_external_intf_counters_printall + + def test_multi_show_intf_counters_printall(self): + return_code, result = get_result_and_return_code('portstat -a -s all') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_intf_counters_printall + + def test_multi_show_intf_counters_printall_asic(self): + return_code, result = get_result_and_return_code( + 'portstat --a -n asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_external_intf_counters_printall + + def test_multi_show_intf_counters_printall_asic_all(self): + return_code, result = get_result_and_return_code( + 'portstat -a -n asic0 -s all') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_intf_counters_asic0_printall + + def test_multi_show_intf_counters_period(self): + return_code, result = get_result_and_return_code( + 'portstat -p {}'.format(TEST_PERIOD)) + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_intf_counters_period + + def test_multi_show_intf_counters_period_all(self): + return_code, result = get_result_and_return_code( + 'portstat -p {} -s all'.format(TEST_PERIOD)) + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_intf_counters_period_all + + def test_multi_show_intf_counters_period_asic(self): + return_code, result = get_result_and_return_code( + 'portstat -p {} -n asic0'.format(TEST_PERIOD)) + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_intf_counters_period + + def test_multi_show_intf_counters_period_asic_all(self): + return_code, result = get_result_and_return_code( + 'portstat -p {} -n asic0 -s all'.format(TEST_PERIOD)) + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == multi_asic_intf_counter_period_asic_all + + def test_multi_asic_clear_intf_counters(self): + return_code, result = get_result_and_return_code('portstat -c') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result.rstrip() == clear_counter + + # check stats for all the interfaces are cleared + return_code, result = get_result_and_return_code('portstat -s all') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + verify_after_clear(result, mutli_asic_intf_counters_after_clear) + + def test_multi_asic_invalid_asic(self): + return_code, result = get_result_and_return_code('portstat -n asic99') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 1 + assert result == intf_invalid_asic_error + + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join( + os.environ["PATH"].split(os.pathsep)[:-1]) + os.environ["UTILITIES_UNIT_TESTING"] = "0" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" + remove_tmp_cnstat_file() From c68d38e36bead557048e947a2b12710428d1cd51 Mon Sep 17 00:00:00 2001 From: Arvindsrinivasan Lakshmi Narasimhan Date: Tue, 1 Sep 2020 13:55:15 -0700 Subject: [PATCH 5/5] fix lgtm warning Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan --- show/main.py | 15 +++------------ tests/portstat_test.py | 2 ++ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/show/main.py b/show/main.py index 4ed395127f..55999afc6d 100755 --- a/show/main.py +++ b/show/main.py @@ -1,34 +1,25 @@ #! /usr/bin/python -u -import ipaddress import json import os -import re import subprocess import sys +import click +from natsort import natsorted import netifaces from pkg_resources import parse_version -import click -from sonic_py_common import device_info -from swsssdk import ConfigDBConnector -from swsssdk import SonicV2Connector -from tabulate import tabulate -import utilities_common.cli as clicommon -from utilities_common.db import Db -from utilities_common.multi_asic import multi_asic_click_options import feature import interfaces import kube import mlnx +import utilities_common.cli as clicommon import vlan -from natsort import natsorted from sonic_py_common import device_info from swsssdk import ConfigDBConnector, SonicV2Connector from tabulate import tabulate -import utilities_common.cli as clicommon from utilities_common.db import Db from utilities_common.multi_asic import multi_asic_click_options diff --git a/tests/portstat_test.py b/tests/portstat_test.py index e39b542f74..487cdca1bc 100644 --- a/tests/portstat_test.py +++ b/tests/portstat_test.py @@ -262,6 +262,7 @@ def test_clear_intf_counters(self): assert return_code == 0 verify_after_clear(result, intf_counter_after_clear) + @classmethod def teardown_class(cls): print("TEARDOWN") os.environ["PATH"] = os.pathsep.join( @@ -391,6 +392,7 @@ def test_multi_asic_invalid_asic(self): assert return_code == 1 assert result == intf_invalid_asic_error + @classmethod def teardown_class(cls): print("TEARDOWN") os.environ["PATH"] = os.pathsep.join(