T-REX stl traffic send improvement for async calls 90/1090/10
authorMiroslav Miklus <mmiklus@cisco.com>
Thu, 12 May 2016 22:35:53 +0000 (00:35 +0200)
committerMiroslav Miklus <mmiklus@cisco.com>
Wed, 18 May 2016 09:01:05 +0000 (09:01 +0000)
JIRA: CSIT-68
- show runtime statistics with running traffic
- T-REX driver async. driver

Change-Id: Ie5eb7021f610fb58383b033dda5b1b867f7d3d2c
Signed-off-by: Miroslav Miklus <mmiklus@cisco.com>
resources/libraries/python/TrafficGenerator.py
resources/libraries/python/VppCounters.py
resources/libraries/robot/counters.robot
resources/libraries/robot/performance.robot
resources/templates/vat/clear_runtime.vat [new file with mode: 0644]
resources/templates/vat/show_runtime.vat [new file with mode: 0644]
resources/tools/t-rex/t-rex-stateless-stop.py [new file with mode: 0755]
resources/tools/t-rex/t-rex-stateless.py

index 7f53836..3969891 100644 (file)
@@ -35,7 +35,7 @@ class TGDropRateSearchImpl(DropRateSearch):
                      loss_acceptance_type, traffic_type):
 
         # we need instance of TrafficGenerator instantiated by Robot Framework
                      loss_acceptance_type, traffic_type):
 
         # we need instance of TrafficGenerator instantiated by Robot Framework
-        # to be able to use trex_stateless_remote_exec method
+        # to be able to use trex_stl-*()
         tg_instance = BuiltIn().get_library_instance(
             'resources.libraries.python.TrafficGenerator')
 
         tg_instance = BuiltIn().get_library_instance(
             'resources.libraries.python.TrafficGenerator')
 
@@ -43,9 +43,9 @@ class TGDropRateSearchImpl(DropRateSearch):
             raise Exception('TG subtype not defined')
         elif tg_instance._node['subtype'] == NodeSubTypeTG.TREX:
             unit_rate = str(rate) + self.get_rate_type_str()
             raise Exception('TG subtype not defined')
         elif tg_instance._node['subtype'] == NodeSubTypeTG.TREX:
             unit_rate = str(rate) + self.get_rate_type_str()
