Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ND neigh-suppress config and show cli command #15

Open
wants to merge 1 commit into
base: 202311.X
Choose a base branch
from
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
57 changes: 29 additions & 28 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,7 @@ def config(ctx):
config.add_command(kube.kubernetes)
config.add_command(muxcable.muxcable)
config.add_command(nat.nat)
config.add_command(vlan.neigh_suppress)
config.add_command(vlan.vlan)
config.add_command(vxlan.vxlan)

Expand Down Expand Up @@ -1769,7 +1770,7 @@ def load_minigraph(db, no_service_restart, traffic_shift_away, override_config,
cfggen_namespace_option = ['-n', str(namespace)]
clicommon.run_command([db_migrator, '-o', 'set_version'] + cfggen_namespace_option)

# Keep device isolated with TSA
# Keep device isolated with TSA
if traffic_shift_away:
clicommon.run_command(["TSA"], display_cmd=True)
if override_config:
Expand Down Expand Up @@ -2033,23 +2034,23 @@ def synchronous_mode(sync_mode):
if ADHOC_VALIDATION:
if sync_mode != 'enable' and sync_mode != 'disable':
raise click.BadParameter("Error: Invalid argument %s, expect either enable or disable" % sync_mode)

config_db = ValidatedConfigDBConnector(ConfigDBConnector())
config_db.connect()
try:
config_db.mod_entry('DEVICE_METADATA' , 'localhost', {"synchronous_mode" : sync_mode})
except ValueError as e:
ctx = click.get_current_context()
ctx.fail("Error: Invalid argument %s, expect either enable or disable" % sync_mode)

click.echo("""Wrote %s synchronous mode into CONFIG_DB, swss restart required to apply the configuration: \n
Option 1. config save -y \n
config reload -y \n
Option 2. systemctl restart swss""" % sync_mode)

#
# 'yang_config_validation' command ('config yang_config_validation ...')
#
#
@config.command('yang_config_validation')
@click.argument('yang_config_validation', metavar='<enable|disable>', required=True)
def yang_config_validation(yang_config_validation):
Expand Down Expand Up @@ -2095,7 +2096,7 @@ def portchannel(db, ctx, namespace):
@click.pass_context
def add_portchannel(ctx, portchannel_name, min_links, fallback, fast_rate):
"""Add port channel"""

fvs = {
'admin_status': 'up',
'mtu': '9100',
Expand All @@ -2107,26 +2108,26 @@ def add_portchannel(ctx, portchannel_name, min_links, fallback, fast_rate):
fvs['min_links'] = str(min_links)
if fallback != 'false':
fvs['fallback'] = 'true'

db = ValidatedConfigDBConnector(ctx.obj['db'])
if ADHOC_VALIDATION:
if is_portchannel_name_valid(portchannel_name) != True:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix '{}'"
.format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))
if is_portchannel_present_in_db(db, portchannel_name):
ctx.fail("{} already exists!".format(portchannel_name)) # TODO: MISSING CONSTRAINT IN YANG MODEL

try:
db.set_entry('PORTCHANNEL', portchannel_name, fvs)
except ValueError:
ctx.fail("{} is invalid!, name should have prefix '{}' and suffix '{}'".format(portchannel_name, CFG_PORTCHANNEL_PREFIX, CFG_PORTCHANNEL_NO))

@portchannel.command('del')
@click.argument('portchannel_name', metavar='<portchannel_name>', required=True)
@click.pass_context
def remove_portchannel(ctx, portchannel_name):
"""Remove port channel"""

db = ValidatedConfigDBConnector(ctx.obj['db'])
if ADHOC_VALIDATION:
if is_portchannel_name_valid(portchannel_name) != True:
Expand All @@ -2144,7 +2145,7 @@ def remove_portchannel(ctx, portchannel_name):

if len([(k, v) for k, v in db.get_table('PORTCHANNEL_MEMBER') if k == portchannel_name]) != 0: # TODO: MISSING CONSTRAINT IN YANG MODEL
ctx.fail("Error: Portchannel {} contains members. Remove members before deleting Portchannel!".format(portchannel_name))

