From bf2ff3cf10e9f65df84f1a88fc581ac2e8fbd33f Mon Sep 17 00:00:00 2001 From: Vadym Hlushko <62022266+vadymhlushko-mlnx@users.noreply.github.com> Date: Wed, 8 Sep 2021 14:06:07 +0300 Subject: [PATCH] [portstat, intfstat] added rates and utilization (#1750) #### What I did Depends on [sonic-swss-common/pull/330](https://github.com/Azure/sonic-swss-common/pull/330) According to [HLD](https://github.com/Azure/SONiC/blob/master/doc/rates-and-utilization/Rates_and_utilization_HLD.md) added calculation of rates and utilization columns to the `portstat` and `intfstat` scripts output #### How I did it Modified the `portstat` and `intfstat` scripts #### How to verify it Added UT #### Previous command output (if the output of a command-line utility has changed) ``` admin@sonic:~$ show int count 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 X 0 N/A N/A 0 0 N/A 0 N/A N/A 0 0 N/A Ethernet2 U 287 N/A N/A 0 0 N/A 818 N/A N/A 0 0 N/A Ethernet4 U 380 N/A N/A 0 0 N/A 858 N/A N/A 0 0 N/A Ethernet6 U 286 N/A N/A 0 0 N/A 850 N/A N/A 0 0 N/A ``` #### New command output (if the output of a command-line utility has changed) ``` admin@sonic:~$ show int count 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 X 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% 0 0 N/A Ethernet2 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% 0 0 N/A Ethernet4 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% 0 0 N/A Ethernet6 U 0 0.00 B/s 0.00% 0 0 N/A 0 0.00 B/s 0.00% 0 0 N/A ``` --- config/main.py | 28 +++ scripts/intfstat | 136 ++++++++------- scripts/portstat | 209 +++++++++++++++-------- tests/intfstat_test.py | 183 +++++++++++++------- tests/mock_tables/asic0/counters_db.json | 24 +++ tests/mock_tables/asic1/counters_db.json | 12 ++ tests/mock_tables/asic2/counters_db.json | 24 +++ tests/mock_tables/counters_db.json | 56 +++++- tests/portstat_test.py | 100 +++++------ utilities_common/netstat.py | 39 +++++ 10 files changed, 563 insertions(+), 248 deletions(-) diff --git a/config/main.py b/config/main.py index f9002b8def..3f162f344e 100644 --- a/config/main.py +++ b/config/main.py @@ -5764,6 +5764,34 @@ def disable_link_local(ctx): set_ipv6_link_local_only_on_interface(config_db, table_dict, table_type, key, mode) +# +# 'rate' group ('config rate ...') +# + +@config.group() +def rate(): + """Set port rates configuration.""" + pass + + +@rate.command() +@click.argument('interval', metavar='', type=click.IntRange(min=1, max=1000), required=True) +@click.argument('rates_type', type=click.Choice(['all', 'port', 'rif']), default='all') +def smoothing_interval(interval, rates_type): + """Set rates smoothing interval """ + counters_db = swsssdk.SonicV2Connector() + counters_db.connect('COUNTERS_DB') + + alpha = 2.0/(interval + 1) + + if rates_type in ['port', 'all']: + counters_db.set('COUNTERS_DB', 'RATES:PORT', 'PORT_SMOOTH_INTERVAL', interval) + counters_db.set('COUNTERS_DB', 'RATES:PORT', 'PORT_ALPHA', alpha) + if rates_type in ['rif', 'all']: + counters_db.set('COUNTERS_DB', 'RATES:RIF', 'RIF_SMOOTH_INTERVAL', interval) + counters_db.set('COUNTERS_DB', 'RATES:RIF', 'RIF_ALPHA', alpha) + + # Load plugins and register them helper = util_base.UtilHelper() for plugin in helper.load_plugins(plugins): diff --git a/scripts/intfstat b/scripts/intfstat index 99836a04d9..1d5da781b6 100755 --- a/scripts/intfstat +++ b/scripts/intfstat @@ -11,7 +11,6 @@ import argparse import datetime import sys import os -import sys import time # mock the redis for unit test purposes # @@ -28,15 +27,37 @@ except KeyError: from collections import namedtuple, OrderedDict from natsort import natsorted from tabulate import tabulate -from utilities_common.netstat import ns_diff, ns_brate, ns_prate, table_as_json, STATUS_NA +from utilities_common.netstat import ns_diff, table_as_json, STATUS_NA, format_brate, format_prate from swsscommon.swsscommon import SonicV2Connector +nstat_fields = ( + "rx_b_ok", + "rx_p_ok", + "tx_b_ok", + "tx_p_ok", + "rx_b_err", + "rx_p_err", + "tx_b_err", + "tx_p_err" +) + +NStats = namedtuple("NStats", nstat_fields) -NStats = namedtuple("NStats", "rx_b_ok, rx_p_ok, tx_b_ok, tx_p_ok,\ - rx_b_err, rx_p_err, tx_b_err, tx_p_err,") +header = [ + 'IFACE', + 'RX_OK', + 'RX_BPS', + 'RX_PPS', + 'RX_ERR', + 'TX_OK', + 'TX_BPS', + 'TX_PPS', + 'TX_ERR' +] -header = ['IFACE', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_ERR', - 'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_ERR'] +rates_key_list = [ 'RX_BPS', 'RX_PPS', 'TX_BPS', 'TX_PPS'] +ratestat_fields = ("rx_bps", "rx_pps", "tx_bps", "tx_pps") +RateStats = namedtuple("RateStats", ratestat_fields) counter_names = ( 'SAI_ROUTER_INTERFACE_STAT_IN_OCTETS', @@ -49,18 +70,10 @@ counter_names = ( 'SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS' ) +RATES_TABLE_PREFIX = "RATES:" COUNTER_TABLE_PREFIX = "COUNTERS:" COUNTERS_RIF_NAME_MAP = "COUNTERS_RIF_NAME_MAP" -COUNTERS_RIF_TYPE_MAP = "COUNTERS_RIF_TYPE_MAP" - -INTERFACE_TABLE_PREFIX = "PORT_TABLE:" -INTF_STATUS_VALUE_UP = 'UP' -INTF_STATUS_VALUE_DOWN = 'DOWN' - -INTF_STATE_UP = 'U' -INTF_STATE_DOWN = 'D' -INTF_STATE_DISABLED = 'X' class Intfstat(object): def __init__(self): @@ -76,7 +89,7 @@ class Intfstat(object): """ Get the counters from specific table. """ - fields = [STATUS_NA] * (len(header) - 1) + fields = [STATUS_NA] * len(nstat_fields) for pos, counter_name in enumerate(counter_names): full_table_id = COUNTER_TABLE_PREFIX + table_id counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, counter_name) @@ -85,13 +98,28 @@ class Intfstat(object): cntr = NStats._make(fields) return cntr + def get_rates(table_id): + """ + Get the rates from specific table. + """ + fields = ["0","0","0","0"] + for pos, name in enumerate(rates_key_list): + full_table_id = RATES_TABLE_PREFIX + table_id + counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, name) + if counter_data is None: + fields[pos] = STATUS_NA + elif fields[pos] != STATUS_NA: + fields[pos] = float(counter_data) + cntr = RateStats._make(fields) + return cntr + # Build a dictionary of the stats cnstat_dict = OrderedDict() cnstat_dict['time'] = datetime.datetime.now() + ratestat_dict = OrderedDict() # Get the info from database - counter_rif_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_RIF_NAME_MAP); - + counter_rif_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_RIF_NAME_MAP) if counter_rif_name_map is None: print("No %s in the DB!" % COUNTERS_RIF_NAME_MAP) @@ -103,31 +131,15 @@ class Intfstat(object): if rif: cnstat_dict[rif] = get_counters(counter_rif_name_map[rif]) - return cnstat_dict + ratestat_dict[rif] = get_rates(counter_rif_name_map[rif]) + return cnstat_dict, ratestat_dict for rif in natsorted(counter_rif_name_map): cnstat_dict[rif] = get_counters(counter_rif_name_map[rif]) - return cnstat_dict - - def get_intf_state(self, port_name): - """ - 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 + ratestat_dict[rif] = get_rates(counter_rif_name_map[rif]) + return cnstat_dict, ratestat_dict - def cnstat_print(self, cnstat_dict, use_json): + def cnstat_print(self, cnstat_dict, ratestat_dict, use_json): """ Print the cnstat. """ @@ -137,8 +149,17 @@ class Intfstat(object): if key == 'time': continue - table.append((key, data.rx_p_ok, STATUS_NA, STATUS_NA, data.rx_p_err, - data.tx_p_ok, STATUS_NA, STATUS_NA, data.tx_p_err)) + rates = ratestat_dict.get(key, RateStats._make([STATUS_NA] * len(rates_key_list))) + + table.append((key, + data.rx_p_ok, + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), + data.rx_p_err, + data.tx_p_ok, + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), + data.tx_p_err)) if use_json: print(table_as_json(table, header)) @@ -146,7 +167,7 @@ class Intfstat(object): else: print(tabulate(table, header, tablefmt='simple', stralign='right')) - def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, use_json): + def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, ratestat_dict, use_json): """ Print the difference between two cnstat results. """ @@ -155,33 +176,34 @@ class Intfstat(object): for key, cntr in cnstat_new_dict.items(): if key == 'time': - time_gap = cnstat_new_dict.get('time') - cnstat_old_dict.get('time') - time_gap = time_gap.total_seconds() continue old_cntr = None if key in cnstat_old_dict: old_cntr = cnstat_old_dict.get(key) + rates = ratestat_dict.get(key, RateStats._make([STATUS_NA] * len(rates_key_list))) + if old_cntr is not None: table.append((key, ns_diff(cntr.rx_p_ok, old_cntr.rx_p_ok), - ns_brate(cntr.rx_b_ok, old_cntr.rx_b_ok, time_gap), - ns_prate(cntr.rx_p_ok, old_cntr.rx_p_ok, time_gap), + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), ns_diff(cntr.rx_p_err, old_cntr.rx_p_err), ns_diff(cntr.tx_p_ok, old_cntr.tx_p_ok), - ns_brate(cntr.tx_b_ok, old_cntr.tx_b_ok, time_gap), - ns_prate(cntr.tx_p_ok, old_cntr.tx_p_ok, time_gap), + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), ns_diff(cntr.tx_p_err, old_cntr.tx_p_err))) else: table.append((key, cntr.rx_p_ok, - STATUS_NA, - STATUS_NA, + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), cntr.rx_p_err, cntr.tx_p_ok, - STATUS_NA, - STATUS_NA, + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), cntr.tx_p_err)) + if use_json: print(table_as_json(table, header)) else: @@ -293,7 +315,7 @@ def main(): sys.exit(0) intfstat = Intfstat() - cnstat_dict = intfstat.get_cnstat(rif=interface_name) + cnstat_dict, ratestat_dict = intfstat.get_cnstat(rif=interface_name) # At this point, either we'll create a file or open an existing one. if not os.path.exists(cnstat_dir): @@ -347,7 +369,7 @@ def main(): if interface_name: intfstat.cnstat_single_interface(interface_name, cnstat_dict, cnstat_cached_dict) else: - intfstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, use_json) + intfstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, ratestat_dict, use_json) except IOError as e: print(e.errno, e) else: @@ -358,16 +380,16 @@ def main(): if interface_name: intfstat.cnstat_single_interface(interface_name, cnstat_dict, None) else: - intfstat.cnstat_print(cnstat_dict, use_json) + intfstat.cnstat_print(cnstat_dict, ratestat_dict, use_json) else: #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 = intfstat.get_cnstat(rif=interface_name) + cnstat_new_dict, ratestat_new_dict = intfstat.get_cnstat(rif=interface_name) if interface_name: intfstat.cnstat_single_interface(interface_name, cnstat_new_dict, cnstat_dict) else: - intfstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, use_json) + intfstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, ratestat_new_dict, use_json) if __name__ == "__main__": main() diff --git a/scripts/portstat b/scripts/portstat index 82d673fea1..ce15fb1ffc 100755 --- a/scripts/portstat +++ b/scripts/portstat @@ -14,7 +14,6 @@ import sys import time from collections import OrderedDict, namedtuple - from natsort import natsorted from tabulate import tabulate from sonic_py_common import multi_asic @@ -36,12 +35,8 @@ except KeyError: from utilities_common import constants from utilities_common.intf_filter import parse_interface_in_filter -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, format_number_with_comma) - - -PORT_RATE = 40 +import utilities_common.multi_asic as multi_asic_util +from utilities_common.netstat import ns_diff, table_as_json, format_brate, format_prate, format_util, format_number_with_comma """ The order and count of statistics mentioned below needs to be in sync with the values in portstat script @@ -55,12 +50,16 @@ NStats = namedtuple("NStats", "rx_ok, rx_err, rx_drop, rx_ovr, tx_ok,\ tx_uca, tx_mca, tx_bca, tx_all,\ rx_jbr, rx_frag, rx_usize, rx_ovrrun") header_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'] + 'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_UTIL', 'TX_ERR', 'TX_DRP', 'TX_OVR'] header_std = ['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'] header_errors_only = ['IFACE', 'STATE', 'RX_ERR', 'RX_DRP', 'RX_OVR', 'TX_ERR', 'TX_DRP', 'TX_OVR'] header_rates_only = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_UTIL'] +rates_key_list = [ 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'TX_BPS', 'TX_PPS', 'TX_UTIL' ] +ratestat_fields = ("rx_bps", "rx_pps", "rx_util", "tx_bps", "tx_pps", "tx_util") +RateStats = namedtuple("RateStats", ratestat_fields) + """ The order and count of statistics mentioned below needs to be in sync with the values in portstat script So, any fields added/deleted in here should be reflected in portstat script also @@ -113,6 +112,8 @@ counter_bucket_dict = { STATUS_NA = 'N/A' +RATES_TABLE_PREFIX = "RATES:" + COUNTER_TABLE_PREFIX = "COUNTERS:" COUNTERS_PORT_NAME_MAP = "COUNTERS_PORT_NAME_MAP" @@ -136,8 +137,9 @@ class Portstat(object): def get_cnstat_dict(self): self.cnstat_dict = OrderedDict() self.cnstat_dict['time'] = datetime.datetime.now() + self.ratestat_dict = OrderedDict() self.collect_stat() - return self.cnstat_dict + return self.cnstat_dict, self.ratestat_dict @multi_asic_util.run_on_multi_asic def collect_stat(self): @@ -145,7 +147,10 @@ class Portstat(object): Collect the statisitics from all the asics present on the device and store in a dict """ - self.cnstat_dict.update(self.get_cnstat()) + + cnstat_dict, ratestat_dict = self.get_cnstat() + self.cnstat_dict.update(cnstat_dict) + self.ratestat_dict.update(ratestat_dict) def get_cnstat(self): """ @@ -169,18 +174,36 @@ class Portstat(object): cntr = NStats._make(fields) return cntr + def get_rates(table_id): + """ + Get the rates from specific table. + """ + fields = ["0","0","0","0","0","0"] + for pos, name in enumerate(rates_key_list): + full_table_id = RATES_TABLE_PREFIX + table_id + counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, name) + if counter_data is None: + fields[pos] = STATUS_NA + elif fields[pos] != STATUS_NA: + fields[pos] = float(counter_data) + cntr = RateStats._make(fields) + return cntr + # Get the info from database 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() + ratestat_dict = OrderedDict() if counter_port_name_map is None: - return cnstat_dict + return cnstat_dict, ratestat_dict for port in natsorted(counter_port_name_map): port_name = port.split(":")[0] 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 + ratestat_dict[port] = get_rates(counter_port_name_map[port]) + return cnstat_dict, ratestat_dict def get_port_speed(self, port_name): """ @@ -192,8 +215,8 @@ class Portstat(object): 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 - return PORT_RATE + return int(speed) + return STATUS_NA def get_port_state(self, port_name): """ @@ -218,7 +241,7 @@ class Portstat(object): return STATUS_NA - def cnstat_print(self, cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail=False): + def cnstat_print(self, cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail=False): """ Print the cnstat. """ @@ -235,16 +258,22 @@ class Portstat(object): continue if intf_list and key not in intf_list: continue + port_speed = self.get_port_speed(key) + rates = ratestat_dict.get(key, RateStats._make([STATUS_NA] * len(rates_key_list))) if print_all: header = header_all table.append((key, self.get_port_state(key), format_number_with_comma(data.rx_ok), - STATUS_NA, STATUS_NA, STATUS_NA, + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), + format_util(rates.rx_bps, port_speed), format_number_with_comma(data.rx_err), format_number_with_comma(data.rx_drop), format_number_with_comma(data.rx_ovr), format_number_with_comma(data.tx_ok), - STATUS_NA, STATUS_NA, STATUS_NA, + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), + format_util(rates.tx_bps, port_speed), format_number_with_comma(data.tx_err), format_number_with_comma(data.tx_drop), format_number_with_comma(data.tx_ovr))) @@ -261,19 +290,25 @@ class Portstat(object): header = header_rates_only table.append((key, self.get_port_state(key), format_number_with_comma(data.rx_ok), - STATUS_NA, STATUS_NA, STATUS_NA, + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), + format_util(rates.rx_bps, port_speed), format_number_with_comma(data.tx_ok), - STATUS_NA, STATUS_NA, STATUS_NA)) + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), + format_util(rates.tx_bps, port_speed))) else: header = header_std table.append((key, self.get_port_state(key), format_number_with_comma(data.rx_ok), - STATUS_NA, STATUS_NA, + format_brate(rates.rx_bps), + format_util(rates.rx_bps, port_speed), format_number_with_comma(data.rx_err), format_number_with_comma(data.rx_drop), format_number_with_comma(data.rx_ovr), format_number_with_comma(data.tx_ok), - STATUS_NA, STATUS_NA, + format_brate(rates.tx_bps), + format_util(rates.tx_bps, port_speed), format_number_with_comma(data.tx_err), format_number_with_comma(data.tx_drop), format_number_with_comma(data.tx_ovr))) @@ -283,7 +318,6 @@ class Portstat(object): else: print(tabulate(table, header, tablefmt='simple', stralign='right')) - def cnstat_intf_diff_print(self, cnstat_new_dict, cnstat_old_dict, intf_list): """ Print the difference between two cnstat results for interface. @@ -345,7 +379,7 @@ class Portstat(object): print("Time Since Counters Last Cleared............... " + str(cnstat_old_dict.get('time'))) - def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, intf_list, use_json, print_all, errors_only, rates_only, detail=False): + def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail=False): """ Print the difference between two cnstat results. """ @@ -359,100 +393,125 @@ class Portstat(object): for key, cntr in cnstat_new_dict.items(): if key == 'time': - time_gap = cnstat_new_dict.get('time') - cnstat_old_dict.get('time') - time_gap = time_gap.total_seconds() continue old_cntr = None if key in cnstat_old_dict: old_cntr = cnstat_old_dict.get(key) + rates = ratestat_dict.get(key, RateStats._make([STATUS_NA] * len(ratestat_fields))) + if intf_list and key not in intf_list: continue port_speed = self.get_port_speed(key) + if print_all: header = header_all if old_cntr is not None: table.append((key, self.get_port_state(key), ns_diff(cntr.rx_ok, old_cntr.rx_ok), - ns_brate(cntr.rx_byt, old_cntr.rx_byt, time_gap), - ns_prate(cntr.rx_ok, old_cntr.rx_ok, time_gap), - ns_util(cntr.rx_byt, old_cntr.rx_byt, time_gap, port_speed), + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), + format_util(rates.rx_bps, port_speed), ns_diff(cntr.rx_err, old_cntr.rx_err), ns_diff(cntr.rx_drop, old_cntr.rx_drop), ns_diff(cntr.rx_ovr, old_cntr.rx_ovr), ns_diff(cntr.tx_ok, old_cntr.tx_ok), - ns_brate(cntr.tx_byt, old_cntr.tx_byt, time_gap), - ns_prate(cntr.tx_ok, old_cntr.tx_ok, time_gap), - ns_util(cntr.tx_byt, old_cntr.tx_byt, time_gap, port_speed), + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), + format_util(rates.tx_bps, port_speed), ns_diff(cntr.tx_err, old_cntr.tx_err), ns_diff(cntr.tx_drop, old_cntr.tx_drop), ns_diff(cntr.tx_ovr, old_cntr.tx_ovr))) else: table.append((key, self.get_port_state(key), format_number_with_comma(cntr.rx_ok), - STATUS_NA, - STATUS_NA, - STATUS_NA, + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), + format_util(rates.rx_bps, port_speed), format_number_with_comma(cntr.rx_err), format_number_with_comma(cntr.rx_drop), format_number_with_comma(cntr.rx_ovr), format_number_with_comma(cntr.tx_ok), - STATUS_NA, - STATUS_NA, - STATUS_NA, + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), + format_util(rates.tx_bps, port_speed), format_number_with_comma(cntr.tx_err), format_number_with_comma(cntr.tx_drop), format_number_with_comma(cntr.tx_ovr))) elif errors_only: header = header_errors_only - table.append((key, self.get_port_state(key), - ns_diff(cntr.rx_err, old_cntr.rx_err), - ns_diff(cntr.rx_drop, old_cntr.rx_drop), - ns_diff(cntr.rx_ovr, old_cntr.rx_ovr), - ns_diff(cntr.tx_err, old_cntr.tx_err), - ns_diff(cntr.tx_drop, old_cntr.tx_drop), - ns_diff(cntr.tx_ovr, old_cntr.tx_ovr))) - elif rates_only: - header = header_rates_only - table.append((key, self.get_port_state(key), - ns_diff(cntr.rx_ok, old_cntr.rx_ok), - STATUS_NA, - STATUS_NA, - STATUS_NA, - ns_diff(cntr.tx_ok, old_cntr.tx_ok), - STATUS_NA, - STATUS_NA, - STATUS_NA)) - else: - header = header_std if old_cntr is not None: table.append((key, self.get_port_state(key), - ns_diff(cntr.rx_ok, old_cntr.rx_ok), - ns_brate(cntr.rx_byt, old_cntr.rx_byt, time_gap), - ns_util(cntr.rx_byt, old_cntr.rx_byt, time_gap, port_speed), ns_diff(cntr.rx_err, old_cntr.rx_err), ns_diff(cntr.rx_drop, old_cntr.rx_drop), ns_diff(cntr.rx_ovr, old_cntr.rx_ovr), - ns_diff(cntr.tx_ok, old_cntr.tx_ok), - ns_brate(cntr.tx_byt, old_cntr.tx_byt, time_gap), - ns_util(cntr.tx_byt, old_cntr.tx_byt, time_gap, port_speed), ns_diff(cntr.tx_err, old_cntr.tx_err), ns_diff(cntr.tx_drop, old_cntr.tx_drop), ns_diff(cntr.tx_ovr, old_cntr.tx_ovr))) else: table.append((key, self.get_port_state(key), - format_number_with_comma(cntr.rx_ok), - STATUS_NA, - STATUS_NA, format_number_with_comma(cntr.rx_err), format_number_with_comma(cntr.rx_drop), format_number_with_comma(cntr.rx_ovr), - format_number_with_comma(cntr.tx_ok), - STATUS_NA, - STATUS_NA, format_number_with_comma(cntr.tx_err), format_number_with_comma(cntr.tx_drop), format_number_with_comma(cntr.tx_ovr))) + elif rates_only: + header = header_rates_only + if old_cntr is not None: + table.append((key, + self.get_port_state(key), + ns_diff(cntr.rx_ok, old_cntr.rx_ok), + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), + format_util(rates.rx_bps, port_speed), + ns_diff(cntr.tx_ok, old_cntr.tx_ok), + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), + format_util(rates.tx_bps, port_speed))) + else: + table.append((key, + self.get_port_state(key), + format_number_with_comma(cntr.rx_ok), + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), + format_util(rates.rx_bps, port_speed), + format_number_with_comma(cntr.tx_ok), + format_brate(rates.tx_bps), + format_prate(rates.tx_pps), + format_util(rates.tx_bps, port_speed))) + else: + header = header_std + if old_cntr is not None: + table.append((key, + self.get_port_state(key), + ns_diff(cntr.rx_ok, old_cntr.rx_ok), + format_brate(rates.rx_bps), + format_util(rates.rx_bps, port_speed), + ns_diff(cntr.rx_err, old_cntr.rx_err), + ns_diff(cntr.rx_drop, old_cntr.rx_drop), + ns_diff(cntr.rx_ovr, old_cntr.rx_ovr), + ns_diff(cntr.tx_ok, old_cntr.tx_ok), + format_brate(rates.tx_bps), + format_util(rates.tx_bps, port_speed), + ns_diff(cntr.tx_err, old_cntr.tx_err), + ns_diff(cntr.tx_drop, old_cntr.tx_drop), + ns_diff(cntr.tx_ovr, old_cntr.tx_ovr))) + else: + table.append((key, + self.get_port_state(key), + format_number_with_comma(cntr.rx_ok), + format_brate(rates.rx_bps), + format_util(rates.rx_bps, port_speed), + format_number_with_comma(cntr.rx_err), + format_number_with_comma(cntr.rx_drop), + format_number_with_comma(cntr.rx_ovr), + format_number_with_comma(cntr.tx_ok), + format_brate(rates.tx_bps), + format_util(rates.tx_bps, port_speed), + format_number_with_comma(cntr.tx_err), + format_number_with_comma(cntr.tx_drop), + format_number_with_comma(cntr.tx_ovr))) if use_json: print(table_as_json(table, header)) @@ -551,11 +610,11 @@ Examples: display_option = constants.DISPLAY_ALL portstat = Portstat(namespace, display_option) - cnstat_dict = portstat.get_cnstat_dict() + cnstat_dict, ratestat_dict = portstat.get_cnstat_dict() # Now decide what information to display if raw_stats: - portstat.cnstat_print(cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only) + portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only) sys.exit(0) # At this point, either we'll create a file or open an existing one. @@ -583,7 +642,7 @@ Examples: cnstat_cached_dict = pickle.load(open(cnstat_fqn_file, 'rb')) if not detail: print("Last cached time was " + str(cnstat_cached_dict.get('time'))) - portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, intf_list, use_json, print_all, errors_only, rates_only, detail) + portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail) except IOError as e: print(e.errno, e) else: @@ -591,13 +650,13 @@ Examples: print("\nFile '%s' does not exist" % cnstat_fqn_file) print("Did you run 'portstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name)) else: - portstat.cnstat_print(cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail) + portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail) else: #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_dict() - portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail) + cnstat_new_dict, ratestat_new_dict = portstat.get_cnstat_dict() + portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, ratestat_new_dict, intf_list, use_json, print_all, errors_only, rates_only, detail) if __name__ == "__main__": main() diff --git a/tests/intfstat_test.py b/tests/intfstat_test.py index 73cda11f1c..4522e08311 100644 --- a/tests/intfstat_test.py +++ b/tests/intfstat_test.py @@ -2,7 +2,11 @@ import os import traceback +import show.main as show +import clear.main as clear + from click.testing import CliRunner +from .mock_tables import dbconnector test_path = os.path.dirname(os.path.abspath(__file__)) modules_path = os.path.dirname(test_path) @@ -10,20 +14,110 @@ sys.path.insert(0, test_path) sys.path.insert(0, modules_path) -from .mock_tables import dbconnector +show_interfaces_counters_rif_output="""\ + IFACE RX_OK RX_BPS RX_PPS RX_ERR TX_OK TX_BPS TX_PPS TX_ERR +--------------- ------- ----------- -------- -------- ------- ---------- -------- -------- + Ethernet20 4 3.00 B/s 4.00/s 2 8 754.00 B/s 8.00/s 6 +PortChannel0001 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0002 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0003 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +PortChannel0004 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 + Vlan1000 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +""" -import show.main as show -import clear.main as clear +show_interfaces_counters_rif_output_verbose="""\ +Running command: intfstat + IFACE RX_OK RX_BPS RX_PPS RX_ERR TX_OK TX_BPS TX_PPS TX_ERR +--------------- ------- ----------- -------- -------- ------- ---------- -------- -------- + Ethernet20 4 3.00 B/s 4.00/s 2 8 754.00 B/s 8.00/s 6 +PortChannel0001 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0002 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0003 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +PortChannel0004 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 + Vlan1000 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +""" -show_interfaces_counters_rif_output="""\ - IFACE RX_OK RX_BPS RX_PPS RX_ERR TX_OK TX_BPS TX_PPS TX_ERR ---------------- ------- -------- -------- -------- ------- -------- -------- -------- - Ethernet20 4 N/A N/A 2 8 N/A N/A 6 -PortChannel0001 883 N/A N/A 0 0 N/A N/A 0 -PortChannel0002 883 N/A N/A 0 0 N/A N/A 0 -PortChannel0003 0 N/A N/A 0 0 N/A N/A 0 -PortChannel0004 883 N/A N/A 0 0 N/A N/A 0 - Vlan1000 0 N/A N/A 0 0 N/A N/A 0 +show_interfaces_counters_rif_period="""\ +The rates are calculated within 3 seconds period + IFACE RX_OK RX_BPS RX_PPS RX_ERR TX_OK TX_BPS TX_PPS TX_ERR +--------------- ------- ----------- -------- -------- ------- ---------- -------- -------- + Ethernet20 0 3.00 B/s 4.00/s 0 0 754.00 B/s 8.00/s 0 +PortChannel0001 0 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0002 0 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0003 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +PortChannel0004 0 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 + Vlan1000 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +""" + +show_interfaces_counters_rif_period_single_intf="""\ +The rates are calculated within 3 seconds period +Ethernet20 +---------- + + RX: + 0 packets + 0 bytes + 0 error packets + 0 error bytes + TX: + 0 packets + 0 bytes + 0 error packets + 0 error bytes +""" + +show_interfaces_counters_rif_single_intf="""\ +Ethernet20 +---------- + + RX: + 4 packets + 3 bytes + 2 error packets + 1128 error bytes + TX: + 8 packets + 754 bytes + 6 error packets + 5 error bytes +""" + +show_interfaces_counters_rif_clear_single_intf="""\ +Ethernet20 +---------- + + RX: + 0 packets + 0 bytes + 0 error packets + 0 error bytes + TX: + 0 packets + 0 bytes + 0 error packets + 0 error bytes +""" + +show_interfaces_counters_rif_clear="""\ + IFACE RX_OK RX_BPS RX_PPS RX_ERR TX_OK TX_BPS TX_PPS TX_ERR +--------------- ------- ----------- -------- -------- ------- ---------- -------- -------- + Ethernet20 0 3.00 B/s 4.00/s 0 0 754.00 B/s 8.00/s 0 +PortChannel0001 0 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0002 0 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0003 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +PortChannel0004 0 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 + Vlan1000 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +""" + +show_single_interface_check_all_clear="""\ + IFACE RX_OK RX_BPS RX_PPS RX_ERR TX_OK TX_BPS TX_PPS TX_ERR +--------------- ------- ----------- -------- -------- ------- ---------- -------- -------- + Ethernet20 0 3.00 B/s 4.00/s 0 0 754.00 B/s 8.00/s 0 +PortChannel0001 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0002 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 +PortChannel0003 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 +PortChannel0004 883 608.99 KB/s 0.00/s 0 0 883.00 B/s 0.00/s 0 + Vlan1000 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0 """ class TestIntfstat(object): @@ -46,38 +140,25 @@ def test_verbose(self): runner = CliRunner() result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["rif"], ["--verbose"]) print(result.output) - assert result.output.split('\n')[0] == "Running command: intfstat" + assert result.output == show_interfaces_counters_rif_output_verbose def test_period(self): runner = CliRunner() result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["rif"], ["-p3"]) print(result.output) - assert result.output.split('\n')[0] == "The rates are calculated within 3 seconds period" + assert result.output == show_interfaces_counters_rif_period def test_period_single_interface(self): runner = CliRunner() result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["rif"], ["Ethernet20", "-p3"]) print(result.output) - assert result.output.split('\n')[0] == "The rates are calculated within 3 seconds period" + assert result.output == show_interfaces_counters_rif_period_single_intf def test_single_intfs(self): runner = CliRunner() result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["rif"], ["Ethernet20"]) - expected = """Ethernet20 ----------- - - RX: - 4 packets - 3 bytes - 2 error packets - 1128 error bytes - TX: - 8 packets - 754 bytes - 6 error packets - 5 error bytes -""" - assert result.output == expected + print(result.output) + assert result.output == show_interfaces_counters_rif_single_intf def test_clear_single_intfs(self): runner = CliRunner() @@ -85,23 +166,11 @@ def test_clear_single_intfs(self): print(result.stdout) assert result.exit_code == 0 result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["rif"], ["Ethernet20"]) - expected = """Ethernet20 ----------- - - RX: - 0 packets - 0 bytes - 0 error packets - 0 error bytes - TX: - 0 packets - 0 bytes - 0 error packets - 0 error bytes -""" + print(result.output) # remove the counters snapshot show.run_command("intfstat -D") - assert expected in result.output + assert 'Last cached time was' in result.output.split('\n')[0] + assert show_interfaces_counters_rif_clear_single_intf in result.output def test_clear_single_interface_check_all(self): runner = CliRunner() @@ -110,18 +179,10 @@ def test_clear_single_interface_check_all(self): assert result.exit_code == 0 result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["rif"], []) print(result.stdout) - expected = [" Ethernet20 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0", - "PortChannel0001 883 N/A N/A 0 0 N/A N/A 0", - "PortChannel0002 883 N/A N/A 0 0 N/A N/A 0", - "PortChannel0003 0 N/A N/A 0 0 N/A N/A 0", - "PortChannel0004 883 N/A N/A 0 0 N/A N/A 0", - " Vlan1000 0 N/A N/A 0 0 N/A N/A 0"] - - # remove the counters snapshot show.run_command("intfstat -D") - for line in expected: - assert line in result.output + assert 'Last cached time was' in result.output.split('\n')[0] + assert show_single_interface_check_all_clear in result.output def test_clear(self): runner = CliRunner() @@ -130,17 +191,10 @@ def test_clear(self): assert result.exit_code == 0 result = runner.invoke(show.cli.commands["interfaces"].commands["counters"].commands["rif"], []) print(result.stdout) - expected = ["Ethernet20 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0", - "PortChannel0001 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0", - "PortChannel0002 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0", - "PortChannel0003 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0", - "PortChannel0004 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0", - "Vlan1000 0 0.00 B/s 0.00/s 0 0 0.00 B/s 0.00/s 0"] - # remove the counters snapshot show.run_command("intfstat -D") - for line in expected: - assert line in result.output + assert 'Last cached time was' in result.output.split('\n')[0] + assert show_interfaces_counters_rif_clear in result.output def test_alias_mode(self): os.environ["SONIC_CLI_IFACE_MODE"] = "alias" @@ -163,3 +217,4 @@ 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" + diff --git a/tests/mock_tables/asic0/counters_db.json b/tests/mock_tables/asic0/counters_db.json index 97dc7739e0..99b89081ed 100644 --- a/tests/mock_tables/asic0/counters_db.json +++ b/tests/mock_tables/asic0/counters_db.json @@ -1578,6 +1578,30 @@ "COUNTERS:oid:0x21000000000000": { "SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000" }, + "RATES:oid:0x1000000000002": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000004": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000006": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000008": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, "COUNTERS_PORT_NAME_MAP": { "Ethernet0": "oid:0x1000000000002", "Ethernet4": "oid:0x1000000000004", diff --git a/tests/mock_tables/asic1/counters_db.json b/tests/mock_tables/asic1/counters_db.json index d346d42774..269aa7ec66 100644 --- a/tests/mock_tables/asic1/counters_db.json +++ b/tests/mock_tables/asic1/counters_db.json @@ -178,6 +178,18 @@ "COUNTERS:oid:0x21000000000000": { "SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000" }, + "RATES:oid:0x1000000000b06": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000b08": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, "COUNTERS_PORT_NAME_MAP": { "Ethernet-BP256": "oid:0x1000000000b06", "Ethernet-BP260": "oid:0x1000000000b08" diff --git a/tests/mock_tables/asic2/counters_db.json b/tests/mock_tables/asic2/counters_db.json index 3c40e04bdb..09343d784b 100644 --- a/tests/mock_tables/asic2/counters_db.json +++ b/tests/mock_tables/asic2/counters_db.json @@ -1578,6 +1578,30 @@ "COUNTERS:oid:0x21000000000000": { "SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000" }, + "RATES:oid:0x1000000000002": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000004": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000006": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000008": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, "COUNTERS_PORT_NAME_MAP": { "Ethernet0": "oid:0x1000000000002", "Ethernet4": "oid:0x1000000000004", diff --git a/tests/mock_tables/counters_db.json b/tests/mock_tables/counters_db.json index 3aed25f1c7..9ad472c03d 100644 --- a/tests/mock_tables/counters_db.json +++ b/tests/mock_tables/counters_db.json @@ -407,7 +407,6 @@ "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "0", "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0", - "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", "SAI_QUEUE_STAT_DROPPED_BYTES": "0", "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", "SAI_QUEUE_STAT_BYTES": "0", @@ -422,7 +421,6 @@ "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS": "0", "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0", - "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", "SAI_QUEUE_STAT_DROPPED_BYTES": "0", "SAI_QUEUE_STAT_DROPPED_PACKETS": "0", "SAI_QUEUE_STAT_BYTES": "0", @@ -468,6 +466,60 @@ "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS": "0", "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS": "0" }, + "RATES:oid:0x1000000000012": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x1000000000013": { + "RX_BPS": "204800", + "RX_PPS": "200", + "TX_BPS": "204848", + "TX_PPS": "201" + }, + "RATES:oid:0x1000000000014": { + "RX_BPS": "1.35e6", + "RX_PPS": "9000", + "TX_BPS": "13.37e6", + "TX_PPS": "9000" + }, + "RATES:oid:0x600000000065f": { + "RX_BPS": "3", + "RX_PPS": "4", + "TX_BPS": "754", + "TX_PPS": "8" + }, + "RATES:oid:0x60000000005a1": { + "RX_BPS": "608985", + "RX_PPS": "0", + "TX_BPS": "883", + "TX_PPS": "0" + }, + "RATES:oid:0x60000000005a2": { + "RX_BPS": "608985", + "RX_PPS": "0", + "TX_BPS": "883", + "TX_PPS": "0" + }, + "RATES:oid:0x600000000063c": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, + "RATES:oid:0x600000000063d": { + "RX_BPS": "608985", + "RX_PPS": "0", + "TX_BPS": "883", + "TX_PPS": "0" + }, + "RATES:oid:0x60000000005a3": { + "RX_BPS": "0", + "RX_PPS": "0", + "TX_BPS": "0", + "TX_PPS": "0" + }, "COUNTERS_RIF_NAME_MAP": { "Ethernet20": "oid:0x600000000065f", "PortChannel0001": "oid:0x60000000005a1", diff --git a/tests/portstat_test.py b/tests/portstat_test.py index 86714b5233..469d478ed6 100644 --- a/tests/portstat_test.py +++ b/tests/portstat_test.py @@ -12,42 +12,42 @@ 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 1,000 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 + 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 0.00 B/s 0.00% 10 100 N/A 10 0.00 B/s 0.00% N/A N/A N/A +Ethernet4 N/A 4 204.80 KB/s N/A 0 1,000 N/A 40 204.85 KB/s N/A N/A N/A N/A +Ethernet8 N/A 6 1350.00 KB/s N/A 100 10 N/A 60 13.37 MB/s 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 1,000 N/A 40 N/A N/A N/A N/A N/A + 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 204.80 KB/s N/A 0 1,000 N/A 40 204.85 KB/s 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 1,000 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 + 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 0.00 B/s 0.00/s 0.00% 10 100 N/A 10 0.00 B/s 0.00/s 0.00% N/A N/A N/A +Ethernet4 N/A 4 204.80 KB/s 200.00/s N/A 0 1,000 N/A 40 204.85 KB/s 201.00/s N/A N/A N/A N/A +Ethernet8 N/A 6 1350.00 KB/s 9000.00/s N/A 100 10 N/A 60 13.37 MB/s 9000.00/s 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 + 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 204.80 KB/s N/A 0 0 N/A 0 204.85 KB/s N/A N/A N/A N/A +Ethernet8 N/A 0 1350.00 KB/s N/A 0 0 N/A 0 13.37 MB/s N/A 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""" + 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 204.80 KB/s N/A 0 0 N/A 0 204.85 KB/s N/A N/A N/A N/A +Ethernet8 N/A 0 1350.00 KB/s N/A 0 0 N/A 0 13.37 MB/s N/A N/A N/A N/A""" clear_counter = """\ Cleared counters""" @@ -55,54 +55,54 @@ 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 1,000 N/A 40 N/A N/A N/A N/A N/A +Ethernet0 U 8 0.00 B/s 0.00% 10 100 N/A 10 0.00 B/s 0.00% N/A N/A N/A +Ethernet4 U 4 0.00 B/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00% 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 1,000 N/A 40 N/A N/A N/A N/A N/A - Ethernet-BP0 U 6 N/A N/A 0 1,000 N/A 60 N/A N/A N/A N/A N/A - Ethernet-BP4 U 8 N/A N/A 0 1,000 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 1,000 N/A 40 N/A N/A N/A N/A N/A + Ethernet0 U 8 0.00 B/s 0.00% 10 100 N/A 10 0.00 B/s 0.00% N/A N/A N/A + Ethernet4 U 4 0.00 B/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00% N/A N/A N/A + Ethernet-BP0 U 6 0.00 B/s 0.00% 0 1,000 N/A 60 0.00 B/s 0.00% N/A N/A N/A + Ethernet-BP4 U 8 0.00 B/s 0.00% 0 1,000 N/A 80 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP256 U 8 0.00 B/s 0.00% 10 100 N/A 10 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP260 U 4 0.00 B/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00% 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 1,000 N/A 40 N/A N/A N/A N/A N/A -Ethernet-BP0 U 6 N/A N/A 0 1,000 N/A 60 N/A N/A N/A N/A N/A -Ethernet-BP4 U 8 N/A N/A 0 1,000 N/A 80 N/A N/A N/A N/A N/A + Ethernet0 U 8 0.00 B/s 0.00% 10 100 N/A 10 0.00 B/s 0.00% N/A N/A N/A + Ethernet4 U 4 0.00 B/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP0 U 6 0.00 B/s 0.00% 0 1,000 N/A 60 0.00 B/s 0.00% N/A N/A N/A +Ethernet-BP4 U 8 0.00 B/s 0.00% 0 1,000 N/A 80 0.00 B/s 0.00% 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 + 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 1,000 N/A 40 N/A N/A N/A N/A N/A N/A +Ethernet0 U 8 0.00 B/s 0.00/s 0.00% 10 100 N/A 10 0.00 B/s 0.00/s 0.00% N/A N/A N/A +Ethernet4 U 4 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00/s 0.00% 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 + 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 1,000 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 1,000 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 1,000 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 1,000 N/A 40 N/A N/A N/A N/A N/A N/A + Ethernet0 U 8 0.00 B/s 0.00/s 0.00% 10 100 N/A 10 0.00 B/s 0.00/s 0.00% N/A N/A N/A + Ethernet4 U 4 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00/s 0.00% N/A N/A N/A + Ethernet-BP0 U 6 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 60 0.00 B/s 0.00/s 0.00% N/A N/A N/A + Ethernet-BP4 U 8 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 80 0.00 B/s 0.00/s 0.00% N/A N/A N/A +Ethernet-BP256 U 8 0.00 B/s 0.00/s 0.00% 10 100 N/A 10 0.00 B/s 0.00/s 0.00% N/A N/A N/A +Ethernet-BP260 U 4 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00/s 0.00% 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 + 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 1,000 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 1,000 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 1,000 N/A 80 N/A N/A N/A N/A N/A N/A + Ethernet0 U 8 0.00 B/s 0.00/s 0.00% 10 100 N/A 10 0.00 B/s 0.00/s 0.00% N/A N/A N/A + Ethernet4 U 4 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 40 0.00 B/s 0.00/s 0.00% N/A N/A N/A +Ethernet-BP0 U 6 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 60 0.00 B/s 0.00/s 0.00% N/A N/A N/A +Ethernet-BP4 U 8 0.00 B/s 0.00/s 0.00% 0 1,000 N/A 80 0.00 B/s 0.00/s 0.00% N/A N/A N/A """ multi_asic_intf_counters_period = """\ The rates are calculated within 3 seconds period diff --git a/utilities_common/netstat.py b/utilities_common/netstat.py index 3d856e576f..5f17c1f4c6 100755 --- a/utilities_common/netstat.py +++ b/utilities_common/netstat.py @@ -79,3 +79,42 @@ def format_number_with_comma(number_in_str): return '{:,}'.format(int(number_in_str)) else: return number_in_str + + +def format_brate(rate): + """ + Show the byte rate. + """ + if rate == STATUS_NA: + return STATUS_NA + else: + rate = float(rate) + if rate > 1000*1000*10: + rate = "{:.2f}".format(rate/1000/1000.0)+' MB' + elif rate > 1000*10: + rate = "{:.2f}".format(rate/1000.0)+' KB' + else: + rate = "{:.2f}".format(rate)+' B' + return rate+'/s' + + +def format_prate(rate): + """ + Show the packet rate. + """ + if rate == STATUS_NA: + return STATUS_NA + else: + return "{:.2f}".format(float(rate))+'/s' + + +def format_util(brate, port_rate): + """ + Calculate the util. + """ + if brate == STATUS_NA or port_rate == STATUS_NA: + return STATUS_NA + else: + util = brate/(float(port_rate)*1000*1000/8.0)*100 + return "{:.2f}%".format(util) +