From 46a0f9a96ee75dcf9a36b452ff7348e49244ba68 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Sun, 31 May 2020 23:49:39 -0700 Subject: [PATCH 01/19] CLICK CLI - Configuration and show commands for BUM Storm-control feature. configuration commands ---------------------- config interface storm-control broadcast add Ethernet0 10000 config interface storm-control unknown-multicast add Ethernet0 10000 config interface storm-control unknown-unicast add Ethernet0 10000 config interface storm-control broadcast del Ethernet0 config interface storm-control unknown-multicast del Ethernet0 config interface storm-control unknown-unicast del Ethernet0 show commands ------------- show storm-control all show storm-control interface Ethernet0 Sample output ------------- show storm-control interface Ethernet0 +------------------+-------------------+---------------+ | Interface Name | Storm Type | Rate (kbps) | +==================+===================+===============+ | Ethernet0 | broadcast | 10000 | +------------------+-------------------+---------------+ | Ethernet0 | unknown-unicast | 10000 | +------------------+-------------------+---------------+ | Ethernet0 | unknown-multicast | 10000 | +------------------+-------------------+---------------+ --- config/main.py | 150 +++++++++++++++++++++++++++++++++++++++++++++++++ show/main.py | 66 ++++++++++++++++++++++ 2 files changed, 216 insertions(+) diff --git a/config/main.py b/config/main.py index 377a7adf32..cae20882d3 100755 --- a/config/main.py +++ b/config/main.py @@ -283,6 +283,72 @@ def _change_hostname(hostname): run_command('sed -i "/\s{}$/d" /etc/hosts'.format(current_hostname), display_cmd=True) run_command('echo "127.0.0.1 {}" >> /etc/hosts'.format(hostname), display_cmd=True) +def storm_control_interface_validate(port_name): + if get_interface_naming_mode() == "alias": + port_name = interface_alias_to_name(port_name) + if port_name is None: + click.echo("'port_name' is None!") + return False + + if (port_name.startswith("Ethernet")): + if interface_name_is_valid(port_name) is False: + click.echo("Interface name %s is invalid. Please enter a valid interface name" %(port_name)) + return False + else: + click.echo("Storm-control is supported only on Ethernet interfaces. Not supported on %s" %(port_name)) + return False + + return True + +def storm_control_bps_validate(bps): + # if bps not in range(0,100000000001): + # click.echo("bps value must be in range 0-100000000000") + # return False + return True + +def storm_control_set_entry(port_name, kbps, storm_type): + + if storm_control_interface_validate(port_name) is False: + return False + + if storm_control_bps_validate(kbps) is False: + return False + + config_db = ConfigDBConnector() + config_db.connect() + key = port_name + '|' + storm_type + entry = config_db.get_entry('PORT_STORM_CONTROL',key) + + if len(entry) == 0: + config_db.set_entry('PORT_STORM_CONTROL', key, {'kbps':kbps}) + else: + kbps_value = int(entry.get('kbps',0)) + click.echo("Existing value of bps %d"%(kbps_value)) + if kbps_value != kbps: + config_db.mod_entry('PORT_STORM_CONTROL',key,{'kbps':kbps}) + + return True + +def storm_control_delete_entry(port_name, storm_type): + + if storm_control_interface_validate(port_name) is False: + return False + + config_db = ConfigDBConnector() + config_db.connect() + key = port_name + '|' + storm_type + entry = config_db.get_entry('PORT_STORM_CONTROL',key) + + if len(entry) == 0: + click.echo("%s storm-control not enabled on interface %s"%(storm_type, port_name)) + return False + else: + config_db.set_entry('PORT_STORM_CONTROL',key,None) + click.echo("deleted %s storm-control from interface %s"%(storm_type, port_name)) + + return True + + def _clear_qos(): QOS_TABLE_NAMES = [ 'TC_TO_PRIORITY_GROUP_MAP', @@ -1410,6 +1476,90 @@ def naming_mode_alias(): """Set CLI interface naming mode to ALIAS (Vendor port alias)""" set_interface_naming_mode('alias') +@interface.group('storm-control') +@click.pass_context +def storm_control(ctx): + """ Configure storm-control""" + pass + +@storm_control.group('broadcast') +def broadcast(): + """ Configure broadcast storm-control""" + pass + +@broadcast.command('add') +@click.argument('port_name',metavar='', required=True) +@click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) +@click.pass_context +def add_broadcast_storm(ctx,port_name,kbps): + print"add broadcast storm-control" + + if storm_control_set_entry(port_name, kbps, 'broadcast') is False: + ctx.fail("Unable to add broadcast storm-control") + +@broadcast.command('del') +@click.argument('port_name',metavar='', required=True) +#@click.argument('bps',metavar='', required=True, type=int) +@click.pass_context +#def del_broadcast_storm(ctx,port_name,bps): +def del_broadcast_storm(ctx,port_name): + print"del broadcast storm-control" + + if storm_control_delete_entry(port_name, 'broadcast') is False: + ctx.fail("Unable to delete broadcast storm-control") + +@storm_control.group('unknown-unicast') +def unknown_unicast(): + """ Configure unknown-unicast storm-control""" + pass + +@unknown_unicast.command('add') +@click.argument('port_name',metavar='', required=True) +@click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) +@click.pass_context +def add_unknown_unicast_storm(ctx,port_name,kbps): + print"add unknown-unicast storm-control" + + if storm_control_set_entry(port_name, kbps, 'unknown-unicast') is False: + ctx.fail("Unable to add unknown-unicast storm-control") + +@unknown_unicast.command('del') +@click.argument('port_name',metavar='', required=True) +#@click.argument('bps',metavar='', required=True, type=int) +@click.pass_context +#def del_unknown_unicast_storm(ctx,port_name,bps): +def del_unknown_unicast_storm(ctx,port_name): + print"del unknown-unicast storm-control" + + if storm_control_delete_entry(port_name, 'unknown-unicast') is False: + ctx.fail("Unable to delete unknown-unicast storm-control") + +@storm_control.group('unknown-multicast') +def unknown_multicast(): + """ Configure unknown-multicast storm-control""" + pass + +@unknown_multicast.command('add') +@click.argument('port_name',metavar='', required=True) +@click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) +@click.pass_context +def add_unknown_multicast_storm(ctx,port_name,kbps): + print"add unknown-multicast storm-control" + + if storm_control_set_entry(port_name, kbps, 'unknown-multicast') is False: + ctx.fail("Unable to add unknown-multicast storm-control") + +@unknown_multicast.command('del') +@click.argument('port_name',metavar='', required=True) +#@click.argument('bps',metavar='', required=True, type=int) +@click.pass_context +#def del_unknown_multicast_storm(ctx,port_name,bps): +def del_unknown_multicast_storm(ctx,port_name): + print"del unknown-multicast storm-control" + + if storm_control_delete_entry(port_name, 'unknown-multicast') is False: + ctx.fail("Unable to delete unknown-multicast storm-control") + # # 'syslog' group ('config syslog ...') # diff --git a/show/main.py b/show/main.py index 3d2d225fd2..36acfd3960 100755 --- a/show/main.py +++ b/show/main.py @@ -464,6 +464,72 @@ def alias(interfacename): click.echo(tabulate(body, header)) +@cli.group('storm-control') +def storm_control(): + """ show storm-control """ + pass +@storm_control.command('all') +def storm_control_all(): + """ Show storm-control """ + + header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] + body = [] + + config_db = ConfigDBConnector() + config_db.connect() + + table = config_db.get_table('PORT_STORM_CONTROL') + + #To avoid further looping below + if not table: + return + + sorted_table = natsorted(table) + + for storm_key in sorted_table: + interface_name = storm_key[0] + storm_type = storm_key[1] + #interface_name, storm_type = storm_key.split(':') + data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) + + if not data: + return + + kbps = data['kbps'] + + body.append([interface_name, storm_type, kbps]) + + click.echo(tabulate(body, header, tablefmt="grid")) + +@storm_control.command('interface') +@click.argument('interfacename', required=True) +def storm_control_interface(interfacename): + """ Show storm-control """ + + storm_type_list = ['broadcast','unknown-unicast','unknown-multicast'] + + header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] + body = [] + + config_db = ConfigDBConnector() + config_db.connect() + + table = config_db.get_table('PORT_STORM_CONTROL') + + #To avoid further looping below + if not table: + return + + for storm_type in storm_type_list: + storm_key = interfacename + '|' + storm_type + data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) + + if data: + kbps = data['kbps'] + body.append([interfacename, storm_type, kbps]) + + click.echo(tabulate(body, header, tablefmt="grid")) + # # 'neighbor' group ### # From a073d9348fd0d38313375c386c61033edf7e6015 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Mon, 1 Nov 2021 23:47:30 -0700 Subject: [PATCH 02/19] Update parameters to interface_alias_to_name and interface_name_is_valid APIs --- config/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/main.py b/config/main.py index 0bdddc3d74..a62273108d 100644 --- a/config/main.py +++ b/config/main.py @@ -635,13 +635,13 @@ def _clear_cbf(): def storm_control_interface_validate(port_name): if get_interface_naming_mode() == "alias": - port_name = interface_alias_to_name(port_name) + port_name = interface_alias_to_name(None, port_name) if port_name is None: click.echo("'port_name' is None!") return False if (port_name.startswith("Ethernet")): - if interface_name_is_valid(port_name) is False: + if interface_name_is_valid(None, port_name) is False: click.echo("Interface name %s is invalid. Please enter a valid interface name" %(port_name)) return False else: From 37b41f0314d2458b3c05d67a1f2072655c0d14d9 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Wed, 3 Nov 2021 14:36:28 -0700 Subject: [PATCH 03/19] addressed review comments. --- config/main.py | 76 +++++++++++++++++++++----------------------------- show/main.py | 14 ++++------ 2 files changed, 38 insertions(+), 52 deletions(-) diff --git a/config/main.py b/config/main.py index a62273108d..41ef47b34a 100644 --- a/config/main.py +++ b/config/main.py @@ -632,7 +632,7 @@ def _clear_cbf(): for cbf_table in CBF_TABLE_NAMES: config_db.delete_table(cbf_table) - +#API to validate the interface passed for storm-control configuration def storm_control_interface_validate(port_name): if get_interface_naming_mode() == "alias": port_name = interface_alias_to_name(None, port_name) @@ -650,35 +650,29 @@ def storm_control_interface_validate(port_name): return True -def storm_control_bps_validate(bps): - # if bps not in range(0,100000000001): - # click.echo("bps value must be in range 0-100000000000") - # return False - return True - +#API to configure the PORT_STORM_CONTROL table def storm_control_set_entry(port_name, kbps, storm_type): if storm_control_interface_validate(port_name) is False: return False - if storm_control_bps_validate(kbps) is False: - return False - + #Validate kbps value config_db = ConfigDBConnector() config_db.connect() key = port_name + '|' + storm_type - entry = config_db.get_entry('PORT_STORM_CONTROL',key) + entry = config_db.get_entry('PORT_STORM_CONTROL', key) if len(entry) == 0: config_db.set_entry('PORT_STORM_CONTROL', key, {'kbps':kbps}) else: kbps_value = int(entry.get('kbps',0)) - click.echo("Existing value of bps %d"%(kbps_value)) + click.echo("Existing value of kbps %d" %(kbps_value)) if kbps_value != kbps: - config_db.mod_entry('PORT_STORM_CONTROL',key,{'kbps':kbps}) + config_db.mod_entry('PORT_STORM_CONTROL', key, {'kbps':kbps}) return True +#API to remove an entry from PORT_STORM_CONTROL table def storm_control_delete_entry(port_name, storm_type): if storm_control_interface_validate(port_name) is False: @@ -687,14 +681,14 @@ def storm_control_delete_entry(port_name, storm_type): config_db = ConfigDBConnector() config_db.connect() key = port_name + '|' + storm_type - entry = config_db.get_entry('PORT_STORM_CONTROL',key) + entry = config_db.get_entry('PORT_STORM_CONTROL', key) if len(entry) == 0: - click.echo("%s storm-control not enabled on interface %s"%(storm_type, port_name)) + click.echo("%s storm-control not enabled on interface %s" %(storm_type, port_name)) return False else: - config_db.set_entry('PORT_STORM_CONTROL',key,None) - click.echo("deleted %s storm-control from interface %s"%(storm_type, port_name)) + config_db.set_entry('PORT_STORM_CONTROL', key, None) + click.echo("deleted %s storm-control from interface %s" %(storm_type, port_name)) return True @@ -5402,22 +5396,20 @@ def broadcast(): pass @broadcast.command('add') -@click.argument('port_name',metavar='', required=True) -@click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) +@click.argument('port_name', metavar='', required=True) +@click.argument('kbps', metavar='', required=True, type=click.IntRange(0,100000000)) @click.pass_context -def add_broadcast_storm(ctx,port_name,kbps): - print"add broadcast storm-control" +def add_broadcast_storm(ctx, port_name, kbps): + click.echo("add broadcast storm-control") if storm_control_set_entry(port_name, kbps, 'broadcast') is False: ctx.fail("Unable to add broadcast storm-control") @broadcast.command('del') -@click.argument('port_name',metavar='', required=True) -#@click.argument('bps',metavar='', required=True, type=int) +@click.argument('port_name', metavar='', required=True) @click.pass_context -#def del_broadcast_storm(ctx,port_name,bps): -def del_broadcast_storm(ctx,port_name): - print"del broadcast storm-control" +def del_broadcast_storm(ctx, port_name): + click.echo("del broadcast storm-control") if storm_control_delete_entry(port_name, 'broadcast') is False: ctx.fail("Unable to delete broadcast storm-control") @@ -5428,22 +5420,20 @@ def unknown_unicast(): pass @unknown_unicast.command('add') -@click.argument('port_name',metavar='', required=True) -@click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) +@click.argument('port_name', metavar='', required=True) +@click.argument('kbps', metavar='', required=True, type=click.IntRange(0,100000000)) @click.pass_context -def add_unknown_unicast_storm(ctx,port_name,kbps): - print"add unknown-unicast storm-control" +def add_unknown_unicast_storm(ctx, port_name, kbps): + click.echo("add unknown-unicast storm-control") if storm_control_set_entry(port_name, kbps, 'unknown-unicast') is False: ctx.fail("Unable to add unknown-unicast storm-control") @unknown_unicast.command('del') -@click.argument('port_name',metavar='', required=True) -#@click.argument('bps',metavar='', required=True, type=int) +@click.argument('port_name', metavar='', required=True) @click.pass_context -#def del_unknown_unicast_storm(ctx,port_name,bps): -def del_unknown_unicast_storm(ctx,port_name): - print"del unknown-unicast storm-control" +def del_unknown_unicast_storm(ctx, port_name): + click.echo("del unknown-unicast storm-control") if storm_control_delete_entry(port_name, 'unknown-unicast') is False: ctx.fail("Unable to delete unknown-unicast storm-control") @@ -5454,22 +5444,20 @@ def unknown_multicast(): pass @unknown_multicast.command('add') -@click.argument('port_name',metavar='', required=True) -@click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) +@click.argument('port_name', metavar='', required=True) +@click.argument('kbps', metavar='', required=True, type=click.IntRange(0,100000000)) @click.pass_context -def add_unknown_multicast_storm(ctx,port_name,kbps): - print"add unknown-multicast storm-control" +def add_unknown_multicast_storm(ctx, port_name, kbps): + click.echo("add unknown-multicast storm-control") if storm_control_set_entry(port_name, kbps, 'unknown-multicast') is False: ctx.fail("Unable to add unknown-multicast storm-control") @unknown_multicast.command('del') -@click.argument('port_name',metavar='', required=True) -#@click.argument('bps',metavar='', required=True, type=int) +@click.argument('port_name', metavar='', required=True) @click.pass_context -#def del_unknown_multicast_storm(ctx,port_name,bps): -def del_unknown_multicast_storm(ctx,port_name): - print"del unknown-multicast storm-control" +def del_unknown_multicast_storm(ctx, port_name): + click.echo("del unknown-multicast storm-control") if storm_control_delete_entry(port_name, 'unknown-multicast') is False: ctx.fail("Unable to delete unknown-multicast storm-control") diff --git a/show/main.py b/show/main.py index 0122281a2f..6bf3e411a4 100755 --- a/show/main.py +++ b/show/main.py @@ -311,9 +311,10 @@ def is_mgmt_vrf_enabled(ctx): def storm_control(): """ show storm-control """ pass + @storm_control.command('all') def storm_control_all(): - """ Show storm-control """ + """ Show storm-control for all interfaces""" header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] body = [] @@ -335,19 +336,16 @@ def storm_control_all(): #interface_name, storm_type = storm_key.split(':') data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) - if not data: - return - - kbps = data['kbps'] - - body.append([interface_name, storm_type, kbps]) + if data: + kbps = data['kbps'] + body.append([interface_name, storm_type, kbps]) click.echo(tabulate(body, header, tablefmt="grid")) @storm_control.command('interface') @click.argument('interfacename', required=True) def storm_control_interface(interfacename): - """ Show storm-control """ + """ Show storm-control for an interface""" storm_type_list = ['broadcast','unknown-unicast','unknown-multicast'] From f5b354ec57920591f3f14274c7b8cc315add1866 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Mon, 8 Nov 2021 23:58:31 -0800 Subject: [PATCH 04/19] utilities test code for storm-control --- scripts/storm_control.py | 141 +++++++++++++++++++++++++++++++ setup.py | 1 + tests/mock_tables/config_db.json | 20 +++++ 3 files changed, 162 insertions(+) create mode 100644 scripts/storm_control.py diff --git a/scripts/storm_control.py b/scripts/storm_control.py new file mode 100644 index 0000000000..16cf27a246 --- /dev/null +++ b/scripts/storm_control.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 + +############################################ +# +# script to test storm_control functionality +# +############################################ + +import _pickle as pickle +import argparse +import datetime +import json +import sys +import os +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 natsort import natsorted +from tabulate import tabulate +from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector +from utilities_common.general import load_db_config + +STORM_TABLE_NAME = "PORT_STORM_CONTROL" + +class storm_control(object): + def __init__(self): + self.config_db = ConfigDBConnector() + self.config_db.connect() + self.db = SonicV2Connector(use_unix_socket_path=False) + self.db.connect(self.db.CONFIG_DB) + def show_storm_config(self, port): + header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] + storm_type_list = ['broadcast','unknown-unicast','unknown-multicast'] + body = [] + configs = self.db.get_table(STORM_TABLE_NAME) + if not configs: + return + storm_configs = natsorted(configs) + if port is not None: + for storm_type in storm_type_list: + storm_key = port + '|' + storm_type + data = self.db.get_entry(STORM_TABLE_NAME, storm_key) + if data: + kbps = data['kbps'] + body.append([port, storm_type, kbps]) + else: + for storm_key in sorted_table: + interface_name = storm_key[0] + storm_type = storm_key[1] + data = self.db.get_entry(STORM_TABLE_NAME, storm_key) + if data: + kbps = data['kbps'] + body.append([interface_name, storm_type, kbps]) + print(tabulate(body,header,tablefmt="grid")) + + def validate_interface(self, port): + if not (port.startswith("Eth")): + return False + return True + + def validate_kbps(self, kbps): + return True + + def add_storm_config(self, port, storm_type, kbps): + if not validate_interface(port): + print ("Invalid Interface:{}".format(port)) + return False + if not validate_kbps(kbps): + print ("Invalid kbps value:{}".format(kbps)) + return False + key = port + '|' + storm_type + entry = self.db.get_entry(STORM_TABLE_NAME,key) + if len(entry) == 0: + self.db.set_entry(STORM_TABLE_NAME, key, {'kbps':kbps}) + else: + kbps_value = int(entry.get('kbps',0)) + if kbps_value != kbps: + self.db.mod_entry(STORM_TABLE_NAME, key, {'kbps':kbps}) + return True + + def del_storm_config(self, port, storm_type): + if not validate_interface(port): + print ("Invalid Interface:{}".format(port)) + return False + key = port_name + '|' + storm_type + entry = self.db.get_entry(STORM_TABLE_NAME, key) + if len(entry): + self.db.set_entry(STORM_TABLE_NAME, key, None) + return True + +def main(): + parser = argparse.ArgumentParser(description='Configure and Display storm-control configuration', + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-l', '--list', action='store_true', help='show storm-control configuration', default=False) + parser.add_argument('-p', '--port', type=str, help='port name (e.g. Ethernet0)', required=True, default=None) + parser.add_argument('-t', '--storm-type', type=str, help='storm-type (broadcast, unknown-unicast, unknown-multicast)', required=True, default=None) + parser.add_argument('-r', '--rate-kbps', type=int, help='kbps value', required=True, default=None) + parser.add_argument('-d', '--delete', help='delete storm-control') + parser.add_argument('-f', '--filename', help='file used by mock test', type=str, default=None) + args = parser.parse_args() + + # Load database config files + load_db_config() + try: + storm = storm_control() + if args.list: + input_port="" + if args.port: + input_port = args.port + storm.show_storm_config(input_port) + elif args.port and args.storm_type and args.rate_kbps: + if args.delete: + storm.del_storm_config(args.port, args.storm_type) + else: + storm.add_storm_config(args.port, args.storm_type, args.rate_kbps) + else: + parser.print_help() + sys.exit(1) + + except Exception as e: + try: + if os.environ["UTILITIES_UNIT_TESTING"] == "1" or os.environ["UTILITIES_UNIT_TESTING"] == "2": + print(str(e), file=sys.stdout) + except KeyError: + print(str(e), file=sys.stderr) + + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 30e8c7bfd4..57dbebc695 100644 --- a/setup.py +++ b/setup.py @@ -138,6 +138,7 @@ 'scripts/centralize_database', 'scripts/null_route_helper', 'scripts/check_db_integrity.py' + 'scripts/storm_control.py' ], entry_points={ 'console_scripts': [ diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index 06305d3046..22357745c2 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -1529,6 +1529,26 @@ "nhopself": "0", "rrclient": "0" }, + "PORT_STORM_CONTROL": { + "Ethernet0|broadcast": { + "kbps":"100000" + }, + "Ethernet0|unknown-unicast": { + "kbps":"200000" + }, + "Ethernet0|unknown-multicast": { + "kbps":"300000" + }, + "Ethernet4|broadcast": { + "kbps":"400000" + }, + "Ethernet8|unknown-unicast": { + "kbps":"500000" + }, + "Ethernet8|unknown-multicast": { + "kbps":"600000" + } + }, "FLEX_COUNTER_TABLE|QUEUE": { "POLL_INTERVAL": "10000", "FLEX_COUNTER_STATUS": "enable" From 55768bdb29aefb371473fa92412e74fd25e48f58 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 9 Nov 2021 00:46:53 -0800 Subject: [PATCH 05/19] --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 57dbebc695..356b13ddbc 100644 --- a/setup.py +++ b/setup.py @@ -137,7 +137,7 @@ 'scripts/sonic-kdump-config', 'scripts/centralize_database', 'scripts/null_route_helper', - 'scripts/check_db_integrity.py' + 'scripts/check_db_integrity.py', 'scripts/storm_control.py' ], entry_points={ From 7542172694a26d1ca85a356df6208ad6dc3f2a23 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 9 Nov 2021 01:06:50 -0800 Subject: [PATCH 06/19] --- scripts/storm_control.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/storm_control.py b/scripts/storm_control.py index 16cf27a246..ff66a9e87b 100644 --- a/scripts/storm_control.py +++ b/scripts/storm_control.py @@ -6,13 +6,9 @@ # ############################################ -import _pickle as pickle import argparse -import datetime -import json import sys import os -import time # mock the redis for unit test purposes # try: @@ -55,7 +51,7 @@ def show_storm_config(self, port): kbps = data['kbps'] body.append([port, storm_type, kbps]) else: - for storm_key in sorted_table: + for storm_key in storm_configs: interface_name = storm_key[0] storm_type = storm_key[1] data = self.db.get_entry(STORM_TABLE_NAME, storm_key) From 5194411819b1a1dc86cb0527b91403fda4a6e3d5 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 23 Nov 2021 03:15:22 -0800 Subject: [PATCH 07/19] Modified storm-control configuration commands to config interface storm-control add/del Ethernet0 broadcast 10000 config interface storm-control add/del Ethernet0 unknown-multicast 10000 config interface storm-control add/del Ethernet0 unknown-unicast 10000 --- config/main.py | 82 ++++++++------------------------------------------ 1 file changed, 13 insertions(+), 69 deletions(-) diff --git a/config/main.py b/config/main.py index 997398aaa3..a98954ac3a 100644 --- a/config/main.py +++ b/config/main.py @@ -666,7 +666,6 @@ def storm_control_set_entry(port_name, kbps, storm_type): config_db.set_entry('PORT_STORM_CONTROL', key, {'kbps':kbps}) else: kbps_value = int(entry.get('kbps',0)) - click.echo("Existing value of kbps %d" %(kbps_value)) if kbps_value != kbps: config_db.mod_entry('PORT_STORM_CONTROL', key, {'kbps':kbps}) @@ -688,7 +687,6 @@ def storm_control_delete_entry(port_name, storm_type): return False else: config_db.set_entry('PORT_STORM_CONTROL', key, None) - click.echo("deleted %s storm-control from interface %s" %(storm_type, port_name)) return True @@ -5390,77 +5388,23 @@ def storm_control(ctx): """ Configure storm-control""" pass -@storm_control.group('broadcast') -def broadcast(): - """ Configure broadcast storm-control""" - pass - -@broadcast.command('add') -@click.argument('port_name', metavar='', required=True) -@click.argument('kbps', metavar='', required=True, type=click.IntRange(0,100000000)) -@click.pass_context -def add_broadcast_storm(ctx, port_name, kbps): - click.echo("add broadcast storm-control") - - if storm_control_set_entry(port_name, kbps, 'broadcast') is False: - ctx.fail("Unable to add broadcast storm-control") - -@broadcast.command('del') -@click.argument('port_name', metavar='', required=True) -@click.pass_context -def del_broadcast_storm(ctx, port_name): - click.echo("del broadcast storm-control") - - if storm_control_delete_entry(port_name, 'broadcast') is False: - ctx.fail("Unable to delete broadcast storm-control") - -@storm_control.group('unknown-unicast') -def unknown_unicast(): - """ Configure unknown-unicast storm-control""" - pass - -@unknown_unicast.command('add') -@click.argument('port_name', metavar='', required=True) -@click.argument('kbps', metavar='', required=True, type=click.IntRange(0,100000000)) +@storm_control.command('add') +@click.argument('port_name',metavar='', required=True) +@click.argument('storm_type',metavar='', required=True, type=click.Choice(["broadcast", "unknown-unicast", "unknown-multicast"])) +@click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) @click.pass_context -def add_unknown_unicast_storm(ctx, port_name, kbps): - click.echo("add unknown-unicast storm-control") - - if storm_control_set_entry(port_name, kbps, 'unknown-unicast') is False: - ctx.fail("Unable to add unknown-unicast storm-control") +def add_interface_storm(ctx, port_name,storm_type, kbps): + if storm_control_set_entry(port_name, kbps, storm_type) is False: + ctx.fail("Unable to add {} storm-control to interface {}".format(storm_type, port_name)) -@unknown_unicast.command('del') -@click.argument('port_name', metavar='', required=True) -@click.pass_context -def del_unknown_unicast_storm(ctx, port_name): - click.echo("del unknown-unicast storm-control") - - if storm_control_delete_entry(port_name, 'unknown-unicast') is False: - ctx.fail("Unable to delete unknown-unicast storm-control") - -@storm_control.group('unknown-multicast') -def unknown_multicast(): - """ Configure unknown-multicast storm-control""" - pass - -@unknown_multicast.command('add') -@click.argument('port_name', metavar='', required=True) -@click.argument('kbps', metavar='', required=True, type=click.IntRange(0,100000000)) -@click.pass_context -def add_unknown_multicast_storm(ctx, port_name, kbps): - click.echo("add unknown-multicast storm-control") - - if storm_control_set_entry(port_name, kbps, 'unknown-multicast') is False: - ctx.fail("Unable to add unknown-multicast storm-control") - -@unknown_multicast.command('del') -@click.argument('port_name', metavar='', required=True) +@storm_control.command('del') +@click.argument('port_name',metavar='', required=True) +@click.argument('storm_type',metavar='', required=True, type=click.Choice(["broadcast", "unknown-unicast", "unknown-multicast"])) @click.pass_context -def del_unknown_multicast_storm(ctx, port_name): - click.echo("del unknown-multicast storm-control") +def del_interface_storm(ctx,port_name,storm_type): + if storm_control_delete_entry(port_name, storm_type) is False: + ctx.fail("Unable to delete {} storm-control from interface {}".format(storm_type, port_name)) - if storm_control_delete_entry(port_name, 'unknown-multicast') is False: - ctx.fail("Unable to delete unknown-multicast storm-control") def is_loopback_name_valid(loopback_name): """Loopback name validation """ From 61e21072ab5ec0cd6d3f6bb093835fce9e533895 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 23 Nov 2021 22:31:54 -0800 Subject: [PATCH 08/19] modified storm-control show commands old: show storm-control {all | interface } new: show storm-control [interface ] show storm-control +------------------+-------------------+---------------+ | Interface Name | Storm Type | Rate (kbps) | +==================+===================+===============+ | Ethernet0 | broadcast | 12345 | +------------------+-------------------+---------------+ | Ethernet10 | unknown-multicast | 234234 | +------------------+-------------------+---------------+ show storm-control interface Ethernet10 +------------------+-------------------+---------------+ | Interface Name | Storm Type | Rate (kbps) | +==================+===================+===============+ | Ethernet10 | unknown-multicast | 234234 | +------------------+-------------------+---------------+ --- show/main.py | 137 ++++++++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 61 deletions(-) diff --git a/show/main.py b/show/main.py index c09bab77a9..49464fd898 100755 --- a/show/main.py +++ b/show/main.py @@ -129,7 +129,69 @@ def run_command(command, display_cmd=False, return_cmd=False): # Global class instance for SONiC interface name to alias conversion iface_alias_converter = clicommon.InterfaceAliasConverter() +# +# Display all storm-control data +# +def display_storm_all(): + """ Show storm-control """ + header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] + body = [] + + config_db = ConfigDBConnector() + config_db.connect() + + table = config_db.get_table('PORT_STORM_CONTROL') + + #To avoid further looping below + if not table: + return + + sorted_table = natsorted(table) + + for storm_key in sorted_table: + interface_name = storm_key[0] + storm_type = storm_key[1] + #interface_name, storm_type = storm_key.split(':') + data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) + + if not data: + return + + kbps = data['kbps'] + + body.append([interface_name, storm_type, kbps]) + + click.echo(tabulate(body, header, tablefmt="grid")) + +# +# Display storm-control data of given interface +# +def display_storm_interface(intf): + """ Show storm-control """ + + storm_type_list = ['broadcast','unknown-unicast','unknown-multicast'] + + header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] + body = [] + + config_db = ConfigDBConnector() + config_db.connect() + + table = config_db.get_table('PORT_STORM_CONTROL') + #To avoid further looping below + if not table: + return + + for storm_type in storm_type_list: + storm_key = intf + '|' + storm_type + data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) + + if data: + kbps = data['kbps'] + body.append([intf, storm_type, kbps]) + + click.echo(tabulate(body, header, tablefmt="grid")) def connect_config_db(): """ @@ -307,69 +369,22 @@ def is_mgmt_vrf_enabled(ctx): return False -@cli.group('storm-control') -def storm_control(): - """ show storm-control """ - pass - -@storm_control.command('all') -def storm_control_all(): - """ Show storm-control for all interfaces""" - - header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] - body = [] - - config_db = ConfigDBConnector() - config_db.connect() - - table = config_db.get_table('PORT_STORM_CONTROL') - - #To avoid further looping below - if not table: - return - - sorted_table = natsorted(table) - - for storm_key in sorted_table: - interface_name = storm_key[0] - storm_type = storm_key[1] - #interface_name, storm_type = storm_key.split(':') - data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) - - if data: - kbps = data['kbps'] - body.append([interface_name, storm_type, kbps]) - - click.echo(tabulate(body, header, tablefmt="grid")) +# +# 'storm-control' group +# "show storm-control [interface ]" +# +@cli.group('storm-control', invoke_without_command=True) +@click.pass_context +def storm_control(ctx): + """ Show storm-control """ + if ctx.invoked_subcommand is None: + display_storm_all() @storm_control.command('interface') -@click.argument('interfacename', required=True) -def storm_control_interface(interfacename): - """ Show storm-control for an interface""" - - storm_type_list = ['broadcast','unknown-unicast','unknown-multicast'] - - header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] - body = [] - - config_db = ConfigDBConnector() - config_db.connect() - - table = config_db.get_table('PORT_STORM_CONTROL') - - #To avoid further looping below - if not table: - return - - for storm_type in storm_type_list: - storm_key = interfacename + '|' + storm_type - data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) - - if data: - kbps = data['kbps'] - body.append([interfacename, storm_type, kbps]) - - click.echo(tabulate(body, header, tablefmt="grid")) +@click.argument('interface', metavar='',required=True) +def interface(interface): + if interface: + display_storm_interface(interface) # # 'mgmt-vrf' group ("show mgmt-vrf ...") From 30c6fa737a486589eee63ac559750926ee9e76b1 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 23 Nov 2021 22:47:41 -0800 Subject: [PATCH 09/19] --- show/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/show/main.py b/show/main.py index 49464fd898..2249a0b3e9 100755 --- a/show/main.py +++ b/show/main.py @@ -377,8 +377,8 @@ def is_mgmt_vrf_enabled(ctx): @click.pass_context def storm_control(ctx): """ Show storm-control """ - if ctx.invoked_subcommand is None: - display_storm_all() + if ctx.invoked_subcommand is None: + display_storm_all() @storm_control.command('interface') @click.argument('interface', metavar='',required=True) From 779ab88befbe9ff4205dcad0221b6b8685be45a6 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 30 Nov 2021 04:53:26 -0800 Subject: [PATCH 10/19] support for capability check before proceeding with updating CONFIG_DB. partial support for namespace --- config/main.py | 38 ++++++++++++++++++++++++++++++++++---- show/main.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/config/main.py b/config/main.py index 76a3fde7a5..5246a5444c 100644 --- a/config/main.py +++ b/config/main.py @@ -650,12 +650,26 @@ def storm_control_interface_validate(port_name): return True +def is_storm_control_supported(storm_type, namespace=EMPTY_NAMESPACE): + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + #state_db[asic_id] = swsscommon.DBConnector("STATE_DB", REDIS_TIMEOUT_MSECS, True, namespace) + #supported = state_db[asic_id].get_entry('BUM_STORM_CAPABILITY', storm_type) + state_db = SonicV2Connector(host='127.0.0.1') + state_db.connect(state_db.STATE_DB, False) + entry_name="BUM_STORM_CAPABILITY|"+storm_type + supported = state_db.get(state_db.STATE_DB, entry_name,"supported") + return supported + #API to configure the PORT_STORM_CONTROL table -def storm_control_set_entry(port_name, kbps, storm_type): +def storm_control_set_entry(port_name, kbps, storm_type, namespace): if storm_control_interface_validate(port_name) is False: return False + if is_storm_control_supported(storm_type, namespace) == 0: + click.echo("Storm-control is not supported on this namespace {}".format(namespace)) + return False + #Validate kbps value config_db = ConfigDBConnector() config_db.connect() @@ -5392,16 +5406,32 @@ def storm_control(ctx): @click.argument('port_name',metavar='', required=True) @click.argument('storm_type',metavar='', required=True, type=click.Choice(["broadcast", "unknown-unicast", "unknown-multicast"])) @click.argument('kbps',metavar='', required=True, type=click.IntRange(0,100000000)) +@click.option('--namespace', + '-n', + 'namespace', + default=None, + type=str, + show_default=True, + help='Namespace name or all', + callback=multi_asic_util.multi_asic_namespace_validation_callback) @click.pass_context -def add_interface_storm(ctx, port_name,storm_type, kbps): - if storm_control_set_entry(port_name, kbps, storm_type) is False: +def add_interface_storm(ctx, port_name,storm_type, kbps, namespace): + if storm_control_set_entry(port_name, kbps, storm_type, namespace) is False: ctx.fail("Unable to add {} storm-control to interface {}".format(storm_type, port_name)) @storm_control.command('del') @click.argument('port_name',metavar='', required=True) @click.argument('storm_type',metavar='', required=True, type=click.Choice(["broadcast", "unknown-unicast", "unknown-multicast"])) +@click.option('--namespace', + '-n', + 'namespace', + default=None, + type=str, + show_default=True, + help='Namespace name or all', + callback=multi_asic_util.multi_asic_namespace_validation_callback) @click.pass_context -def del_interface_storm(ctx,port_name,storm_type): +def del_interface_storm(ctx,port_name,storm_type, namespace): if storm_control_delete_entry(port_name, storm_type) is False: ctx.fail("Unable to delete {} storm-control from interface {}".format(storm_type, port_name)) diff --git a/show/main.py b/show/main.py index be12ca3217..14c1147bec 100755 --- a/show/main.py +++ b/show/main.py @@ -164,6 +164,29 @@ def display_storm_all(): click.echo(tabulate(body, header, tablefmt="grid")) +# +# Get storm-control configurations per interface append to body +# +def get_storm_interface(intf, body): + storm_type_list = ['broadcast','unknown-unicast','unknown-multicast'] + + config_db = ConfigDBConnector() + config_db.connect() + + table = config_db.get_table('PORT_STORM_CONTROL') + + #To avoid further looping below + if not table: + return + + for storm_type in storm_type_list: + storm_key = intf + '|' + storm_type + data = config_db.get_entry('PORT_STORM_CONTROL', storm_key) + + if data: + kbps = data['kbps'] + body.append([intf, storm_type, kbps]) + # # Display storm-control data of given interface # @@ -376,15 +399,35 @@ def is_mgmt_vrf_enabled(ctx): # "show storm-control [interface ]" # @cli.group('storm-control', invoke_without_command=True) +@click.option('--namespace', + '-n', + 'namespace', + default=None, + type=str, + show_default=True, + help='Namespace name or all', + callback=multi_asic_util.multi_asic_namespace_validation_callback) +@click.option('--display', '-d', 'display', default=None, show_default=False, type=str, help='all|frontend') @click.pass_context -def storm_control(ctx): +def storm_control(ctx, namespace, display): """ Show storm-control """ + header = ['Interface Name', 'Storm Type', 'Rate (kbps)'] + body = [] if ctx.invoked_subcommand is None: - display_storm_all() + if namespace is None: + display_storm_all() + else: + interfaces = multi_asic.multi_asic_get_ip_intf_from_ns(namespace) + for intf in interfaces: + get_storm_interface(interface, body) + click.echo(tabulate(body, header, tablefmt="grid")) @storm_control.command('interface') @click.argument('interface', metavar='',required=True) -def interface(interface): +def interface(interface, namespace, display): + if multi_asic.is_multi_asic() and namespace not in multi_asic.get_namespace_list(): + ctx = click.get_current_context() + ctx.fail('-n/--namespace option required. provide namespace from list {}'.format(multi_asic.get_namespace_list())) if interface: display_storm_interface(interface) From 7c850c809dfbbed56950cf8dfe2d047b4daa7042 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 30 Nov 2021 05:05:42 -0800 Subject: [PATCH 11/19] --- config/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index 5246a5444c..d239fee16f 100644 --- a/config/main.py +++ b/config/main.py @@ -650,7 +650,7 @@ def storm_control_interface_validate(port_name): return True -def is_storm_control_supported(storm_type, namespace=EMPTY_NAMESPACE): +def is_storm_control_supported(storm_type, namespace): asic_id = multi_asic.get_asic_index_from_namespace(namespace) #state_db[asic_id] = swsscommon.DBConnector("STATE_DB", REDIS_TIMEOUT_MSECS, True, namespace) #supported = state_db[asic_id].get_entry('BUM_STORM_CAPABILITY', storm_type) From f1996c5c0511bbc0f5f95e20412b1b70f11c6f52 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Tue, 30 Nov 2021 11:19:54 -0800 Subject: [PATCH 12/19] --- show/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/show/main.py b/show/main.py index 14c1147bec..9b5bf13143 100755 --- a/show/main.py +++ b/show/main.py @@ -419,7 +419,7 @@ def storm_control(ctx, namespace, display): else: interfaces = multi_asic.multi_asic_get_ip_intf_from_ns(namespace) for intf in interfaces: - get_storm_interface(interface, body) + get_storm_interface(intf, body) click.echo(tabulate(body, header, tablefmt="grid")) @storm_control.command('interface') From 60dc37276440533de14b079df9de76109cb1098f Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Wed, 1 Dec 2021 01:25:25 -0800 Subject: [PATCH 13/19] --- config/main.py | 4 ++-- show/main.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/main.py b/config/main.py index d239fee16f..8bb9fd74fe 100644 --- a/config/main.py +++ b/config/main.py @@ -5413,7 +5413,7 @@ def storm_control(ctx): type=str, show_default=True, help='Namespace name or all', - callback=multi_asic_util.multi_asic_namespace_validation_callback) + callback=multi_asic.multi_asic_namespace_validation_callback) @click.pass_context def add_interface_storm(ctx, port_name,storm_type, kbps, namespace): if storm_control_set_entry(port_name, kbps, storm_type, namespace) is False: @@ -5429,7 +5429,7 @@ def add_interface_storm(ctx, port_name,storm_type, kbps, namespace): type=str, show_default=True, help='Namespace name or all', - callback=multi_asic_util.multi_asic_namespace_validation_callback) + callback=multi_asic.multi_asic_namespace_validation_callback) @click.pass_context def del_interface_storm(ctx,port_name,storm_type, namespace): if storm_control_delete_entry(port_name, storm_type) is False: diff --git a/show/main.py b/show/main.py index 9b5bf13143..5f5814158c 100755 --- a/show/main.py +++ b/show/main.py @@ -406,7 +406,7 @@ def is_mgmt_vrf_enabled(ctx): type=str, show_default=True, help='Namespace name or all', - callback=multi_asic_util.multi_asic_namespace_validation_callback) + callback=multi_asic.multi_asic_namespace_validation_callback) @click.option('--display', '-d', 'display', default=None, show_default=False, type=str, help='all|frontend') @click.pass_context def storm_control(ctx, namespace, display): From df63165dc4020e6285d0ea1115ddce24f8609f49 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Wed, 1 Dec 2021 02:50:29 -0800 Subject: [PATCH 14/19] --- config/main.py | 5 +++-- show/main.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/main.py b/config/main.py index 8bb9fd74fe..4d33662e7a 100644 --- a/config/main.py +++ b/config/main.py @@ -28,6 +28,7 @@ from utilities_common import bgp_util import utilities_common.cli as clicommon from utilities_common.general import load_db_config +import utilities_common.multi_asic as multi_asic_util from .utils import log @@ -5413,7 +5414,7 @@ def storm_control(ctx): type=str, show_default=True, help='Namespace name or all', - callback=multi_asic.multi_asic_namespace_validation_callback) + callback=multi_asic_util.multi_asic_namespace_validation_callback) @click.pass_context def add_interface_storm(ctx, port_name,storm_type, kbps, namespace): if storm_control_set_entry(port_name, kbps, storm_type, namespace) is False: @@ -5429,7 +5430,7 @@ def add_interface_storm(ctx, port_name,storm_type, kbps, namespace): type=str, show_default=True, help='Namespace name or all', - callback=multi_asic.multi_asic_namespace_validation_callback) + callback=multi_asic_util.multi_asic_namespace_validation_callback) @click.pass_context def del_interface_storm(ctx,port_name,storm_type, namespace): if storm_control_delete_entry(port_name, storm_type) is False: diff --git a/show/main.py b/show/main.py index 5f5814158c..482b8ce42b 100755 --- a/show/main.py +++ b/show/main.py @@ -6,6 +6,7 @@ import click import utilities_common.cli as clicommon +from sonic_py_common import multi_asic import utilities_common.multi_asic as multi_asic_util from importlib import reload from natsort import natsorted @@ -406,7 +407,7 @@ def is_mgmt_vrf_enabled(ctx): type=str, show_default=True, help='Namespace name or all', - callback=multi_asic.multi_asic_namespace_validation_callback) + callback=multi_asic_util.multi_asic_namespace_validation_callback) @click.option('--display', '-d', 'display', default=None, show_default=False, type=str, help='all|frontend') @click.pass_context def storm_control(ctx, namespace, display): From d288b0865cbeaf553d953a8b2c500ee57e926afb Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Thu, 5 May 2022 05:28:27 -0700 Subject: [PATCH 15/19] storm-control config/show test code --- tests/storm_control_test.py | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 tests/storm_control_test.py diff --git a/tests/storm_control_test.py b/tests/storm_control_test.py new file mode 100644 index 0000000000..f54e88774e --- /dev/null +++ b/tests/storm_control_test.py @@ -0,0 +1,86 @@ +import os +import traceback + +from click.testing import CliRunner + +import config.main as config +import show.main as show +from utilities_common.db import Db + +class TestStormControl(object): + @classmethod + def setup_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "1" + print("SETUP") + + def test_add_broadcast_storm(self): + runner = CliRunner() + db = Db() + obj = {'db':db.cfgdb} + + result = runner.invoke(config.config.commands["storm_control"].commands["add"], ["Ethernet0", "broadcast", "10000"], obj = obj) + print (result.exit_code) + print (result.output) + assert result.exit_code == 0 + + def test_add_uucast_storm(self): + runner = CliRunner() + db = Db() + obj = {'db':db.cfgdb} + + result = runner.invoke(config.config.commands["storm_control"].commands["add"], ["Ethernet0", "unknown-unicast", "20000"], obj = obj) + print (result.exit_code) + print (result.output) + assert result.exit_code == 0 + + def test_add_umcast_storm(self): + runner = CliRunner() + db = Db() + obj = {'db':db.cfgdb} + + result = runner.invoke(config.config.commands["storm_control"].commands["add"], ["Ethernet0", "unknown-multicast", "30000"], obj = obj) + print (result.exit_code) + print (result.output) + assert result.exit_code == 0 + + def test_del_broadcast_storm(self): + runner = CliRunner() + db = Db() + obj = {'db':db.cfgdb} + + result = runner.invoke(config.config.commands["storm_control"].commands["del"], ["Ethernet0", "broadcast"], obj = obj) + print (result.exit_code) + print (result.output) + assert result.exit_code == 0 + + def test_del_uucast_storm(self): + runner = CliRunner() + db = Db() + obj = {'db':db.cfgdb} + + result = runner.invoke(config.config.commands["storm_control"].commands["del"], ["Ethernet0", "unknown-unicast"], obj = obj) + print (result.exit_code) + print (result.output) + assert result.exit_code == 0 + + def test_del_umcast_storm(self): + runner = CliRunner() + db = Db() + obj = {'db':db.cfgdb} + + result = runner.invoke(config.config.commands["storm_control"].commands["del"], ["Ethernet0", "unknown-multicast"], obj = obj) + print (result.exit_code) + print (result.output) + assert result.exit_code == 0 + + def test_show_storm(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["storm-control"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + @classmethod + def teardown_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "0" + print("TEARDOWN") From 9a85aad9e1564067b73245e38c4e925606b28174 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Thu, 5 May 2022 08:22:05 -0700 Subject: [PATCH 16/19] --- tests/storm_control_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/storm_control_test.py b/tests/storm_control_test.py index f54e88774e..2f2320576a 100644 --- a/tests/storm_control_test.py +++ b/tests/storm_control_test.py @@ -18,7 +18,7 @@ def test_add_broadcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm_control"].commands["add"], ["Ethernet0", "broadcast", "10000"], obj = obj) + result = runner.invoke(config.config.commands["storm-control"].commands["add"], ["Ethernet0", "broadcast", "10000"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -28,7 +28,7 @@ def test_add_uucast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm_control"].commands["add"], ["Ethernet0", "unknown-unicast", "20000"], obj = obj) + result = runner.invoke(config.config.commands["storm-control"].commands["add"], ["Ethernet0", "unknown-unicast", "20000"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -38,7 +38,7 @@ def test_add_umcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm_control"].commands["add"], ["Ethernet0", "unknown-multicast", "30000"], obj = obj) + result = runner.invoke(config.config.commands["storm-control"].commands["add"], ["Ethernet0", "unknown-multicast", "30000"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -48,7 +48,7 @@ def test_del_broadcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm_control"].commands["del"], ["Ethernet0", "broadcast"], obj = obj) + result = runner.invoke(config.config.commands["storm-control"].commands["del"], ["Ethernet0", "broadcast"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -58,7 +58,7 @@ def test_del_uucast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm_control"].commands["del"], ["Ethernet0", "unknown-unicast"], obj = obj) + result = runner.invoke(config.config.commands["storm-control"].commands["del"], ["Ethernet0", "unknown-unicast"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -68,7 +68,7 @@ def test_del_umcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm_control"].commands["del"], ["Ethernet0", "unknown-multicast"], obj = obj) + result = runner.invoke(config.config.commands["storm-control"].commands["del"], ["Ethernet0", "unknown-multicast"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 From 5b63779b3f27fb61f4f4efde216d72811e22b6e0 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Thu, 5 May 2022 08:55:30 -0700 Subject: [PATCH 17/19] --- tests/storm_control_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/storm_control_test.py b/tests/storm_control_test.py index 2f2320576a..66267c8e97 100644 --- a/tests/storm_control_test.py +++ b/tests/storm_control_test.py @@ -18,7 +18,7 @@ def test_add_broadcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm-control"].commands["add"], ["Ethernet0", "broadcast", "10000"], obj = obj) + result = runner.invoke(config.config.commands["interface"].commands["storm-control"].commands["add"], ["Ethernet0", "broadcast", "10000"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -28,7 +28,7 @@ def test_add_uucast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm-control"].commands["add"], ["Ethernet0", "unknown-unicast", "20000"], obj = obj) + result = runner.invoke(config.config.commands["interface"].commands["storm-control"].commands["add"], ["Ethernet0", "unknown-unicast", "10000"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -38,7 +38,7 @@ def test_add_umcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm-control"].commands["add"], ["Ethernet0", "unknown-multicast", "30000"], obj = obj) + result = runner.invoke(config.config.commands["interface"].commands["storm-control"].commands["add"], ["Ethernet0", "unknown-multicast", "10000"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -48,7 +48,7 @@ def test_del_broadcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm-control"].commands["del"], ["Ethernet0", "broadcast"], obj = obj) + result = runner.invoke(config.config.commands["interface"].commands["storm-control"].commands["del"], ["Ethernet0", "broadcast"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 @@ -58,7 +58,7 @@ def test_del_uucast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm-control"].commands["del"], ["Ethernet0", "unknown-unicast"], obj = obj) + result = runner.invoke(config.config.commands["interface"].commands["storm-control"].commands["del"], ["Ethernet0", "unknown-unicast"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0 From f1bb1cbb475428b83ccb120b1d1f5ec045c02dc4 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Thu, 5 May 2022 09:14:11 -0700 Subject: [PATCH 18/19] --- config/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index 80fdd8d457..1ef32b3ef7 100644 --- a/config/main.py +++ b/config/main.py @@ -636,7 +636,7 @@ def _clear_cbf(): #API to validate the interface passed for storm-control configuration def storm_control_interface_validate(port_name): - if get_interface_naming_mode() == "alias": + if clicommon.get_interface_naming_mode() == "alias": port_name = interface_alias_to_name(None, port_name) if port_name is None: click.echo("'port_name' is None!") From e4389e5e149bf2e21832d1f0720e06f7f1e7f8bc Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Thu, 5 May 2022 10:22:41 -0700 Subject: [PATCH 19/19] --- tests/storm_control_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/storm_control_test.py b/tests/storm_control_test.py index 66267c8e97..a8b0d36b9e 100644 --- a/tests/storm_control_test.py +++ b/tests/storm_control_test.py @@ -68,7 +68,7 @@ def test_del_umcast_storm(self): db = Db() obj = {'db':db.cfgdb} - result = runner.invoke(config.config.commands["storm-control"].commands["del"], ["Ethernet0", "unknown-multicast"], obj = obj) + result = runner.invoke(config.config.commands["interface"].commands["storm-control"].commands["del"], ["Ethernet0", "unknown-multicast"], obj = obj) print (result.exit_code) print (result.output) assert result.exit_code == 0