Skip to content

Commit

Permalink
sonic-utilities: Add CLI commands to set sflow drop-monitor-limit
Browse files Browse the repository at this point in the history
* added CLI: config sflow drop-monitor-limit 1-999 (0 to disable)
* added line to show sflow output to indicate current setting
* added test to ensure that out-of-range value is denied

The effect is to add the redis field drop_monitor_limit to the
sflow configuration table in redis, as described in
pull-request #1484 on the sonic-net/SONiC repo.

Note: hsflowd version 2.0.52 will apply this setting.
Older versions will ignore it.

Signed-off-by: Neil McKee  neil.mckee@inmon.com
  • Loading branch information
= committed Feb 2, 2024
1 parent 3d45c0c commit 686f87b
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 16 deletions.
51 changes: 35 additions & 16 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from utilities_common.intf_filter import parse_interface_in_filter
from utilities_common import bgp_util
import utilities_common.cli as clicommon
from utilities_common.helper import get_port_pbh_binding, get_port_acl_binding, update_config
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
from .validated_config_db_connector import ValidatedConfigDBConnector
import utilities_common.multi_asic as multi_asic_util
Expand Down Expand Up @@ -1771,7 +1771,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 @@ -1950,7 +1950,6 @@ def override_config_table(db, input_config_db, dry_run):
ns_config_input = config_input
# Generate sysinfo if missing in ns_config_input
generate_sysinfo(current_config, ns_config_input, ns)
# Use deepcopy by default to avoid modifying input config
updated_config = update_config(current_config, ns_config_input)

yang_enabled = device_info.is_yang_config_validation_enabled(config_db)
Expand Down Expand Up @@ -1986,6 +1985,14 @@ def validate_config_by_cm(cm, config_json, jname):
sys.exit(1)


def update_config(current_config, config_input):
updated_config = copy.deepcopy(current_config)
# Override current config with golden config
for table in config_input:
updated_config[table] = config_input[table]
return updated_config


def override_config_db(config_db, config_input):
# Deserialized golden config to DB recognized format
sonic_cfggen.FormatConverter.to_deserialized(config_input)
Expand Down Expand Up @@ -2049,21 +2056,9 @@ def synchronous_mode(sync_mode):
config reload -y \n
Option 2. systemctl restart swss""" % sync_mode)

#
# 'suppress-fib-pending' command ('config suppress-fib-pending ...')
#
@config.command('suppress-fib-pending')
@click.argument('state', metavar='<enabled|disabled>', required=True, type=click.Choice(['enabled', 'disabled']))
@clicommon.pass_db
def suppress_pending_fib(db, state):
''' Enable or disable pending FIB suppression. Once enabled, BGP will not advertise routes that are not yet installed in the hardware '''

config_db = db.cfgdb
config_db.mod_entry('DEVICE_METADATA' , 'localhost', {"suppress-fib-pending" : state})

#
# '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 @@ -6735,6 +6730,30 @@ def global_sample_direction(ctx, direction):
def is_valid_sample_rate(rate):
return rate.isdigit() and int(rate) in range(256, 8388608 + 1)

#
# 'sflow' command ('config sflow drop-monitor-limit ...')
#
@sflow.command('drop-monitor-limit')
@click.argument('limit', metavar='<drop_monitor_limit>', required=True,
type=click.IntRange(0, 999))
@click.pass_context
def drop_monitor_limit_int(ctx, limit):
"""Set rate limit for drop notifications (0 to disable)"""
if ADHOC_VALIDATION:
if limit not in range(1, 999) and limit != 0:
ctx.fail("Rate limit not in the valid range, must be between 1-999 (0 to disable)")

config_db = ValidatedConfigDBConnector(ctx.obj['db'])
sflow_tbl = config_db.get_table('SFLOW')

if not sflow_tbl:
sflow_tbl = {'global': {'admin_state': 'down'}}

sflow_tbl['global']['drop_monitor_limit'] = limit
try:
config_db.mod_entry('SFLOW', 'global', sflow_tbl['global'])
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))

#
# 'sflow interface' group
Expand Down
6 changes: 6 additions & 0 deletions show/sflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ def show_sflow_global(config_db):
else:
click.echo("default")

click.echo(" sFlow Drop Rate Limit:".ljust(30), nl=False)
if (sflow_info and 'drop_monitor_limit' in sflow_info['global']):
click.echo("{}".format(sflow_info['global']['drop_monitor_limit']))
else:
click.echo("0")

sflow_info = config_db.get_table('SFLOW_COLLECTOR')
click.echo("\n {} Collectors configured:".format(len(sflow_info)))
for collector_name in sorted(list(sflow_info.keys())):
Expand Down
51 changes: 51 additions & 0 deletions tests/sflow_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
sFlow Sample Direction: both
sFlow Polling Interval: 0
sFlow AgentID: default
sFlow Drop Rate Limit: 0
2 Collectors configured:
Name: prod IP addr: fe80::6e82:6aff:fe1e:cd8e UDP port: 6343 VRF: mgmt
Expand Down Expand Up @@ -267,6 +268,56 @@ def test_config_sflow_polling_interval(self):

return

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

config.ADHOC_VALIDATION = False
result = runner.invoke(config.config.commands["sflow"].
commands["drop-monitor-limit"], ["1000"], obj=obj)
print(result.exit_code, result.output)
assert "not in the valid range" in result.output

def test_config_sflow_drop_monitor_limit(self):
db = Db()
runner = CliRunner()
obj = {'db':db.cfgdb}
config.ADHOC_VALIDATION = True

# set to 1 out of range
result = runner.invoke(config.config.commands["sflow"].
commands["drop-monitor-limit"], ["1000"], obj=obj)
print(result.exit_code, result.output)
assert result.exit_code != 0
assert "not in the valid range" in result.output

# set to 50
result = runner.invoke(config.config.commands["sflow"].
commands["drop-monitor-limit"], ["50"], obj=obj)
print(result.exit_code, result.output)
assert result.exit_code == 0

# change the expected output
global show_sflow_output
show_sflow_output_local = show_sflow_output.replace(
'sFlow Drop Rate Limit: 0',
'sFlow Drop Rate Limit: 50')

# run show and check
result = runner.invoke(show.cli.commands["sflow"], [], obj=db)
print(result.exit_code, result.output)
assert result.exit_code == 0
assert result.output == show_sflow_output_local

#reset to 0, no need to verify this one
result = runner.invoke(config.config.commands["sflow"].
commands["polling-interval"], ["0"], obj=obj)
print(result.exit_code, result.output)
assert result.exit_code == 0

return

@patch("config.main.ConfigDBConnector.get_table", mock.Mock(return_value={'Ethernet1': {'admin_state': 'sample_state'}}))
@patch("validated_config_db_connector.device_info.is_yang_config_validation_enabled", mock.Mock(return_value=True))
@patch("config.validated_config_db_connector.ValidatedConfigDBConnector.validated_mod_entry", mock.Mock(side_effect=ValueError))
Expand Down

0 comments on commit 686f87b

Please sign in to comment.