Skip to content

Commit

Permalink
Merge branch 'master' into counters_cache
Browse files Browse the repository at this point in the history
  • Loading branch information
stepanblyschak committed Jun 24, 2022
2 parents 88d49d3 + f64d280 commit 913e376
Show file tree
Hide file tree
Showing 106 changed files with 3,958 additions and 432 deletions.
Binary file added .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ stages:
- job:
displayName: "Python3"
variables:
DIFF_COVER_CHECK_THRESHOLD: 50
DIFF_COVER_CHECK_THRESHOLD: 80
DIFF_COVER_ENABLE: 'true'
pool:
vmImage: ubuntu-20.04
Expand Down
5 changes: 3 additions & 2 deletions config/config_mgmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ConfigMgmt():
to verify config for the commands which are capable of change in config DB.
'''

def __init__(self, source="configDB", debug=False, allowTablesWithoutYang=True):
def __init__(self, source="configDB", debug=False, allowTablesWithoutYang=True, sonicYangOptions=0):
'''
Initialise the class, --read the config, --load in data tree.
Expand All @@ -53,6 +53,7 @@ def __init__(self, source="configDB", debug=False, allowTablesWithoutYang=True):
self.configdbJsonOut = None
self.source = source
self.allowTablesWithoutYang = allowTablesWithoutYang
self.sonicYangOptions = sonicYangOptions

# logging vars
self.SYSLOG_IDENTIFIER = "ConfigMgmt"
Expand All @@ -67,7 +68,7 @@ def __init__(self, source="configDB", debug=False, allowTablesWithoutYang=True):
return

def __init_sonic_yang(self):
self.sy = sonic_yang.SonicYang(YANG_DIR, debug=self.DEBUG)
self.sy = sonic_yang.SonicYang(YANG_DIR, debug=self.DEBUG, sonic_yang_options=self.sonicYangOptions)
# load yang models
self.sy.loadYangModel()
# load jIn from config DB or from config DB json file.
Expand Down
173 changes: 161 additions & 12 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import utilities_common.cli as clicommon
from utilities_common.helper import get_port_pbh_binding, get_port_acl_binding
from utilities_common.general import load_db_config, load_module_from_source
import utilities_common.multi_asic as multi_asic_util

from .utils import log

Expand Down Expand Up @@ -638,6 +639,78 @@ def _clear_cbf():
for cbf_table in CBF_TABLE_NAMES:
config_db.delete_table(cbf_table)

#API to validate the interface passed for storm-control configuration
def storm_control_interface_validate(port_name):
if clicommon.get_interface_naming_mode() == "alias":
port_name = interface_alias_to_name(None, port_name)
if port_name is None:
click.echo("'port_name' is None!")
return False

if (port_name.startswith("Ethernet")):
if interface_name_is_valid(None, port_name) is False:
click.echo("Interface name %s is invalid. Please enter a valid interface name" %(port_name))
return False
else:
click.echo("Storm-control is supported only on Ethernet interfaces. Not supported on %s" %(port_name))
return False

return True

def is_storm_control_supported(storm_type, namespace):
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
#state_db[asic_id] = swsscommon.DBConnector("STATE_DB", REDIS_TIMEOUT_MSECS, True, namespace)
#supported = state_db[asic_id].get_entry('BUM_STORM_CAPABILITY', storm_type)
state_db = SonicV2Connector(host='127.0.0.1')
state_db.connect(state_db.STATE_DB, False)
entry_name="BUM_STORM_CAPABILITY|"+storm_type
supported = state_db.get(state_db.STATE_DB, entry_name,"supported")
return supported

#API to configure the PORT_STORM_CONTROL table
def storm_control_set_entry(port_name, kbps, storm_type, namespace):

if storm_control_interface_validate(port_name) is False:
return False

if is_storm_control_supported(storm_type, namespace) == 0:
click.echo("Storm-control is not supported on this namespace {}".format(namespace))
return False

#Validate kbps value
config_db = ConfigDBConnector()
config_db.connect()
key = port_name + '|' + storm_type
entry = config_db.get_entry('PORT_STORM_CONTROL', key)

if len(entry) == 0:
config_db.set_entry('PORT_STORM_CONTROL', key, {'kbps':kbps})
else:
kbps_value = int(entry.get('kbps',0))
if kbps_value != kbps:
config_db.mod_entry('PORT_STORM_CONTROL', key, {'kbps':kbps})

return True

#API to remove an entry from PORT_STORM_CONTROL table
def storm_control_delete_entry(port_name, storm_type):

if storm_control_interface_validate(port_name) is False:
return False

config_db = ConfigDBConnector()
config_db.connect()
key = port_name + '|' + storm_type
entry = config_db.get_entry('PORT_STORM_CONTROL', key)

if len(entry) == 0:
click.echo("%s storm-control not enabled on interface %s" %(storm_type, port_name))
return False
else:
config_db.set_entry('PORT_STORM_CONTROL', key, None)

return True


