From 1b0d542e9014fc405ac627545b6173bab85486b2 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Mon, 4 Nov 2019 19:09:47 -0800 Subject: [PATCH] show subinterfaces status (#642) * Add sub port interface to intfutil status Signed-off-by: Wenda Ni * Format change Signed-off-by: Wenda Ni * Hook 'intfutil status' with show subinterfaces status Signed-off-by: Wenda Ni * Add 'intfutil status subport' to show only the status of sub port interfaces Signed-off-by: Wenda Ni * Hook 'intfutil status subport' with 'show subinterfaces status' Signed-off-by: Wenda Ni * Support intfutil status Signed-off-by: Wenda Ni * Add alias naming mode support Signed-off-by: Wenda Ni * Address comments Signed-off-by: Wenda Ni * Address comment: concatenate command line, and validate input Signed-off-by: Wenda Ni * Address comment: keep show interface status intact Signed-off-by: Wenda Ni * Add unit test for show interfaces status / intfutil status Signed-off-by: Wenda Ni * Add unit test for 'show interfaces status --verbose' Signed-off-by: Wenda Ni * Add unit test for 'show subinterfaces status' / 'intfutil status subport' Signed-off-by: Wenda Ni * Add unit test for 'show subinterfaces status --verbose' Signed-off-by: Wenda Ni * Add unit test for single sub interface status show Signed-off-by: Wenda Ni * Add unit test for '--verbose' single sub interface status show Signed-off-by: Wenda Ni * Add unit test for showing status of single sub interface in alias naming mode Signed-off-by: Wenda Ni * Add unit test for '--verbose' status of single sub interface in alias naming mode Signed-off-by: Wenda Ni --- scripts/intfutil | 165 ++++++++++++++---- show/main.py | 58 +++++- sonic-utilities-tests/intfutil_test.py | 129 ++++++++++++++ .../mock_tables/appl_db.json | 5 +- .../mock_tables/config_db.json | 3 + 5 files changed, 325 insertions(+), 35 deletions(-) create mode 100644 sonic-utilities-tests/intfutil_test.py diff --git a/scripts/intfutil b/scripts/intfutil index f8509db93f34..bad72f27c408 100755 --- a/scripts/intfutil +++ b/scripts/intfutil @@ -8,7 +8,18 @@ from tabulate import tabulate from natsort import natsorted from swsssdk import ConfigDBConnector from pprint import pprint - +import os + +# mock the redis for unit test purposes # +try: + if os.environ["UTILITIES_UNIT_TESTING"] == "1": + modules_path = os.path.join(os.path.dirname(__file__), "..") + tests_path = os.path.join(modules_path, "sonic-utilities-tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, tests_path) + import mock_tables.dbconnector +except KeyError: + pass # ========================== Common interface-utils logic ========================== @@ -25,6 +36,11 @@ PORT_DESCRIPTION = "description" PORT_OPTICS_TYPE = "type" PORT_PFC_ASYM_STATUS = "pfc_asym" +VLAN_SUB_INTERFACE_SEPARATOR = "." +VLAN_SUB_INTERFACE_TYPE = "802.1q-encapsulation" + +SUB_PORT = "subport" + def db_connect_configdb(): """ Connect to configdb @@ -43,6 +59,15 @@ def get_frontpanel_port_list(config_db): return front_panel_ports_list +def get_sub_port_intf_list(config_db): + sub_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE') + sub_intf_list = [] + for sub_intf in sub_intf_dict.keys(): + if isinstance(sub_intf, basestring): + sub_intf_list.append(sub_intf) + return sub_intf_list + + def get_interface_vlan_dict(config_db): """ Get info from REDIS ConfigDB and create interface to vlan mapping @@ -93,6 +118,24 @@ def appl_db_keys_get(appl_db, front_panel_ports_list, intf_name): return appl_db_keys +def appl_db_sub_intf_keys_get(appl_db, sub_intf_list, sub_intf_name): + """ + Get APPL_DB sub port interface keys + """ + if sub_intf_name is None: + appl_db_sub_intf_keys = [] + appl_db_intf_keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:*") + if appl_db_intf_keys is not None: + for appl_db_intf_key in appl_db_intf_keys: + if re.split(':', appl_db_intf_key, maxsplit=1)[-1].strip() in sub_intf_list: + appl_db_sub_intf_keys.append(appl_db_intf_key) + elif sub_intf_name in sub_intf_list: + appl_db_sub_intf_keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:%s" % sub_intf_name) + else: + return [] + return appl_db_sub_intf_keys + + def appl_db_port_status_get(appl_db, intf_name, status_type): """ Get the port status @@ -267,13 +310,42 @@ def appl_db_portchannel_status_get(appl_db, config_db, po_name, status_type, por return "N/A" return status +def appl_db_sub_intf_status_get(appl_db, config_db, front_panel_ports_list, portchannel_speed_dict, sub_intf_name, status_type): + sub_intf_sep_idx = sub_intf_name.find(VLAN_SUB_INTERFACE_SEPARATOR) + if sub_intf_sep_idx != -1: + parent_port_name = sub_intf_name[:sub_intf_sep_idx] + vlan_id = sub_intf_name[sub_intf_sep_idx + 1:] + + full_intf_table_name = "INTF_TABLE" + ":" + sub_intf_name + + if status_type == "vlan": + return vlan_id + + if status_type == "admin_status": + status = appl_db.get(appl_db.APPL_DB, full_intf_table_name, status_type) + return status if status is not None else "N/A" + + if status_type == "type": + return VLAN_SUB_INTERFACE_TYPE + + if status_type == "mtu" or status_type == "speed": + if parent_port_name in front_panel_ports_list: + return appl_db_port_status_get(appl_db, parent_port_name, status_type) + elif parent_port_name in portchannel_speed_dict.keys(): + return appl_db_portchannel_status_get(appl_db, config_db, parent_port_name, status_type, portchannel_speed_dict) + else: + return "N/A" + + return "N/A" + # ========================== interface-status logic ========================== header_stat = ['Interface', 'Lanes', 'Speed', 'MTU', 'Alias', 'Vlan', 'Oper', 'Admin', 'Type', 'Asym PFC'] +header_stat_sub_intf = ['Sub port interface', 'Speed', 'MTU', 'Vlan', 'Admin', 'Type'] class IntfStatus(object): - def display_intf_status(self, appl_db_keys, front_panel_ports_list, portchannel_speed_dict): + 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): """ Generate interface-status output """ @@ -286,35 +358,47 @@ class IntfStatus(object): # Iterate through all the keys and append port's associated state to # the result table. # - for i in appl_db_keys: - key = re.split(':', i, maxsplit=1)[-1].strip() - if key in front_panel_ports_list: - 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), - appl_db_port_status_get(self.appl_db, key, PORT_ALIAS), - config_db_vlan_port_keys_get(self.combined_int_to_vlan_po_dict, self.front_panel_ports_list, key), - appl_db_port_status_get(self.appl_db, key, PORT_OPER_STATUS), - appl_db_port_status_get(self.appl_db, key, PORT_ADMIN_STATUS), - state_db_port_optics_get(self.state_db, key, PORT_OPTICS_TYPE), - appl_db_port_status_get(self.appl_db, key, PORT_PFC_ASYM_STATUS))) - # Sorting and tabulating the result table. - for po, value in portchannel_speed_dict.iteritems(): - if po: - 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), - appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ALIAS, self.portchannel_speed_dict), - appl_db_portchannel_status_get(self.appl_db, self.config_db, po, "vlan", self.portchannel_speed_dict), - appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPER_STATUS, self.portchannel_speed_dict), - appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ADMIN_STATUS, self.portchannel_speed_dict), - appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPTICS_TYPE, self.portchannel_speed_dict), - appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_PFC_ASYM_STATUS, self.portchannel_speed_dict))) + if not sub_intf_only: + for i in appl_db_keys: + key = re.split(':', i, maxsplit=1)[-1].strip() + if key in front_panel_ports_list: + 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), + appl_db_port_status_get(self.appl_db, key, PORT_ALIAS), + config_db_vlan_port_keys_get(self.combined_int_to_vlan_po_dict, self.front_panel_ports_list, key), + appl_db_port_status_get(self.appl_db, key, PORT_OPER_STATUS), + appl_db_port_status_get(self.appl_db, key, PORT_ADMIN_STATUS), + state_db_port_optics_get(self.state_db, key, PORT_OPTICS_TYPE), + appl_db_port_status_get(self.appl_db, key, PORT_PFC_ASYM_STATUS))) + + for po, value in portchannel_speed_dict.iteritems(): + if po: + 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), + appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ALIAS, self.portchannel_speed_dict), + appl_db_portchannel_status_get(self.appl_db, self.config_db, po, "vlan", self.portchannel_speed_dict), + appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPER_STATUS, self.portchannel_speed_dict), + appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_ADMIN_STATUS, self.portchannel_speed_dict), + appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_OPTICS_TYPE, self.portchannel_speed_dict), + appl_db_portchannel_status_get(self.appl_db, self.config_db, po, PORT_PFC_ASYM_STATUS, self.portchannel_speed_dict))) + else: + for key in appl_db_sub_intf_keys: + sub_intf = re.split(':', key, maxsplit=1)[-1].strip() + if sub_intf in sub_intf_list: + table.append((sub_intf, + appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_SPEED), + appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_MTU_STATUS), + appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, "vlan"), + appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_ADMIN_STATUS), + appl_db_sub_intf_status_get(self.appl_db, self.config_db, self.front_panel_ports_list, self.portchannel_speed_dict, sub_intf, PORT_OPTICS_TYPE))) + # Sorting and tabulating the result table. sorted_table = natsorted(table) - print tabulate(sorted_table, header_stat, tablefmt="simple", stralign='right') + print tabulate(sorted_table, header_stat if not sub_intf_only else header_stat_sub_intf, tablefmt="simple", stralign='right') def __init__(self, intf_name): @@ -333,6 +417,20 @@ class IntfStatus(object): return if self.config_db is None: return + + sub_intf_only = False + sub_intf_name = intf_name + if intf_name is not None: + if intf_name == SUB_PORT: + intf_name = None + sub_intf_name = None + sub_intf_only = True + else: + sub_intf_sep_idx = intf_name.find(VLAN_SUB_INTERFACE_SEPARATOR) + if sub_intf_sep_idx != -1: + sub_intf_only = True + 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) self.int_to_vlan_dict = get_interface_vlan_dict(self.config_db) @@ -344,9 +442,12 @@ class IntfStatus(object): self.combined_int_to_vlan_po_dict = merge_dicts(self.int_to_vlan_dict, self.int_po_dict) self.portchannel_speed_dict = po_speed_dict(self.po_int_dict, self.appl_db) self.portchannel_keys = self.portchannel_speed_dict.keys() + + self.sub_intf_list = get_sub_port_intf_list(self.config_db) + 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) + 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) @@ -392,6 +493,10 @@ class IntfDescription(object): return if self.config_db is None: return + + if intf_name is not None and intf_name == SUB_PORT: + intf_name = None + 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) if appl_db_keys is None: diff --git a/show/main.py b/show/main.py index 9aa119c0ebe6..824de63c99ab 100755 --- a/show/main.py +++ b/show/main.py @@ -22,6 +22,8 @@ SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +VLAN_SUB_INTERFACE_SEPARATOR = '.' + try: # noinspection PyPep8Naming import ConfigParser as configparser @@ -74,25 +76,42 @@ def name_to_alias(self, interface_name): """Return vendor interface alias if SONiC interface name is given as argument """ + vlan_id = '' + sub_intf_sep_idx = -1 if interface_name is not None: + sub_intf_sep_idx = interface_name.find(VLAN_SUB_INTERFACE_SEPARATOR) + if sub_intf_sep_idx != -1: + vlan_id = interface_name[sub_intf_sep_idx + 1:] + # interface_name holds the parent port name + interface_name = interface_name[:sub_intf_sep_idx] + for port_name in self.port_dict.keys(): if interface_name == port_name: - return self.port_dict[port_name]['alias'] + return self.port_dict[port_name]['alias'] if sub_intf_sep_idx == -1 \ + else self.port_dict[port_name]['alias'] + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id # interface_name not in port_dict. Just return interface_name - return interface_name + return interface_name if sub_intf_sep_idx == -1 else interface_name + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id def alias_to_name(self, interface_alias): """Return SONiC interface name if vendor port alias is given as argument """ + vlan_id = '' + sub_intf_sep_idx = -1 if interface_alias is not None: + sub_intf_sep_idx = interface_alias.find(VLAN_SUB_INTERFACE_SEPARATOR) + if sub_intf_sep_idx != -1: + vlan_id = interface_alias[sub_intf_sep_idx + 1:] + # interface_alias holds the parent port alias + interface_alias = interface_alias[:sub_intf_sep_idx] + for port_name in self.port_dict.keys(): if interface_alias == self.port_dict[port_name]['alias']: - return port_name + return port_name if sub_intf_sep_idx == -1 else port_name + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id # interface_alias not in port_dict. Just return interface_alias - return interface_alias + return interface_alias if sub_intf_sep_idx == -1 else interface_alias + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id # Global Config object @@ -789,6 +808,37 @@ def portchannel(verbose): cmd = "sudo teamshow" run_command(cmd, display_cmd=verbose) +# +# 'subinterfaces' group ("show subinterfaces ...") +# + +@cli.group(cls=AliasedGroup, default_if_no_args=False) +def subinterfaces(): + """Show details of the sub port interfaces""" + pass + +# 'subinterfaces' subcommand ("show subinterfaces status") +@subinterfaces.command() +@click.argument('subinterfacename', type=str, required=False) +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def status(subinterfacename, verbose): + """Show sub port interface status information""" + cmd = "intfutil status " + + if subinterfacename is not None: + sub_intf_sep_idx = subinterfacename.find(VLAN_SUB_INTERFACE_SEPARATOR) + if sub_intf_sep_idx == -1: + print("Invalid sub port interface name") + return + + if get_interface_mode() == "alias": + subinterfacename = iface_alias_converter.alias_to_name(subinterfacename) + + cmd += subinterfacename + else: + cmd += "subport" + run_command(cmd, display_cmd=verbose) + # # 'pfc' group ("show pfc ...") # diff --git a/sonic-utilities-tests/intfutil_test.py b/sonic-utilities-tests/intfutil_test.py new file mode 100644 index 000000000000..44791729bb44 --- /dev/null +++ b/sonic-utilities-tests/intfutil_test.py @@ -0,0 +1,129 @@ +import os +import sys +from click.testing import CliRunner +from unittest import TestCase +import subprocess + +import show.main as show + +root_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(root_path) +scripts_path = os.path.join(modules_path, "scripts") + +class TestIntfutil(TestCase): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + def setUp(self): + self.runner = CliRunner() + + + # Test 'show interfaces status' / 'intfutil status' + def test_intf_status(self): + # Test 'show interfaces status' + result = self.runner.invoke(show.cli.commands["interfaces"].commands["status"], []) + print >> sys.stderr, result.output + expected_output = ( + "Interface Lanes Speed MTU Alias Vlan Oper Admin Type Asym PFC\n" + "----------- ------- ------- ----- --------- ------ ------ ------- --------------- ----------\n" + " Ethernet0 0 25G 9100 Ethernet0 routed down up QSFP28 or later off" + ) + self.assertEqual(result.output.strip(), expected_output) + + # Test 'intfutil status' + output = subprocess.check_output('intfutil status', stderr=subprocess.STDOUT, shell=True) + print >> sys.stderr, output + self.assertEqual(output.strip(), expected_output) + + # Test 'show interfaces status --verbose' + def test_intf_status_verbose(self): + result = self.runner.invoke(show.cli.commands["interfaces"].commands["status"], ["--verbose"]) + print >> sys.stderr, result.output + expected_output = "Command: intfutil status" + self.assertEqual(result.output.split('\n')[0], expected_output) + + + # Test 'show subinterfaces status' / 'intfutil status subport' + def test_subintf_status(self): + # Test 'show subinterfaces status' + result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], []) + print >> sys.stderr, result.output + expected_output = ( + "Sub port interface Speed MTU Vlan Admin Type\n" + "-------------------- ------- ----- ------ ------- --------------------\n" + " Ethernet0.10 25G 9100 10 up 802.1q-encapsulation" + ) + self.assertEqual(result.output.strip(), expected_output) + + # Test 'intfutil status subport' + output = subprocess.check_output('intfutil status subport', stderr=subprocess.STDOUT, shell=True) + print >> sys.stderr, output + self.assertEqual(output.strip(), expected_output) + + # Test 'show subinterfaces status --verbose' + def test_subintf_status_verbose(self): + result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["--verbose"]) + print >> sys.stderr, result.output + expected_output = "Command: intfutil status subport" + self.assertEqual(result.output.split('\n')[0], expected_output) + + + # Test single sub interface status + def test_single_subintf_status(self): + # Test 'show subinterfaces status Ethernet0.10' + result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["Ethernet0.10"]) + print >> sys.stderr, result.output + expected_output = ( + "Sub port interface Speed MTU Vlan Admin Type\n" + "-------------------- ------- ----- ------ ------- --------------------\n" + " Ethernet0.10 25G 9100 10 up 802.1q-encapsulation" + ) + self.assertEqual(result.output.strip(), expected_output) + + # Test 'intfutil status Ethernet0.10' + output = subprocess.check_output('intfutil status Ethernet0.10', stderr=subprocess.STDOUT, shell=True) + print >> sys.stderr, output + self.assertEqual(output.strip(), expected_output) + + # Test '--verbose' status of single sub interface + def test_single_subintf_status_verbose(self): + result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["Ethernet0.10", "--verbose"]) + print >> sys.stderr, result.output + expected_output = "Command: intfutil status Ethernet0.10" + self.assertEqual(result.output.split('\n')[0], expected_output) + + + # Test status of single sub interface in alias naming mode + def test_single_subintf_status_alias_mode(self): + os.environ["SONIC_CLI_IFACE_MODE"] = "alias" + + result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["etp1.10"]) + print >> sys.stderr, result.output + expected_output = ( + "Sub port interface Speed MTU Vlan Admin Type\n" + "-------------------- ------- ----- ------ ------- --------------------\n" + " Ethernet0.10 25G 9100 10 up 802.1q-encapsulation" + ) + self.assertEqual(result.output.strip(), expected_output) + + os.environ["SONIC_CLI_IFACE_MODE"] = "default" + + # Test '--verbose' status of single sub interface in alias naming mode + def test_single_subintf_status_alias_mode_verbose(self): + os.environ["SONIC_CLI_IFACE_MODE"] = "alias" + + result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["etp1.10", "--verbose"]) + print >> sys.stderr, result.output + expected_output = "Command: intfutil status Ethernet0.10" + self.assertEqual(result.output.split('\n')[0], expected_output) + + os.environ["SONIC_CLI_IFACE_MODE"] = "default" + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) + os.environ["UTILITIES_UNIT_TESTING"] = "0" diff --git a/sonic-utilities-tests/mock_tables/appl_db.json b/sonic-utilities-tests/mock_tables/appl_db.json index 1bc3af3c0801..19768f75a213 100644 --- a/sonic-utilities-tests/mock_tables/appl_db.json +++ b/sonic-utilities-tests/mock_tables/appl_db.json @@ -18,5 +18,8 @@ "fec": "rs", "mtu": "9100", "pfc_asym": "off" + }, + "INTF_TABLE:Ethernet0.10": { + "admin_status": "up" } -} \ No newline at end of file +} diff --git a/sonic-utilities-tests/mock_tables/config_db.json b/sonic-utilities-tests/mock_tables/config_db.json index 6cb8e981c71f..97ae4b2edbe1 100644 --- a/sonic-utilities-tests/mock_tables/config_db.json +++ b/sonic-utilities-tests/mock_tables/config_db.json @@ -42,6 +42,9 @@ "mtu": "9100", "speed": "40000" }, + "VLAN_SUB_INTERFACE|Ethernet0.10": { + "admin_status": "up" + }, "ACL_RULE|DATAACL|DEFAULT_RULE": { "PACKET_ACTION": "DROP", "PRIORITY": "1"