From 8a80a13e0dd781ae6ed9f6fd8d1f447119d75c15 Mon Sep 17 00:00:00 2001 From: Mohanarajan Selvaraj Date: Sun, 31 May 2020 23:49:39 -0700 Subject: [PATCH] JIRA-SONIC-1512: Broadcast Unknown-multicast and Unknown-unicast Storm-control (#928) 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 | 67 +++++++++++++++++++++- 2 files changed, 216 insertions(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index 968f834422..c8dd7344d6 100644 --- a/config/main.py +++ b/config/main.py @@ -736,6 +736,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', @@ -3690,6 +3756,90 @@ def enable(enable): command = "ztp enable" run_command(command, display_cmd=True) +@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 decf8f5111..311798766c 100755 --- a/show/main.py +++ b/show/main.py @@ -814,7 +814,6 @@ def alias(interfacename): click.echo(tabulate(body, header)) - # # 'breakout' group ### # @@ -908,6 +907,72 @@ def currrent_mode(ctx, interface): body.append([name, str(curBrkout_tbl[name]['brkout_mode'])]) click.echo(tabulate(body, header, tablefmt="grid")) +@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 ###