From 59a511d3855cc151b510201e1aaefb33d0b8a8a5 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Mon, 19 Oct 2020 17:51:44 -0700 Subject: [PATCH] [config/show] Add CLI support for proxy arp (#1168) * Add `config vlan proxy_arp ` * Add proxy ARP info to `show vlan brief` --- config/vlan.py | 39 ++++++- doc/Command-Reference.md | 31 +++-- show/vlan.py | 31 +++-- tests/vlan_test.py | 246 ++++++++++++++++++++++++--------------- utilities_common/cli.py | 4 + 5 files changed, 240 insertions(+), 111 deletions(-) diff --git a/config/vlan.py b/config/vlan.py index a43a374495..ff1a669f75 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -1,6 +1,7 @@ import click - import utilities_common.cli as clicommon + +from time import sleep from .utils import log # @@ -50,6 +51,42 @@ def del_vlan(db, vid): db.cfgdb.set_entry('VLAN_MEMBER', k, None) db.cfgdb.set_entry('VLAN', 'Vlan{}'.format(vid), None) +def restart_ndppd(): + verify_swss_running_cmd = "docker container inspect -f '{{.State.Status}}' swss" + docker_exec_cmd = "docker exec -it swss {}" + ndppd_config_gen_cmd = "sonic-cfggen -d -t /usr/share/sonic/templates/ndppd.conf.j2,/etc/ndppd.conf" + ndppd_restart_cmd = "supervisorctl restart ndppd" + + output = clicommon.run_command(verify_swss_running_cmd, return_cmd=True) + + if output and output.strip() != "running": + click.echo(click.style('SWSS container is not running, changes will take effect the next time the SWSS container starts', fg='red'),) + return + + clicommon.run_command(docker_exec_cmd.format(ndppd_config_gen_cmd), display_cmd=True) + sleep(3) + clicommon.run_command(docker_exec_cmd.format(ndppd_restart_cmd), display_cmd=True) + + +@vlan.command('proxy_arp') +@click.argument('vid', metavar='', required=True, type=int) +@click.argument('mode', metavar='', required=True, type=click.Choice(["enabled", "disabled"])) +@clicommon.pass_db +def config_proxy_arp(db, vid, mode): + """Configure proxy ARP for a VLAN""" + + log.log_info("'setting proxy ARP to {} for Vlan{}".format(mode, vid)) + + ctx = click.get_current_context() + + vlan = 'Vlan{}'.format(vid) + + if not clicommon.is_valid_vlan_interface(db.cfgdb, vlan): + ctx.fail("Interface {} does not exist".format(vlan)) + + db.cfgdb.set_entry('VLAN_INTERFACE', vlan, {"proxy_arp": mode}) + click.echo('Proxy ARP setting saved to ConfigDB') + restart_ndppd() # # 'member' group ('config vlan member ...') # diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index ae1cf7f226..9e4f8c7d1b 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -6134,7 +6134,7 @@ Go Back To [Beginning of the document](#) or [Beginning of this section](#System **show vlan brief** -This command displays brief information about all the vlans configured in the device. It displays the vlan ID, IP address (if configured for the vlan), list of vlan member ports, whether the port is tagged or in untagged mode and the DHCP Helper Address. +This command displays brief information about all the vlans configured in the device. It displays the vlan ID, IP address (if configured for the vlan), list of vlan member ports, whether the port is tagged or in untagged mode, the DHCP Helper Address, and the proxy ARP status - Usage: ``` @@ -6145,13 +6145,13 @@ This command displays brief information about all the vlans configured in the de ``` admin@sonic:~$ show vlan brief - +-----------+--------------+-----------+----------------+-----------------------+ - | VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | - +===========+==============+===========+================+=======================+ - | 100 | 1.1.2.2/16 | Ethernet0 | tagged | 192.0.0.1 | - | | | Ethernet4 | tagged | 192.0.0.2 | - | | | | | 192.0.0.3 | - +-----------+--------------+-----------+----------------+-----------------------+ + +-----------+--------------+-----------+----------------+-----------------------+-------------+ + | VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | + +===========+==============+===========+================+=======================+=============+ + | 100 | 1.1.2.2/16 | Ethernet0 | tagged | 192.0.0.1 | disabled | + | | | Ethernet4 | tagged | 192.0.0.2 | | + | | | | | 192.0.0.3 | | + +-----------+--------------+-----------+----------------+-----------------------+-------------+ ``` **show vlan config** @@ -6212,6 +6212,21 @@ This command is to add or delete a member port into the already created vlan. This command will add Ethernet4 as member of the vlan 100. ``` +**config proxy_arp enabled/disabled** + +This command is used to enable or disable proxy ARP for a VLAN interface + +- Usage: + ``` + config vlan proxy_arp enabled/disabled + ``` + +- Example: + ``` + admin@sonic:~$ sudo config vlan proxy_arp 1000 enabled + This command will enable proxy ARP for the interface 'Vlan1000' + ``` + Go Back To [Beginning of the document](#) or [Beginning of this section](#vlan--FDB) ### FDB diff --git a/show/vlan.py b/show/vlan.py index fa0eb524fd..f9869e2ba7 100644 --- a/show/vlan.py +++ b/show/vlan.py @@ -14,7 +14,7 @@ def vlan(): @clicommon.pass_db def brief(db, verbose): """Show all bridge information""" - header = ['VLAN ID', 'IP Address', 'Ports', 'Port Tagging', 'DHCP Helper Address'] + header = ['VLAN ID', 'IP Address', 'Ports', 'Port Tagging', 'DHCP Helper Address', 'Proxy ARP'] body = [] # Fetching data from config db for VLAN, VLAN_INTERFACE and VLAN_MEMBER @@ -28,6 +28,7 @@ def brief(db, verbose): vlan_ip_dict = {} vlan_ports_dict = {} vlan_tagging_dict = {} + vlan_proxy_arp_dict = {} # Parsing DHCP Helpers info for key in natsorted(vlan_dhcp_helper_data.keys()): @@ -39,14 +40,25 @@ def brief(db, verbose): # Parsing VLAN Gateway info for key in natsorted(vlan_ip_data.keys()): - if not clicommon.is_ip_prefix_in_key(key): - continue - interface_key = str(key[0].strip("Vlan")) - interface_value = str(key[1]) - if interface_key in vlan_ip_dict: - vlan_ip_dict[interface_key].append(interface_value) + + if clicommon.is_ip_prefix_in_key(key): + interface_key = str(key[0].strip("Vlan")) + interface_value = str(key[1]) + + if interface_key in vlan_ip_dict: + vlan_ip_dict[interface_key].append(interface_value) + else: + vlan_ip_dict[interface_key] = [interface_value] else: - vlan_ip_dict[interface_key] = [interface_value] + interface_key = str(key.strip("Vlan")) + if 'proxy_arp' in vlan_ip_data[key]: + proxy_arp_status = vlan_ip_data[key]['proxy_arp'] + else: + proxy_arp_status = "disabled" + + vlan_proxy_arp_dict[interface_key] = proxy_arp_status + + iface_alias_converter = clicommon.InterfaceAliasConverter(db) @@ -88,7 +100,8 @@ def brief(db, verbose): vlan_tagging = "" else: vlan_tagging = ','.replace(',', '\n').join((vlan_tagging_dict[key])) - body.append([key, ip_address, vlan_ports, vlan_tagging, dhcp_helpers]) + vlan_proxy_arp = vlan_proxy_arp_dict.get(key, "disabled") + body.append([key, ip_address, vlan_ports, vlan_tagging, dhcp_helpers, vlan_proxy_arp]) click.echo(tabulate(body, header, tablefmt="grid")) @vlan.command() diff --git a/tests/vlan_test.py b/tests/vlan_test.py index 17b234efcf..b37e438108 100644 --- a/tests/vlan_test.py +++ b/tests/vlan_test.py @@ -8,63 +8,63 @@ from utilities_common.db import Db show_vlan_brief_output="""\ -+-----------+-----------------+------------+----------------+-----------------------+ -| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | -+===========+=================+============+================+=======================+ -| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | -| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | -| | | Ethernet12 | untagged | 192.0.0.3 | -| | | Ethernet16 | untagged | 192.0.0.4 | -+-----------+-----------------+------------+----------------+-----------------------+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | -| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | -| | | | | 192.0.0.3 | -| | | | | 192.0.0.4 | -+-----------+-----------------+------------+----------------+-----------------------+ ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | ++===========+=================+============+================+=======================+=============+ +| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | disabled | +| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | | +| | | Ethernet12 | untagged | 192.0.0.3 | | +| | | Ethernet16 | untagged | 192.0.0.4 | | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | enabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | | +| | | | | 192.0.0.3 | | +| | | | | 192.0.0.4 | | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ """ show_vlan_brief_in_alias_mode_output="""\ -+-----------+-----------------+---------+----------------+-----------------------+ -| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | -+===========+=================+=========+================+=======================+ -| 1000 | 192.168.0.1/21 | etp2 | untagged | 192.0.0.1 | -| | fc02:1000::1/64 | etp3 | untagged | 192.0.0.2 | -| | | etp4 | untagged | 192.0.0.3 | -| | | etp5 | untagged | 192.0.0.4 | -+-----------+-----------------+---------+----------------+-----------------------+ -| 2000 | 192.168.0.10/21 | etp7 | untagged | 192.0.0.1 | -| | fc02:1011::1/64 | etp8 | untagged | 192.0.0.2 | -| | | | | 192.0.0.3 | -| | | | | 192.0.0.4 | -+-----------+-----------------+---------+----------------+-----------------------+ ++-----------+-----------------+---------+----------------+-----------------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | ++===========+=================+=========+================+=======================+=============+ +| 1000 | 192.168.0.1/21 | etp2 | untagged | 192.0.0.1 | disabled | +| | fc02:1000::1/64 | etp3 | untagged | 192.0.0.2 | | +| | | etp4 | untagged | 192.0.0.3 | | +| | | etp5 | untagged | 192.0.0.4 | | ++-----------+-----------------+---------+----------------+-----------------------+-------------+ +| 2000 | 192.168.0.10/21 | etp7 | untagged | 192.0.0.1 | enabled | +| | fc02:1011::1/64 | etp8 | untagged | 192.0.0.2 | | +| | | | | 192.0.0.3 | | +| | | | | 192.0.0.4 | | ++-----------+-----------------+---------+----------------+-----------------------+-------------+ """ show_vlan_brief_empty_output="""\ -+-----------+-----------------+------------+----------------+-----------------------+ -| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | -+===========+=================+============+================+=======================+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | -| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | -| | | | | 192.0.0.3 | -| | | | | 192.0.0.4 | -+-----------+-----------------+------------+----------------+-----------------------+ ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | ++===========+=================+============+================+=======================+=============+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | enabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | | +| | | | | 192.0.0.3 | | +| | | | | 192.0.0.4 | | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ """ show_vlan_brief_with_portchannel_output="""\ -+-----------+-----------------+-----------------+----------------+-----------------------+ -| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | -+===========+=================+=================+================+=======================+ -| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | -| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | -| | | Ethernet12 | untagged | 192.0.0.3 | -| | | Ethernet16 | untagged | 192.0.0.4 | -| | | PortChannel1001 | untagged | | -+-----------+-----------------+-----------------+----------------+-----------------------+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | -| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | -| | | | | 192.0.0.3 | -| | | | | 192.0.0.4 | -+-----------+-----------------+-----------------+----------------+-----------------------+ ++-----------+-----------------+-----------------+----------------+-----------------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | ++===========+=================+=================+================+=======================+=============+ +| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | disabled | +| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | | +| | | Ethernet12 | untagged | 192.0.0.3 | | +| | | Ethernet16 | untagged | 192.0.0.4 | | +| | | PortChannel1001 | untagged | | | ++-----------+-----------------+-----------------+----------------+-----------------------+-------------+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | enabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | | +| | | | | 192.0.0.3 | | +| | | | | 192.0.0.4 | | ++-----------+-----------------+-----------------+----------------+-----------------------+-------------+ """ show_vlan_config_output="""\ @@ -100,56 +100,56 @@ """ show_vlan_brief_output_with_new_dhcp_relay_address="""\ -+-----------+-----------------+------------+----------------+-----------------------+ -| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | -+===========+=================+============+================+=======================+ -| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | -| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | -| | | Ethernet12 | untagged | 192.0.0.3 | -| | | Ethernet16 | untagged | 192.0.0.4 | -| | | | | 192.0.0.100 | -+-----------+-----------------+------------+----------------+-----------------------+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | -| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | -| | | | | 192.0.0.3 | -| | | | | 192.0.0.4 | -+-----------+-----------------+------------+----------------+-----------------------+ ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | ++===========+=================+============+================+=======================+=============+ +| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | disabled | +| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | | +| | | Ethernet12 | untagged | 192.0.0.3 | | +| | | Ethernet16 | untagged | 192.0.0.4 | | +| | | | | 192.0.0.100 | | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | enabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | | +| | | | | 192.0.0.3 | | +| | | | | 192.0.0.4 | | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ """ config_add_del_vlan_and_vlan_member_output="""\ -+-----------+-----------------+------------+----------------+-----------------------+ -| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | -+===========+=================+============+================+=======================+ -| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | -| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | -| | | Ethernet12 | untagged | 192.0.0.3 | -| | | Ethernet16 | untagged | 192.0.0.4 | -+-----------+-----------------+------------+----------------+-----------------------+ -| 1001 | | Ethernet20 | untagged | | -+-----------+-----------------+------------+----------------+-----------------------+ -| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | -| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | -| | | | | 192.0.0.3 | -| | | | | 192.0.0.4 | -+-----------+-----------------+------------+----------------+-----------------------+ ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | ++===========+=================+============+================+=======================+=============+ +| 1000 | 192.168.0.1/21 | Ethernet4 | untagged | 192.0.0.1 | disabled | +| | fc02:1000::1/64 | Ethernet8 | untagged | 192.0.0.2 | | +| | | Ethernet12 | untagged | 192.0.0.3 | | +| | | Ethernet16 | untagged | 192.0.0.4 | | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| 1001 | | Ethernet20 | untagged | | disabled | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ +| 2000 | 192.168.0.10/21 | Ethernet24 | untagged | 192.0.0.1 | enabled | +| | fc02:1011::1/64 | Ethernet28 | untagged | 192.0.0.2 | | +| | | | | 192.0.0.3 | | +| | | | | 192.0.0.4 | | ++-----------+-----------------+------------+----------------+-----------------------+-------------+ """ config_add_del_vlan_and_vlan_member_in_alias_mode_output="""\ -+-----------+-----------------+---------+----------------+-----------------------+ -| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | -+===========+=================+=========+================+=======================+ -| 1000 | 192.168.0.1/21 | etp2 | untagged | 192.0.0.1 | -| | fc02:1000::1/64 | etp3 | untagged | 192.0.0.2 | -| | | etp4 | untagged | 192.0.0.3 | -| | | etp5 | untagged | 192.0.0.4 | -+-----------+-----------------+---------+----------------+-----------------------+ -| 1001 | | etp6 | untagged | | -+-----------+-----------------+---------+----------------+-----------------------+ -| 2000 | 192.168.0.10/21 | etp7 | untagged | 192.0.0.1 | -| | fc02:1011::1/64 | etp8 | untagged | 192.0.0.2 | -| | | | | 192.0.0.3 | -| | | | | 192.0.0.4 | -+-----------+-----------------+---------+----------------+-----------------------+ ++-----------+-----------------+---------+----------------+-----------------------+-------------+ +| VLAN ID | IP Address | Ports | Port Tagging | DHCP Helper Address | Proxy ARP | ++===========+=================+=========+================+=======================+=============+ +| 1000 | 192.168.0.1/21 | etp2 | untagged | 192.0.0.1 | disabled | +| | fc02:1000::1/64 | etp3 | untagged | 192.0.0.2 | | +| | | etp4 | untagged | 192.0.0.3 | | +| | | etp5 | untagged | 192.0.0.4 | | ++-----------+-----------------+---------+----------------+-----------------------+-------------+ +| 1001 | | etp6 | untagged | | disabled | ++-----------+-----------------+---------+----------------+-----------------------+-------------+ +| 2000 | 192.168.0.10/21 | etp7 | untagged | 192.0.0.1 | enabled | +| | fc02:1011::1/64 | etp8 | untagged | 192.0.0.2 | | +| | | | | 192.0.0.3 | | +| | | | | 192.0.0.4 | | ++-----------+-----------------+---------+----------------+-----------------------+-------------+ """ class TestVlan(object): @classmethod @@ -190,6 +190,12 @@ def test_show_vlan_brief_in_alias_mode(self): assert result.exit_code == 0 assert result.output == show_vlan_brief_in_alias_mode_output + def test_show_vlan_brief_explicit_proxy_arp_disable(self): + runner = CliRunner() + db = Db() + + db.cfgdb.set_entry("VLAN_INTERFACE", "Vlan1000", {"proxy_arp": "disabled"}) + def test_show_vlan_config(self): runner = CliRunner() result = runner.invoke(show.cli.commands["vlan"].commands["config"], []) @@ -400,6 +406,7 @@ def test_config_add_del_vlan_and_vlan_member_in_alias_mode(self): # show output result = runner.invoke(show.cli.commands["vlan"].commands["brief"], [], obj=db) + print(result.exit_code) print(result.output) assert result.output == config_add_del_vlan_and_vlan_member_in_alias_mode_output @@ -423,7 +430,7 @@ def test_config_add_del_vlan_and_vlan_member_in_alias_mode(self): assert result.exit_code == 0 assert result.output == show_vlan_brief_in_alias_mode_output - os.environ['SONIC_CLI_IFACE_MODE'] = "" + os.environ['SONIC_CLI_IFACE_MODE'] = "default" def test_config_vlan_add_dhcp_relay_with_nonexist_vlanid(self): runner = CliRunner() @@ -515,6 +522,59 @@ def test_config_vlan_remove_dhcp_relay_dest_with_nonexist_vlanid(self): assert result.exit_code != 0 assert "Error: Vlan1001 doesn't exist" in result.output + def test_config_vlan_proxy_arp_with_nonexist_vlan_intf_table(self): + modes = ["enabled", "disabled"] + runner = CliRunner() + db = Db() + db.cfgdb.delete_table("VLAN_INTERFACE") + + for mode in modes: + result = runner.invoke(config.config.commands["vlan"].commands["proxy_arp"], ["1000", mode], obj=db) + + print(result.exit_code) + print(result.output) + + assert result.exit_code != 0 + assert "Interface Vlan1000 does not exist" in result.output + + def test_config_vlan_proxy_arp_with_nonexist_vlan_intf(self): + modes = ["enabled", "disabled"] + runner = CliRunner() + db = Db() + + for mode in modes: + result = runner.invoke(config.config.commands["vlan"].commands["proxy_arp"], ["1001", mode], obj=db) + + print(result.exit_code) + print(result.output) + + assert result.exit_code != 0 + assert "Interface Vlan1001 does not exist" in result.output + + def test_config_vlan_proxy_arp_enable(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(config.config.commands["vlan"].commands["proxy_arp"], ["1000", "enabled"], obj=db) + + print(result.exit_code) + print(result.output) + + assert result.exit_code == 0 + assert db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan1000") == {"proxy_arp": "enabled"} + + def test_config_vlan_proxy_arp_disable(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(config.config.commands["vlan"].commands["proxy_arp"], ["2000", "disabled"], obj=db) + + print(result.exit_code) + print(result.output) + + assert result.exit_code == 0 + assert db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan2000") == {"proxy_arp": "disabled"} + @classmethod def teardown_class(cls): os.environ['UTILITIES_UNIT_TESTING'] = "0" diff --git a/utilities_common/cli.py b/utilities_common/cli.py index 32b77eb681..ff55750234 100644 --- a/utilities_common/cli.py +++ b/utilities_common/cli.py @@ -262,6 +262,10 @@ def interface_is_in_vlan(vlan_member_table, interface_name): return False +def is_valid_vlan_interface(config_db, interface): + """ Check an interface is a valid VLAN interface """ + return interface in config_db.get_table("VLAN_INTERFACE") + def interface_is_in_portchannel(portchannel_member_table, interface_name): """ Check if an interface is part of portchannel """ for _,intf in portchannel_member_table.keys():