Skip to content

Commit

Permalink
[pytest] Fix ptf_runner issue introduced by COPP test conversion (#1644)
Browse files Browse the repository at this point in the history
* [copp] Convert COPP test to pytest (#1633)
* Fix missing space in ptf_runner

Signed-off-by: Danny Allen <daall@microsoft.com>
  • Loading branch information
daall authored May 6, 2020
1 parent e355432 commit 4163834
Show file tree
Hide file tree
Showing 11 changed files with 469 additions and 9 deletions.
10 changes: 10 additions & 0 deletions tests/common/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,16 @@ def check_bgp_session_nsf(self, neighbor_ip):
return True
return False

def get_version(self):
"""
Gets the SONiC version this device is running.
Returns:
str: the firmware version number (e.g. 20181130.31)
"""
output = dut.command("sonic-cfggen -y /etc/sonic/sonic_version.yml -v build_version")
return output["stdout_lines"][0].strip()

class EosHost(AnsibleHostBase):
"""
@summary: Class for Eos switch
Expand Down
Empty file added tests/copp/__init__.py
Empty file.
31 changes: 31 additions & 0 deletions tests/copp/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Pytest configuration used by the COPP tests.
"""

def pytest_addoption(parser):
"""
Adds options to pytest that are used by the COPP tests.
"""

parser.addoption(
"--nn_target_port",
action="store",
type=int,
default=3,
help="Which port to send traffic to",
)

parser.addoption(
"--pkt_tx_count",
action="store",
type=int,
default=100000,
help="How many packets to send to the DUT"
)

parser.addoption(
"--swap_syncd",
action="store_true",
default=False,
help="Install syncd RPC image for this test case"
)
118 changes: 118 additions & 0 deletions tests/copp/copp_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""
Helpful utilities for writing tests for the COPP feature.
Todo:
Refactor ptfadapter so it can be leveraged in these test cases.
"""

DEFAULT_NN_TARGET_PORT = 3

_REMOVE_IP_SCRIPT = "scripts/remove_ip.sh"
_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"
_TEMP_COPP_CONFIG = "/tmp/copp_config.json"

_PTF_NN_TEMPLATE = "templates/ptf_nn_agent.conf.ptf.j2"
_PTF_NN_DEST = "/etc/supervisor/conf.d/ptf_nn_agent.conf"

_SYNCD_NN_TEMPLATE = "templates/ptf_nn_agent.conf.dut.j2"
_SYNCD_NN_DEST = "/tmp/ptf_nn_agent.conf"

def limit_policer(dut, pps_limit):
"""
Updates the COPP configuration in the SWSS container to respect a given rate limit.
Note:
The SWSS container must be restarted for the config change to take effect.
Args:
dut (SonicHost): The target device.
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))

def restore_policer(dut):
"""
Reloads the default COPP configuration in the SWSS container.
Notes:
This method should only be used after limit_policer.
The SWSS container must be restarted for the config change to take effect.
"""
dut.command("docker cp {} {}".format(_BASE_COPP_CONFIG, _SWSS_COPP_CONFIG))

def configure_ptf(ptf, nn_target_port):
"""
Configures the PTF to run the NN agent on the specified port.
Args:
ptf (PTFHost): The target PTF.
nn_target_port (int): The port to run NN agent on.
"""

ptf.script(cmd=_REMOVE_IP_SCRIPT)
ptf.script(cmd=_ADD_IP_SCRIPT)

facts = {"nn_target_port": nn_target_port}
ptf.host.options['variable_manager'].extra_vars.update(facts)
ptf.template(src=_PTF_NN_TEMPLATE, dest=_PTF_NN_DEST)

ptf.supervisorctl(name="ptf_nn_agent", state="restarted")

ptf.copy(src="ptftests", dest="/root")

def restore_ptf(ptf):
"""
Restores the PTF and the NN agent to default settings.
Args:
ptf (PTFHost): The target PTF.
"""

ptf.script(cmd=_REMOVE_IP_SCRIPT)

facts = {"nn_target_port": DEFAULT_NN_TARGET_PORT}
ptf.host.options['variable_manager'].extra_vars.update(facts)

ptf.template(src=_PTF_NN_TEMPLATE, dest=_PTF_NN_DEST)

ptf.supervisorctl(name="ptf_nn_agent", state="restarted")

def configure_syncd(dut, nn_target_port):
"""
Configures syncd to run the NN agent on the specified port.
Note:
The DUT must be running an RPC syncd image in order for the
NN agent to be available.
Args:
dut (SonicHost): The target device.
nn_target_port (int): The port to run NN agent on.
"""

facts = {"nn_target_port": nn_target_port,
"nn_target_interface": _map_port_number_to_interface(dut, nn_target_port)}
dut.host.options['variable_manager'].extra_vars.update(facts)

dut.template(src=_SYNCD_NN_TEMPLATE, dest=_SYNCD_NN_DEST)
dut.command("docker cp {} syncd:/etc/supervisor/conf.d/".format(_SYNCD_NN_DEST))

dut.command("docker exec syncd supervisorctl reread")
dut.command("docker exec syncd supervisorctl update")

def _map_port_number_to_interface(dut, nn_target_port):
"""
Retrieves the correct interface for a given port number.
"""

interfaces = dut.command("portstat")["stdout_lines"][2:]
return interfaces[nn_target_port].split()[0]
53 changes: 53 additions & 0 deletions tests/copp/scripts/update_copp_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/python
"""
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>
$ python update_copp_config.py 600 /tmp/copp_config.json /tmp/new_copp_config.json
"""
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.
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
"""

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

for trap_group in copp_config:
for _, group_config in trap_group.items():
# Notes:
# CIR (committed information rate) - bandwidth limit set by the policer
# CBS (committed burst size) - largest burst of packets allowed by the policer
#
# Setting these two values to pps_limit restricts the policer to allowing exactly
# that number of packets per second, which is what we want for our tests.

if "cir" in group_config:
group_config["cir"] = pps_limit

if "cbs" in group_config:
group_config["cbs"] = pps_limit

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])
Loading

0 comments on commit 4163834

Please sign in to comment.