Skip to content
142 changes: 142 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5422,6 +5422,148 @@ def interface_type(ctx, interface_name, interface_type_value, verbose):
command += ["-vv"]
clicommon.run_command(command, display_cmd=verbose)


#
# 'damping' subgroup ('config interface damping ...')
#

@interface.group(cls=clicommon.AbbreviationGroup)
@click.pass_context
def damping(ctx):
"""Set interface damping configurations"""
pass


#
# 'algo' subcommand ('config interface damping algo ...')
#

@damping.command()
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('algo_type', metavar='<algo_type>', required=True, type=click.Choice(["aied", "disabled"]))
def algo(ctx, interface_name, algo_type):
"""Set link event damping algorithm"""
# 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!")

port_dict = config_db.get_table('PORT')
if interface_name not in port_dict:
ctx.fail("Invalid port {}".format(interface_name))

log.log_info("Executing: interface link_event_damping_algorithm {} {}".format(interface_name, algo_type))

config_db.mod_entry("PORT", interface_name, {"link_event_damping_algorithm": algo_type})


#
# 'aied-param' subcommand ('config interface damping aied-param ...')
#

@damping.command()
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.option(
'--max-suppress-time',
required=False,
type=int,
help="Set max suppress time in ms"
)
@click.option(
'--decay-half-life',
required=False,
type=int,
help="Set decay half life in ms"
)
@click.option(
'--suppress-threshold',
required=False,
type=int,
help="Set suppress threshold"
)
@click.option(
'--reuse-threshold',
required=False,
type=int,
help="Set reuse threshold"
)
@click.option(
'--flap-penalty',
required=False,
type=int,
help="Set flap penalty"
)
def aied_param(
ctx,
interface_name,
max_suppress_time,
decay_half_life,
suppress_threshold,
reuse_threshold,
flap_penalty
):
"""Set AIED link event damping configuration"""
# 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!")

port_dict = config_db.get_table('PORT')
if interface_name not in port_dict:
ctx.fail("Invalid port {}".format(interface_name))

config_set = {}

if max_suppress_time is not None:
if max_suppress_time < 0:
ctx.fail("Invalid max_suppress_time value {}. It should be >= 0".format(max_suppress_time))
config_set['max_suppress_time'] = max_suppress_time
if decay_half_life is not None:
if decay_half_life < 0:
ctx.fail("Invalid decay_half_life value {}. It should be >= 0".format(decay_half_life))
config_set['decay_half_life'] = decay_half_life
if suppress_threshold is not None:
if suppress_threshold < 0:
ctx.fail("Invalid suppress_threshold value {}. It should be >= 0".format(suppress_threshold))
config_set['suppress_threshold'] = suppress_threshold
if reuse_threshold is not None:
if reuse_threshold < 0:
ctx.fail("Invalid reuse_threshold value {}. It should be >= 0".format(reuse_threshold))
config_set['reuse_threshold'] = reuse_threshold
if flap_penalty is not None:
if flap_penalty < 0:
ctx.fail("Invalid flap_penalty value {}. It should be >= 0".format(flap_penalty))
config_set['flap_penalty'] = flap_penalty

if reuse_threshold is not None and suppress_threshold is not None:
if reuse_threshold >= suppress_threshold:
ctx.fail(
"Invalid configuration: reuse_threshold ({}) must be less than suppress_threshold ({})"
.format(reuse_threshold, suppress_threshold)
)

if decay_half_life is not None and max_suppress_time is not None:
if decay_half_life > max_suppress_time:
ctx.fail(
"Invalid configuration: decay_half_life ({}) must be <= max_suppress_time ({})"
.format(decay_half_life, max_suppress_time)
)
Comment on lines +5546 to +5558

if len(config_set) == 0:
ctx.fail("Expected at least one valid AIED config parameter")

log.log_info("Executing: interface aied_config {}".format(interface_name))
config_db.mod_entry("PORT", interface_name, config_set)


#
# 'advertised-interface-types' subcommand
#
Expand Down
75 changes: 75 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -6931,6 +6931,7 @@ This sub-section explains the following list of configuration on the interfaces.
11) mpls - To add or remove MPLS operation for the interface
12) loopback-action - to set action for packet that ingress and gets routed on the same IP interface
13) link-training - to set interface link-training mode
14) damping - to set link event damping configuration on an interface

From 201904 release onwards, the “config interface” command syntax is changed and the format is as follows:

Expand Down Expand Up @@ -7540,6 +7541,80 @@ This command is used for setting link-training mode of a interface.
admin@sonic:~$ sudo config interface link-training Ethernet0 off
```

**config interface damping <...> (Versions >= 202311)**

This sub-section contains the config commands that are supported for configuring link event damping on an interface.
- Link event damping algorithm.
- Link event damping configuration.

***config interface damping algo (Versions >= 202311)***

This command is used to configure link event damping algorithm on an interface.

- Usage
```
config interface damping algo --help
Usage: config interface damping algo [OPTIONS] <interface_name> <algo_type>

Set link event damping algorithm

