From a2766557eb8d711957b8fa519cfa6d49f04a5925 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Wed, 14 Jul 2021 03:37:31 +0000 Subject: [PATCH 01/15] Tunnel counters implementation --- clear/main.py | 6 + counterpoll/main.py | 37 +++++ scripts/tunnelstat | 325 ++++++++++++++++++++++++++++++++++++++++++++ show/vxlan.py | 15 ++ 4 files changed, 383 insertions(+) create mode 100755 scripts/tunnelstat diff --git a/clear/main.py b/clear/main.py index 8f93597b68..5cbaee9d62 100755 --- a/clear/main.py +++ b/clear/main.py @@ -193,6 +193,12 @@ def dropcounters(): command = "dropstat -c clear" run_command(command) +@cli.command() +def tunnelcounters(): + """Clear Tunnel counters""" + command = "tunnelstat -c" + run_command(command) + # # 'clear watermarks # diff --git a/counterpoll/main.py b/counterpoll/main.py index 7c062e9d74..f6d5d6c885 100644 --- a/counterpoll/main.py +++ b/counterpoll/main.py @@ -241,6 +241,40 @@ def disable(): configdb.mod_entry("FLEX_COUNTER_TABLE", "PG_WATERMARK", fc_info) configdb.mod_entry("FLEX_COUNTER_TABLE", BUFFER_POOL_WATERMARK, fc_info) +# Tunnel counter commands +@cli.group() +def tunnel(): + """ Tunnel counter commands """ + +@tunnel.command() +@click.argument('poll_interval') +def interval(poll_interval): + """ Set tunnel counter query interval """ + configdb = ConfigDBConnector() + configdb.connect() + tunnel_info = {} + if poll_interval is not None: + tunnel_info['POLL_INTERVAL'] = poll_interval + configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info) + +@tunnel.command() +def enable(): + """ Enable tunnel counter query """ + configdb = ConfigDBConnector() + configdb.connect() + tunnel_info = {} + tunnel_info['FLEX_COUNTER_STATUS'] = 'enable' + configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info) + +@tunnel.command() +def disable(): + """ Disable tunnel counter query """ + configdb = ConfigDBConnector() + configdb.connect() + tunnel_info = {} + tunnel_info['FLEX_COUNTER_STATUS'] = 'disable' + configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info) + @cli.command() def show(): """ Show the counter configuration """ @@ -254,6 +288,7 @@ def show(): pg_wm_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'PG_WATERMARK') pg_drop_info = configdb.get_entry('FLEX_COUNTER_TABLE', PG_DROP) buffer_pool_wm_info = configdb.get_entry('FLEX_COUNTER_TABLE', BUFFER_POOL_WATERMARK) + tunnel_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'TUNNEL') header = ("Type", "Interval (in ms)", "Status") data = [] @@ -273,6 +308,8 @@ def show(): data.append(['PG_DROP_STAT', pg_drop_info.get("POLL_INTERVAL", DEFLT_10_SEC), pg_drop_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if buffer_pool_wm_info: data.append(["BUFFER_POOL_WATERMARK_STAT", buffer_pool_wm_info.get("POLL_INTERVAL", DEFLT_10_SEC), buffer_pool_wm_info.get("FLEX_COUNTER_STATUS", DISABLE)]) + if rif_info: + data.append(["TUNNEL_STAT", rif_info.get("POLL_INTERVAL", DEFLT_10_SEC), rif_info.get("FLEX_COUNTER_STATUS", DISABLE)]) click.echo(tabulate(data, headers=header, tablefmt="simple", missingval="")) diff --git a/scripts/tunnelstat b/scripts/tunnelstat new file mode 100755 index 0000000000..15f6940e97 --- /dev/null +++ b/scripts/tunnelstat @@ -0,0 +1,325 @@ +#!/usr/bin/env python3 + +##################################################################### +# +# tunnelstat is a tool for summarizing l3 network statistics. +# +##################################################################### + +import _pickle as pickle +import argparse +import datetime +import sys +import os +import sys +import time + +# mock the redis for unit test purposes # +try: + if os.environ["UTILITIES_UNIT_TESTING"] == "2": + modules_path = os.path.join(os.path.dirname(__file__), "..") + test_path = os.path.join(modules_path, "tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, test_path) + import mock_tables.dbconnector +except KeyError: + pass + +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 swsscommon.swsscommon import SonicV2Connector + + +NStats = namedtuple("NStats", "rx_b_ok, rx_p_ok, tx_b_ok, tx_p_ok") + +header = ['IFACE', 'RX_OK', 'RX_BPS', 'RX_PPS','TX_OK', 'TX_BPS', 'TX_PPS'] + +counter_names = ( + 'SAI_TUNNEL_STAT_IN_OCTETS', + 'SAI_TUNNEL_STAT_IN_PACKETS', + 'SAI_TUNNEL_STAT_OUT_OCTETS', + 'SAI_TUNNEL_STAT_OUT_PACKETS' +) + +counter_types = { + "vxlan": "SAI_TUNNEL_TYPE_VXLAN" +} + +COUNTER_TABLE_PREFIX = "COUNTERS:" +COUNTERS_TUNNEL_NAME_MAP = "COUNTERS_TUNNEL_NAME_MAP" +COUNTERS_TUNNEL_TYPE_MAP = "COUNTERS_TUNNEL_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 Tunnelstat(object): + def __init__(self): + self.db = SonicV2Connector(use_unix_socket_path=False) + self.db.connect(self.db.COUNTERS_DB) + self.db.connect(self.db.APPL_DB) + + def get_cnstat(self, tunnel=None, tun_type=None): + """ + Get the counters info from database. + """ + def get_counters(table_id): + """ + Get the counters from specific table. + """ + fields = [STATUS_NA] * (len(header) - 1) + 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) + if counter_data: + fields[pos] = str(counter_data) + cntr = NStats._make(fields) + return cntr + + # Build a dictionary of the stats + cnstat_dict = OrderedDict() + cnstat_dict['time'] = datetime.datetime.now() + + # Get the info from database + counter_tunnel_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_TUNNEL_NAME_MAP) + counter_tunnel_type_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_TUNNEL_TYPE_MAP) + + if counter_tunnel_name_map is None: + print("No %s in the DB!" % COUNTERS_TUNNEL_NAME_MAP) + sys.exit(1) + + if counter_tunnel_type_map is None: + print("No %s in the DB!" % COUNTERS_TUNNEL_TYPE_MAP) + sys.exit(1) + + if tun_type and tun_type not in counter_types: + print("Unknown tunnel type %s" % tun_type) + sys.exit(1) + + if tunnel and not tunnel in counter_tunnel_name_map: + print("Interface %s missing from %s! Make sure it exists" % (tunnel, COUNTERS_TUNNEL_NAME_MAP)) + sys.exit(2) + + if tunnel: + if tun_type and counter_types[tun_type] != counter_tunnel_type_map[counter_tunnel_name_map[tunnel]]: + print("Mismtch in tunnel type. Requested type %s actual type %s" % ( + counter_types[tun_type], counter_tunnel_type_map[counter_tunnel_name_map[tunnel])) + sys.exit(2) + cnstat_dict[tunnel] = get_counters(counter_tunnel_name_map[tunnel]) + return cnstat_dict + + for tunnel in natsorted(counter_tunnel_name_map): + if not tun_type or counter_types[tun_type] == counter_tunnel_type_map[counter_tunnel_name_map[tunnel]]: + cnstat_dict[tunnel] = get_counters(counter_tunnel_name_map[tunnel]) + return cnstat_dict + + def cnstat_print(self, cnstat_dict, use_json): + """ + Print the cnstat. + """ + table = [] + + for key, data in cnstat_dict.items(): + if key == 'time': + continue + + table.append((key, data.rx_p_ok, STATUS_NA, STATUS_NA, + data.tx_p_ok, STATUS_NA, STATUS_NA)) + + if use_json: + print(table_as_json(table, header)) + + else: + print(tabulate(table, header, tablefmt='simple', stralign='right')) + + def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, use_json): + """ + Print the difference between two cnstat results. + """ + + table = [] + + 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) + + 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), + 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))) + else: + table.append((key, + cntr.rx_p_ok, + STATUS_NA, + STATUS_NA, + cntr.tx_p_ok, + STATUS_NA, + STATUS_NA)) + if use_json: + print(table_as_json(table, header)) + else: + print(tabulate(table, header, tablefmt='simple', stralign='right')) + + def cnstat_single_tunnel(self, tunnel, cnstat_new_dict, cnstat_old_dict): + + header = tunnel + '\n' + '-'*len(tunnel) + body = """ + RX: + %10s packets + %10s bytes + TX: + %10s packets + %10s bytes""" + + cntr = cnstat_new_dict.get(tunnel) + + if cnstat_old_dict: + old_cntr = cnstat_old_dict.get(tunnel) + if old_cntr: + body = body % (ns_diff(cntr.rx_p_ok, old_cntr.rx_p_ok), + ns_diff(cntr.rx_b_ok, old_cntr.rx_b_ok), + ns_diff(cntr.tx_p_ok, old_cntr.tx_p_ok), + ns_diff(cntr.tx_b_ok, old_cntr.tx_b_ok)) + else: + body = body % (cntr.rx_p_ok, cntr.rx_b_ok, cntr.tx_p_ok, cntr.tx_b_ok) + + print(header) + print(body) + + +def main(): + parser = argparse.ArgumentParser(description='Display the tunnels state and counters', + formatter_class=argparse.RawTextHelpFormatter, + epilog=""" + Port state: (U)-Up (D)-Down (X)-Disabled + Examples: + tunnelstat -c -t test + tunnelstat -t test + tunnelstat -d -t test + tunnelstat + tunnelstat -p 20 + tunnelstat -i Vlan1000 + """) + + parser.add_argument('-c', '--clear', action='store_true', help='Copy & clear stats') + parser.add_argument('-d', '--delete', action='store_true', help='Delete saved stats, either the uid or the specified tag') + parser.add_argument('-D', '--delete-all', action='store_true', help='Delete all saved stats') + parser.add_argument('-j', '--json', action='store_true', help='Display in JSON format') + parser.add_argument('-t', '--tag', type=str, help='Save stats with name TAG', default=None) + parser.add_argument('-i', '--tunnel', type=str, help='Show stats for a single tunnel', required=False) + parser.add_argument('-p', '--period', type=int, help='Display stats over a specified period (in seconds).', default=0) + parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0') + parser.add_argument('-T', '--type', type=str, help ='Display Vxlan tunnel stats', required=False) + args = parser.parse_args() + + save_fresh_stats = args.clear + delete_saved_stats = args.delete + delete_all_stats = args.delete_all + use_json = args.json + tag_name = args.tag if args.tag else "" + uid = str(os.getuid()) + wait_time_in_seconds = args.period + tunnel_name = args.tunnel if args.tunnel else "" + tunnel_type = args.type if args.type else "" + + # fancy filename with dashes: uid-tag-tunnel / uid-tunnel / uid-tag etc + filename_components = [uid, tag_name] + cnstat_file = "-".join(filter(None, filename_components)) + + cnstat_dir = "/tmp/tunnelstat-" + uid + cnstat_fqn_file = cnstat_dir + "/" + cnstat_file + + if delete_all_stats: + # There is nothing to delete + if not os.path.isdir(cnstat_dir): + sys.exit(0) + + for file in os.listdir(cnstat_dir): + os.remove(cnstat_dir + "/" + file) + + try: + os.rmdir(cnstat_dir) + sys.exit(0) + except IOError as e: + print(e.errno, e) + sys.exit(e) + + if delete_saved_stats: + try: + os.remove(cnstat_fqn_file) + except IOError as e: + if e.errno != ENOENT: + print(e.errno, e) + sys.exit(1) + finally: + if os.listdir(cnstat_dir) == []: + os.rmdir(cnstat_dir) + sys.exit(0) + + tunnelstat = Tunnelstat() + cnstat_dict = tunnelstat.get_cnstat(tunnel=tunnel_name, tun_type=tunnel_type) + + # At this point, either we'll create a file or open an existing one. + if not os.path.exists(cnstat_dir): + try: + os.makedirs(cnstat_dir) + except IOError as e: + print(e.errno, e) + sys.exit(1) + + if save_fresh_stats: + try: + pickle.dump(cnstat_dict, open(cnstat_fqn_file, 'wb')) + except IOError as e: + sys.exit(e.errno) + else: + print("Cleared counters") + sys.exit(0) + + if wait_time_in_seconds == 0: + if os.path.isfile(cnstat_fqn_file): + try: + cnstat_cached_dict = pickle.load(open(cnstat_fqn_file, 'rb')) + print("Last cached time was " + str(cnstat_cached_dict.get('time'))) + if tunnel_name: + tunnelstat.cnstat_single_tunnel(tunnel_name, cnstat_dict, cnstat_cached_dict) + else: + tunnelstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, use_json) + except IOError as e: + print(e.errno, e) + else: + if tag_name: + print("\nFile '%s' does not exist" % cnstat_fqn_file) + print("Did you run 'tunnelstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name)) + else: + if tunnel_name: + tunnelstat.cnstat_single_tunnel(tunnel_name, cnstat_dict, None) + else: + tunnelstat.cnstat_print(cnstat_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 = tunnelstat.get_cnstat(tunnel=tunnel_name, tun_type=tunnel_type) + if tunnel_name: + tunnelstat.cnstat_single_tunnel(tunnel_name, cnstat_new_dict, cnstat_dict) + else: + tunnelstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, use_json) + +if __name__ == "__main__": + main() diff --git a/show/vxlan.py b/show/vxlan.py index bb20580689..9c165cec58 100644 --- a/show/vxlan.py +++ b/show/vxlan.py @@ -305,3 +305,18 @@ def remotemac(remote_vtep_ip, count): output += ('%s \n' % (str(num))) click.echo(output) +@vxlan.command() +@click.argument('tunnel', required=False) +@click.option('-p', '--period') +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def counter(tunnel): + """Show VxLAN counters""" + + cmd = "tunnelstat -T vxlan" + if period is not None: + cmd += " -p {}".format(period) + if interface is not None: + cmd += " -i {}".format(tunnel) + + clicommon.run_command(cmd, display_cmd=verbose) + From d9c9fcaa41577fe7b7425019802d8d2bfdbd18f1 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 16 Jul 2021 00:43:55 +0000 Subject: [PATCH 02/15] Calculate rates from lua --- scripts/tunnelstat | 72 +++++++++++++++++++++++++------------ utilities_common/netstat.py | 25 +++++++++++++ 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index 15f6940e97..39f83453f8 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -28,14 +28,20 @@ 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, ns_brate, ns_prate, table_as_json, STATUS_NA, format_brate, format_prate, format_util from swsscommon.swsscommon import SonicV2Connector -NStats = namedtuple("NStats", "rx_b_ok, rx_p_ok, tx_b_ok, tx_p_ok") +nstat_fields = ("rx_b_ok, rx_p_ok, tx_b_ok, tx_p_ok") +NStats = namedtuple("NStats", nstat_fields) header = ['IFACE', 'RX_OK', 'RX_BPS', 'RX_PPS','TX_OK', 'TX_BPS', 'TX_PPS'] +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_TUNNEL_STAT_IN_OCTETS', 'SAI_TUNNEL_STAT_IN_PACKETS', @@ -48,6 +54,7 @@ counter_types = { } COUNTER_TABLE_PREFIX = "COUNTERS:" +RATES_TABLE_PREFIX = "RATES:" COUNTERS_TUNNEL_NAME_MAP = "COUNTERS_TUNNEL_NAME_MAP" COUNTERS_TUNNEL_TYPE_MAP = "COUNTERS_TUNNEL_TYPE_MAP" @@ -73,7 +80,7 @@ class Tunnelstat(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) @@ -82,8 +89,24 @@ class Tunnelstat(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() + ratestat_dict = OrderedDict() cnstat_dict['time'] = datetime.datetime.now() # Get the info from database @@ -112,14 +135,16 @@ class Tunnelstat(object): counter_types[tun_type], counter_tunnel_type_map[counter_tunnel_name_map[tunnel])) sys.exit(2) cnstat_dict[tunnel] = get_counters(counter_tunnel_name_map[tunnel]) - return cnstat_dict + ratestat_dict[tunnel] = get_rates(counter_tunnel_name_map[tunnel]) + return cnstat_dict, ratestat_dict for tunnel in natsorted(counter_tunnel_name_map): if not tun_type or counter_types[tun_type] == counter_tunnel_type_map[counter_tunnel_name_map[tunnel]]: cnstat_dict[tunnel] = get_counters(counter_tunnel_name_map[tunnel]) - return cnstat_dict + ratestat_dict[tunnel] = get_rates(counter_tunnel_name_map[tunnel]) + 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. """ @@ -129,8 +154,9 @@ class Tunnelstat(object): if key == 'time': continue - table.append((key, data.rx_p_ok, STATUS_NA, STATUS_NA, - data.tx_p_ok, STATUS_NA, STATUS_NA)) + 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.tx_p_ok, format_brate(rates.tx_bps), format_prate(rates.tx_pps))) if use_json: print(table_as_json(table, header)) @@ -138,7 +164,7 @@ class Tunnelstat(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. """ @@ -154,22 +180,23 @@ class Tunnelstat(object): 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.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))) else: table.append((key, cntr.rx_p_ok, - STATUS_NA, - STATUS_NA, + format_brate(rates.rx_bps), + format_prate(rates.rx_pps), cntr.tx_p_ok, - STATUS_NA, - STATUS_NA)) + format_brate(rates.tx_bps), + format_prate(rates.tx_pps))) if use_json: print(table_as_json(table, header)) else: @@ -272,7 +299,7 @@ def main(): sys.exit(0) tunnelstat = Tunnelstat() - cnstat_dict = tunnelstat.get_cnstat(tunnel=tunnel_name, tun_type=tunnel_type) + cnstat_dict,ratestat_dict = tunnelstat.get_cnstat(tunnel=tunnel_name, tun_type=tunnel_type) # At this point, either we'll create a file or open an existing one. if not os.path.exists(cnstat_dir): @@ -299,7 +326,7 @@ def main(): if tunnel_name: tunnelstat.cnstat_single_tunnel(tunnel_name, cnstat_dict, cnstat_cached_dict) else: - tunnelstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, use_json) + tunnelstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, ratestat_dict, use_json) except IOError as e: print(e.errno, e) else: @@ -310,16 +337,15 @@ def main(): if tunnel_name: tunnelstat.cnstat_single_tunnel(tunnel_name, cnstat_dict, None) else: - tunnelstat.cnstat_print(cnstat_dict, use_json) + tunnelstat.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 = tunnelstat.get_cnstat(tunnel=tunnel_name, tun_type=tunnel_type) + cnstat_new_dict, ratestat_dict = tunnelstat.get_cnstat(tunnel=tunnel_name, tun_type=tunnel_type) if tunnel_name: tunnelstat.cnstat_single_tunnel(tunnel_name, cnstat_new_dict, cnstat_dict) else: - tunnelstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, use_json) + tunnelstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, ratestat_dict, use_json) if __name__ == "__main__": main() diff --git a/utilities_common/netstat.py b/utilities_common/netstat.py index 5f17c1f4c6..8cdab71b26 100755 --- a/utilities_common/netstat.py +++ b/utilities_common/netstat.py @@ -56,6 +56,31 @@ def ns_util(newstr, oldstr, delta, port_rate=PORT_RATE): util = rate/(port_rate*1000*1000*1000/8.0)*100 return "{:.2f}%".format(util) +def format_brate(rate): + """ + Show the byte rate. + """ + if rate == STATUS_NA: + return STATUS_NA + else: + rate = float(rate) + if rate > 1024*1024*10: + rate = "{:.2f}".format(rate/1024/1024.0)+' MB' + elif rate > 1024*10: + rate = "{:.2f}".format(rate/1024.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 table_as_json(table, header): """ Print table as json format. From dc934cac0ba2dfd2be364dac9ec617bfa42156cb Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 16 Jul 2021 18:53:01 +0000 Subject: [PATCH 03/15] Added UT for tunnel stats --- scripts/tunnelstat | 6 +- show/vxlan.py | 4 +- tests/mock_tables/counters_db.json | 18 +++++ tests/tunnelstat_test.py | 108 +++++++++++++++++++++++++++++ utilities_common/netstat.py | 2 +- 5 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 tests/tunnelstat_test.py diff --git a/scripts/tunnelstat b/scripts/tunnelstat index 39f83453f8..d59dd22d54 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -28,11 +28,11 @@ 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, format_brate, format_prate, format_util +from utilities_common.netstat import ns_diff, ns_brate, ns_prate, 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") +nstat_fields = ("rx_b_ok", "rx_p_ok", "tx_b_ok", "tx_p_ok") NStats = namedtuple("NStats", nstat_fields) header = ['IFACE', 'RX_OK', 'RX_BPS', 'RX_PPS','TX_OK', 'TX_BPS', 'TX_PPS'] @@ -132,7 +132,7 @@ class Tunnelstat(object): if tunnel: if tun_type and counter_types[tun_type] != counter_tunnel_type_map[counter_tunnel_name_map[tunnel]]: print("Mismtch in tunnel type. Requested type %s actual type %s" % ( - counter_types[tun_type], counter_tunnel_type_map[counter_tunnel_name_map[tunnel])) + counter_types[tun_type], counter_tunnel_type_map[counter_tunnel_name_map[tunnel]])) sys.exit(2) cnstat_dict[tunnel] = get_counters(counter_tunnel_name_map[tunnel]) ratestat_dict[tunnel] = get_rates(counter_tunnel_name_map[tunnel]) diff --git a/show/vxlan.py b/show/vxlan.py index 9c165cec58..398de798f9 100644 --- a/show/vxlan.py +++ b/show/vxlan.py @@ -309,13 +309,13 @@ def remotemac(remote_vtep_ip, count): @click.argument('tunnel', required=False) @click.option('-p', '--period') @click.option('--verbose', is_flag=True, help="Enable verbose output") -def counter(tunnel): +def counters(tunnel, period, verbose): """Show VxLAN counters""" cmd = "tunnelstat -T vxlan" if period is not None: cmd += " -p {}".format(period) - if interface is not None: + if tunnel is not None: cmd += " -i {}".format(tunnel) clicommon.run_command(cmd, display_cmd=verbose) diff --git a/tests/mock_tables/counters_db.json b/tests/mock_tables/counters_db.json index 9ad472c03d..053165079e 100644 --- a/tests/mock_tables/counters_db.json +++ b/tests/mock_tables/counters_db.json @@ -520,6 +520,12 @@ "TX_BPS": "0", "TX_PPS": "0" }, + "COUNTERS:oid:0x2a0000000035e": { + "SAI_TUNNEL_STAT_IN_OCTETS": "81922", + "SAI_TUNNEL_STAT_IN_PACKETS": "452", + "SAI_TUNNEL_STAT_OUT_OCTETS": "23434", + "SAI_TUNNEL_STAT_OUT_PACKETS": "154" + }, "COUNTERS_RIF_NAME_MAP": { "Ethernet20": "oid:0x600000000065f", "PortChannel0001": "oid:0x60000000005a1", @@ -536,6 +542,18 @@ "oid:0x600000000063d": "SAI_ROUTER_INTERFACE_TYPE_PORT", "oid:0x600000000065f": "SAI_ROUTER_INTERFACE_TYPE_PORT" }, + "COUNTERS_TUNNEL_NAME_MAP": { + "vtep1": "oid:0x2a0000000035e" + }, + "COUNTERS_TUNNEL_TYPE_MAP": { + "oid:0x2a0000000035e": "SAI_TUNNEL_TYPE_VXLAN" + }, + "RATES:oid:0x2a0000000035e": { + "RX_BPS": "20971520", + "RX_PPS": "20523", + "TX_BPS": "2048", + "TX_PPS": "201" + }, "COUNTERS:DATAACL:DEFAULT_RULE": { "Bytes": "1", "Packets": "2" diff --git a/tests/tunnelstat_test.py b/tests/tunnelstat_test.py new file mode 100644 index 0000000000..4d17eb7931 --- /dev/null +++ b/tests/tunnelstat_test.py @@ -0,0 +1,108 @@ +import sys +import os +import traceback + +from click.testing import CliRunner + +test_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(test_path) +scripts_path = os.path.join(modules_path, "scripts") +sys.path.insert(0, test_path) +sys.path.insert(0, modules_path) + +from .mock_tables import dbconnector + +import show.main as show +import clear.main as clear + +show_vxlan_counters_output="""\ + IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS +------- ------- ---------- -------- ------- ----------- -------- + vtep1 452 20.00 MB/s 20523 154 2048.00 B/s 201 +""" + +show_vxlan_counters_clear_output="""\ + IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS +------- ------- ---------- -------- ------- ----------- -------- + vtep1 0 20.00 MB/s 20523 0 2048.00 B/s 201 +""" + +show_vxlan_counters_interface_output="""\ +vtep1 +----- + + RX: + 452 packets + 81922 bytes + TX: + 154 packets + 23434 bytes +""" + +show_vxlan_counters_clear_interface_output="""\ +vtep1 +----- + + RX: + 0 packets + 0 bytes + TX: + 0 packets + 0 bytes +""" +class TestTunnelstat(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "2" + + def test_no_param(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["vxlan"].commands["counters"], []) + print(result.exit_code) + print(result.output) + traceback.print_tb(result.exc_info[2]) + assert result.exit_code == 0 + assert result.output == show_vxlan_counters_output + + def test_single_tunnel(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["vxlan"].commands["counters"], ["vtep1"]) + expected = show_vxlan_counters_interface_output + assert result.output == expected + + + def test_clear(self): + runner = CliRunner() + result = runner.invoke(clear.cli.commands["tunnelcounters"], []) + print(result.stdout) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["vxlan"].commands["counters"], []) + print(result.stdout) + expected = show_vxlan_counters_clear_output + + # remove the counters snapshot + show.run_command("tunnelstat -D") + for line in expected: + assert line in result.output + + def test_clear_interface(self): + runner = CliRunner() + result = runner.invoke(clear.cli.commands["tunnelcounters"], []) + print(result.stdout) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["vxlan"].commands["counters"], ["vtep1"]) + print(result.stdout) + expected = show_vxlan_counters_clear_interface_output + + # remove the counters snapshot + show.run_command("tunnelstat -D") + for line in expected: + assert line in result.output + + @classmethod + 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/utilities_common/netstat.py b/utilities_common/netstat.py index 8cdab71b26..4fa48ca041 100755 --- a/utilities_common/netstat.py +++ b/utilities_common/netstat.py @@ -79,7 +79,7 @@ def format_prate(rate): if rate == STATUS_NA: return STATUS_NA else: - return "{:.2f}".format(float(rate))+'/s' + return "{:.2f}".format(float(rate)) def table_as_json(table, header): """ From 3a8643728b41034ee4306ba3fa69e39798cc7310 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 6 Aug 2021 04:48:47 +0000 Subject: [PATCH 04/15] Addressing code review comments --- counterpoll/main.py | 11 +++++------ scripts/tunnelstat | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/counterpoll/main.py b/counterpoll/main.py index f6d5d6c885..e04575d225 100644 --- a/counterpoll/main.py +++ b/counterpoll/main.py @@ -247,14 +247,13 @@ def tunnel(): """ Tunnel counter commands """ @tunnel.command() -@click.argument('poll_interval') +@click.argument('poll_interval', type=click.IntRange(100, 30000)) def interval(poll_interval): """ Set tunnel counter query interval """ configdb = ConfigDBConnector() configdb.connect() tunnel_info = {} - if poll_interval is not None: - tunnel_info['POLL_INTERVAL'] = poll_interval + tunnel_info['POLL_INTERVAL'] = poll_interval configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info) @tunnel.command() @@ -263,7 +262,7 @@ def enable(): configdb = ConfigDBConnector() configdb.connect() tunnel_info = {} - tunnel_info['FLEX_COUNTER_STATUS'] = 'enable' + tunnel_info['FLEX_COUNTER_STATUS'] = ENABLE configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info) @tunnel.command() @@ -272,7 +271,7 @@ def disable(): configdb = ConfigDBConnector() configdb.connect() tunnel_info = {} - tunnel_info['FLEX_COUNTER_STATUS'] = 'disable' + tunnel_info['FLEX_COUNTER_STATUS'] = DISABLE configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info) @cli.command() @@ -308,7 +307,7 @@ def show(): data.append(['PG_DROP_STAT', pg_drop_info.get("POLL_INTERVAL", DEFLT_10_SEC), pg_drop_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if buffer_pool_wm_info: data.append(["BUFFER_POOL_WATERMARK_STAT", buffer_pool_wm_info.get("POLL_INTERVAL", DEFLT_10_SEC), buffer_pool_wm_info.get("FLEX_COUNTER_STATUS", DISABLE)]) - if rif_info: + if tunnel_info: data.append(["TUNNEL_STAT", rif_info.get("POLL_INTERVAL", DEFLT_10_SEC), rif_info.get("FLEX_COUNTER_STATUS", DISABLE)]) click.echo(tabulate(data, headers=header, tablefmt="simple", missingval="")) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index d59dd22d54..527730a6b7 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -2,7 +2,7 @@ ##################################################################### # -# tunnelstat is a tool for summarizing l3 network statistics. +# tunnelstat is a tool for summarizing various tunnel statistics. # ##################################################################### From 4df3a51a177af3f6aa0efddcf8574bc69d6408f5 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Sat, 7 Aug 2021 17:37:50 +0000 Subject: [PATCH 05/15] Fixing lgtm --- scripts/tunnelstat | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index 527730a6b7..9576960555 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -21,14 +21,13 @@ try: test_path = os.path.join(modules_path, "tests") sys.path.insert(0, modules_path) sys.path.insert(0, test_path) - import mock_tables.dbconnector except KeyError: pass 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, format_brate, format_prate +from utilities_common.netstat import ns_diff, table_as_json, STATUS_NA, format_brate, format_prate from swsscommon.swsscommon import SonicV2Connector @@ -173,8 +172,6 @@ class Tunnelstat(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: @@ -331,7 +328,7 @@ def main(): print(e.errno, e) else: if tag_name: - print("\nFile '%s' does not exist" % cnstat_fqn_file) + print("\nFile belonging to tag %s does not exist" % tag_name) print("Did you run 'tunnelstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name)) else: if tunnel_name: From 4162427e7631de8c9ecb8490c6b85d5b44a982ce Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Sat, 7 Aug 2021 18:30:36 +0000 Subject: [PATCH 06/15] Fixing build failure --- scripts/tunnelstat | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index 9576960555..22b492696c 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -21,6 +21,7 @@ try: test_path = os.path.join(modules_path, "tests") sys.path.insert(0, modules_path) sys.path.insert(0, test_path) + import mock_tables.dbconnector except KeyError: pass From 44dc509a51de49d4f5bb5e938a78415ec00213c4 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 10 Sep 2021 02:45:45 +0000 Subject: [PATCH 07/15] Updating setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index c28af558ab..30e8c7bfd4 100644 --- a/setup.py +++ b/setup.py @@ -128,6 +128,7 @@ 'scripts/storyteller', 'scripts/syseeprom-to-json', 'scripts/tempershow', + 'scripts/tunnelstat', 'scripts/update_json.py', 'scripts/voqutil', 'scripts/warm-reboot', From 5fdbffc34fca39ae5ebda32faf01dfcd025eb1e9 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Tue, 14 Sep 2021 03:49:19 +0000 Subject: [PATCH 08/15] Removing unused variables --- scripts/tunnelstat | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index 22b492696c..571f703788 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -58,13 +58,6 @@ RATES_TABLE_PREFIX = "RATES:" COUNTERS_TUNNEL_NAME_MAP = "COUNTERS_TUNNEL_NAME_MAP" COUNTERS_TUNNEL_TYPE_MAP = "COUNTERS_TUNNEL_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 Tunnelstat(object): def __init__(self): From 5fa80f21cb3aaa5aa0aeca9227e2a26206e7b39f Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Sat, 16 Oct 2021 04:42:53 +0000 Subject: [PATCH 09/15] Removing duplicate code --- utilities_common/netstat.py | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/utilities_common/netstat.py b/utilities_common/netstat.py index 4fa48ca041..5f17c1f4c6 100755 --- a/utilities_common/netstat.py +++ b/utilities_common/netstat.py @@ -56,31 +56,6 @@ def ns_util(newstr, oldstr, delta, port_rate=PORT_RATE): util = rate/(port_rate*1000*1000*1000/8.0)*100 return "{:.2f}%".format(util) -def format_brate(rate): - """ - Show the byte rate. - """ - if rate == STATUS_NA: - return STATUS_NA - else: - rate = float(rate) - if rate > 1024*1024*10: - rate = "{:.2f}".format(rate/1024/1024.0)+' MB' - elif rate > 1024*10: - rate = "{:.2f}".format(rate/1024.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)) - def table_as_json(table, header): """ Print table as json format. From c2bb8edbb379dcce7ebdf659fa12eba27aab0844 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Sat, 16 Oct 2021 05:01:06 +0000 Subject: [PATCH 10/15] Fixing UT --- tests/tunnelstat_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/tunnelstat_test.py b/tests/tunnelstat_test.py index 4d17eb7931..1ff21bdba9 100644 --- a/tests/tunnelstat_test.py +++ b/tests/tunnelstat_test.py @@ -16,15 +16,15 @@ import clear.main as clear show_vxlan_counters_output="""\ - IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS -------- ------- ---------- -------- ------- ----------- -------- - vtep1 452 20.00 MB/s 20523 154 2048.00 B/s 201 + IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS +------- ------- ---------- ---------- ------- ----------- -------- + vtep1 452 20.97 MB/s 20523.00/s 154 2048.00 B/s 201.00/s """ show_vxlan_counters_clear_output="""\ - IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS -------- ------- ---------- -------- ------- ----------- -------- - vtep1 0 20.00 MB/s 20523 0 2048.00 B/s 201 + IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS +------- ------- ---------- ---------- ------- ----------- -------- + vtep1 452 20.97 MB/s 20523.00/s 0 2048.00 B/s 201.00/s """ show_vxlan_counters_interface_output="""\ From 91c96c4efc61076554489c091b7b17c057b52c93 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 22 Oct 2021 03:39:54 +0000 Subject: [PATCH 11/15] Changing bytes/sec to bytes since its more appropriate for tunnel stats --- scripts/tunnelstat | 14 +++++++------- tests/tunnelstat_test.py | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index 571f703788..c53fc0f0e4 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -35,7 +35,7 @@ from swsscommon.swsscommon import SonicV2Connector nstat_fields = ("rx_b_ok", "rx_p_ok", "tx_b_ok", "tx_p_ok") NStats = namedtuple("NStats", nstat_fields) -header = ['IFACE', 'RX_OK', 'RX_BPS', 'RX_PPS','TX_OK', 'TX_BPS', 'TX_PPS'] +header = ['IFACE', 'RX_OK', 'RX_BYTES', 'RX_PPS','TX_OK', 'TX_BYTES', 'TX_PPS'] rates_key_list = [ 'RX_BPS', 'RX_PPS', 'TX_BPS', 'TX_PPS'] ratestat_fields = ("rx_bps", "rx_pps", "tx_bps", "tx_pps") @@ -148,8 +148,8 @@ class Tunnelstat(object): continue 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.tx_p_ok, format_brate(rates.tx_bps), format_prate(rates.tx_pps))) + table.append((key, data.rx_p_ok, data.rx_b_ok, format_prate(rates.rx_pps), + data.tx_p_ok, data.tx_b_ok, format_prate(rates.tx_pps))) if use_json: print(table_as_json(table, header)) @@ -175,18 +175,18 @@ class Tunnelstat(object): if old_cntr is not None: table.append((key, ns_diff(cntr.rx_p_ok, old_cntr.rx_p_ok), - format_brate(rates.rx_bps), + ns_diff(cntr.rx_b_ok, old_cntr.rx_b_ok), format_prate(rates.rx_pps), ns_diff(cntr.tx_p_ok, old_cntr.tx_p_ok), - format_brate(rates.tx_bps), + ns_diff(cntr.tx_b_ok, old_cntr.tx_b_ok), format_prate(rates.tx_pps))) else: table.append((key, cntr.rx_p_ok, - format_brate(rates.rx_bps), + cntr.rx_b_ok, format_prate(rates.rx_pps), cntr.tx_p_ok, - format_brate(rates.tx_bps), + cntr.tx_b_ok, format_prate(rates.tx_pps))) if use_json: print(table_as_json(table, header)) diff --git a/tests/tunnelstat_test.py b/tests/tunnelstat_test.py index 1ff21bdba9..c816009a45 100644 --- a/tests/tunnelstat_test.py +++ b/tests/tunnelstat_test.py @@ -16,15 +16,15 @@ import clear.main as clear show_vxlan_counters_output="""\ - IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS -------- ------- ---------- ---------- ------- ----------- -------- - vtep1 452 20.97 MB/s 20523.00/s 154 2048.00 B/s 201.00/s + IFACE RX_OK RX_BYTES RX_PPS TX_OK TX_BYTES TX_PPS +------- ------- ---------- ---------- ------- ---------- -------- + vtep1 452 81922 20523.00/s 154 23434 201.00/s """ show_vxlan_counters_clear_output="""\ - IFACE RX_OK RX_BPS RX_PPS TX_OK TX_BPS TX_PPS -------- ------- ---------- ---------- ------- ----------- -------- - vtep1 452 20.97 MB/s 20523.00/s 0 2048.00 B/s 201.00/s + IFACE RX_OK RX_BYTES RX_PPS TX_OK TX_BYTES TX_PPS +------- ------- ---------- ---------- ------- ---------- -------- + vtep1 0 0 20523.00/s 0 0 201.00/s """ show_vxlan_counters_interface_output="""\ From 5d0c0589e5fff52f72fcf243477afc05fce693c3 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 22 Oct 2021 05:20:50 +0000 Subject: [PATCH 12/15] Addressing code review comments --- scripts/tunnelstat | 2 +- tests/tunnelstat_test.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index c53fc0f0e4..829a5ab5d2 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -35,7 +35,7 @@ from swsscommon.swsscommon import SonicV2Connector nstat_fields = ("rx_b_ok", "rx_p_ok", "tx_b_ok", "tx_p_ok") NStats = namedtuple("NStats", nstat_fields) -header = ['IFACE', 'RX_OK', 'RX_BYTES', 'RX_PPS','TX_OK', 'TX_BYTES', 'TX_PPS'] +header = ['IFACE', 'RX_PKTS', 'RX_BYTES', 'RX_PPS','TX_PKTS', 'TX_BYTES', 'TX_PPS'] rates_key_list = [ 'RX_BPS', 'RX_PPS', 'TX_BPS', 'TX_PPS'] ratestat_fields = ("rx_bps", "rx_pps", "tx_bps", "tx_pps") diff --git a/tests/tunnelstat_test.py b/tests/tunnelstat_test.py index c816009a45..286cd7feeb 100644 --- a/tests/tunnelstat_test.py +++ b/tests/tunnelstat_test.py @@ -16,15 +16,15 @@ import clear.main as clear show_vxlan_counters_output="""\ - IFACE RX_OK RX_BYTES RX_PPS TX_OK TX_BYTES TX_PPS -------- ------- ---------- ---------- ------- ---------- -------- - vtep1 452 81922 20523.00/s 154 23434 201.00/s + IFACE RX_PKTS RX_BYTES RX_PPS TX_PKTS TX_BYTES TX_PPS +------- --------- ---------- ---------- --------- ---------- -------- + vtep1 452 81922 20523.00/s 154 23434 201.00/s """ show_vxlan_counters_clear_output="""\ - IFACE RX_OK RX_BYTES RX_PPS TX_OK TX_BYTES TX_PPS -------- ------- ---------- ---------- ------- ---------- -------- - vtep1 0 0 20523.00/s 0 0 201.00/s + IFACE RX_PKTS RX_BYTES RX_PPS TX_PKTS TX_BYTES TX_PPS +------- --------- ---------- ---------- --------- ---------- -------- + vtep1 0 0 20523.00/s 0 0 201.00/s """ show_vxlan_counters_interface_output="""\ From fe622b20ff339b465125195d48cced5868d5f560 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 22 Oct 2021 05:32:04 +0000 Subject: [PATCH 13/15] Fixing lgtm --- scripts/tunnelstat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tunnelstat b/scripts/tunnelstat index 829a5ab5d2..00aab5d832 100755 --- a/scripts/tunnelstat +++ b/scripts/tunnelstat @@ -28,7 +28,7 @@ except KeyError: from collections import namedtuple, OrderedDict from natsort import natsorted from tabulate import tabulate -from utilities_common.netstat import ns_diff, table_as_json, STATUS_NA, format_brate, format_prate +from utilities_common.netstat import ns_diff, table_as_json, STATUS_NA, format_prate from swsscommon.swsscommon import SonicV2Connector From 61d85fb431fd2c2e7ff7d66d83419ebd91668b64 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 22 Oct 2021 16:47:29 +0000 Subject: [PATCH 14/15] Cosmetic changes --- tests/tunnelstat_test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/tunnelstat_test.py b/tests/tunnelstat_test.py index 286cd7feeb..d8308e0290 100644 --- a/tests/tunnelstat_test.py +++ b/tests/tunnelstat_test.py @@ -1,3 +1,6 @@ +import clear.main as clear +import show.main as show +from .mock_tables import dbconnector import sys import os import traceback @@ -10,24 +13,20 @@ sys.path.insert(0, test_path) sys.path.insert(0, modules_path) -from .mock_tables import dbconnector - -import show.main as show -import clear.main as clear -show_vxlan_counters_output="""\ +show_vxlan_counters_output = """\ IFACE RX_PKTS RX_BYTES RX_PPS TX_PKTS TX_BYTES TX_PPS ------- --------- ---------- ---------- --------- ---------- -------- vtep1 452 81922 20523.00/s 154 23434 201.00/s """ -show_vxlan_counters_clear_output="""\ +show_vxlan_counters_clear_output = """\ IFACE RX_PKTS RX_BYTES RX_PPS TX_PKTS TX_BYTES TX_PPS ------- --------- ---------- ---------- --------- ---------- -------- vtep1 0 0 20523.00/s 0 0 201.00/s """ -show_vxlan_counters_interface_output="""\ +show_vxlan_counters_interface_output = """\ vtep1 ----- @@ -39,7 +38,7 @@ 23434 bytes """ -show_vxlan_counters_clear_interface_output="""\ +show_vxlan_counters_clear_interface_output = """\ vtep1 ----- @@ -50,6 +49,8 @@ 0 packets 0 bytes """ + + class TestTunnelstat(object): @classmethod def setup_class(cls): @@ -72,7 +73,6 @@ def test_single_tunnel(self): expected = show_vxlan_counters_interface_output assert result.output == expected - def test_clear(self): runner = CliRunner() result = runner.invoke(clear.cli.commands["tunnelcounters"], []) From 81df07d093c2ee860fd3200cb1802837d078328a Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 22 Oct 2021 16:49:38 +0000 Subject: [PATCH 15/15] Cosmetic changes --- tests/tunnelstat_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tunnelstat_test.py b/tests/tunnelstat_test.py index d8308e0290..f1fe716ef3 100644 --- a/tests/tunnelstat_test.py +++ b/tests/tunnelstat_test.py @@ -1,6 +1,3 @@ -import clear.main as clear -import show.main as show -from .mock_tables import dbconnector import sys import os import traceback @@ -13,6 +10,9 @@ sys.path.insert(0, test_path) sys.path.insert(0, modules_path) +import clear.main as clear +import show.main as show +from .mock_tables import dbconnector show_vxlan_counters_output = """\ IFACE RX_PKTS RX_BYTES RX_PPS TX_PKTS TX_BYTES TX_PPS