Skip to content
Merged
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
48 changes: 34 additions & 14 deletions tests/copp/copp_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
_ADD_IP_SCRIPT = "scripts/add_ip.sh"
_UPDATE_COPP_SCRIPT = "copp/scripts/update_copp_config.py"

_BASE_COPP_CONFIG = "/tmp/00-copp.config.json"
_SWSS_COPP_CONFIG = "swss:/etc/swss/config.d/00-copp.config.json"
_BASE_COPP_CONFIG = "/tmp/base_copp_config.json"
_APP_DB_COPP_CONFIG = "swss:/etc/swss/config.d/00-copp.config.json"
_CONFIG_DB_COPP_CONFIG = "/etc/sonic/copp_cfg.json"
_TEMP_COPP_CONFIG = "/tmp/copp_config.json"
_TEMP_COPP_TEMPLATE = "/tmp/copp.json.j2"
_COPP_TEMPLATE_PATH = "/usr/share/sonic/templates/copp.json.j2"
Expand All @@ -36,16 +37,31 @@ def limit_policer(dut, pps_limit):
pps_limit (int): The rate limit for COPP to enforce on ALL trap groups.
"""

dut.command("docker cp {} {}".format(_SWSS_COPP_CONFIG, _BASE_COPP_CONFIG))
dut.script(cmd="{} {} {} {}".format(_UPDATE_COPP_SCRIPT, pps_limit,
_BASE_COPP_CONFIG, _TEMP_COPP_CONFIG))
dut.command("docker cp {} {}".format(_TEMP_COPP_CONFIG, _SWSS_COPP_CONFIG))

# As copp config is regenerated each time swss starts need to replace the template with
# config updated above. But before doing that need store the original template in a temporary file
# for restore after test.
dut.command("docker cp {} {}".format(_SWSS_COPP_TEMPLATE, _TEMP_COPP_TEMPLATE))
dut.command("docker cp {} {}".format(_TEMP_COPP_CONFIG, _SWSS_COPP_TEMPLATE))
if "201811" in dut.os_version or "201911" in dut.os_version:
dut.command("docker cp {} {}".format(_APP_DB_COPP_CONFIG, _BASE_COPP_CONFIG))
config_format = "app_db"
else:
dut.command("cp {} {}".format(_CONFIG_DB_COPP_CONFIG, _BASE_COPP_CONFIG))
config_format = "config_db"

dut.script(
cmd="{} {} {} {} {}".format(_UPDATE_COPP_SCRIPT,
pps_limit,
_BASE_COPP_CONFIG,
_TEMP_COPP_CONFIG,
config_format)
)

if config_format == "app_db":
dut.command("docker cp {} {}".format(_TEMP_COPP_CONFIG, _APP_DB_COPP_CONFIG))

# As copp config is regenerated each time swss starts need to replace the template with
# config updated above. But before doing that need store the original template in a
# temporary file for restore after test.
dut.command("docker cp {} {}".format(_SWSS_COPP_TEMPLATE, _TEMP_COPP_TEMPLATE))
dut.command("docker cp {} {}".format(_TEMP_COPP_CONFIG, _SWSS_COPP_TEMPLATE))
else:
dut.command("cp {} {}".format(_TEMP_COPP_CONFIG, _CONFIG_DB_COPP_CONFIG))

def restore_policer(dut):
"""
Expand All @@ -56,8 +72,12 @@ def restore_policer(dut):

The SWSS container must be restarted for the config change to take effect.
"""
# Restore the copp template in swss
dut.command("docker cp {} {}".format(_TEMP_COPP_TEMPLATE, _SWSS_COPP_TEMPLATE))
# Restore the copp template in swss
if "201811" in dut.os_version or "201911" in dut.os_version:
dut.command("docker cp {} {}".format(_BASE_COPP_CONFIG, _APP_DB_COPP_CONFIG))
dut.command("docker cp {} {}".format(_TEMP_COPP_TEMPLATE, _SWSS_COPP_TEMPLATE))
else:
dut.command("cp {} {}".format(_BASE_COPP_CONFIG, _CONFIG_DB_COPP_CONFIG))

def configure_ptf(ptf, nn_target_port):
"""
Expand Down
91 changes: 71 additions & 20 deletions tests/copp/scripts/update_copp_config.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,80 @@
#!/usr/bin/python
"""
Script to modify a COPP configuration to follow a specified rate limit.
"""Script to modify a COPP configuration to follow a specified rate limit.

This is used by the COPP tests to reduce the rate limit below that of the
PTF host's sending rate.

Example:
python update_copp_config.py <rate limit in pps> <input file> <output file> <config_format>
python update_copp_config.py 600 /tmp/copp_config.json /tmp/new_copp_config.json app_db

Note:
Historically, there was a 00-copp.config.json file in the SWSS docker that specified
the parameters for each trap group like so:

This is used by the COPP tests to reduce the rate limit below that of the
PTF host's sending rate.
[
"COPP_TABLE:default": {
"cir": "600",
"cbs": "600",
...
},
"COPP_TABLE:trap.group.bgp.lacp": {
...
},
...
]

Example::
This is the "app_db" format used for 202006 images and earlier.

$ python update_copp_config.py <rate limit in pps> <input file> <output file>
$ python update_copp_config.py 600 /tmp/copp_config.json /tmp/new_copp_config.json
In newer SONiC versions, there is a copp_cfg.json file on the host that specifies the parameters
for each trap group like so:

{
"COPP_GROUP": {
"default": {
"cir":"600",
"cbs":"600",
...
},
"queue4_group1": {
...
},
...
},
...
}

This is the "config_db" format used for 202012 images and later (including the master branch).
"""
import json
import sys

def generate_limited_pps_config(pps_limit, input_config_file, output_config_file):
"""
Modifies a COPP config to use the specified rate limit.

Notes:
This only affects COPP policies that enforce a rate limit. Other
policies are left alone.
def generate_limited_pps_config(pps_limit, input_config_file, output_config_file, config_format="app_db"):
"""Modifies a COPP config to use the specified rate limit.

Args:
pps_limit (int): The rate limit to enforce expressed in PPS (packets-per-second)
input_config_file (str): The name of the file containing the initial config
output_config_file (str): The name of the file to output the modified config
"""
Notes:
This only affects COPP policies that enforce a rate limit. Other
policies are left alone.

Args:
pps_limit (int): The rate limit to enforce expressed in PPS (packets-per-second)
input_config_file (str): The name of the file containing the initial config
output_config_file (str): The name of the file to output the modified config
config_format (str): The format of the input COPP config file

"""
with open(input_config_file) as input_stream:
copp_config = json.load(input_stream)

for trap_group in copp_config:
if config_format == "app_db":
trap_groups = copp_config
elif config_format == "config_db":
trap_groups = [{x: y} for x, y in copp_config["COPP_GROUP"].items()]
else:
raise ValueError("Invalid config format specified")

for trap_group in trap_groups:
for _, group_config in trap_group.items():
# Notes:
# CIR (committed information rate) - bandwidth limit set by the policer
Expand All @@ -48,6 +92,13 @@ def generate_limited_pps_config(pps_limit, input_config_file, output_config_file
with open(output_config_file, "w+") as output_stream:
json.dump(copp_config, output_stream)


if __name__ == "__main__":
ARGS = sys.argv[1:]
generate_limited_pps_config(ARGS[0], ARGS[1], ARGS[2])

if len(ARGS) < 4:
config_format = "app_db"
else:
config_format = ARGS[3]

generate_limited_pps_config(ARGS[0], ARGS[1], ARGS[2], config_format)