diff --git a/config/main.py b/config/main.py index 6f6db602ee31..102927d0b885 100755 --- a/config/main.py +++ b/config/main.py @@ -84,6 +84,8 @@ PORT_MTU = "mtu" PORT_SPEED = "speed" +PORT_TPID = "tpid" +DEFAULT_TPID = "0x8100" asic_type = None @@ -1583,6 +1585,15 @@ def add_portchannel_member(ctx, portchannel_name, port_name): ctx.fail("Port MTU of {} is different than the {} MTU size" .format(port_name, portchannel_name)) + # Dont allow a port to be member of port channel if its TPID is not at default 0x8100 + # If TPID is supported at LAG level, when member is added, the LAG's TPID is applied to the + # new member by SAI. + port_entry = db.get_entry('PORT', port_name) + if port_entry and port_entry.get(PORT_TPID) is not None: + port_tpid = port_entry.get(PORT_TPID) + if port_tpid != DEFAULT_TPID: + ctx.fail("Port TPID of {}: {} is not at default 0x8100".format(port_name, port_tpid)) + db.set_entry('PORTCHANNEL_MEMBER', (portchannel_name, port_name), {'NULL': 'NULL'}) @@ -3367,6 +3378,34 @@ def mtu(ctx, interface_name, interface_mtu, verbose): command += " -vv" clicommon.run_command(command, display_cmd=verbose) +# +# 'tpid' subcommand +# + +@interface.command() +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('interface_tpid', metavar='', required=True) +@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") +def tpid(ctx, interface_name, interface_tpid, verbose): + """Set interface tpid""" + # Get the config_db connector + config_db = ctx.obj['config_db'] + if clicommon.get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(config_db, interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if ctx.obj['namespace'] is DEFAULT_NAMESPACE: + command = "portconfig -p {} -tp {}".format(interface_name, interface_tpid) + else: + command = "portconfig -p {} -tp {} -n {}".format(interface_name, interface_tpid, ctx.obj['namespace']) + + if verbose: + command += " -vv" + clicommon.run_command(command, display_cmd=verbose) + + @interface.command() @click.pass_context @click.argument('interface_name', metavar='', required=True) diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index 90dcf00597b8..fa0afe36aa41 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -406,6 +406,7 @@ The same syntax applies to all subgroups of `show` which themselves contain subc neighbor Show neighbor related information portchannel Show PortChannel information status Show Interface status information + tpid Show Interface tpid information transceiver Show SFP Transceiver information ``` @@ -3076,6 +3077,7 @@ Subsequent pages explain each of these commands in detail. neighbor Show neighbor related information portchannel Show PortChannel information status Show Interface status information + tpid Show Interface tpid information transceiver Show SFP Transceiver information ``` @@ -3310,6 +3312,48 @@ This command displays the key fields of the interfaces such as Operational Statu Ethernet4 down up hundredGigE1/2 T0-2:hundredGigE1/30 ``` +**show interfaces tpid** + +This command displays the key fields of the interfaces such as Operational Status, Administrative Status, Alias and TPID. + +- Usage: + ``` + show interfaces tpid [] + ``` + +- Example: + ``` + admin@sonic:~$ show interfaces tpid + Interface Alias Oper Admin TPID + --------------- --------------- ------ ------- ------ + Ethernet0 fortyGigE1/1/1 up up 0x8100 + Ethernet1 fortyGigE1/1/2 up up 0x8100 + Ethernet2 fortyGigE1/1/3 down down 0x8100 + Ethernet3 fortyGigE1/1/4 down down 0x8100 + Ethernet4 fortyGigE1/1/5 up up 0x8100 + Ethernet5 fortyGigE1/1/6 up up 0x8100 + Ethernet6 fortyGigE1/1/7 up up 0x9200 + Ethernet7 fortyGigE1/1/8 up up 0x88A8 + Ethernet8 fortyGigE1/1/9 up up 0x8100 + ... + Ethernet63 fortyGigE1/4/16 down down 0x8100 + PortChannel0001 N/A up up 0x8100 + PortChannel0002 N/A up up 0x8100 + PortChannel0003 N/A up up 0x8100 + PortChannel0004 N/A up up 0x8100 + admin@sonic:~$ + ``` + +- Example (to only display the TPID for interface Ethernet6): + + ``` + admin@sonic:~$ show interfaces tpid Ethernet6 + Interface Alias Oper Admin TPID + ----------- -------------- ------ ------- ------ + Ethernet6 fortyGigE1/1/7 up up 0x9200 + admin@sonic:~$ + ``` + **show interfaces naming_mode** Refer sub-section [Interface-Naming-Mode](#Interface-Naming-Mode) @@ -3715,6 +3759,22 @@ This command is used to configure the mtu for the Physical interface. Use the va admin@sonic:~$ sudo config interface mtu Ethernet64 1500 ``` +**config interface tpid (Versions >= 202106)** + +This command is used to configure the TPID for the Physical/PortChannel interface. default is 0x8100. Other allowed values if supported by HW SKU (0x9100, 0x9200, 0x88A8). + +- Usage: + + *Versions >= 202106* + ``` + config interface tpid + ``` + +- Example (Versions >= 202106): + ``` + admin@sonic:~$ sudo config interface tpid Ethernet64 0x9200 + ``` + **config interface breakout** This command is used to set breakout mode available for user-specified interface. diff --git a/scripts/intfutil b/scripts/intfutil index a409d1a29dd2..9600b6a8ff16 100755 --- a/scripts/intfutil +++ b/scripts/intfutil @@ -45,6 +45,7 @@ PORT_AUTONEG = 'autoneg' PORT_ADV_SPEEDS = 'adv_speeds' PORT_INTERFACE_TYPE = 'interface_type' PORT_ADV_INTERFACE_TYPES = 'adv_interface_types' +PORT_TPID = "tpid" VLAN_SUB_INTERFACE_SEPARATOR = "." VLAN_SUB_INTERFACE_TYPE = "802.1q-encapsulation" @@ -298,6 +299,11 @@ def appl_db_portchannel_status_get(appl_db, config_db, po_name, status_type, por if status_type == "mtu": status = config_db.get(config_db.CONFIG_DB, po_table_id, status_type) return status + if status_type == "tpid": + status = config_db.get(config_db.CONFIG_DB, po_table_id, status_type) + if status is None: + return "0x8100" + return status status = appl_db.get(appl_db.APPL_DB, full_table_id, status_type) #print(status) if status is None: @@ -583,10 +589,95 @@ class IntfAutoNegStatus(object): self.table += self.generate_autoneg_status() +# ========================== interface-tpid logic ========================== + +header_tpid = ['Interface', 'Alias', 'Oper', 'Admin', 'TPID'] + +class IntfTpid(object): + + def __init__(self, intf_name, namespace_option, display_option): + """ + Class constructor method + :param self: + :param intf_name: string of interface + :return: + """ + self.db = None + self.config_db = None + self.intf_name = intf_name + self.table = [] + self.multi_asic = multi_asic_util.MultiAsic( + display_option, namespace_option) + + if intf_name is not None and intf_name == SUB_PORT: + self.intf_name = None + + def display_intf_tpid(self): + self.get_intf_tpid() + + # Sorting and tabulating the result table. + sorted_table = natsorted(self.table) + print(tabulate(sorted_table, header_tpid, tablefmt="simple", stralign='right')) + + def generate_intf_tpid(self): + """ + Generate interface-tpid output + """ + + i = {} + table = [] + key = [] + + intf_fs = parse_interface_in_filter(self.intf_name) + # + # Iterate through all the keys and append port's associated state to + # the result table. + # + for i in self.appl_db_keys: + key = re.split(':', i, maxsplit=1)[-1].strip() + if key in self.front_panel_ports_list: + if self.multi_asic.skip_display(constants.PORT_OBJ, key): + continue + + if self.intf_name is None or key in intf_fs: + table.append((key, + appl_db_port_status_get(self.db, key, PORT_ALIAS), + appl_db_port_status_get(self.db, key, PORT_OPER_STATUS), + appl_db_port_status_get(self.db, key, PORT_ADMIN_STATUS), + appl_db_port_status_get(self.db, key, PORT_TPID))) + + for po, value in self.po_speed_dict.items(): + if po: + if self.multi_asic.skip_display(constants.PORT_CHANNEL_OBJ, po): + continue + if self.intf_name is None or po in intf_fs: + table.append((po, + appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_ALIAS, self.po_speed_dict), + appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_OPER_STATUS, self.po_speed_dict), + appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_ADMIN_STATUS, self.po_speed_dict), + appl_db_portchannel_status_get(self.db, self.config_db, po, PORT_TPID, self.po_speed_dict))) + return table + + @multi_asic_util.run_on_multi_asic + def get_intf_tpid(self): + self.front_panel_ports_list = get_frontpanel_port_list(self.config_db) + self.appl_db_keys = appl_db_keys_get(self.db, self.front_panel_ports_list, None) + 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) + self.po_int_tuple_list = create_po_int_tuple_list(self.get_raw_po_int_configdb_info) + self.po_int_dict = create_po_int_dict(self.po_int_tuple_list) + self.int_po_dict = create_int_to_portchannel_dict(self.po_int_tuple_list) + self.po_speed_dict = po_speed_dict(self.po_int_dict, self.db) + self.portchannel_keys = self.po_speed_dict.keys() + + if self.appl_db_keys: + self.table += self.generate_intf_tpid() + + def main(): parser = argparse.ArgumentParser(description='Display Interface information', formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('-c', '--command', type=str, help='get interface status or description or auto negotiation status', default=None) + parser.add_argument('-c', '--command', type=str, help='get interface status or description or auto negotiation status or tpid', default=None) parser.add_argument('-i', '--interface', type=str, help='interface information for specific port: Ethernet0', default=None) parser = multi_asic_util.multi_asic_args(parser) args = parser.parse_args() @@ -600,6 +691,9 @@ def main(): elif args.command == "autoneg": interface_autoneg_status = IntfAutoNegStatus(args.interface, args.namespace, args.display) interface_autoneg_status.display_autoneg_status() + elif args.command == "tpid": + interface_tpid = IntfTpid(args.interface, args.namespace, args.display) + interface_tpid.display_intf_tpid() sys.exit(0) diff --git a/scripts/portconfig b/scripts/portconfig index a37a86a82f54..6293b0819819 100755 --- a/scripts/portconfig +++ b/scripts/portconfig @@ -3,7 +3,7 @@ """ portconfig is the utility to show and change ECN configuration -usage: portconfig [-h] [-v] [-s] [-f] [-m] [-p PROFILE] [-gmin GREEN_MIN] +usage: portconfig [-h] [-v] [-s] [-f] [-m] [-tp] [-p PROFILE] [-gmin GREEN_MIN] [-gmax GREEN_MAX] [-ymin YELLOW_MIN] [-ymax YELLOW_MAX] [-rmin RED_MIN] [-rmax RED_MAX] [-vv] [-n namespace] @@ -15,6 +15,7 @@ optional arguments: -s --speed port speed in Mbits -f --fec port fec mode -m --mtu port mtu in bytes + -tp --tpid interface tpid (0x8100, 9100, 9200, 88A8) -n --namesapce Namespace name -an --autoneg port auto negotiation mode -S --adv-speeds port advertised speeds @@ -27,7 +28,7 @@ import argparse # mock the redis for unit test purposes # try: - if os.environ["UTILITIES_UNIT_TESTING"] == "1": + if os.environ["UTILITIES_UNIT_TESTING"] == "1" or 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) @@ -47,6 +48,11 @@ PORT_AUTONEG_CONFIG_FIELD_NAME = "autoneg" PORT_ADV_SPEEDS_CONFIG_FIELD_NAME = "adv_speeds" PORT_INTERFACE_TYPE_CONFIG_FIELD_NAME = "interface_type" PORT_ADV_INTERFACE_TYPES_CONFIG_FIELD_NAME = "adv_interface_types" +PORT_CHANNEL_TABLE_NAME = "PORTCHANNEL" +PORT_CHANNEL_MBR_TABLE_NAME = "PORTCHANNEL_MEMBER" +TPID_CONFIG_FIELD_NAME = "tpid" +SWITCH_CAPABILITY = "SWITCH_CAPABILITY|switch" + # STATE_DB constants PORT_STATE_TABLE_NAME = "PORT_TABLE" @@ -65,17 +71,33 @@ class portconfig(object): def __init__(self, verbose, port, namespace): self.verbose = verbose self.namespace = namespace + self.is_lag = False + self.is_lag_mbr = False + self.parent = port # Set up db connections if namespace is None: self.db = ConfigDBConnector() + self.state_db = SonicV2Connector(host='127.0.0.1') else: self.db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + self.state_db = SonicV2Connector(use_unix_socket_path=True, namespace=front_asic_namespaces) self.db.connect() + self.state_db.connect(self.state_db.STATE_DB, False) # check whether table for this port exists port_tables = self.db.get_table(PORT_TABLE_NAME) - if port not in port_tables: - raise Exception("Invalid port specified") + lag_tables = self.db.get_table(PORT_CHANNEL_TABLE_NAME) + lag_mbr_tables = self.db.get_table(PORT_CHANNEL_MBR_TABLE_NAME) + if port in port_tables: + for key in lag_mbr_tables: + if port == key[1]: + self.parent = key[0] + self.is_lag_mbr = True + break; + elif port in lag_tables: + self.is_lag = True + else: + raise Exception("Invalid port %s" % (port)) def list_params(self, port): # chack whether table for this port exists @@ -157,6 +179,49 @@ class portconfig(object): state_db.connect(state_db.STATE_DB) return state_db.get(state_db.STATE_DB, '{}|{}'.format(PORT_STATE_TABLE_NAME, port), PORT_STATE_SUPPORTED_SPEEDS) + def set_tpid(self, port, tpid): + if self.verbose: + print("Setting tpid %s on port %s" % (tpid, port)) + + tpid_config_ready = False + tpid_port_capable = False + tpid_lag_capable = False + # check TPID Config capability + port_tpid_capable = self.state_db.get(self.state_db.STATE_DB, SWITCH_CAPABILITY, "PORT_TPID_CAPABLE") + lag_tpid_capable = self.state_db.get(self.state_db.STATE_DB, SWITCH_CAPABILITY, "LAG_TPID_CAPABLE") + if port_tpid_capable: + tpid_config_ready = True + if port_tpid_capable == "true": + tpid_port_capable = True + if lag_tpid_capable: + tpid_config_ready = True + if lag_tpid_capable == "true": + tpid_lag_capable = True + + if tpid_config_ready: + # TPID allowed are : 8100, 9100, 9200 and 88A8. Reject all other values. + if tpid == '0x8100' or tpid == '0x9100' or tpid == '0x9200' or tpid == '0x88A8' or tpid == '0x88a8': + if tpid == '0x88a8': + tpid = '0x88A8' + + if self.is_lag: + if tpid_lag_capable: + self.db.mod_entry(PORT_CHANNEL_TABLE_NAME, port, {TPID_CONFIG_FIELD_NAME: tpid}) + else: + raise Exception("HW is not capable to support PortChannel TPID config.") + else: + if self.is_lag_mbr: + raise Exception("%s is already member of %s. Set TPID NOT allowed." % (port, self.parent)) + else: + if tpid_port_capable: + self.db.mod_entry(PORT_TABLE_NAME, port, {TPID_CONFIG_FIELD_NAME: tpid}) + else: + raise Exception("HW is not capable to support Port TPID config.") + else: + raise Exception("TPID %s is not allowed. Allowed: 0x8100, 9100, 9200, or 88A8." % (tpid)) + else: + raise Exception("System not ready to accept TPID config. Please try again later.") + def main(): parser = argparse.ArgumentParser(description='Set SONiC port parameters', @@ -166,6 +231,7 @@ def main(): parser.add_argument('-s', '--speed', type=int, help='port speed value in Mbit', default=None) parser.add_argument('-f', '--fec', type=str, help='port fec mode value in (none, rs, fc)', default=None) parser.add_argument('-m', '--mtu', type=int, help='port mtu value in bytes', default=None) + parser.add_argument('-tp', '--tpid', type=str, help='port TPID value in hex (e.g. 0x8100)', default=None) parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0') parser.add_argument('-vv', '--verbose', action='store_true', help='Verbose output', default=False) parser.add_argument('-n', '--namespace', metavar='namespace details', type = str, required = False, @@ -189,7 +255,7 @@ def main(): port = portconfig(args.verbose, args.port, args.namespace) if args.list: port.list_params(args.port) - elif args.speed or args.fec or args.mtu or args.autoneg or args.adv_speeds or args.interface_type or args.adv_interface_types: + elif args.speed or args.fec or args.mtu or args.autoneg or args.adv_speeds or args.interface_type or args.adv_interface_types or args.tpid: if args.speed: port.set_speed(args.port, args.speed) if args.fec: @@ -204,12 +270,19 @@ def main(): port.set_interface_type(args.port, args.interface_type) if args.adv_interface_types: port.set_adv_interface_types(args.port, args.adv_interface_types) + if args.tpid: + port.set_tpid(args.port, args.tpid) else: parser.print_help() sys.exit(1) except Exception as e: - print(str(e), file=sys.stderr) + 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__": diff --git a/show/interfaces/__init__.py b/show/interfaces/__init__.py index 6d31890b22ee..7d95100ecb17 100644 --- a/show/interfaces/__init__.py +++ b/show/interfaces/__init__.py @@ -147,6 +147,29 @@ def status(interfacename, namespace, display, verbose): clicommon.run_command(cmd, display_cmd=verbose) +@interfaces.command() +@click.argument('interfacename', required=False) +@multi_asic_util.multi_asic_click_options +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def tpid(interfacename, namespace, display, verbose): + """Show Interface tpid information""" + + ctx = click.get_current_context() + + cmd = "intfutil -c tpid" + + if interfacename is not None: + interfacename = try_convert_interfacename_from_alias(ctx, interfacename) + + cmd += " -i {}".format(interfacename) + else: + cmd += " -d {}".format(display) + + if namespace is not None: + cmd += " -n {}".format(namespace) + + clicommon.run_command(cmd, display_cmd=verbose) + # # 'breakout' group ### # diff --git a/tests/mock_tables/appl_db.json b/tests/mock_tables/appl_db.json index c82562579a72..926e05f0ee86 100644 --- a/tests/mock_tables/appl_db.json +++ b/tests/mock_tables/appl_db.json @@ -33,6 +33,7 @@ "oper_status": "down", "pfc_asym": "off", "mtu": "9100", + "tpid": "0x9200", "fec": "rs", "admin_status": "up", "adv_speeds": "50000,10000", @@ -49,6 +50,7 @@ "oper_status": "up", "pfc_asym": "off", "mtu": "9100", + "tpid": "0x8100", "fec": "rs", "admin_status": "up", "autoneg": "off", @@ -64,6 +66,7 @@ "oper_status": "up", "pfc_asym": "off", "mtu": "9100", + "tpid": "0x8100", "fec": "rs", "admin_status": "up" }, @@ -76,6 +79,7 @@ "oper_status": "up", "pfc_asym": "off", "mtu": "9100", + "tpid": "0x8100", "fec": "rs", "admin_status": "up" }, @@ -88,6 +92,7 @@ "oper_status": "up", "pfc_asym": "off", "mtu": "9100", + "tpid": "0x8100", "fec": "rs", "admin_status": "up" }, @@ -100,6 +105,7 @@ "oper_status": "up", "pfc_asym": "off", "mtu": "9100", + "tpid": "0x8100", "fec": "rs", "admin_status": "up" }, @@ -112,6 +118,7 @@ "oper_status": "down", "fec": "rs", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "admin_status": "up" }, @@ -123,6 +130,7 @@ "index": "148", "lanes": "109,0,0,0,0,0,0,0", "mtu": "9100", + "tpid": "0x8100", "oper_status": "up", "role": "Int", "speed": "100000" @@ -169,21 +177,25 @@ "LAG_TABLE:PortChannel0001": { "admin_status": "up", "mtu": "9100", + "tpid": "0x8100", "oper_status": "down" }, "LAG_TABLE:PortChannel0002": { "admin_status": "up", "mtu": "9100", + "tpid": "0x8100", "oper_status": "up" }, "LAG_TABLE:PortChannel0003": { "admin_status": "up", "mtu": "9100", + "tpid": "0x8100", "oper_status": "up" }, "LAG_TABLE:PortChannel0004": { "admin_status": "up", "mtu": "9100", + "tpid": "0x88A8", "oper_status": "up" }, "SWITCH_TABLE:switch": { diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index 6c554f8f980c..e4be4606dabd 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -28,6 +28,7 @@ "index": "0", "lanes": "25,26,27,28", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -38,6 +39,7 @@ "index": "1", "lanes": "29,30,31,32", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -48,6 +50,7 @@ "index": "2", "lanes": "33,34,35,36", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -58,6 +61,7 @@ "index": "3", "lanes": "37,38,39,40", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -68,6 +72,7 @@ "index": "4", "lanes": "45,46,47,48", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -78,6 +83,7 @@ "index": "5", "lanes": "41,42,43,44", "mtu": "9100", + "tpid": "0x9200", "pfc_asym": "off", "speed": "40000" }, @@ -88,6 +94,7 @@ "index": "6", "lanes": "1,2,3,4", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -98,6 +105,7 @@ "index": "7", "lanes": "5,6,7,8", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -108,6 +116,7 @@ "index": "8", "lanes": "13,14,15,16", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -118,6 +127,7 @@ "index": "9", "lanes": "9,10,11,12", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -128,6 +138,7 @@ "index": "10", "lanes": "17,18,19,20", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -138,6 +149,7 @@ "index": "11", "lanes": "21,22,23,24", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -148,6 +160,7 @@ "index": "12", "lanes": "53,54,55,56", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -158,6 +171,7 @@ "index": "13", "lanes": "49,50,51,52", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -168,6 +182,7 @@ "index": "14", "lanes": "57,58,59,60", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -178,6 +193,7 @@ "index": "15", "lanes": "61,62,63,64", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -188,6 +204,7 @@ "index": "16", "lanes": "69,70,71,72", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -198,6 +215,7 @@ "index": "17", "lanes": "65,66,67,68", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -208,6 +226,7 @@ "index": "18", "lanes": "73,74,75,76", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -218,6 +237,7 @@ "index": "19", "lanes": "77,78,79,80", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -228,6 +248,7 @@ "index": "20", "lanes": "109,110,111,112", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -238,6 +259,7 @@ "index": "21", "lanes": "105,106,107,108", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -248,6 +270,7 @@ "index": "22", "lanes": "113,114,115,116", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -258,6 +281,7 @@ "index": "23", "lanes": "117,118,119,120", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -268,6 +292,7 @@ "index": "24", "lanes": "125,126,127,128", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -277,6 +302,7 @@ "index": "25", "lanes": "121,122,123,124", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -286,6 +312,7 @@ "index": "26", "lanes": "81,82,83,84", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -295,6 +322,7 @@ "index": "27", "lanes": "85,86,87,88", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -305,6 +333,7 @@ "index": "28", "lanes": "93,94,95,96", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -315,6 +344,7 @@ "index": "29", "lanes": "89,90,91,92", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -325,6 +355,7 @@ "index": "30", "lanes": "101,102,103,104", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -335,6 +366,7 @@ "index": "31", "lanes": "97,98,99,100", "mtu": "9100", + "tpid": "0x8100", "pfc_asym": "off", "speed": "40000" }, @@ -495,30 +527,35 @@ "admin_status": "up", "members@": "Ethernet32", "min_links": "1", + "tpid": "0x8100", "mtu": "9100" }, "PORTCHANNEL|PortChannel0001": { "admin_status": "up", "members@": "Ethernet112", "min_links": "1", + "tpid": "0x8100", "mtu": "9100" }, "PORTCHANNEL|PortChannel0002": { "admin_status": "up", "members@": "Ethernet116", "min_links": "1", + "tpid": "0x8100", "mtu": "9100" }, "PORTCHANNEL|PortChannel0003": { "admin_status": "up", "members@": "Ethernet120", "min_links": "1", + "tpid": "0x8100", "mtu": "9100" }, "PORTCHANNEL|PortChannel0004": { "admin_status": "up", "members@": "Ethernet124", "min_links": "1", + "tpid": "0x8100", "mtu": "9100" }, "PORTCHANNEL_MEMBER|PortChannel1001|Ethernet32": { diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index 4fb858691cc3..aa33612f22f4 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -268,6 +268,8 @@ "SWITCH_CAPABILITY|switch": { "MIRROR": "true", "MIRRORV6": "true", + "PORT_TPID_CAPABLE": "true", + "LAG_TPID_CAPABLE": "true", "ACL_ACTIONS|INGRESS": "PACKET_ACTION,REDIRECT_ACTION,MIRROR_INGRESS_ACTION", "ACL_ACTIONS|EGRESS": "PACKET_ACTION,MIRROR_EGRESS_ACTION", "ACL_ACTION|PACKET_ACTION": "FORWARD" diff --git a/tests/tpid_test.py b/tests/tpid_test.py new file mode 100644 index 000000000000..0c3ca4feeea1 --- /dev/null +++ b/tests/tpid_test.py @@ -0,0 +1,188 @@ +import sys +import os +import click +from click.testing import CliRunner +import pytest +import swsssdk +import traceback + +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) + +mock_db_path = os.path.join(test_path, "mock_tables") + +import show.main as show +import clear.main as clear +import config.main as config + +import mock_tables.dbconnector + +from unittest import mock +from unittest.mock import patch +from utilities_common.db import Db + + +add_lag_member_with_non_deft_tpid_configured="""\ +Usage: add [OPTIONS] +Try "add --help" for help. + +Error: Port TPID of Ethernet20: 0x9200 is not at default 0x8100 +""" + +bad_tpid_configured="""\ +TPID 0x2000 is not allowed. Allowed: 0x8100, 9100, 9200, or 88A8. +""" + +bad_lag_tpid_configured="""\ +TPID 0x2100 is not allowed. Allowed: 0x8100, 9100, 9200, or 88A8. +""" + +tpid_set_on_lag_mbr_attempted_not_allowed="""\ +Ethernet32 is already member of PortChannel1001. Set TPID NOT allowed. +""" + +show_interface_tpid_output="""\ + Interface Alias Oper Admin TPID +--------------- --------- ------ ------- ------ + Ethernet0 Ethernet0 down up 0x9200 + Ethernet32 etp9 up up 0x8100 + Ethernet112 etp29 up up 0x8100 + Ethernet116 etp30 up up 0x8100 + Ethernet120 etp31 up up 0x8100 + Ethernet124 etp32 up up 0x8100 +PortChannel0001 N/A down up 0x8100 +PortChannel0002 N/A up up 0x8100 +PortChannel0003 N/A up up 0x8100 +PortChannel0004 N/A up up 0x8100 +PortChannel1001 N/A N/A N/A 0x8100 +""" + +show_interface_tpid_ethernet0_output="""\ + Interface Alias Oper Admin TPID +----------- --------- ------ ------- ------ + Ethernet0 Ethernet0 down up 0x9200 +""" + + +class TestTpid(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "2" + import mock_tables.dbconnector + + def test_tpid_config_bad_tpid(self): + db = Db() + obj = {'config_db': db.cfgdb, 'namespace': ''} + runner = CliRunner() + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["Ethernet0", "0x2000"], obj=obj) + print(result.exit_code) + print(result.output) + #traceback.print_tb(result.exc_info[2]) + assert result.exit_code == 1 + assert result.output == bad_tpid_configured + + def test_tpid_config_lag_mbr(self): + db = Db() + obj = {'config_db': db.cfgdb, 'namespace': ''} + runner = CliRunner() + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["Ethernet32", "0x9100"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 1 + assert result.output == tpid_set_on_lag_mbr_attempted_not_allowed + + def test_tpid_add_lag_mbr_with_non_default_tpid(self): + db = Db() + obj = {'db':db.cfgdb} + runner = CliRunner() + result = runner.invoke(config.config.commands["portchannel"].commands["member"].commands["add"], ["PortChannel0001","Ethernet20"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code != 0 + assert result.output == add_lag_member_with_non_deft_tpid_configured + + def test_tpid_config_port_interface(self): + db = Db() + obj = {'config_db': db.cfgdb, 'namespace': ''} + runner = CliRunner() + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["Ethernet0", "0x9200"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["Ethernet0", "0x9100"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["Ethernet0", "0x88a8"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["Ethernet0", "0x8100"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["Ethernet0", "0x2000"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 1 + assert result.output == bad_tpid_configured + + def test_tpid_config_portchannel_interface(self): + db = Db() + obj = {'config_db': db.cfgdb, 'namespace': ''} + runner = CliRunner() + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["PortChannel1001", "0x9200"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["PortChannel1001", "0x9100"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["PortChannel1001", "0x88A8"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["PortChannel1001", "0x8100"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + result = runner.invoke(config.config.commands["interface"].commands["tpid"], ["PortChannel1001", "0x2100"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 1 + assert result.output == bad_lag_tpid_configured + + def test_show_tpid(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["tpid"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_interface_tpid_output + + def test_show_tpid_ethernet0(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["tpid"], ["Ethernet0"]) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_interface_tpid_ethernet0_output + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["UTILITIES_UNIT_TESTING"] = "0"