From 69b28409b96e752d7379be049dc7ded837990e02 Mon Sep 17 00:00:00 2001 From: Ann Pokora Date: Sun, 4 Jul 2021 15:15:04 -0700 Subject: [PATCH 1/2] sonic-utilities updates for MPLS --- config/main.py | 50 +++++++ crm/main.py | 54 ++++++- doc/Command-Reference.md | 77 ++++++++++ show/interfaces/__init__.py | 46 +++++- tests/crm_test.py | 182 +++++++++++++++++++++++ tests/mock_tables/asic0/config_db.json | 8 +- tests/mock_tables/asic0/counters_db.json | 6 +- tests/mock_tables/asic1/config_db.json | 8 +- tests/mock_tables/asic1/counters_db.json | 6 +- tests/mock_tables/config_db.json | 8 +- tests/mock_tables/counters_db.json | 6 +- tests/mpls_input/appl_db.json | 47 ++++++ tests/mpls_test.py | 91 ++++++++++++ 13 files changed, 577 insertions(+), 12 deletions(-) create mode 100644 tests/mpls_input/appl_db.json create mode 100644 tests/mpls_test.py diff --git a/config/main.py b/config/main.py index 937933f852..a5d6726b52 100644 --- a/config/main.py +++ b/config/main.py @@ -3936,6 +3936,56 @@ def reset(ctx, interface_name): cmd = "sudo sfputil reset {}".format(interface_name) clicommon.run_command(cmd) +# +# 'mpls' subgroup ('config interface mpls ...') +# + +@interface.group(cls=clicommon.AbbreviationGroup) +@click.pass_context +def mpls(ctx): + """Add or remove MPLS""" + pass + +# +# 'add' subcommand +# + +@mpls.command() +@click.argument('interface_name', metavar='', required=True) +@click.pass_context +def add(ctx, interface_name): + """Add MPLS operation on the interface""" + 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!") + + table_name = get_interface_table_name(interface_name) + if table_name == "": + ctx.fail("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan]") + config_db.set_entry(table_name, interface_name, {"mpls": "enable"}) + +# +# 'del' subcommand +# + +@mpls.command() +@click.argument('interface_name', metavar='', required=True) +@click.pass_context +def remove(ctx, interface_name): + """Remove MPLS operation from the interface""" + 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!") + + table_name = get_interface_table_name(interface_name) + if table_name == "": + ctx.fail("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan]") + config_db.set_entry(table_name, interface_name, {"mpls": "disable"}) + # # 'vrf' subgroup ('config interface vrf ...') # diff --git a/crm/main.py b/crm/main.py index fdde198b1a..04181c67a6 100644 --- a/crm/main.py +++ b/crm/main.py @@ -70,7 +70,8 @@ def show_thresholds(self, resource): if resource == 'all': for res in ["ipv4_route", "ipv6_route", "ipv4_nexthop", "ipv6_nexthop", "ipv4_neighbor", "ipv6_neighbor", "nexthop_group_member", "nexthop_group", "acl_table", "acl_group", "acl_entry", - "acl_counter", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry"]: + "acl_counter", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry", "mpls_inseg", + "mpls_nexthop"]: try: data.append([res, crm_info[res + "_threshold_type"], crm_info[res + "_low_threshold"], crm_info[res + "_high_threshold"]]) except KeyError: @@ -97,7 +98,8 @@ def get_resources(self, resource): if crm_stats: if resource == 'all': for res in ["ipv4_route", "ipv6_route", "ipv4_nexthop", "ipv6_nexthop", "ipv4_neighbor", "ipv6_neighbor", - "nexthop_group_member", "nexthop_group", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry"]: + "nexthop_group_member", "nexthop_group", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry", + "mpls_inseg", "mpls_nexthop"]: if 'crm_stats_' + res + "_used" in crm_stats.keys() and 'crm_stats_' + res + "_available" in crm_stats.keys(): data.append([res, crm_stats['crm_stats_' + res + "_used"], crm_stats['crm_stats_' + res + "_available"]]) else: @@ -262,6 +264,18 @@ def ipv6(ctx): """CRM resource IPv6 address-family""" ctx.obj["crm"].addr_family = 'ipv6' +@thresholds.group() +@click.pass_context +def mpls(ctx): + """CRM resource MPLS address-family""" + ctx.obj["crm"].addr_family = 'mpls' + +@mpls.group() +@click.pass_context +def inseg(ctx): + """CRM configuration for in-segment resource""" + ctx.obj["crm"].res_type = 'inseg' + @ipv4.group() @click.pass_context def route(ctx): @@ -284,7 +298,7 @@ def nexthop(ctx): @click.argument('value', type=click.Choice(['percentage', 'used', 'free'])) @click.pass_context def type(ctx, value): - """CRM threshod type configuration""" + """CRM threshold type configuration""" attr = '' if ctx.obj["crm"].addr_family != None: @@ -298,7 +312,7 @@ def type(ctx, value): @click.argument('value', type=click.INT) @click.pass_context def low(ctx, value): - """CRM low threshod configuration""" + """CRM low threshold configuration""" attr = '' if ctx.obj["crm"].addr_family != None: @@ -312,7 +326,7 @@ def low(ctx, value): @click.argument('value', type=click.INT) @click.pass_context def high(ctx, value): - """CRM high threshod configuration""" + """CRM high threshold configuration""" attr = '' if ctx.obj["crm"].addr_family != None: @@ -328,9 +342,13 @@ def high(ctx, value): nexthop.add_command(type) nexthop.add_command(low) nexthop.add_command(high) +inseg.add_command(type) +inseg.add_command(low) +inseg.add_command(high) ipv6.add_command(route) ipv6.add_command(neighbor) ipv6.add_command(nexthop) +mpls.add_command(nexthop) @thresholds.group() @click.pass_context @@ -493,6 +511,21 @@ def ipv6(ctx): """CRM resource IPv6 address family""" ctx.obj["crm"].addr_family = 'ipv6' +@resources.group() +@click.pass_context +def mpls(ctx): + """CRM resource MPLS address family""" + ctx.obj["crm"].addr_family = 'mpls' + +@mpls.command() +@click.pass_context +def inseg(ctx): + """Show CRM information for in-segment resource""" + if ctx.obj["crm"].cli_mode == 'thresholds': + ctx.obj["crm"].show_thresholds('{0}_inseg'.format(ctx.obj["crm"].addr_family)) + elif ctx.obj["crm"].cli_mode == 'resources': + ctx.obj["crm"].show_resources('{0}_inseg'.format(ctx.obj["crm"].addr_family)) + @ipv4.command() @click.pass_context def route(ctx): @@ -520,9 +553,19 @@ def nexthop(ctx): elif ctx.obj["crm"].cli_mode == 'resources': ctx.obj["crm"].show_resources('{0}_nexthop'.format(ctx.obj["crm"].addr_family)) +@mpls.command() +@click.pass_context +def inseg(ctx): + """Show CRM information for in-segment resource""" + if ctx.obj["crm"].cli_mode == 'thresholds': + ctx.obj["crm"].show_thresholds('{0}_inseg'.format(ctx.obj["crm"].addr_family)) + elif ctx.obj["crm"].cli_mode == 'resources': + ctx.obj["crm"].show_resources('{0}_inseg'.format(ctx.obj["crm"].addr_family)) + ipv6.add_command(route) ipv6.add_command(neighbor) ipv6.add_command(nexthop) +mpls.add_command(nexthop) @resources.group() @click.pass_context @@ -619,6 +662,7 @@ def dnat(ctx): thresholds.add_command(fdb) thresholds.add_command(ipv4) thresholds.add_command(ipv6) +thresholds.add_command(mpls) thresholds.add_command(nexthop) thresholds.add_command(ipmc) thresholds.add_command(snat) diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index f6cf4a646c..abf31bdc9d 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -3095,6 +3095,7 @@ Subsequent pages explain each of these commands in detail. breakout Show Breakout Mode information by interfaces counters Show interface counters description Show interface status, protocol and... + mpls Show Interface MPLS status naming_mode Show interface naming_mode status neighbor Show neighbor related information portchannel Show PortChannel information @@ -3334,6 +3335,36 @@ This command displays the key fields of the interfaces such as Operational Statu Ethernet4 down up hundredGigE1/2 T0-2:hundredGigE1/30 ``` +**show interfaces mpls** + +This command is used to display the configured MPLS state for the list of configured interfaces. + +- Usage: + ``` + show interfaces mpls [] + ``` + +- Example: + ``` + admin@sonic:~$ show interfaces mpls + Interface MPLS State + ----------- ------------ + Ethernet0 disable + Ethernet4 enable + Ethernet8 enable + Ethernet12 disable + Ethernet16 disable + Ethernet20 disable + ``` + +- Example (to only display the MPLS state for interface Ethernet4): + ``` + admin@sonic:~$ show interfaces mpls Ethernet4 + Interface MPLS State + ----------- ------------ + Ethernet4 enable + ``` + **show interfaces tpid** This command displays the key fields of the interfaces such as Operational Status, Administrative Status, Alias and TPID. @@ -3479,6 +3510,7 @@ This sub-section explains the following list of configuration on the interfaces. 8) advertised-speeds - to set interface advertised speeds 9) advertised-types - to set interface advertised types 10) type - to set interface type +11) mpls - To add or remove MPLS operation for the interface From 201904 release onwards, the “config interface” command syntax is changed and the format is as follows: @@ -3951,6 +3983,51 @@ For details please refer [dynamic buffer management](#dynamic-buffer-management) Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces) +**config interface mpls add (Versions >= 202106)** + +This command is used for adding MPLS operation on the interface. +MPLS operation for either physical, portchannel, or VLAN interface can be configured using this command. + + +- Usage: + ``` + sudo config interface mpls add --help + Usage: config interface mpls add [OPTIONS] + + Add MPLS operation on the interface + + Options: + -?, -h, --help Show this message and exit. + ``` + +- Example: + ``` + admin@sonic:~$ sudo config interface mpls add Ethernet4 + ``` + +**config interface mpls remove (Versions >= 202106)** + +This command is used for removing MPLS operation on the interface. +MPLS operation for either physical, portchannel, or VLAN interface can be configured using this command. + +- Usage: + ``` + sudo config interface mpls remove --help + Usage: config interface mpls remove [OPTIONS] + + Remove MPLS operation from the interface + + Options: + -?, -h, --help Show this message and exit. + ``` + +- Example: + ``` + admin@sonic:~$ sudo config interface mpls remove Ethernet4 + ``` + +Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces) + ## Interface Naming Mode ### Interface naming mode show commands diff --git a/show/interfaces/__init__.py b/show/interfaces/__init__.py index 296be9fc9e..204ba84e6c 100644 --- a/show/interfaces/__init__.py +++ b/show/interfaces/__init__.py @@ -9,7 +9,7 @@ from tabulate import tabulate from sonic_py_common import multi_asic from sonic_py_common import device_info -from swsscommon.swsscommon import ConfigDBConnector +from swsscommon.swsscommon import ConfigDBConnector, SonicV2Connector from portconfig import get_child_ports import sonic_platform_base.sonic_sfp.sfputilhelper @@ -321,6 +321,50 @@ def expected(db, interfacename): click.echo(tabulate(body, header)) +# 'mpls' subcommand ("show interfaces mpls") +@interfaces.command() +@click.argument('interfacename', required=False) +@click.pass_context +def mpls(ctx, interfacename): + """Show Interface MPLS status""" + + appl_db = SonicV2Connector() + appl_db.connect(appl_db.APPL_DB) + + if interfacename is not None: + interfacename = try_convert_interfacename_from_alias(ctx, interfacename) + + # Fetching data from appl_db for intfs + keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:*") + intfs_data = {} + for key in keys if keys else []: + tokens = key.split(":") + # Skip INTF_TABLE entries with address information + if len(tokens) != 2: + continue + + if (interfacename is not None) and (interfacename != tokens[1]): + continue + + mpls = appl_db.get(appl_db.APPL_DB, key, 'mpls') + if mpls is None or mpls == '': + intfs_data.update({tokens[1]: 'disable'}) + else: + intfs_data.update({tokens[1]: mpls}) + + header = ['Interface', 'MPLS State'] + body = [] + + # Output name and alias for all interfaces + for intf_name in natsorted(list(intfs_data.keys())): + if clicommon.get_interface_naming_mode() == "alias": + alias = clicommon.InterfaceAliasConverter().name_to_alias(intf_name) + body.append([alias, intfs_data[intf_name]]) + else: + body.append([intf_name, intfs_data[intf_name]]) + + click.echo(tabulate(body, header)) + interfaces.add_command(portchannel.portchannel) # diff --git a/tests/crm_test.py b/tests/crm_test.py index d99402e057..4f10b44d69 100644 --- a/tests/crm_test.py +++ b/tests/crm_test.py @@ -51,6 +51,8 @@ ipmc_entry percentage 70 85 snat_entry percentage 70 85 dnat_entry percentage 70 85 +mpls_inseg percentage 70 85 +mpls_nexthop percentage 70 85 """ @@ -142,6 +144,22 @@ """ +crm_show_thresholds_mpls_inseg = """\ + +Resource Name Threshold Type Low Threshold High Threshold +--------------- ---------------- --------------- ---------------- +mpls_inseg percentage 70 85 + +""" + +crm_show_thresholds_mpls_nexthop = """\ + +Resource Name Threshold Type Low Threshold High Threshold +--------------- ---------------- --------------- ---------------- +mpls_nexthop percentage 70 85 + +""" + crm_show_thresholds_ipmc = """\ Resource Name Threshold Type Low Threshold High Threshold @@ -260,6 +278,22 @@ """ +crm_new_show_thresholds_mpls_inseg = """\ + +Resource Name Threshold Type Low Threshold High Threshold +--------------- ---------------- --------------- ---------------- +mpls_inseg percentage 60 90 + +""" + +crm_new_show_thresholds_mpls_nexthop = """\ + +Resource Name Threshold Type Low Threshold High Threshold +--------------- ---------------- --------------- ---------------- +mpls_nexthop percentage 60 90 + +""" + crm_new_show_thresholds_ipmc = """\ Resource Name Threshold Type Low Threshold High Threshold @@ -322,6 +356,8 @@ ipmc_entry 0 24576 snat_entry 0 1024 dnat_entry 0 1024 +mpls_inseg 0 1024 +mpls_nexthop 0 1024 Stage Bind Point Resource Name Used Count Available Count @@ -445,6 +481,22 @@ """ +crm_show_resources_mpls_inseg = """\ + +Resource Name Used Count Available Count +--------------- ------------ ----------------- +mpls_inseg 0 1024 + +""" + +crm_show_resources_mpls_nexthop = """\ + +Resource Name Used Count Available Count +--------------- ------------ ----------------- +mpls_nexthop 0 1024 + +""" + crm_show_resources_ipmc = """\ Resource Name Used Count Available Count @@ -549,6 +601,8 @@ ipmc_entry 0 24576 snat_entry 0 1024 dnat_entry 0 1024 +mpls_inseg 0 1024 +mpls_nexthop 0 1024 ASIC1 @@ -567,6 +621,8 @@ ipmc_entry 0 24576 snat_entry 0 1024 dnat_entry 0 1024 +mpls_inseg 0 1024 +mpls_nexthop 0 1024 ASIC0 @@ -829,6 +885,40 @@ """ +crm_multi_asic_show_resources_mpls_inseg = """\ + +ASIC0 + +Resource Name Used Count Available Count +--------------- ------------ ----------------- +mpls_inseg 0 1024 + + +ASIC1 + +Resource Name Used Count Available Count +--------------- ------------ ----------------- +mpls_inseg 0 1024 + +""" + +crm_multi_asic_show_resources_mpls_nexthop = """\ + +ASIC0 + +Resource Name Used Count Available Count +--------------- ------------ ----------------- +mpls_nexthop 0 1024 + + +ASIC1 + +Resource Name Used Count Available Count +--------------- ------------ ----------------- +mpls_nexthop 0 1024 + +""" + crm_multi_asic_show_resources_ipmc = """\ ASIC0 @@ -1082,6 +1172,38 @@ def test_crm_show_thresholds_dnat(self): assert result.exit_code == 0 assert result.output == crm_new_show_thresholds_dnat + def test_crm_show_thresholds_mpls_nexthop(self): + runner = CliRunner() + db = Db() + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'nexthop'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_show_thresholds_mpls_nexthop + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'nexthop', 'high', '90'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'nexthop', 'low', '60'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'nexthop'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_new_show_thresholds_mpls_nexthop + + def test_crm_show_thresholds_mpls_inseg(self): + runner = CliRunner() + db = Db() + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'inseg'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_show_thresholds_mpls_inseg + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'inseg', 'high', '90'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'inseg', 'low', '60'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'inseg'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_new_show_thresholds_mpls_inseg + def test_crm_show_thresholds_ipmc(self): runner = CliRunner() db = Db() @@ -1196,6 +1318,20 @@ def test_crm_show_resources_dnat(self): assert result.exit_code == 0 assert result.output == crm_show_resources_dnat + def test_crm_show_resources_mpls_inseg(self): + runner = CliRunner() + result = runner.invoke(crm.cli, ['show', 'resources', 'mpls', 'inseg']) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_show_resources_mpls_inseg + + def test_crm_show_resources_mpls_nexthop(self): + runner = CliRunner() + result = runner.invoke(crm.cli, ['show', 'resources', 'mpls', 'nexthop']) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_show_resources_mpls_nexthop + def test_crm_show_resources_ipmc(self): runner = CliRunner() result = runner.invoke(crm.cli, ['show', 'resources', 'ipmc']) @@ -1448,6 +1584,38 @@ def test_crm_show_thresholds_dnat(self): assert result.exit_code == 0 assert result.output == crm_new_show_thresholds_dnat + def test_crm_show_thresholds_mpls_nexthop(self): + runner = CliRunner() + db = Db() + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'nexthop'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_show_thresholds_mpls_nexthop + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'nexthop', 'high', '90'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'nexthop', 'low', '60'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'nexthop'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_new_show_thresholds_mpls_nexthop + + def test_crm_show_thresholds_mpls_inseg(self): + runner = CliRunner() + db = Db() + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'inseg'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_show_thresholds_mpls_inseg + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'inseg', 'high', '90'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['config', 'thresholds', 'mpls', 'inseg', 'low', '60'], obj=db) + print(sys.stderr, result.output) + result = runner.invoke(crm.cli, ['show', 'thresholds', 'mpls', 'inseg'], obj=db) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_new_show_thresholds_mpls_inseg + def test_crm_show_thresholds_ipmc(self): runner = CliRunner() db = Db() @@ -1563,6 +1731,20 @@ def test_crm_multi_asic_show_resources_dnat(self): assert result.exit_code == 0 assert result.output == crm_multi_asic_show_resources_dnat + def test_crm_multi_asic_show_resources_mpls_inseg(self): + runner = CliRunner() + result = runner.invoke(crm.cli, ['show', 'resources', 'mpls', 'inseg']) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_multi_asic_show_resources_mpls_inseg + + def test_crm_multi_asic_show_resources_mpls_nexthop(self): + runner = CliRunner() + result = runner.invoke(crm.cli, ['show', 'resources', 'mpls', 'nexthop']) + print(sys.stderr, result.output) + assert result.exit_code == 0 + assert result.output == crm_multi_asic_show_resources_mpls_nexthop + def test_crm_multi_asic_show_resources_ipmc(self): runner = CliRunner() result = runner.invoke(crm.cli, ['show', 'resources', 'ipmc']) diff --git a/tests/mock_tables/asic0/config_db.json b/tests/mock_tables/asic0/config_db.json index adc620ffb1..79d6c30bb6 100644 --- a/tests/mock_tables/asic0/config_db.json +++ b/tests/mock_tables/asic0/config_db.json @@ -178,7 +178,13 @@ "dnat_entry_low_threshold": "70", "ipmc_entry_threshold_type": "percentage", "ipmc_entry_high_threshold": "85", - "ipmc_entry_low_threshold": "70" + "ipmc_entry_low_threshold": "70", + "mpls_inseg_threshold_type": "percentage", + "mpls_inseg_high_threshold": "85", + "mpls_inseg_low_threshold": "70", + "mpls_nexthop_threshold_type": "percentage", + "mpls_nexthop_high_threshold": "85", + "mpls_nexthop_low_threshold": "70" }, "MUX_CABLE|Ethernet32": { "state": "auto", diff --git a/tests/mock_tables/asic0/counters_db.json b/tests/mock_tables/asic0/counters_db.json index 9976978c64..167805e313 100644 --- a/tests/mock_tables/asic0/counters_db.json +++ b/tests/mock_tables/asic0/counters_db.json @@ -1693,7 +1693,11 @@ "crm_stats_snat_entry_used":"0", "crm_stats_snat_entry_available":"1024", "crm_stats_dnat_entry_used":"0", - "crm_stats_dnat_entry_available":"1024" + "crm_stats_dnat_entry_available":"1024", + "crm_stats_mpls_inseg_used":"0", + "crm_stats_mpls_inseg_available":"1024", + "crm_stats_mpls_nexthop_used":"0", + "crm_stats_mpls_nexthop_available":"1024" }, "CRM:ACL_STATS:EGRESS:PORT":{ "crm_stats_acl_table_used":"0", diff --git a/tests/mock_tables/asic1/config_db.json b/tests/mock_tables/asic1/config_db.json index f5caae6d35..733a35e660 100644 --- a/tests/mock_tables/asic1/config_db.json +++ b/tests/mock_tables/asic1/config_db.json @@ -146,7 +146,13 @@ "dnat_entry_low_threshold": "70", "ipmc_entry_threshold_type": "percentage", "ipmc_entry_high_threshold": "85", - "ipmc_entry_low_threshold": "70" + "ipmc_entry_low_threshold": "70", + "mpls_inseg_threshold_type": "percentage", + "mpls_inseg_high_threshold": "85", + "mpls_inseg_low_threshold": "70", + "mpls_nexthop_threshold_type": "percentage", + "mpls_nexthop_high_threshold": "85", + "mpls_nexthop_low_threshold": "70" }, "MUX_CABLE|Ethernet32": { "state": "auto", diff --git a/tests/mock_tables/asic1/counters_db.json b/tests/mock_tables/asic1/counters_db.json index 798bb80b4f..279963b81b 100644 --- a/tests/mock_tables/asic1/counters_db.json +++ b/tests/mock_tables/asic1/counters_db.json @@ -900,7 +900,11 @@ "crm_stats_snat_entry_used":"0", "crm_stats_snat_entry_available":"1024", "crm_stats_dnat_entry_used":"0", - "crm_stats_dnat_entry_available":"1024" + "crm_stats_dnat_entry_available":"1024", + "crm_stats_mpls_inseg_used":"0", + "crm_stats_mpls_inseg_available":"1024", + "crm_stats_mpls_nexthop_used":"0", + "crm_stats_mpls_nexthop_available":"1024" }, "CRM:ACL_STATS:EGRESS:PORT":{ "crm_stats_acl_table_used":"0", diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index 24bab1f8b9..430fe3b162 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -1567,7 +1567,13 @@ "dnat_entry_low_threshold": "70", "ipmc_entry_threshold_type": "percentage", "ipmc_entry_high_threshold": "85", - "ipmc_entry_low_threshold": "70" + "ipmc_entry_low_threshold": "70", + "mpls_inseg_threshold_type": "percentage", + "mpls_inseg_high_threshold": "85", + "mpls_inseg_low_threshold": "70", + "mpls_nexthop_threshold_type": "percentage", + "mpls_nexthop_high_threshold": "85", + "mpls_nexthop_low_threshold": "70" }, "CHASSIS_MODULE|LINE-CARD1": { "admin_status": "down" diff --git a/tests/mock_tables/counters_db.json b/tests/mock_tables/counters_db.json index 4765556f45..1d4ce33a02 100644 --- a/tests/mock_tables/counters_db.json +++ b/tests/mock_tables/counters_db.json @@ -1828,7 +1828,11 @@ "crm_stats_snat_entry_used":"0", "crm_stats_snat_entry_available":"1024", "crm_stats_dnat_entry_used":"0", - "crm_stats_dnat_entry_available":"1024" + "crm_stats_dnat_entry_available":"1024", + "crm_stats_mpls_inseg_used":"0", + "crm_stats_mpls_inseg_available":"1024", + "crm_stats_mpls_nexthop_used":"0", + "crm_stats_mpls_nexthop_available":"1024" }, "CRM:ACL_STATS:EGRESS:PORT":{ "crm_stats_acl_table_used":"0", diff --git a/tests/mpls_input/appl_db.json b/tests/mpls_input/appl_db.json new file mode 100644 index 0000000000..0bdb59a3ff --- /dev/null +++ b/tests/mpls_input/appl_db.json @@ -0,0 +1,47 @@ +{ + "INTF_TABLE:Ethernet16": { + "NULL": "NULL" + }, + "INTF_TABLE:Ethernet16:192.168.16.1/24": { + "NULL": "NULL" + }, + "INTF_TABLE:Ethernet2": { + "mpls": "enable" + }, + "INTF_TABLE:Ethernet2:192.168.2.1/24": { + "NULL": "NULL" + }, + "INTF_TABLE:Ethernet4": { + "NULL": "NULL" + }, + "INTF_TABLE:Ethernet4:192.168.4.1/24": { + "NULL": "NULL" + }, + "INTF_TABLE:Ethernet4:192.168.40.1/24": { + "NULL": "NULL" + }, + "INTF_TABLE:Ethernet8": { + "NULL": "NULL" + }, + "INTF_TABLE:Ethernet8:192.168.8.1/24": { + "NULL": "NULL" + }, + "INTF_TABLE:Loopback0": { + "NULL": "NULL" + }, + "INTF_TABLE:Loopback0:192.168.0.1/24": { + "NULL": "NULL" + }, + "INTF_TABLE:PortChannel2": { + "mpls": "disable" + }, + "INTF_TABLE:PortChannel2:10.0.0.56/31": { + "NULL": "NULL" + }, + "INTF_TABLE:Vlan2": { + "mpls": "enable" + }, + "INTF_TABLE:Vlan2:192.168.1.1/21": { + "NULL": "NULL" + } +} diff --git a/tests/mpls_test.py b/tests/mpls_test.py new file mode 100644 index 0000000000..3f413518c5 --- /dev/null +++ b/tests/mpls_test.py @@ -0,0 +1,91 @@ +import os +import sys +import traceback +from unittest import mock + +from click.testing import CliRunner + +from .mock_tables import dbconnector + +import config.main as config +import show.main as show +from utilities_common.db import Db + +show_interfaces_mpls_output="""\ +Interface MPLS State +------------ ------------ +Ethernet2 enable +Ethernet4 disable +Ethernet8 disable +Ethernet16 disable +Loopback0 disable +PortChannel2 disable +Vlan2 enable +""" + +show_interfaces_mpls_specific_output="""\ +Interface MPLS State +----------- ------------ +Ethernet2 enable +""" + +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) +mock_db_path = os.path.join(test_path, "mpls_input") + + +class TestMpls(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ['UTILITIES_UNIT_TESTING'] = "1" + + def test_config_mpls_add(self): + runner = CliRunner() + db = Db() + obj = {'config_db':db.cfgdb} + + result = runner.invoke(config.config.commands["interface"].commands["mpls"].commands["add"], ["Ethernet4"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_config_mpls_remove(self): + runner = CliRunner() + db = Db() + obj = {'config_db':db.cfgdb} + + result = runner.invoke(config.config.commands["interface"].commands["mpls"].commands["remove"], ["Ethernet4"], obj=obj) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + def test_show_interfaces_mpls(self): + jsonfile = os.path.join(mock_db_path, 'appl_db') + dbconnector.dedicated_dbs['APPL_DB'] = jsonfile + + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["mpls"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_interfaces_mpls_output + + def test_show_interfaces_mpls_specific(self): + jsonfile = os.path.join(mock_db_path, 'appl_db') + dbconnector.dedicated_dbs['APPL_DB'] = jsonfile + + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["mpls"], ["Ethernet2"]) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_interfaces_mpls_specific_output + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ['UTILITIES_UNIT_TESTING'] = "0" + dbconnector.dedicated_dbs['APPL_DB'] = None From e58c9fc13fcc6be7339e2e41524a1ffbeb6c56bc Mon Sep 17 00:00:00 2001 From: Ann Pokora Date: Tue, 6 Jul 2021 14:28:39 -0700 Subject: [PATCH 2/2] sonic-utilities updates for MPLS --- crm/main.py | 9 --------- tests/mpls_test.py | 2 ++ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/crm/main.py b/crm/main.py index 04181c67a6..173dca852c 100644 --- a/crm/main.py +++ b/crm/main.py @@ -553,15 +553,6 @@ def nexthop(ctx): elif ctx.obj["crm"].cli_mode == 'resources': ctx.obj["crm"].show_resources('{0}_nexthop'.format(ctx.obj["crm"].addr_family)) -@mpls.command() -@click.pass_context -def inseg(ctx): - """Show CRM information for in-segment resource""" - if ctx.obj["crm"].cli_mode == 'thresholds': - ctx.obj["crm"].show_thresholds('{0}_inseg'.format(ctx.obj["crm"].addr_family)) - elif ctx.obj["crm"].cli_mode == 'resources': - ctx.obj["crm"].show_resources('{0}_inseg'.format(ctx.obj["crm"].addr_family)) - ipv6.add_command(route) ipv6.add_command(neighbor) ipv6.add_command(nexthop) diff --git a/tests/mpls_test.py b/tests/mpls_test.py index 3f413518c5..a833ef61d3 100644 --- a/tests/mpls_test.py +++ b/tests/mpls_test.py @@ -51,6 +51,7 @@ def test_config_mpls_add(self): print(result.exit_code) print(result.output) assert result.exit_code == 0 + assert db.cfgdb.get_entry("INTERFACE", "Ethernet4") == {"mpls": "enable"} def test_config_mpls_remove(self): runner = CliRunner() @@ -61,6 +62,7 @@ def test_config_mpls_remove(self): print(result.exit_code) print(result.output) assert result.exit_code == 0 + assert db.cfgdb.get_entry("INTERFACE", "Ethernet4") == {"mpls": "disable"} def test_show_interfaces_mpls(self): jsonfile = os.path.join(mock_db_path, 'appl_db')