-            tg_instance.trex_stateless_remote_exec(self.get_duration(),
+            tg_instance.trex_stl_start_remote_exec(self.get_duration(),
                                                    unit_rate, frame_size,
                                                    unit_rate, frame_size,
-                                                   traffic_type)
+                                                   traffic_type, False)
 
             # TODO: getters for tg_instance and loss_acceptance_type
             logger.trace("comparing: {} < {} ".format(tg_instance._loss,
 
             # TODO: getters for tg_instance and loss_acceptance_type
             logger.trace("comparing: {} < {} ".format(tg_instance._loss,
@@ -73,6 +73,7 @@ class TrafficGenerator(object):
         # T-REX interface order mapping
         self._ifaces_reordered = 0
 
         # T-REX interface order mapping
         self._ifaces_reordered = 0
 
+    #pylint: disable=too-many-arguments, too-many-locals
     def initialize_traffic_generator(self, tg_node, tg_if1, tg_if2,
                                      dut1_node, dut1_if1, dut1_if2,
                                      dut2_node, dut2_if1, dut2_if2,
     def initialize_traffic_generator(self, tg_node, tg_if1, tg_if2,
                                      dut1_node, dut1_if1, dut1_if2,
                                      dut2_node, dut2_if1, dut2_if2,
@@ -197,19 +198,54 @@ class TrafficGenerator(object):
                 logger.error('pkill t-rex failed: {0}'.format(stdout + stderr))
                 raise RuntimeError('pkill t-rex failed')
 
                 logger.error('pkill t-rex failed: {0}'.format(stdout + stderr))
                 raise RuntimeError('pkill t-rex failed')
 
-    def trex_stateless_remote_exec(self, duration, rate, framesize,
-                                   traffic_type):
-        """Execute stateless script on remote node over ssh.
+    @staticmethod
+    def trex_stl_stop_remote_exec(node):
+        """Execute script on remote node over ssh to stop running traffic.
+
+        :param node: T-REX generator node.
+        :type node: dict
+        :return: Nothing
+        """
+        ssh = SSH()
+        ssh.connect(node)
+
+        (ret, stdout, stderr) = ssh.exec_command(
+            "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
+            "t-rex-stateless-stop.py'")
+        logger.trace(ret)
+        logger.trace(stdout)
+        logger.trace(stderr)
+
+        if int(ret) != 0:
+            raise RuntimeError('T-rex stateless runtime error')
+
+    def trex_stl_start_remote_exec(self, duration, rate, framesize,
+                                   traffic_type, async_call, warmup_time=5):
+        """Execute script on remote node over ssh to start traffic.
 
 
+        :param duration: Time expresed in seconds for how long to send traffic.
+        :param rate: Traffic rate expressed with units (pps, %)
+        :param framesize: L2 frame size to send (without padding and IPG).
         :param traffic_type: Traffic profile.
         :param traffic_type: Traffic profile.
+        :param async_call: If enabled then don't wait for all incomming trafic.
+        :param warmup_time: Warmup time period.
+        :type duration: int
+        :type rate: str
+        :type framesize: int
         :type traffic_type: str
         :type traffic_type: str
+        :type async_call: bool
+        :type warmup_time: int
+        :return: Nothing
         """
         ssh = SSH()
         ssh.connect(self._node)
 
         _p0 = 1
         _p1 = 2
         """
         ssh = SSH()
         ssh.connect(self._node)
 
         _p0 = 1
         _p1 = 2
+        _async = ""
 
 
+        if async_call:
+            _async = "--async"
         if self._ifaces_reordered != 0:
             _p0, _p1 = _p1, _p0
 
         if self._ifaces_reordered != 0:
             _p0, _p1 = _p1, _p0
 
@@ -217,40 +253,43 @@ class TrafficGenerator(object):
             (ret, stdout, stderr) = ssh.exec_command(
                 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
                 "t-rex-stateless.py "
             (ret, stdout, stderr) = ssh.exec_command(
                 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
                 "t-rex-stateless.py "
-                "-{0} -r {1} -s {2} "
+                "--duration={0} -r {1} -s {2} "
                 "--p{3}_src_start_ip 10.10.10.1 "
                 "--p{3}_src_end_ip 10.10.10.254 "
                 "--p{3}_dst_start_ip 20.20.20.1 "
                 "--p{4}_src_start_ip 20.20.20.1 "
                 "--p{4}_src_end_ip 20.20.20.254 "
                 "--p{3}_src_start_ip 10.10.10.1 "
                 "--p{3}_src_end_ip 10.10.10.254 "
                 "--p{3}_dst_start_ip 20.20.20.1 "
                 "--p{4}_src_start_ip 20.20.20.1 "
                 "--p{4}_src_end_ip 20.20.20.254 "
-                "--p{4}_dst_start_ip 10.10.10.1'".\
-                format(duration, rate, framesize, _p0, _p1),\
+                "--p{4}_dst_start_ip 10.10.10.1 "
+                "{5} --warmup_time={6}'".format(duration, rate, framesize, _p0,
+                                                _p1, _async, warmup_time),
                 timeout=int(duration)+60)
         elif traffic_type in ["3-node-IPv4"]:
             (ret, stdout, stderr) = ssh.exec_command(
                 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
                 "t-rex-stateless.py "
                 timeout=int(duration)+60)
         elif traffic_type in ["3-node-IPv4"]:
             (ret, stdout, stderr) = ssh.exec_command(
                 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
                 "t-rex-stateless.py "
-                "-{0} -r {1} -s {2} "
+                "--duration={0} -r {1} -s {2} "
                 "--p{3}_src_start_ip 10.10.10.2 "
                 "--p{3}_src_end_ip 10.10.10.254 "
                 "--p{3}_dst_start_ip 20.20.20.2 "
                 "--p{4}_src_start_ip 20.20.20.2 "
                 "--p{4}_src_end_ip 20.20.20.254 "
                 "--p{3}_src_start_ip 10.10.10.2 "
                 "--p{3}_src_end_ip 10.10.10.254 "
                 "--p{3}_dst_start_ip 20.20.20.2 "
                 "--p{4}_src_start_ip 20.20.20.2 "
                 "--p{4}_src_end_ip 20.20.20.254 "
-                "--p{4}_dst_start_ip 10.10.10.2'".\
-                format(duration, rate, framesize, _p0, _p1),\
+                "--p{4}_dst_start_ip 10.10.10.2 "
+                "{5} --warmup_time={6}'".format(duration, rate, framesize, _p0,
+                                                _p1, _async, warmup_time),
                 timeout=int(duration)+60)
         elif traffic_type in ["3-node-IPv6"]:
             (ret, stdout, stderr) = ssh.exec_command(
                 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
                 "t-rex-stateless.py "
                 timeout=int(duration)+60)
         elif traffic_type in ["3-node-IPv6"]:
             (ret, stdout, stderr) = ssh.exec_command(
                 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
                 "t-rex-stateless.py "
-                "-{0} -r {1} -s {2} -6 "
+                "--duration={0} -r {1} -s {2} -6 "
                 "--p{3}_src_start_ip 2001:1::2 "
                 "--p{3}_src_end_ip 2001:1::FE "
                 "--p{3}_dst_start_ip 2001:2::2 "
                 "--p{4}_src_start_ip 2001:2::2 "
                 "--p{4}_src_end_ip 2001:2::FE "
                 "--p{3}_src_start_ip 2001:1::2 "
                 "--p{3}_src_end_ip 2001:1::FE "
                 "--p{3}_dst_start_ip 2001:2::2 "
                 "--p{4}_src_start_ip 2001:2::2 "
                 "--p{4}_src_end_ip 2001:2::FE "
-                "--p{4}_dst_start_ip 2001:1::2'".\
-                format(duration, rate, framesize, _p0, _p1),\
+                "--p{4}_dst_start_ip 2001:1::2 "
+                "{5} --warmup_time={6}'".format(duration, rate, framesize, _p0,
+                                                _p1, _async, warmup_time),
                 timeout=int(duration)+60)
         else:
             raise NotImplementedError('Unsupported traffic type')
                 timeout=int(duration)+60)
         else:
             raise NotImplementedError('Unsupported traffic type')
@@ -261,6 +300,11 @@ class TrafficGenerator(object):
 
         if int(ret) != 0:
             raise RuntimeError('T-rex stateless runtime error')
 
         if int(ret) != 0:
             raise RuntimeError('T-rex stateless runtime error')
+        elif async_call:
+            #no result
+            self._received = None
+            self._sent = None
+            self._loss = None
         else:
             # last line from console output
             line = stdout.splitlines()[-1]
         else:
             # last line from console output
             line = stdout.splitlines()[-1]
@@ -272,16 +316,24 @@ class TrafficGenerator(object):
             self._sent = self._result.split(', ')[2].split('=')[1]
             self._loss = self._result.split(', ')[3].split('=')[1]
 
             self._sent = self._result.split(', ')[2].split('=')[1]
             self._loss = self._result.split(', ')[3].split('=')[1]
 
-    def send_traffic_on(self, node, duration, rate,
-                        framesize, traffic_type):
+    def stop_traffic_on_tg(self):
+        """Stop all traffic on TG
+
+        :return: Nothing
+        """
+        if self._node is None:
+            raise RuntimeError("TG is not set")
+        if self._node['subtype'] == NodeSubTypeTG.TREX:
+            self.trex_stl_stop_remote_exec(self._node)
+
+    def send_traffic_on_tg(self, duration, rate, framesize,
+                           traffic_type, warmup_time=5, async_call=False):
         """Send traffic from all configured interfaces on TG.
 
         """Send traffic from all configured interfaces on TG.
 
-        :param node: Dictionary containing TG information.
         :param duration: Duration of test traffic generation in seconds.
         :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...).
         :param framesize: Frame size (L2) in Bytes.
         :param traffic_type: Traffic profile.
         :param duration: Duration of test traffic generation in seconds.
         :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...).
         :param framesize: Frame size (L2) in Bytes.
         :param traffic_type: Traffic profile.
-        :type node: dict
         :type duration: str
         :type rate: str
         :type framesize: str
         :type duration: str
         :type rate: str
         :type framesize: str
@@ -289,14 +341,20 @@ class TrafficGenerator(object):
         :return: TG output.
         :rtype: str
         """
         :return: TG output.
         :rtype: str
         """
+
+        node = self._node
+        if node is None:
+            raise RuntimeError("TG is not set")
+
         if node['type'] != NodeType.TG:
             raise Exception('Node type is not a TG')
 
         if node['subtype'] is None:
             raise Exception('TG subtype not defined')
         elif node['subtype'] == NodeSubTypeTG.TREX:
         if node['type'] != NodeType.TG:
             raise Exception('Node type is not a TG')
 
         if node['subtype'] is None:
             raise Exception('TG subtype not defined')
         elif node['subtype'] == NodeSubTypeTG.TREX:
-            self.trex_stateless_remote_exec(duration, rate, framesize,
-                                            traffic_type)
+            self.trex_stl_start_remote_exec(duration, rate, framesize,
+                                            traffic_type, async_call,
+                                            warmup_time=warmup_time)
         else:
             raise NotImplementedError("TG subtype not supported")
 
         else:
             raise NotImplementedError("TG subtype not supported")
 
index d8d4554..4bb7d63 100644 (file)
@@ -57,9 +57,19 @@ class VppCounters(object):
         vat = VatExecutor()
         vat.execute_script("show_errors_verbose.vat", node, json_out=False)
 
         vat = VatExecutor()
         vat.execute_script("show_errors_verbose.vat", node, json_out=False)
 
+    @staticmethod
+    def vpp_show_runtime(node):
+        """Run "show runtime" CLI command.
+
+        :param node: Node to run command on.
+        :type node: dict
+        """
+        vat = VatExecutor()
+        vat.execute_script("show_runtime.vat", node, json_out=False)
+
     @staticmethod
     def vpp_show_runtime_verbose(node):
     @staticmethod
     def vpp_show_runtime_verbose(node):
-        """Run "show runtime" debug CLI command.
+        """Run "show runtime verbose" CLI command.
 
         :param node: Node to run command on.
         :type node: dict
 
         :param node: Node to run command on.
         :type node: dict
@@ -77,6 +87,16 @@ class VppCounters(object):
         vat = VatExecutor()
         vat.execute_script("show_hardware_detail.vat", node, json_out=False)
 
         vat = VatExecutor()
         vat.execute_script("show_hardware_detail.vat", node, json_out=False)
 
+    @staticmethod
+    def vpp_clear_runtime(node):
+        """Run "clear runtime" CLI command.
+
+        :param node: Node to run command on.
+        :type node: dict
+        """
+        vat = VatExecutor()
+        vat.execute_script("clear_runtime.vat", node, json_out=False)
+
     @staticmethod
     def vpp_clear_interface_counters(node):
         """Clear interface counters on VPP node.
     @staticmethod
     def vpp_clear_interface_counters(node):
         """Clear interface counters on VPP node.
index b4db3fe..0cb18c1 100644 (file)
 | | [Arguments] | ${node}
 | | Vpp Dump Stats Table | ${node}
 | | Vpp Show Errors | ${node}
 | | [Arguments] | ${node}
 | | Vpp Dump Stats Table | ${node}
 | | Vpp Show Errors | ${node}
-| | Vpp Show Errors Verbose | ${node}
 | | Vpp Show Hardware Detail | ${node}
 | | Vpp Show Hardware Detail | ${node}
-| | Vpp Show Runtime Verbose | ${node}
+| | Vpp Show Runtime | ${node}
+
+| Clear runtime statistics on all DUTs
+| | [Documentation] | Clear VPP runtime statistics on all DUTs
+| | ${duts}= | Get Matches | ${nodes} | DUT*
+| | :FOR | ${dut} | IN | @{duts}
+| | | Vpp clear runtime | ${nodes['${dut}']}
+
+| Show runtime statistics on all DUTs
+| | [Documentation] | Show VPP runtime statistics on all DUTs
+| | ${duts}= | Get Matches | ${nodes} | DUT*
+| | :FOR | ${dut} | IN | @{duts}
+| | | Vpp show runtime | ${nodes['${dut}']}
index d43073d..e26bc19 100644 (file)
 | | [Documentation] | Find throughput by using RFC2544 linear search
 | | [Arguments] | ${framesize} | ${start_rate} | ${step_rate}
 | | ...         | ${topology_type} | ${min_rate} | ${max_rate}
 | | [Documentation] | Find throughput by using RFC2544 linear search
 | | [Arguments] | ${framesize} | ${start_rate} | ${step_rate}
 | | ...         | ${topology_type} | ${min_rate} | ${max_rate}
-| | Set Duration | 60
+| | ${duration}= | Set Variable | 60
+| | Set Duration | ${duration}
 | | Set Search Rate Boundaries | ${max_rate} | ${min_rate}
 | | Set Search Linear Step | ${step_rate}
 | | Set Search Frame Size | ${framesize}
 | | Set Search Rate Boundaries | ${max_rate} | ${min_rate}
 | | Set Search Linear Step | ${step_rate}
 | | Set Search Frame Size | ${framesize}
 | | Linear Search | ${start_rate} | ${topology_type}
 | | ${rate_per_stream}= | Verify Search Result
 | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2
 | | Linear Search | ${start_rate} | ${topology_type}
 | | ${rate_per_stream}= | Verify Search Result
 | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2
+| | Clear and show runtime stats with running traffic | ${duration}
+| | ...  | ${rate_per_stream}pps | ${framesize} | ${topology_type}
 
 | Find NDR using binary search and pps
 | | [Documentation] | Find throughput by using RFC2544 binary search
 | | [Arguments] | ${framesize} | ${binary_min} | ${binary_max}
 | | ...         | ${topology_type} | ${min_rate} | ${max_rate} | ${threshold}
 
 | Find NDR using binary search and pps
 | | [Documentation] | Find throughput by using RFC2544 binary search
 | | [Arguments] | ${framesize} | ${binary_min} | ${binary_max}
 | | ...         | ${topology_type} | ${min_rate} | ${max_rate} | ${threshold}
-| | Set Duration | 60
+| | ${duration}= | Set Variable | 60
+| | Set Duration | ${duration}
 | | Set Search Rate Boundaries | ${max_rate} | ${min_rate}
 | | Set Search Frame Size | ${framesize}
 | | Set Search Rate Type pps
 | | Set Search Rate Boundaries | ${max_rate} | ${min_rate}
 | | Set Search Frame Size | ${framesize}
 | | Set Search Rate Type pps
 | | Binary Search | ${binary_min} | ${binary_max} | ${topology_type}
 | | ${rate_per_stream}= | Verify Search Result
 | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2
 | | Binary Search | ${binary_min} | ${binary_max} | ${topology_type}
 | | ${rate_per_stream}= | Verify Search Result
 | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2
+| | Clear and show runtime stats with running traffic | ${duration}
+| | ...  | ${rate_per_stream}pps | ${framesize} | ${topology_type}
 
 | Find NDR using combined search and pps
 | | [Documentation] | Find throughput by using RFC2544 combined search
 | | ...             | (linear + binary)
 | | [Arguments] | ${framesize} | ${start_rate} | ${step_rate}
 | | ...         | ${topology_type} | ${min_rate} | ${max_rate} | ${threshold}
 
 | Find NDR using combined search and pps
 | | [Documentation] | Find throughput by using RFC2544 combined search
 | | ...             | (linear + binary)
 | | [Arguments] | ${framesize} | ${start_rate} | ${step_rate}
 | | ...         | ${topology_type} | ${min_rate} | ${max_rate} | ${threshold}
-| | Set Duration | 60
+| | ${duration}= | Set Variable | 60
+| | Set Duration | ${duration}
 | | Set Search Rate Boundaries | ${max_rate} | ${min_rate}
 | | Set Search Linear Step | ${step_rate}
 | | Set Search Frame Size | ${framesize}
 | | Set Search Rate Boundaries | ${max_rate} | ${min_rate}
 | | Set Search Linear Step | ${step_rate}
 | | Set Search Frame Size | ${framesize}
 | | Combined Search | ${start_rate} | ${topology_type}
 | | ${rate_per_stream}= | Verify Search Result
 | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2
 | | Combined Search | ${start_rate} | ${topology_type}
 | | ${rate_per_stream}= | Verify Search Result
 | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2
+| | Clear and show runtime stats with running traffic | ${duration}
+| | ...  | ${rate_per_stream}pps | ${framesize} | ${topology_type}
 
 | Display result of NDR search
 | | [Documentation] | Display result of NDR search in packet per seconds (total
 
 | Display result of NDR search
 | | [Documentation] | Display result of NDR search in packet per seconds (total
 | | Set Test Message | (${nr_streams}x ${rate_per_stream} pps) | append=yes
 | | Set Test Message | FINAL_BANDWIDTH: ${bandwidth_total} Gbps | append=yes
 
 | | Set Test Message | (${nr_streams}x ${rate_per_stream} pps) | append=yes
 | | Set Test Message | FINAL_BANDWIDTH: ${bandwidth_total} Gbps | append=yes
 
-
 | Traffic should pass with no loss
 | | [Arguments] | ${duration} | ${rate} | ${framesize} | ${topology_type}
 | Traffic should pass with no loss
 | | [Arguments] | ${duration} | ${rate} | ${framesize} | ${topology_type}
-| | Send traffic on | ${tg} | ${duration}
-| | ...             | ${rate} | ${framesize} | ${topology_type}
+| | Clear and show runtime stats with running traffic | ${duration}
+| | ...  | ${rate} | ${framesize} | ${topology_type}
+| | Send traffic on tg | ${duration} | ${rate} | ${framesize}
+| | ...                | ${topology_type}
 | | No traffic loss occurred
 | | No traffic loss occurred
+
+| Clear and show runtime stats with running traffic
+| | [Arguments] | ${duration} | ${rate} | ${framesize} | ${topology_type}
+| | Send traffic on tg | -1 | ${rate} | ${framesize}
+| | ...                | ${topology_type} | warmup_time=0 | async_call=True
+| | Clear runtime statistics on all DUTs
+| | Sleep | ${duration}
+| | Show runtime statistics on all DUTs
+| | Stop traffic on tg
diff --git a/resources/templates/vat/clear_runtime.vat b/resources/templates/vat/clear_runtime.vat
new file mode 100644 (file)
index 0000000..931fd5f
--- /dev/null
@@ -0,0 +1 @@
+exec clear runtime
diff --git a/resources/templates/vat/show_runtime.vat b/resources/templates/vat/show_runtime.vat
new file mode 100644 (file)
index 0000000..1baaedb
--- /dev/null
@@ -0,0 +1 @@
+exec show runtime
diff --git a/resources/tools/t-rex/t-rex-stateless-stop.py b/resources/tools/t-rex/t-rex-stateless-stop.py
new file mode 100755 (executable)
index 0000000..e9accbe
--- /dev/null
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This script uses T-REX stateless API to drive t-rex instance.
+
+Requirements:
+- T-REX: https://github.com/cisco-system-traffic-generator/trex-core
+ - compiled and running T-REX process (eg. ./t-rex-64 -i -c 4)
+ - trex_stl_lib.api library
+- Script must be executed on a node with T-REX instance
+
+Functionality:
+1. Stop any running traffic
+
+"""
+
+import sys
+
+sys.path.insert(0, "/opt/trex-core-2.00/scripts/automation/"+\
+                   "trex_control_plane/stl/")
+from trex_stl_lib.api import *
+
+
+def stop_all_traffic_streams():
+    """Stop traffic if any is running.
+
+    :return: nothing
+    """
+
+    # create client
+    client = STLClient()
+
+    try:
+        # turn this off if too many logs
+        #client.set_verbose("high")
+
+        # connect to server
+        client.connect()
+
+        client.acquire(force=True)
+        client.stop(ports=[0, 1])
+
+        # read the stats after the test
+        stats = client.get_stats()
+
+        print "#####statistics (approx.)#####"
+        print json.dumps(stats, indent=4,
+                         separators=(',', ': '), sort_keys=True)
+
+        lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
+        lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
+
+        total_sent = stats[0]["opackets"] + stats[1]["opackets"]
+        total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
+
+        print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
+        print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
+
+    except STLError as ex_error:
+        print_error(str(ex_error))
+        sys.exit(1)
+
+    finally:
+        client.disconnect()
+
+
+
+def print_error(msg):
+    """Print error message on stderr.
+
+    :param msg: Error message to print.
+    :type msg: string
+    :return: nothing
+    """
+
+    sys.stderr.write(msg+'\n')
+
+
+def main():
+    """Main function."""
+
+    stop_all_traffic_streams()
+
+if __name__ == "__main__":
+    main()
index 97ccc97..5a03273 100755 (executable)
@@ -41,11 +41,12 @@ Functionality:
 
 """
 
 
 """
 
+import argparse
 import json
 import socket
 import string
 import struct
 import json
 import socket
 import string
 import struct
-import sys, getopt
+import sys
 
 sys.path.insert(0, "/opt/trex-core-2.00/scripts/automation/"+\
                    "trex_control_plane/stl/")
 
 sys.path.insert(0, "/opt/trex-core-2.00/scripts/automation/"+\
                    "trex_control_plane/stl/")
@@ -216,19 +217,21 @@ def create_packets_v6(traffic_options, frame_size=78):
     return(pkt_a, pkt_b)
 
 
     return(pkt_a, pkt_b)
 
 
-def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps", warmup_time=5):
+def simple_burst(pkt_a, pkt_b, duration, rate, warmup_time, async_start):
     """Run the traffic with specific parameters.
 
     :param pkt_a: Base packet for stream 1.
     :param pkt_b: Base packet for stream 2.
     """Run the traffic with specific parameters.
 
     :param pkt_a: Base packet for stream 1.
     :param pkt_b: Base packet for stream 2.
-    :param duration: Duration of traffic run in seconds.
+    :param duration: Duration of traffic run in seconds (-1=infinite).
     :param rate: Rate of traffic run [percentage, pps, bps].
     :param warmup_time: Warm up duration.
     :param rate: Rate of traffic run [percentage, pps, bps].
     :param warmup_time: Warm up duration.
+    :async_start: Start the traffic and exit
     :type pkt_a: STLPktBuilder
     :type pkt_b: STLPktBuilder
     :type duration: int
     :type rate: string
     :type warmup_time: int
     :type pkt_a: STLPktBuilder
     :type pkt_b: STLPktBuilder
     :type duration: int
     :type rate: string
     :type warmup_time: int
+    :type async_start: bool
     :return: nothing
     """
 
     :return: nothing
     """
 
@@ -264,7 +267,7 @@ def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps", warmup_time=5):
         client.add_streams(stream2, ports=[1])
 
         #warmup phase
         client.add_streams(stream2, ports=[1])
 
         #warmup phase
-        if warmup_time is not None:
+        if warmup_time > 0:
             client.clear_stats()
             client.start(ports=[0, 1], mult=rate, duration=warmup_time)
             client.wait_on_traffic(ports=[0, 1], timeout=(warmup_time+30))
             client.clear_stats()
             client.start(ports=[0, 1], mult=rate, duration=warmup_time)
             client.wait_on_traffic(ports=[0, 1], timeout=(warmup_time+30))
@@ -290,54 +293,37 @@ def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps", warmup_time=5):
         # choose rate and start traffic
         client.start(ports=[0, 1], mult=rate, duration=duration)
 
         # choose rate and start traffic
         client.start(ports=[0, 1], mult=rate, duration=duration)
 
-        # block until done
-        client.wait_on_traffic(ports=[0, 1], timeout=(duration+30))
+        if not async_start:
+            # block until done
+            client.wait_on_traffic(ports=[0, 1], timeout=(duration+30))
 
 
-        # read the stats after the test
-        stats = client.get_stats()
+            # read the stats after the test
+            stats = client.get_stats()
 
 
-        print "#####statistics#####"
-        print json.dumps(stats, indent=4,
-                         separators=(',', ': '), sort_keys=True)
+            print "#####statistics#####"
+            print json.dumps(stats, indent=4,
+                             separators=(',', ': '), sort_keys=True)
 
 
-        lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
-        lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
+            lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
+            lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
 
 
-        total_sent = stats[0]["opackets"] + stats[1]["opackets"]
-        total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
+            total_sent = stats[0]["opackets"] + stats[1]["opackets"]
+            total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
 
 
-        print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
-        print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
+            print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
+            print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
 
     except STLError as ex_error:
         print_error(str(ex_error))
         sys.exit(1)
 
     finally:
 
     except STLError as ex_error:
         print_error(str(ex_error))
         sys.exit(1)
 
     finally:
-        client.disconnect()
-        print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\
-              .format(rate, total_rcvd, total_sent, lost_a+lost_b)
-
-
-def print_help():
-    """Print help on stdout."""
-
-    print "args: [-h] -d <duration> -s <size of frame in bytes>"+\
-    " [-r] <traffic rate with unit: %, mpps> "+\
-    " [-6] Use of ipv6 "+\
-    "--p1_src_mac <port1_src_mac> "+\
-    "--p1_dst_mac <port1_dst_mac> "+\
-    "--p1_src_start_ip <port1_src_start_ip> "+\
-    "--p1_src_end_ip <port1_src_end_ip> "+\
-    "--p1_dst_start_ip <port1_dst_start_ip> "+\
-    "--p1_dst_end_ip <port1_dst_end_ip> "+\
-    "--p2_src_mac <port2_src_mac> "+\
-    "--p2_dst_mac <port2_dst_mac> "+\
-    "--p2_src_start_ip <port2_src_start_ip> "+\
-    "--p2_src_end_ip <port2_src_end_ip> "+\
-    "--p2_dst_start_ip <port2_dst_start_ip> "+\
-    "--p2_dst_end_ip <port2_dst_end_ip>"
-
+        if async_start:
+            client.disconnect(stop_traffic=False, release_ports=True)
+        else:
+            client.disconnect()
+            print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\
+                .format(rate, total_rcvd, total_sent, lost_a+lost_b)
 
 def print_error(msg):
     """Print error message on stderr.
 
 def print_error(msg):
     """Print error message on stderr.
@@ -350,53 +336,69 @@ def print_error(msg):
     sys.stderr.write(msg+'\n')
 
 
     sys.stderr.write(msg+'\n')
 
 
-def main(argv):
+def main():
     """Main function."""
 
     """Main function."""
 
-    _duration = 10
-    _frame_size = 64
-    _rate = '1mpps'
     _traffic_options = {}
     _traffic_options = {}
+    #default L3 profile is IPv4
     _use_ipv6 = False
     _use_ipv6 = False
-
-    try:
-        opts, _ = getopt.getopt(argv, "hd:s:r:6o:",
-                                ["help",
-                                 "p1_src_mac=",
-                                 "p1_dst_mac=",
-                                 "p1_src_start_ip=",
-                                 "p1_src_end_ip=",
-                                 "p1_dst_start_ip=",
-                                 "p1_dst_end_ip=",
-                                 "p2_src_mac=",
-                                 "p2_dst_mac=",
-                                 "p2_src_start_ip=",
-                                 "p2_src_end_ip=",
-                                 "p2_dst_start_ip=",
-                                 "p2_dst_end_ip="])
-    except getopt.GetoptError:
-        print_help()
-        sys.exit(1)
-    for opt, arg in opts:
-        if opt in ('-h', "--help"):
-            print_help()
-            sys.exit()
-        elif opt == '-d':
-            _duration = int(arg)
-        elif opt == '-s':
-            _frame_size = int(arg)
-        elif opt == '-r':
-            _rate = arg
-        elif opt == '-6':
-            _use_ipv6 = True
-        elif opt.startswith("--p"):
-            _traffic_options[opt[2:]] = arg
-
-    print _traffic_options
-    if len(_traffic_options) != 6:
-        print_error("Supported only: src_start_ip, src_end_ip, dst_start_ip")
-        print_help()
-        sys.exit(1)
+    #default warmup time is 5 seconds
+    _warmup_time = 5
+    #default behaviour of this script is sychronous
+    _async_call = False
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument("-d", "--duration", required=True, type=int,
+                        help="Duration of traffic run")
+    parser.add_argument("-s", "--frame_size", required=True, type=int,
+                        help="Size of a Frame without padding and IPG")
+    parser.add_argument("-r", "--rate", required=True,
+                        help="Traffic rate with included units (%, pps)")
+    parser.add_argument("-6", "--use_IPv6", action="store_true",
+                        help="Use IPv6 traffic profile instead of IPv4")
+    parser.add_argument("--async", action="store_true",
+                        help="Non-blocking call of the script")
+    parser.add_argument("-w", "--warmup_time", type=int,
+                        help="Traffic warmup time in seconds, 0 = disable")
+#    parser.add_argument("--p1_src_mac",
+#                        help="Port 1 source MAC address")
+#    parser.add_argument("--p1_dst_mac",
+#                        help="Port 1 destination MAC address")
+    parser.add_argument("--p1_src_start_ip", required=True,
+                        help="Port 1 source start IP address")
+    parser.add_argument("--p1_src_end_ip", required=True,
+                        help="Port 1 source end IP address")
+    parser.add_argument("--p1_dst_start_ip", required=True,
+                        help="Port 1 destination start IP address")
+#    parser.add_argument("--p1_dst_end_ip",
+#                        help="Port 1 destination end IP address")
+#    parser.add_argument("--p2_src_mac",
+#                        help="Port 2 source MAC address")
+#    parser.add_argument("--p2_dst_mac",
+#                        help="Port 2 destination MAC address")
+    parser.add_argument("--p2_src_start_ip", required=True,
+                        help="Port 2 source start IP address")
+    parser.add_argument("--p2_src_end_ip", required=True,
+                        help="Port 2 source end IP address")
+    parser.add_argument("--p2_dst_start_ip", required=True,
+                        help="Port 2 destination start IP address")
+#    parser.add_argument("--p2_dst_end_ip",
+#                        help="Port 2 destination end IP address")
+
+    args = parser.parse_args()
+
+    _duration = args.duration
+    _frame_size = args.frame_size
+    _rate = args.rate
+    _use_ipv6 = args.use_IPv6
+    _async_call = args.async
+
+    if args.warmup_time is not None:
+        _warmup_time = args.warmup_time
+
+    for attr in [a for a in dir(args) if a.startswith('p')]:
+        if getattr(args, attr) is not None:
+            _traffic_options[attr] = getattr(args, attr)
 
     if _use_ipv6:
         pkt_a, pkt_b = create_packets_v6(_traffic_options,
 
     if _use_ipv6:
         pkt_a, pkt_b = create_packets_v6(_traffic_options,
@@ -405,7 +407,7 @@ def main(argv):
         pkt_a, pkt_b = create_packets(_traffic_options,
                                       frame_size=_frame_size)
 
         pkt_a, pkt_b = create_packets(_traffic_options,
                                       frame_size=_frame_size)
 
-    simple_burst(pkt_a, pkt_b, duration=_duration, rate=_rate)
+    simple_burst(pkt_a, pkt_b, _duration, _rate, _warmup_time, _async_call)
 
 if __name__ == "__main__":
 
 if __name__ == "__main__":
-    main(sys.argv[1:])
+    sys.exit(main())