Options:
-h, -?, --help Show this message and exit.
```
Currently link event damping supports `aied` (Additive Increase Exponential Decrease) algorithm, so expected algo value is either to set `aied` or disable the algorithm using `disabled` value.

- Example

To set `aied` algorithm:
```
config interface damping algo Ethernet20 aied
```

To disable the link event damping algorithm:
```
config interface damping algo Ethernet20 disabled
```

***config interface damping aied-param (Versions >= 202311***

This command is used to configure link event damping AIED parameters on an interface.

- Usage
```
config interface damping aied-param --help
Usage: config interface damping aied-param [OPTIONS] <interface_name>

Set AIED link event damping configuration

Options:
--max-suppress-time INTEGER Set max suppress time in ms
--decay-half-life INTEGER Set decay half life in ms
--suppress-threshold INTEGER Set suppress threshold
--reuse-threshold INTEGER Set reuse threshold
--flap-penalty INTEGER Set flap penalty
-h, -?, --help Show this message and exit.

```

One or more AIED link event damping config params can be configured at a time.

- Examples

Set all the config parameters:
```
config interface damping aied-param Ethernet20 --suppress-threshold 1200 --decay-half-life 15000 --max-suppress-time 30000 --flap-penalty 1000 --reuse-threshold 1000
```

Set only flap penalty:
```
config interface damping aied-param Ethernet20 --flap-penalty 500
```

Set suppress threshold and reuse threshold:
```
config interface damping aied-param Ethernet20 --suppress-threshold 1500 --reuse-threshold 1100
```

Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces)

## Interface Naming Mode
Expand Down
104 changes: 104 additions & 0 deletions tests/config_int_damping_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import config.main as config
import operator
import os
import pytest
import sys

from click.testing import CliRunner
from utilities_common.db import Db

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, "scripts")
sys.path.insert(0, modules_path)


@pytest.fixture(scope='module')
def ctx(scope='module'):
db = Db()
obj = {'config_db': db.cfgdb, 'namespace': ''}
yield obj


class TestDampingConfig(object):
@classmethod
def setup_class(cls):
print("SETUP")
os.environ["UTILITIES_UNIT_TESTING"] = "1"

Comment on lines +24 to +28
def test_damping_algorithm(self, ctx):
self.basic_check("algo", ["Ethernet0", "aied"], ctx)
self.basic_check("algo", ["Ethernet0", "disabled"], ctx)

def test_invalid_damping_algorithm(self, ctx):
self.basic_check("algo", ["Ethernet0", "invalid"], ctx, operator.ne)
result = self.basic_check("algo", ["Invalid", "aied"], ctx, op=operator.ne)
assert "Error: Invalid port" in result.output

def test_invalid_aied_config(self, ctx):
result = self.basic_check("aied-param", ["Invalid"], ctx, op=operator.ne)
assert "Error: Invalid port" in result.output
result = self.basic_check("aied-param", ["Ethernet0"], ctx, op=operator.ne)
assert "Error: Expected at least one valid AIED config parameter" in result.output
result = self.basic_check(
"aied-param",
[
"Ethernet0",
"--suppress-threshold", "10",
"--max-suppress-time", "10",
"--decay-half-life", "-1"
],
ctx,
op=operator.ne)
assert "Error: Invalid decay_half_life value -1. It should be >= 0" in result.output

def test_max_suppress_time_config(self, ctx):
result = self.basic_check("aied-param", ["Ethernet0", "--max-suppress-time", "-1"], ctx, op=operator.ne)
assert "Error: Invalid max_suppress_time value" in result.output
self.basic_check("aied-param", ["Ethernet0", "--max-suppress-time", "50"], ctx)

def test_decay_half_life_config(self, ctx):
result = self.basic_check("aied-param", ["Ethernet0", "--decay-half-life", "-1"], ctx, op=operator.ne)
assert "Error: Invalid decay_half_life value" in result.output
self.basic_check("aied-param", ["Ethernet0", "--decay-half-life", "50"], ctx)

def test_suppress_threshold_config(self, ctx):
result = self.basic_check("aied-param", ["Ethernet0", "--suppress-threshold", "-1"], ctx, op=operator.ne)
assert "Error: Invalid suppress_threshold value" in result.output
self.basic_check("aied-param", ["Ethernet0", "--suppress-threshold", "50"], ctx)

def test_reuse_threshold_config(self, ctx):
result = self.basic_check("aied-param", ["Ethernet0", "--reuse-threshold", "-1"], ctx, op=operator.ne)
assert "Error: Invalid reuse_threshold value" in result.output
self.basic_check("aied-param", ["Ethernet0", "--reuse-threshold", "50"], ctx)

def test_flap_penalty_config(self, ctx):
result = self.basic_check("aied-param", ["Ethernet0", "--flap-penalty", "-1"], ctx, op=operator.ne)
assert "Error: Invalid flap_penalty value" in result.output
self.basic_check("aied-param", ["Ethernet0", "--flap-penalty", "50"], ctx)

def test_all_config(self, ctx):
self.basic_check(
"aied-param",
[
"Ethernet0",
"--decay-half-life", "15000",
"--suppress-threshold", "1600",
"--max-suppress-time", "30000",
"--flap-penalty", "1000",
"--reuse-threshold", "1200"
],
ctx)

def basic_check(self, command_name, para_list, ctx, op=operator.eq, expect_result=0):
runner = CliRunner()
result = runner.invoke(
config.config.commands["interface"]
.commands["damping"]
.commands[command_name],
para_list,
obj=ctx
)
print(result.exit_code, result.output)
assert op(result.exit_code, expect_result)
return result
Loading
Loading