try:
db.set_entry('PORTCHANNEL', portchannel_name, None)
except JsonPatchConflict:
Expand All @@ -2162,7 +2163,7 @@ def portchannel_member(ctx):
def add_portchannel_member(ctx, portchannel_name, port_name):
"""Add member to port channel"""
db = ValidatedConfigDBConnector(ctx.obj['db'])

if ADHOC_VALIDATION:
if clicommon.is_port_mirror_dst_port(db, port_name):
ctx.fail("{} is configured as mirror destination port".format(port_name)) # TODO: MISSING CONSTRAINT IN YANG MODEL
Expand All @@ -2179,7 +2180,7 @@ def add_portchannel_member(ctx, portchannel_name, port_name):
# Dont 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))

# Don't allow a port to be member of port channel if it is configured with an IP address
for key,value in db.get_table('INTERFACE').items():
if type(key) == tuple:
Expand Down Expand Up @@ -2217,7 +2218,7 @@ def add_portchannel_member(ctx, portchannel_name, port_name):
member_port_speed = member_port_entry.get(PORT_SPEED)

port_speed = port_entry.get(PORT_SPEED) # TODO: MISSING CONSTRAINT IN YANG MODEL
if member_port_speed != port_speed:
if member_port_speed != port_speed:
ctx.fail("Port speed of {} is different than the other members of the portchannel {}"
.format(port_name, portchannel_name))

Expand Down Expand Up @@ -2290,7 +2291,7 @@ def del_portchannel_member(ctx, portchannel_name, port_name):
# Dont proceed if the the port is not an existing member of the port channel
if not is_port_member_of_this_portchannel(db, port_name, portchannel_name):
ctx.fail("{} is not a member of portchannel {}".format(port_name, portchannel_name))

try:
db.set_entry('PORTCHANNEL_MEMBER', portchannel_name + '|' + port_name, None)
except JsonPatchConflict:
Expand Down Expand Up @@ -2477,7 +2478,7 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer
if not namespaces['front_ns']:
config_db = ValidatedConfigDBConnector(ConfigDBConnector())
config_db.connect()
if ADHOC_VALIDATION:
if ADHOC_VALIDATION:
if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False:
return
try:
Expand Down Expand Up @@ -3442,7 +3443,7 @@ def del_community(db, community):
if community not in snmp_communities:
click.echo("SNMP community {} is not configured".format(community))
sys.exit(1)

config_db = ValidatedConfigDBConnector(db.cfgdb)
try:
config_db.set_entry('SNMP_COMMUNITY', community, None)
Expand Down Expand Up @@ -4986,7 +4987,7 @@ def cable_length(ctx, interface_name, length):

if not is_dynamic_buffer_enabled(config_db):
ctx.fail("This command can only be supported on a system with dynamic buffer enabled")

if ADHOC_VALIDATION:
# Check whether port is legal
ports = config_db.get_entry("PORT", interface_name)
Expand Down Expand Up @@ -5294,7 +5295,7 @@ def unbind(ctx, interface_name):
config_db.set_entry(table_name, interface_name, subintf_entry)
else:
config_db.set_entry(table_name, interface_name, None)

click.echo("Interface {} IP disabled and address(es) removed due to unbinding VRF.".format(interface_name))
#
# 'ipv6' subgroup ('config interface ipv6 ...')
Expand Down Expand Up @@ -6472,7 +6473,7 @@ def add_loopback(ctx, loopback_name):
lo_intfs = [k for k, v in config_db.get_table('LOOPBACK_INTERFACE').items() if type(k) != tuple]
if loopback_name in lo_intfs:
ctx.fail("{} already exists".format(loopback_name)) # TODO: MISSING CONSTRAINT IN YANG VALIDATION

