Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2435,6 +2435,7 @@ def remove_portchannel(ctx, portchannel_name):
ctx.fail("Error: Portchannel {} contains members. Remove members before deleting Portchannel!".format(portchannel_name))

try:
db.set_entry('PORTCHANNEL_INTERFACE', portchannel_name, None)
db.set_entry('PORTCHANNEL', portchannel_name, None)
except JsonPatchConflict:
ctx.fail("{} is not present.".format(portchannel_name))
Expand Down Expand Up @@ -2673,6 +2674,38 @@ def set_portchannel_retry_count(ctx, portchannel_name, retry_count):
ctx.fail("Unable to set the retry count: {}".format(e))


@portchannel.group(cls=clicommon.AbbreviationGroup, name='mac-addr')
@click.pass_context
def portchannel_mac_addr(ctx):
pass


@portchannel_mac_addr.command('set')
@click.argument('portchannel_name', metavar='<portchannel_name>', required=True)
@click.argument('mac_addr', metavar='<mac_addr>', required=True)
@click.pass_context
def set_portchannel_mac_addr(ctx, portchannel_name, mac_addr):
"""Set the mac address for a port channel"""
db = ValidatedConfigDBConnector(ctx.obj['db'])

# Don't proceed if the port channel name is not valid
if is_portchannel_name_valid(portchannel_name) is False:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix '{}'"
.format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))

# Don't proceed if the port channel does not exist
if is_portchannel_present_in_db(db, portchannel_name) is False:
ctx.fail("{} is not present.".format(portchannel_name))

if not re.match("^[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", mac_addr.lower()):
ctx.fail("Provided mac address is not valid")

try:
db.set_entry("PORTCHANNEL_INTERFACE", portchannel_name, {"mac_addr": mac_addr})
except ValueError:
ctx.fail("Portchannel name is invalid or nonexistent")


#
# 'mirror_session' group ('config mirror_session ...')
#
Expand Down Expand Up @@ -4975,9 +5008,12 @@ def remove(ctx, interface_name, ip_addr):
clicommon.run_command(command)
remove_router_interface_ip_address(config_db, interface_name, ip_address)
interface_addresses = get_interface_ipaddresses(config_db, interface_name)
if len(interface_addresses) == 0 and is_interface_bind_to_vrf(config_db, interface_name) is False and get_intf_ipv6_link_local_mode(ctx, interface_name, table_name) != "enable":
if len(interface_addresses) == 0 and is_interface_bind_to_vrf(config_db, interface_name) is False and \
get_intf_ipv6_link_local_mode(ctx, interface_name, table_name) != "enable":
if table_name != "VLAN_SUB_INTERFACE":
config_db.set_entry(table_name, interface_name, None)
interface_entry = config_db.get_entry(table_name, interface_name)
if len(interface_entry) == 0:
config_db.set_entry(table_name, interface_name, None)

#
# 'loopback-action' subcommand
Expand Down
36 changes: 36 additions & 0 deletions tests/portchannel_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,42 @@ def test_set_non_existing_portchannel_retry_count(self):
assert result.exit_code != 0
assert "Error: PortChannel0005 is not present." in result.output

def test_set_invalid_portchannel_mac_addr(self):
runner = CliRunner()
db = Db()
obj = {'db': db.cfgdb}

result = runner.invoke(config.config.commands["portchannel"].commands["mac-addr"].commands["set"],
["Ethernet48", "00:11:22:33:44:55"], obj=obj)
print(result.exit_code)
print(result.output)
assert result.exit_code != 0
assert "Error: Ethernet48 is invalid!" in result.output

def test_set_non_existing_portchannel_mac_addr(self):
runner = CliRunner()
db = Db()
obj = {'db': db.cfgdb}

result = runner.invoke(config.config.commands["portchannel"].commands["mac-addr"].commands["set"],
["PortChannel0005", "00:11:22:33:44:55"], obj=obj)
print(result.exit_code)
print(result.output)
assert result.exit_code != 0
assert "Error: PortChannel0005 is not present." in result.output

def test_set_portchannel_mac_addr(self):
runner = CliRunner()
db = Db()
obj = {'db': db.cfgdb}

result = runner.invoke(config.config.commands["portchannel"].commands["mac-addr"].commands["set"],
["PortChannel1001", "00:11:22:33:44:55"], obj=obj)
print(result.exit_code)
print(result.output)
assert result.exit_code == 0
assert result.output == ""

originalSubprocessPopen = subprocess.Popen

class SubprocessMock:
Expand Down
16 changes: 12 additions & 4 deletions utilities_common/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,21 +415,29 @@ def is_port_router_interface(config_db, port):
"""Check if port is a router interface"""

interface_table = config_db.get_table('INTERFACE')
for intf in interface_table:
if port == intf:
for intf in interface_table.keys():
if is_ip_prefix_in_key(intf) and port == intf[0]:
return True

entry = config_db.get_entry('INTERFACE', port)
if entry.get('ipv6_use_link_local_only') == 'enable':
return True

return False


def is_pc_router_interface(config_db, pc):
"""Check if portchannel is a router interface"""

pc_interface_table = config_db.get_table('PORTCHANNEL_INTERFACE')
for intf in pc_interface_table:
if pc == intf:
for intf in pc_interface_table.keys():
if is_ip_prefix_in_key(intf) and pc == intf[0]:
return True

entry = config_db.get_entry('PORTCHANNEL_INTERFACE', pc)
if entry.get('ipv6_use_link_local_only') == 'enable':
return True

return False


Expand Down