From 1fc868d1126b3e01afbadaac1d72b58d60f6e283 Mon Sep 17 00:00:00 2001 From: pmikus Date: Wed, 11 Oct 2023 12:12:48 +0000 Subject: feat(core): Multilink TRex Async mode Signed-off-by: pmikus Change-Id: I02468203f3eb4545b6662bad2ce9aa72ecd5a5f6 --- GPL/tools/trex/trex_stl_profile.py | 9 ++-- GPL/tools/trex/trex_stl_stop.py | 67 ++++++++++---------------- resources/libraries/python/TrafficGenerator.py | 18 +++---- 3 files changed, 36 insertions(+), 58 deletions(-) diff --git a/GPL/tools/trex/trex_stl_profile.py b/GPL/tools/trex/trex_stl_profile.py index 324ad41cc0..51c9924668 100644 --- a/GPL/tools/trex/trex_stl_profile.py +++ b/GPL/tools/trex/trex_stl_profile.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2022 Cisco and/or its affiliates. +# Copyright (c) 2023 Cisco and/or its affiliates. # # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later # @@ -197,10 +197,9 @@ def simple_burst( if async_start: # For async stop, we need to export the current snapshot. - xsnap0 = client.ports[0].get_xstats().reference_stats - print(f"Xstats snapshot 0: {xsnap0!r}") - xsnap1 = client.ports[1].get_xstats().reference_stats - print(f"Xstats snapshot 1: {xsnap1!r}") + for i in range(len(client.ports)): + xsnap = client.ports[i].get_xstats().reference_stats + print(f"Xstats snapshot {i}: {xsnap!r}") else: time_start = time.monotonic() # wait_on_traffic fails if duration stretches by 30 seconds or more. diff --git a/GPL/tools/trex/trex_stl_stop.py b/GPL/tools/trex/trex_stl_stop.py index 9cc1814589..c03624ba24 100644 --- a/GPL/tools/trex/trex_stl_stop.py +++ b/GPL/tools/trex/trex_stl_stop.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2022 Cisco and/or its affiliates. +# Copyright (c) 2023 Cisco and/or its affiliates. # # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later # @@ -30,11 +30,6 @@ Requirements: - compiled and running T-REX process (eg. ./t-rex-64 -i) - trex.stl.api library - Script must be executed on a node with T-REX instance - -Functionality: -1. Stop any running traffic -2. Optionally restore reference counter values. -3. Return conter differences. """ import argparse @@ -44,7 +39,7 @@ import sys from collections import OrderedDict # Needed to parse xstats representation. sys.path.insert( - 0, u"/opt/trex-core-3.03/scripts/automation/trex_control_plane/interactive/" + 0, "/opt/trex-core-3.03/scripts/automation/trex_control_plane/interactive/" ) from trex.stl.api import STLClient @@ -53,59 +48,47 @@ def main(): """Stop traffic if any is running. Report xstats.""" parser = argparse.ArgumentParser() parser.add_argument( - u"--xstat0", type=str, default=u"", - help=u"Reference xstat object if any." - ) - parser.add_argument( - u"--xstat1", type=str, default=u"", - help=u"Reference xstat object if any." + "--xstat", type=str, nargs="*", help="Reference xstat object if any." ) args = parser.parse_args() client = STLClient() try: - # connect to server client.connect() - client.acquire(force=True) - # TODO: Support unidirection. - client.stop(ports=[0, 1]) + client.stop() + xstats = list() # Read the stats after the test, # we need to update values before the last trial started. - if args.xstat0: - snapshot = eval(args.xstat0) - client.ports[0].get_xstats().reference_stats = snapshot - if args.xstat1: - snapshot = eval(args.xstat1) - client.ports[1].get_xstats().reference_stats = snapshot - # Now we can call the official method to get differences. - xstats0 = client.get_xstats(0) - xstats1 = client.get_xstats(1) - - # If STLError happens, let the script fail with stack trace. + for i in range(len(client.ports)): + if args.xstat[i]: + snapshot = eval(args.xstat[i]) + client.ports[i].get_xstats().reference_stats = snapshot + # Now we can call the official method to get differences. + xstats.append(client.get_xstats(i)) + print(f"##### statistics port {i} #####") + print(json.dumps(xstats[i], indent=4, separators=(",", ": "))) finally: client.disconnect() - print(u"##### statistics port 0 #####") - print(json.dumps(xstats0, indent=4, separators=(u",", u": "))) - print(u"##### statistics port 1 #####") - print(json.dumps(xstats1, indent=4, separators=(u",", u": "))) - - tx_0, rx_0 = xstats0[u"tx_good_packets"], xstats0[u"rx_good_packets"] - tx_1, rx_1 = xstats1[u"tx_good_packets"], xstats1[u"rx_good_packets"] - lost_a, lost_b = tx_0 - rx_1, tx_1 - rx_0 + for idx,stat in enumerate(zip(xstats[0::2], xstats[1::2])): + lost_r = stat[0]["tx_good_packets"] - stat[1]["rx_good_packets"] + lost_l = stat[1]["tx_good_packets"] - stat[0]["rx_good_packets"] + print(f"packets lost from {idx*2} --> {idx*2+1}: {lost_r} pkts") + print(f"packets lost from {idx*2+1} --> {idx*2}: {lost_l} pkts") - print(f"\npackets lost from 0 --> 1: {lost_a} pkts") - print(f"packets lost from 1 --> 0: {lost_b} pkts") + total_rcvd = 0 + total_sent = 0 + for stat in xstats: + total_rcvd += stat["rx_good_packets"] + total_sent += stat["tx_good_packets"] - total_rcvd, total_sent = rx_0 + rx_1, tx_0 + tx_1 - total_lost = total_sent - total_rcvd print( f"rate='unknown'; " f"total_received={total_rcvd}; " f"total_sent={total_sent}; " - f"frame_loss={total_lost}; " + f"frame_loss={total_sent - total_rcvd}; " f"target_duration='manual'; " f"approximated_duration='manual'; " f"approximated_rate='unknown'; " @@ -114,5 +97,5 @@ def main(): ) -if __name__ == u"__main__": +if __name__ == "__main__": main() diff --git a/resources/libraries/python/TrafficGenerator.py b/resources/libraries/python/TrafficGenerator.py index 6f4483b970..5b98a6ba51 100644 --- a/resources/libraries/python/TrafficGenerator.py +++ b/resources/libraries/python/TrafficGenerator.py @@ -174,7 +174,7 @@ class TrafficGenerator(AbstractMeasurer): self.ramp_up_duration = None self.state_timeout = None # Transient data needed for async measurements. - self._xstats = (None, None) + self._xstats = () @property def node(self): @@ -499,11 +499,11 @@ class TrafficGenerator(AbstractMeasurer): command_line = OptionString().add(u"python3") dirname = f"{Constants.REMOTE_FW_DIR}/GPL/tools/trex" command_line.add(f"'{dirname}/trex_stl_stop.py'") - command_line.change_prefix(u"--") + command_line.add("--xstat") for index, value in enumerate(self._xstats): if value is not None: - value = value.replace(u"'", u"\"") - command_line.add_equals(f"xstat{index}", f"'{value}'") + value = value.replace("'", "\"") + command_line.add(f"'{value}'") stdout, _ = exec_cmd_no_error( node, command_line, message=u"T-Rex STL runtime error!" @@ -654,7 +654,7 @@ class TrafficGenerator(AbstractMeasurer): self._sent = None self._loss = None self._latency = None - xstats = [None, None] + xstats = [] self._l7_data = dict() self._l7_data[u"client"] = dict() self._l7_data[u"client"][u"active_flows"] = None @@ -689,8 +689,6 @@ class TrafficGenerator(AbstractMeasurer): if f"Xstats snapshot {index}: " in line: xstats[index] = line[19:] index += 1 - if index == 2: - break self._xstats = tuple(xstats) else: self._target_duration = duration @@ -761,14 +759,12 @@ class TrafficGenerator(AbstractMeasurer): self._loss = None self._latency = None - xstats = [None, None] + xstats = [] index = 0 for line in stdout.splitlines(): if f"Xstats snapshot {index}: " in line: - xstats[index] = line[19:] + xstats.append(line[19:]) index += 1 - if index == 2: - break self._xstats = tuple(xstats) else: self._target_duration = duration -- cgit 1.2.3-korg