From d2c997cc4e5226dc6aab319026b2e105dd6707e7 Mon Sep 17 00:00:00 2001 From: Steven LU <45245946+stevenlu99@users.noreply.github.com> Date: Fri, 5 Jun 2020 18:24:01 -0700 Subject: [PATCH] Add_intf_range (#913) * Add_intf_range --- config/main.py | 57 ++++++++++++++++++++------------- doc/Command-Reference.md | 31 +++++++++++++++++- scripts/intfutil | 16 ++++++--- scripts/portstat | 23 ++++++++----- show/main.py | 5 ++- utilities_common/intf_filter.py | 43 +++++++++++++++++++++++++ 6 files changed, 137 insertions(+), 38 deletions(-) create mode 100755 utilities_common/intf_filter.py diff --git a/config/main.py b/config/main.py index 08747ca62d5e..41963159e12b 100755 --- a/config/main.py +++ b/config/main.py @@ -14,6 +14,7 @@ import ipaddress from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from minigraph import parse_device_desc_xml +from utilities_common.intf_filter import parse_interface_in_filter import aaa import mlnx @@ -1843,21 +1844,26 @@ def startup(ctx, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: - ctx.fail("Interface name is invalid. Please enter a valid interface name!!") + intf_fs = parse_interface_in_filter(interface_name) + if len(intf_fs) == 1 and interface_name_is_valid(interface_name) is False: + ctx.fail("Interface name is invalid. Please enter a valid interface name!!") log_info("'interface startup {}' executing...".format(interface_name)) + port_dict = config_db.get_table('PORT') + for port_name in port_dict.keys(): + if port_name in intf_fs: + config_db.mod_entry("PORT", port_name, {"admin_status": "up"}) + + portchannel_list = config_db.get_table("PORTCHANNEL") + for po_name in portchannel_list.keys(): + if po_name in intf_fs: + config_db.mod_entry("PORTCHANNEL", po_name, {"admin_status": "up"}) + + subport_list = config_db.get_table("VLAN_SUB_INTERFACE") + for sp_name in subport_list.keys(): + if sp_name in intf_fs: + config_db.mod_entry("VLAN_SUB_INTERFACE", sp_name, {"admin_status": "up"}) - if interface_name.startswith("Ethernet"): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - config_db.mod_entry("VLAN_SUB_INTERFACE", interface_name, {"admin_status": "up"}) - else: - config_db.mod_entry("PORT", interface_name, {"admin_status": "up"}) - elif interface_name.startswith("PortChannel"): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - config_db.mod_entry("VLAN_SUB_INTERFACE", interface_name, {"admin_status": "up"}) - else: - config_db.mod_entry("PORTCHANNEL", interface_name, {"admin_status": "up"}) # # 'shutdown' subcommand # @@ -1874,19 +1880,24 @@ def shutdown(ctx, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + intf_fs = parse_interface_in_filter(interface_name) + if len(intf_fs) == 1 and interface_name_is_valid(interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") - if interface_name.startswith("Ethernet"): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - config_db.mod_entry("VLAN_SUB_INTERFACE", interface_name, {"admin_status": "down"}) - else: - config_db.mod_entry("PORT", interface_name, {"admin_status": "down"}) - elif interface_name.startswith("PortChannel"): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - config_db.mod_entry("VLAN_SUB_INTERFACE", interface_name, {"admin_status": "down"}) - else: - config_db.mod_entry("PORTCHANNEL", interface_name, {"admin_status": "down"}) + port_dict = config_db.get_table('PORT') + for port_name in port_dict.keys(): + if port_name in intf_fs: + config_db.mod_entry("PORT", port_name, {"admin_status": "down"}) + + portchannel_list = config_db.get_table("PORTCHANNEL") + for po_name in portchannel_list.keys(): + if po_name in intf_fs: + config_db.mod_entry("PORTCHANNEL", po_name, {"admin_status": "down"}) + + subport_list = config_db.get_table("VLAN_SUB_INTERFACE") + for sp_name in subport_list.keys(): + if sp_name in intf_fs: + config_db.mod_entry("VLAN_SUB_INTERFACE", sp_name, {"admin_status": "down"}) # # 'speed' subcommand diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index a6598b717e02..e6bb9ba6dfea 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -2312,7 +2312,7 @@ Optional argument "-p" specify a period (in seconds) with which to gather counte show interfaces counters [-a|--printall] [-p|--period ] show interfaces counters errors show interfaces counters rates - show interfaces counters rif [-p|--period ] + show interfaces counters rif [-p|--period ] [-i ] ``` - Example: @@ -2327,6 +2327,13 @@ Optional argument "-p" specify a period (in seconds) with which to gather counte Ethernet16 U 16,679,692,972 13.83 MB/s 0.27% 0 17,605 0 18,206,586,265 17.51 MB/s 0.34% 0 0 0 Ethernet20 U 47,983,339,172 35.89 MB/s 0.70% 0 2,174 0 58,986,354,359 51.83 MB/s 1.01% 0 0 0 Ethernet24 U 33,543,533,441 36.59 MB/s 0.71% 0 1,613 0 43,066,076,370 49.92 MB/s 0.97% 0 0 0 + + admin@sonic:~$ show interfaces counters -i Ethernet4,Ethernet12-16 + IFACE STATE RX_OK RX_BPS RX_UTIL RX_ERR RX_DRP RX_OVR TX_OK TX_BPS TX_UTIL TX_ERR TX_DRP TX_OVR + ----------- ------- --------------- ----------- --------- -------- -------- -------- --------------- ----------- --------- -------- -------- -------- + Ethernet4 U 453,838,006,636 632.97 MB/s 12.36% 0 1,636 0 388,299,875,056 529.34 MB/s 10.34% 0 0 0 + Ethernet12 U 458,052,204,029 636.84 MB/s 12.44% 0 17,614 0 388,341,776,615 527.37 MB/s 10.30% 0 0 0 + Ethernet16 U 16,679,692,972 13.83 MB/s 0.27% 0 17,605 0 18,206,586,265 17.51 MB/s 0.34% 0 0 0 ``` The "errors" subcommand is used to display the interface errors. @@ -2527,6 +2534,18 @@ This command displays some more fields such as Lanes, Speed, MTU, Type, Asymmetr Ethernet0 101,102 40G 9100 fortyGigE1/1/1 up up ``` +- Example (to only display the status for range of interfaces): + ``` + admin@sonic:~$ show interfaces status Ethernet8,Ethernet168-180 + Interface Lanes Speed MTU Alias Oper Admin Type Asym PFC + ----------- ----------------- ------- ----- --------------- ------ ------- ------ ---------- + Ethernet8 49,50,51,52 100G 9100 hundredGigE3 down down N/A N/A + Ethernet168 9,10,11,12 100G 9100 hundredGigE43 down down N/A N/A + Ethernet172 13,14,15,16 100G 9100 hundredGigE44 down down N/A N/A + Ethernet176 109,110,111,112 100G 9100 hundredGigE45 down down N/A N/A + Ethernet180 105,106,107,108 100G 9100 hundredGigE46 down down N/A N/A + ``` + **show interfaces transceiver** This command is already explained [here](#Transceivers) @@ -2720,6 +2739,11 @@ This command is used to administratively shut down either the Physical interface admin@sonic:~$ sudo config interface Ethernet63 shutdown ``` + shutdown multiple interfaces + ``` + admin@sonic:~$ sudo config interface shutdown Ethernet8,Ethernet16-20,Ethernet32 + ``` + **config interface startup (Versions >= 201904)** **config interface startup (Versions <= 201811)** @@ -2748,6 +2772,11 @@ This command is used for administratively bringing up the Physical interface or admin@sonic:~$ sudo config interface Ethernet63 startup ``` + startup multiple interfaces + ``` + admin@sonic:~$ sudo config interface startup Ethernet8,Ethernet16-20,Ethernet32 + ``` + **config interface speed (Versions >= 201904)** **config interface speed (Versions <= 201811)** diff --git a/scripts/intfutil b/scripts/intfutil index b0efa0dd387c..f51c945936a4 100755 --- a/scripts/intfutil +++ b/scripts/intfutil @@ -8,6 +8,8 @@ from tabulate import tabulate from natsort import natsorted from swsssdk import ConfigDBConnector from pprint import pprint +from utilities_common.intf_filter import parse_interface_in_filter + import os # mock the redis for unit test purposes # @@ -345,7 +347,7 @@ header_stat_sub_intf = ['Sub port interface', 'Speed', 'MTU', 'Vlan', 'Admin', ' class IntfStatus(object): - def display_intf_status(self, appl_db_keys, front_panel_ports_list, portchannel_speed_dict, appl_db_sub_intf_keys, sub_intf_list, sub_intf_only): + def display_intf_status(self, intf_name, appl_db_keys, front_panel_ports_list, portchannel_speed_dict, appl_db_sub_intf_keys, sub_intf_list, sub_intf_only): """ Generate interface-status output """ @@ -354,6 +356,8 @@ class IntfStatus(object): table = [] key = [] + intf_fs = parse_interface_in_filter(intf_name) + # # Iterate through all the keys and append port's associated state to # the result table. @@ -362,7 +366,8 @@ class IntfStatus(object): for i in appl_db_keys: key = re.split(':', i, maxsplit=1)[-1].strip() if key in front_panel_ports_list: - table.append((key, + if intf_name is None or key in intf_fs: + table.append((key, appl_db_port_status_get(self.appl_db, key, PORT_LANES_STATUS), appl_db_port_status_get(self.appl_db, key, PORT_SPEED), appl_db_port_status_get(self.appl_db, key, PORT_MTU_STATUS), @@ -376,7 +381,8 @@ class IntfStatus(object): for po, value in portchannel_speed_dict.iteritems(): if po: - table.append((po, + if intf_name is None or po in intf_fs: + table.append((po, appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_LANES_STATUS, self.portchannel_speed_dict), appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_SPEED, self.portchannel_speed_dict), appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_MTU_STATUS, self.portchannel_speed_dict), @@ -434,7 +440,7 @@ class IntfStatus(object): intf_name = intf_name[:sub_intf_sep_idx] self.front_panel_ports_list = get_frontpanel_port_list(self.config_db) - appl_db_keys = appl_db_keys_get(self.appl_db, self.front_panel_ports_list, intf_name) + appl_db_keys = appl_db_keys_get(self.appl_db, self.front_panel_ports_list, None) self.int_to_vlan_dict = get_interface_vlan_dict(self.config_db) self.get_raw_po_int_configdb_info = get_raw_portchannel_info(self.config_db) self.portchannel_list = get_portchannel_list(self.get_raw_po_int_configdb_info) @@ -449,7 +455,7 @@ class IntfStatus(object): appl_db_sub_intf_keys = appl_db_sub_intf_keys_get(self.appl_db, self.sub_intf_list, sub_intf_name) if appl_db_keys is None: return - self.display_intf_status(appl_db_keys, self.front_panel_ports_list, self.portchannel_speed_dict, appl_db_sub_intf_keys, self.sub_intf_list, sub_intf_only) + self.display_intf_status(intf_name, appl_db_keys, self.front_panel_ports_list, self.portchannel_speed_dict, appl_db_sub_intf_keys, self.sub_intf_list, sub_intf_only) diff --git a/scripts/portstat b/scripts/portstat index 3000f5469fba..42757d36770c 100644 --- a/scripts/portstat +++ b/scripts/portstat @@ -18,6 +18,7 @@ from collections import namedtuple, OrderedDict from natsort import natsorted from tabulate import tabulate from utilities_common.netstat import ns_diff, ns_brate, ns_prate, ns_util, table_as_json +from utilities_common.intf_filter import parse_interface_in_filter PORT_RATE = 40 @@ -128,7 +129,7 @@ class Portstat(object): else: return STATUS_NA - def cnstat_print(self, cnstat_dict, use_json, print_all, errors_only, rates_only): + def cnstat_print(self, cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only): """ Print the cnstat. """ @@ -138,7 +139,8 @@ class Portstat(object): for key, data in cnstat_dict.iteritems(): if key == 'time': continue - + if intf_list and key not in intf_list: + continue if print_all: header = header_all table.append((key, self.get_port_state(key), @@ -169,7 +171,7 @@ class Portstat(object): else: print tabulate(table, header, tablefmt='simple', stralign='right') - def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, use_json, print_all, errors_only, rates_only): + def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, intf_list, use_json, print_all, errors_only, rates_only): """ Print the difference between two cnstat results. """ @@ -186,6 +188,8 @@ class Portstat(object): if key in cnstat_old_dict: old_cntr = cnstat_old_dict.get(key) + if intf_list and key not in intf_list: + continue port_speed = self.get_port_speed(key) if print_all: header = header_all @@ -306,6 +310,7 @@ Examples: parser.add_argument('-R', '--rate', action='store_true', help='Display interface rates') parser.add_argument('-t', '--tag', type=str, help='Save stats with name TAG', default=None) parser.add_argument('-p', '--period', type=int, help='Display stats over a specified period (in seconds).', default=0) + parser.add_argument('-i', '--interface', type=str, help='Display stats for interface lists.', default=None) args = parser.parse_args() save_fresh_stats = args.clear @@ -319,7 +324,7 @@ Examples: uid = str(os.getuid()) wait_time_in_seconds = args.period print_all = args.all - + intf_fs = args.interface if tag_name is not None: cnstat_file = uid + "-" + tag_name else: @@ -351,13 +356,15 @@ Examples: os.rmdir(cnstat_dir) sys.exit(0) + intf_list = parse_interface_in_filter(intf_fs) + portstat = Portstat() # The cnstat_dict just give an ordered dict of all output. cnstat_dict = portstat.get_cnstat() # Now decide what information to display if raw_stats: - portstat.cnstat_print(cnstat_dict, use_json, print_all, errors_only, rates_only) + portstat.cnstat_print(cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only) sys.exit(0) # At this point, either we'll create a file or open an existing one. @@ -384,7 +391,7 @@ Examples: try: cnstat_cached_dict = pickle.load(open(cnstat_fqn_file, 'r')) print "Last cached time was " + str(cnstat_cached_dict.get('time')) - portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, use_json, print_all, errors_only, rates_only) + portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, intf_list, use_json, print_all, errors_only, rates_only) except IOError as e: print e.errno, e else: @@ -392,13 +399,13 @@ Examples: print "\nFile '%s' does not exist" % cnstat_fqn_file print "Did you run 'portstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name) else: - portstat.cnstat_print(cnstat_dict, use_json, print_all, errors_only, rates_only) + portstat.cnstat_print(cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only) else: #wait for the specified time and then gather the new stats and output the difference. time.sleep(wait_time_in_seconds) print "The rates are calculated within %s seconds period" % wait_time_in_seconds cnstat_new_dict = portstat.get_cnstat() - portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, use_json, print_all, errors_only, rates_only) + portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, intf_list, use_json, print_all, errors_only, rates_only) if __name__ == "__main__": main() diff --git a/show/main.py b/show/main.py index f2d4df53084f..6fdc243da9a3 100755 --- a/show/main.py +++ b/show/main.py @@ -947,9 +947,10 @@ def status(interfacename, verbose): @interfaces.group(invoke_without_command=True) @click.option('-a', '--printall', is_flag=True) @click.option('-p', '--period') +@click.option('-i', '--interface') @click.option('--verbose', is_flag=True, help="Enable verbose output") @click.pass_context -def counters(ctx, verbose, period, printall): +def counters(ctx, verbose, period, interface, printall): """Show interface counters""" if ctx.invoked_subcommand is None: @@ -959,6 +960,8 @@ def counters(ctx, verbose, period, printall): cmd += " -a" if period is not None: cmd += " -p {}".format(period) + if interface is not None: + cmd += " -i {}".format(interface) run_command(cmd, display_cmd=verbose) diff --git a/utilities_common/intf_filter.py b/utilities_common/intf_filter.py new file mode 100755 index 000000000000..be5ddaed8f9d --- /dev/null +++ b/utilities_common/intf_filter.py @@ -0,0 +1,43 @@ +# Interface filtering functions + +SONIC_PORT_NAME_PREFIX = "Ethernet" +SONIC_LAG_NAME_PREFIX = "PortChannel" + +def parse_interface_in_filter(intf_filter): + intf_fs = [] + + if intf_filter is None: + return intf_fs + + fs = intf_filter.split(',') + for x in fs: + if '-' in x: + # handle range + if not x.startswith(SONIC_PORT_NAME_PREFIX) and not x.startswith(SONIC_LAG_NAME_PREFIX): + continue + if x.startswith(SONIC_PORT_NAME_PREFIX): + intf = SONIC_PORT_NAME_PREFIX + if x.startswith(SONIC_LAG_NAME_PREFIX): + intf = SONIC_LAG_NAME_PREFIX + start = x.split('-')[0].split(intf,1)[1] + end = x.split('-')[1] + + if not start.isdigit() or not end.isdigit(): + continue + for i in range(int(start), int(end)+1): + intf_fs.append(intf+str(i)) + else: + intf_fs.append(x) + + return intf_fs + +def interface_in_filter(intf, filter): + if filter is None: + return True + + intf_fs = parse_interface_in_filter(filter) + if intf in intf_fs: + return True + + return False +