try:
config_db.set_entry('LOOPBACK_INTERFACE', loopback_name, {"NULL" : "NULL"})
except ValueError:
Expand All @@ -6496,7 +6497,7 @@ def del_loopback(ctx, loopback_name):
ips = [ k[1] for k in lo_config_db if type(k) == tuple and k[0] == loopback_name ]
for ip in ips:
config_db.set_entry('LOOPBACK_INTERFACE', (loopback_name, ip), None)

try:
config_db.set_entry('LOOPBACK_INTERFACE', loopback_name, None)
except JsonPatchConflict:
Expand Down Expand Up @@ -6554,9 +6555,9 @@ def ntp(ctx):
def add_ntp_server(ctx, ntp_ip_address):
""" Add NTP server IP """
if ADHOC_VALIDATION:
if not clicommon.is_ipaddress(ntp_ip_address):
if not clicommon.is_ipaddress(ntp_ip_address):
ctx.fail('Invalid IP address')
db = ValidatedConfigDBConnector(ctx.obj['db'])
db = ValidatedConfigDBConnector(ctx.obj['db'])
ntp_servers = db.get_table("NTP_SERVER")
if ntp_ip_address in ntp_servers:
click.echo("NTP server {} is already configured".format(ntp_ip_address))
Expand All @@ -6567,7 +6568,7 @@ def add_ntp_server(ctx, ntp_ip_address):
{'resolve_as': ntp_ip_address,
'association_type': 'server'})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
click.echo("NTP server {} added to configuration".format(ntp_ip_address))
try:
click.echo("Restarting ntp-config service...")
Expand All @@ -6583,7 +6584,7 @@ def del_ntp_server(ctx, ntp_ip_address):
if ADHOC_VALIDATION:
if not clicommon.is_ipaddress(ntp_ip_address):
ctx.fail('Invalid IP address')
db = ValidatedConfigDBConnector(ctx.obj['db'])
db = ValidatedConfigDBConnector(ctx.obj['db'])
ntp_servers = db.get_table("NTP_SERVER")
if ntp_ip_address in ntp_servers:
try:
Expand Down Expand Up @@ -6911,19 +6912,19 @@ def add(ctx, name, ipaddr, port, vrf):
if not is_valid_collector_info(name, ipaddr, port, vrf):
return

config_db = ValidatedConfigDBConnector(ctx.obj['db'])
config_db = ValidatedConfigDBConnector(ctx.obj['db'])
collector_tbl = config_db.get_table('SFLOW_COLLECTOR')

if (collector_tbl and name not in collector_tbl and len(collector_tbl) == 2):
click.echo("Only 2 collectors can be configured, please delete one")
return

try:
config_db.mod_entry('SFLOW_COLLECTOR', name,
{"collector_ip": ipaddr, "collector_port": port,
"collector_vrf": vrf})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
return

#
Expand Down Expand Up @@ -7256,7 +7257,7 @@ def add_subinterface(ctx, subinterface_name, vid):
if vid is not None:
subintf_dict.update({"vlan" : vid})
subintf_dict.update({"admin_status" : "up"})

try:
config_db.set_entry('VLAN_SUB_INTERFACE', subinterface_name, subintf_dict)
except ValueError as e:
Expand Down
31 changes: 28 additions & 3 deletions config/vlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def add_vlan_member(db, vid, port, untagged):
log.log_info("'vlan member add {} {}' executing...".format(vid, port))

vlan = 'Vlan{}'.format(vid)

config_db = ValidatedConfigDBConnector(db.cfgdb)
if ADHOC_VALIDATION:
if not clicommon.is_vlanid_in_range(vid):
Expand Down Expand Up @@ -233,7 +233,7 @@ def add_vlan_member(db, vid, port, untagged):
if (is_port and clicommon.is_port_router_interface(db.cfgdb, port)) or \
(not is_port and clicommon.is_pc_router_interface(db.cfgdb, port)): # TODO: MISSING CONSTRAINT IN YANG MODEL
ctx.fail("{} is a router interface!".format(port))

portchannel_member_table = db.cfgdb.get_table('PORTCHANNEL_MEMBER')