def _clear_qos():
QOS_TABLE_NAMES = [
Expand Down Expand Up @@ -739,20 +812,23 @@ def _get_sonic_services():
return (unit.strip() for unit in out.splitlines())


def _get_delayed_sonic_services():
def _get_delayed_sonic_units(get_timers=False):
rc1 = clicommon.run_command("systemctl list-dependencies --plain sonic-delayed.target | sed '1d'", return_cmd=True)
rc2 = clicommon.run_command("systemctl is-enabled {}".format(rc1.replace("\n", " ")), return_cmd=True)
timer = [line.strip() for line in rc1.splitlines()]
state = [line.strip() for line in rc2.splitlines()]
services = []
for unit in timer:
if state[timer.index(unit)] == "enabled":
services.append(re.sub('\.timer$', '', unit, 1))
if not get_timers:
services.append(re.sub('\.timer$', '', unit, 1))
else:
services.append(unit)
return services


def _reset_failed_services():
for service in itertools.chain(_get_sonic_services(), _get_delayed_sonic_services()):
for service in itertools.chain(_get_sonic_services(), _get_delayed_sonic_units()):
clicommon.run_command("systemctl reset-failed {}".format(service))


Expand All @@ -771,12 +847,8 @@ def _restart_services():
click.echo("Reloading Monit configuration ...")
clicommon.run_command("sudo monit reload")

def _get_delay_timers():
out = clicommon.run_command("systemctl list-dependencies sonic-delayed.target --plain |sed '1d'", return_cmd=True)
return [timer.strip() for timer in out.splitlines()]

def _delay_timers_elapsed():
for timer in _get_delay_timers():
for timer in _get_delayed_sonic_units(get_timers=True):
out = clicommon.run_command("systemctl show {} --property=LastTriggerUSecMonotonic --value".format(timer), return_cmd=True)
if out.strip() == "0":
return False
Expand Down Expand Up @@ -1374,18 +1446,19 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart, disable_arp_cach
"""Clear current configuration and import a previous saved config DB dump file.
<filename> : Names of configuration file(s) to load, separated by comma with no spaces in between
"""
CONFIG_RELOAD_NOT_READY = 1
if not force and not no_service_restart:
if _is_system_starting():
click.echo("System is not up. Retry later or use -f to avoid system checks")
return
sys.exit(CONFIG_RELOAD_NOT_READY)

if not _delay_timers_elapsed():
click.echo("Relevant services are not up. Retry later or use -f to avoid system checks")
return
sys.exit(CONFIG_RELOAD_NOT_READY)

if not _swss_ready():
click.echo("SwSS container is not ready. Retry later or use -f to avoid system checks")
return
sys.exit(CONFIG_RELOAD_NOT_READY)

if filename is None:
message = 'Clear current config and reload config in {} format from the default config file(s) ?'.format(file_format)
Expand Down Expand Up @@ -1848,6 +1921,11 @@ def remove_portchannel(ctx, portchannel_name):
if is_portchannel_present_in_db(db, portchannel_name) is False:
ctx.fail("{} is not present.".format(portchannel_name))

# Dont let to remove port channel if vlan membership exists
for k,v in db.get_table('VLAN_MEMBER'):
if v == portchannel_name:
ctx.fail("{} has vlan {} configured, remove vlan membership to proceed".format(portchannel_name, str(k)))

if len([(k, v) for k, v in db.get_table('PORTCHANNEL_MEMBER') if k == portchannel_name]) != 0:
click.echo("Error: Portchannel {} contains members. Remove members before deleting Portchannel!".format(portchannel_name))
else:
Expand Down Expand Up @@ -3687,6 +3765,36 @@ def speed(ctx, interface_name, interface_speed, verbose):
command += " -vv"
clicommon.run_command(command, display_cmd=verbose)

#
# 'link-training' subcommand
#

@interface.command()
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('mode', metavar='<mode>', required=True, type=click.Choice(["on", "off"]))
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
def link_training(ctx, interface_name, mode, verbose):
"""Set interface link training mode"""
# Get the config_db connector
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!")

log.log_info("'interface link-training {} {}' executing...".format(interface_name, mode))

if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
command = "portconfig -p {} -lt {}".format(interface_name, mode)
else:
command = "portconfig -p {} -lt {} -n {}".format(interface_name, mode, ctx.obj['namespace'])

if verbose:
command += " -vv"
clicommon.run_command(command, display_cmd=verbose)

#
# 'autoneg' subcommand
#
Expand Down Expand Up @@ -4169,7 +4277,8 @@ def remove(ctx, interface_name, ip_addr):
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":
config_db.set_entry(table_name, interface_name, None)
if table_name != "VLAN_SUB_INTERFACE":
config_db.set_entry(table_name, interface_name, None)

if multi_asic.is_multi_asic():
command = "sudo ip netns exec {} ip neigh flush dev {} {}".format(ctx.obj['namespace'], interface_name, str(ip_address))
Expand Down Expand Up @@ -4944,6 +5053,7 @@ def add_route(ctx, command_str):
if (not route['ifname'] in config_db.get_keys('VLAN_INTERFACE') and
not route['ifname'] in config_db.get_keys('INTERFACE') and
not route['ifname'] in config_db.get_keys('PORTCHANNEL_INTERFACE') and
not route['ifname'] in config_db.get_keys('VLAN_SUB_INTERFACE') and
not route['ifname'] == 'null'):
ctx.fail('interface {} doesn`t exist'.format(route['ifname']))

Expand Down Expand Up @@ -5749,6 +5859,45 @@ def naming_mode_alias():
"""Set CLI interface naming mode to ALIAS (Vendor port alias)"""
set_interface_naming_mode('alias')

@interface.group('storm-control')
@click.pass_context
def storm_control(ctx):
""" Configure storm-control"""
pass

@storm_control.command('add')
@click.argument('port_name',metavar='<port_name>', required=True)
@click.argument('storm_type',metavar='<storm_type>', required=True, type=click.Choice(["broadcast", "unknown-unicast", "unknown-multicast"]))
@click.argument('kbps',metavar='<kbps_value>', required=True, type=click.IntRange(0,100000000))
@click.option('--namespace',
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
@click.pass_context
def add_interface_storm(ctx, port_name,storm_type, kbps, namespace):
if storm_control_set_entry(port_name, kbps, storm_type, namespace) is False:
ctx.fail("Unable to add {} storm-control to interface {}".format(storm_type, port_name))

@storm_control.command('del')
@click.argument('port_name',metavar='<port_name>', required=True)
@click.argument('storm_type',metavar='<storm_type>', required=True, type=click.Choice(["broadcast", "unknown-unicast", "unknown-multicast"]))
@click.option('--namespace',
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
@click.pass_context
def del_interface_storm(ctx,port_name,storm_type, namespace):
if storm_control_delete_entry(port_name, storm_type) is False:
ctx.fail("Unable to delete {} storm-control from interface {}".format(storm_type, port_name))

def is_loopback_name_valid(loopback_name):
"""Loopback name validation
"""
Expand Down
16 changes: 13 additions & 3 deletions config/muxcable.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from swsscommon import swsscommon
from tabulate import tabulate
from utilities_common import platform_sfputil_helper
from utilities_common.general import get_optional_value_for_key_in_config_tbl

platform_sfputil = None

Expand Down Expand Up @@ -203,7 +204,6 @@ def update_and_get_response_for_xcvr_cmd(cmd_name, rsp_name, exp_rsp, cmd_table_

return res_dict


def get_value_for_key_in_config_tbl(config_db, port, key, table):
info_dict = {}
info_dict = config_db.get_entry(table, port)
Expand Down Expand Up @@ -244,6 +244,8 @@ def lookup_statedb_and_update_configdb(db, per_npu_statedb, config_db, port, sta
configdb_state = get_value_for_key_in_config_tbl(config_db, port, "state", "MUX_CABLE")
ipv4_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv4", "MUX_CABLE")
ipv6_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv6", "MUX_CABLE")
soc_ipv4_value = get_optional_value_for_key_in_config_tbl(config_db, port, "soc_ipv4", "MUX_CABLE")
cable_type = get_optional_value_for_key_in_config_tbl(config_db, port, "cable_type", "MUX_CABLE")

state = get_value_for_key_in_dict(muxcable_statedb_dict, port, "state", "MUX_CABLE_TABLE")

Expand All @@ -252,8 +254,16 @@ def lookup_statedb_and_update_configdb(db, per_npu_statedb, config_db, port, sta
if str(state_cfg_val) == str(configdb_state):
port_status_dict[port_name] = 'OK'
else:
config_db.set_entry("MUX_CABLE", port, {"state": state_cfg_val,
"server_ipv4": ipv4_value, "server_ipv6": ipv6_value})
if cable_type is not None or soc_ipv4_value is not None:
config_db.set_entry("MUX_CABLE", port, {"state": state_cfg_val,
"server_ipv4": ipv4_value,
"server_ipv6": ipv6_value,
"soc_ipv4":soc_ipv4_value,
"cable_type": cable_type})
else:
config_db.set_entry("MUX_CABLE", port, {"state": state_cfg_val,
"server_ipv4": ipv4_value,
"server_ipv6": ipv6_value})
if (str(state_cfg_val) == 'active' and str(state) != 'active') or (str(state_cfg_val) == 'standby' and str(state) != 'standby'):
port_status_dict[port_name] = 'INPROGRESS'
else:
Expand Down
1 change: 1 addition & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -8431,6 +8431,7 @@ This command is used to add a static route. Note that prefix /nexthop vrf`s and
```
admin@sonic:~$ config route add prefix 2.2.3.4/32 nexthop 30.0.0.9
admin@sonic:~$ config route add prefix 4.0.0.0/24 nexthop dev Ethernet32.10
```
It also supports ECMP, and adding a new nexthop to the existing prefix will complement it and not overwrite them.
Expand Down
Loading

0 comments on commit 913e376

Please sign in to comment.