if (is_port and clicommon.interface_is_in_portchannel(portchannel_member_table, port)): # TODO: MISSING CONSTRAINT IN YANG MODEL
Expand All @@ -257,7 +257,7 @@ def del_vlan_member(db, vid, port):
ctx = click.get_current_context()
log.log_info("'vlan member del {} {}' executing...".format(vid, port))
vlan = 'Vlan{}'.format(vid)

config_db = ValidatedConfigDBConnector(db.cfgdb)
if ADHOC_VALIDATION:
if not clicommon.is_vlanid_in_range(vid):
Expand All @@ -283,3 +283,28 @@ def del_vlan_member(db, vid, port):
except JsonPatchConflict:
ctx.fail("{} invalid or does not exist, or {} is not a member of {}".format(vlan, port, vlan))

#######
#
# 'neigh-suppress' group ('config neigh-suppress vlan...')
#
@click.group(cls=clicommon.AbbreviationGroup, name='neigh-suppress')
def neigh_suppress():
""" Neighbour Suppress VLAN-related configuration """
pass

@neigh_suppress.command('vlan')
@click.argument('vid', metavar='<vid>', required=True, type=int)
@click.argument('state', metavar='<on|off>', required=True, type=click.Choice(["on", "off"]))
@clicommon.pass_db
def set_neigh_suppress(db, vid, state):
if vid<1 or vid>4094:
ctx.fail("Invalid Vlan Id, Valid Range : 1 to 4094")
vlan = 'Vlan{}'.format(vid)
if clicommon.check_if_vlanid_exist(db.cfgdb, vlan) == False:
click.echo("{} doesn't exist".format(vlan))
return
if state == "on":
fvs = {'suppress': "on"}
db.cfgdb.set_entry('SUPPRESS_VLAN_NEIGH', vlan, fvs)
else:
db.cfgdb.set_entry('SUPPRESS_VLAN_NEIGH', vlan, None)
9 changes: 5 additions & 4 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def get_cmd_output(cmd):
iface_alias_converter = lazy_object_proxy.Proxy(lambda: clicommon.InterfaceAliasConverter())

#
# Display all storm-control data
# Display all storm-control data
#
def display_storm_all():
""" Show storm-control """
Expand Down Expand Up @@ -293,6 +293,7 @@ def cli(ctx):
cli.add_command(processes.processes)
cli.add_command(reboot_cause.reboot_cause)
cli.add_command(sflow.sflow)
cli.add_command(vlan.neigh_suppress)
cli.add_command(vlan.vlan)
cli.add_command(vnet.vnet)
cli.add_command(vxlan.vxlan)
Expand Down Expand Up @@ -444,7 +445,7 @@ def is_mgmt_vrf_enabled(ctx):
return False

#
# 'storm-control' group
# 'storm-control' group
# "show storm-control [interface <interface>]"
#
@cli.group('storm-control', invoke_without_command=True)
Expand Down Expand Up @@ -2094,7 +2095,7 @@ def summary(db):
key_values = key.split('|')
values = db.db.get_all(db.db.STATE_DB, key)
if "local_discriminator" not in values.keys():
values["local_discriminator"] = "NA"
values["local_discriminator"] = "NA"
bfd_body.append([key_values[3], key_values[2], key_values[1], values["state"], values["type"], values["local_addr"],
values["tx_interval"], values["rx_interval"], values["multiplier"], values["multihop"], values["local_discriminator"]])

Expand Down Expand Up @@ -2125,7 +2126,7 @@ def peer(db, peer_ip):
key_values = key.split(delimiter)
values = db.db.get_all(db.db.STATE_DB, key)
if "local_discriminator" not in values.keys():
values["local_discriminator"] = "NA"
values["local_discriminator"] = "NA"
bfd_body.append([key_values[3], key_values[2], key_values[1], values.get("state"), values.get("type"), values.get("local_addr"),
values.get("tx_interval"), values.get("rx_interval"), values.get("multiplier"), values.get("multihop"), values.get("local_discriminator")])

Expand Down
Loading