trex: Add support for burst traffic type 71/52971/3
authorMartin Klozik <martinx.klozik@intel.com>
Wed, 28 Feb 2018 14:34:23 +0000 (06:34 -0800)
committerMartin Klozik <martinx.klozik@intel.com>
Thu, 22 Mar 2018 05:43:56 +0000 (05:43 +0000)
Support for burst traffic type was added into T-Rex. This
traffic type is useful for tests, where a limited number
of frames should be sent through DUT.

JIRA: VSPERF-562

Change-Id: I03b7150e66a0210cce91b20c751b8624c16f951b
Signed-off-by: Martin Klozik <martinx.klozik@intel.com>
Reviewed-by: Al Morton <acmorton@att.com>
Reviewed-by: Christian Trautman <ctrautma@redhat.com>
Reviewed-by: Sridhar Rao <sridhar.rao@spirent.com>
Reviewed-by: Richard Elias <richardx.elias@intel.com>
15 files changed:
conf/01_testcases.conf
conf/03_traffic.conf
conf/integration/01_testcases.conf
core/traffic_controller_rfc2544.py
docs/testing/developer/devguide/design/trafficgen_integration_guide.rst
docs/testing/developer/devguide/design/vswitchperf_design.rst
docs/testing/user/configguide/trafficgen.rst
tools/pkt_gen/dummy/dummy.py
tools/pkt_gen/ixia/ixia.py
tools/pkt_gen/ixnet/ixnet.py
tools/pkt_gen/moongen/moongen.py
tools/pkt_gen/testcenter/testcenter.py
tools/pkt_gen/trafficgen/trafficgen.py
tools/pkt_gen/trex/trex.py
tools/pkt_gen/xena/xena.py

index bd5ba9e..03cf78d 100755 (executable)
@@ -243,6 +243,18 @@ PERFORMANCE_TESTS = [
             },
         },
     },
+    {
+        "Name": "phy2phy_burst",
+        "Deployment": "p2p",
+        "Description": "Phy2Phy single burst of 1000 frames at 100% frame rate",
+        "Parameters" : {
+            "TRAFFIC" : {
+                "traffic_type" : "burst",
+                "frame_rate" : 100,
+                "burst_size" : 1000,
+            },
+        },
+    },
     {
         "Name": "pvp_cont",
         "Deployment": "pvp",
index 8aff2e3..288278f 100644 (file)
@@ -23,8 +23,8 @@ LOG_FILE_TRAFFIC_GEN = 'traffic-gen.log'
 # Detailed description of TRAFFIC dictionary items follows:
 #
 #    'traffic_type'  - One of the supported traffic types.
-#                      E.g. rfc2544_throughput, rfc2544_back2back
-#                      or rfc2544_continuous
+#                      E.g. rfc2544_throughput, rfc2544_back2back,
+#                      rfc2544_continuous or burst
 #                      Data type: str
 #                      Default value: "rfc2544_throughput".
 #    'bidir'         - Specifies if generated traffic will be full-duplex (True)
@@ -36,6 +36,12 @@ LOG_FILE_TRAFFIC_GEN = 'traffic-gen.log'
 #                      continuous stream tests.
 #                      Data type: int
 #                      Default value: 100.
+#    'burst_size'    - Defines a number of frames in the single burst, which is sent
+#                      by burst traffic type. Burst size is applied for each direction,
+#                      i.e. the total number of tx frames will be 2*burst_size in case of
+#                      bidirectional traffic.
+#                      Data type: int
+#                      Default value: 100.
 #    'multistream'   - Defines number of flows simulated by traffic generator.
 #                      Value 0 disables multistream feature
 #                      Data type: int
@@ -174,6 +180,7 @@ LOG_FILE_TRAFFIC_GEN = 'traffic-gen.log'
 TRAFFIC = {
     'traffic_type' : 'rfc2544_throughput',
     'frame_rate' : 100,
+    'burst_size' : 100,
     'bidir' : 'True',  # will be passed as string in title format to tgen
     'multistream' : 0,
     'stream_type' : 'L4',
index bb2809b..8c013d2 100644 (file)
@@ -1129,10 +1129,11 @@ INTEGRATION_TESTS += [
         "vSwitch" : "OvsDpdkVhost", # works also for Vanilla OVS
         "Parameters" : {
             "TRAFFICGEN" : "Trex",
-            "TRAFFICGEN_DURATION" : 5,
+            "TRAFFICGEN_TREX_LEARNING_MODE" : True,
             "TRAFFIC" : {
-                "traffic_type" : "rfc2544_continuous",
+                "traffic_type" : "burst",
                 "frame_rate" : 100,
+                "burst_size" : 5,
                 # enable capture of five RX frames
                 'capture': {
                     'enabled': True,
index 488dde6..cdd001e 100644 (file)
@@ -62,6 +62,9 @@ class TrafficControllerRFC2544(TrafficController, IResults):
             elif traffic['traffic_type'] == 'rfc2544_continuous':
                 result = self._traffic_gen_class.send_cont_traffic(
                     traffic, duration=self._duration)
+            elif traffic['traffic_type'] == 'burst':
+                result = self._traffic_gen_class.send_burst_traffic(
+                    traffic, duration=self._duration)
             elif traffic['traffic_type'] == 'rfc2544_throughput':
                 result = self._traffic_gen_class.send_rfc2544_throughput(
                     traffic, tests=self._tests, duration=self._duration, lossrate=self._lossrate)
index c88b80e..0298a47 100644 (file)
@@ -200,12 +200,16 @@ functions:
       which are discussed in detail at :ref:`integration-tests` userguide.
 
       * param **traffic_type**: One of the supported traffic types,
-        e.g. **rfc2544_throughput**, **rfc2544_continuous**
-        or **rfc2544_back2back**.
-      * param **frame_rate**: Defines desired percentage of frame
-        rate used during continuous stream tests.
+        e.g. **rfc2544_throughput**, **rfc2544_continuous**,
+        **rfc2544_back2back** or **burst**.
       * param **bidir**: Specifies if generated traffic will be full-duplex
         (true) or half-duplex (false).
+      * param **frame_rate**: Defines desired percentage of frame
+        rate used during continuous stream tests.
+      * param **burst_size**: Defines a number of frames in the single burst,
+        which is sent by burst traffic type. Burst size is applied for each
+        direction, i.e. the total number of tx frames will be 2*burst_size
+        in case of bidirectional traffic.
       * param **multistream**: Defines number of flows simulated by traffic
         generator. Value 0 disables MultiStream feature.
       * param **stream_type**: Stream Type defines ISO OSI network layer
index 96ffcf6..9317d87 100644 (file)
@@ -291,8 +291,8 @@ Detailed description of ``TRAFFIC`` dictionary items follows:
 .. code-block:: console
 
     'traffic_type'  - One of the supported traffic types.
-                      E.g. rfc2544_throughput, rfc2544_back2back
-                      or rfc2544_continuous
+                      E.g. rfc2544_throughput, rfc2544_back2back,
+                      rfc2544_continuous or burst
                       Data type: str
                       Default value: "rfc2544_throughput".
     'bidir'         - Specifies if generated traffic will be full-duplex (True)
@@ -304,6 +304,12 @@ Detailed description of ``TRAFFIC`` dictionary items follows:
                       continuous stream tests.
                       Data type: int
                       Default value: 100.
+    'burst_size'    - Defines a number of frames in the single burst, which is sent
+                      by burst traffic type. Burst size is applied for each direction,
+                      i.e. the total number of tx frames will be 2*burst_size in case of
+                      bidirectional traffic.
+                      Data type: int
+                      Default value: 100.
     'multistream'   - Defines number of flows simulated by traffic generator.
                       Value 0 disables multistream feature
                       Data type: int
@@ -786,7 +792,7 @@ ITrafficGenerator
       connect()
       disconnect()
 
-      send_burst_traffic(traffic, numpkts, time, framerate)
+      send_burst_traffic(traffic, time)
 
       send_cont_traffic(traffic, time, framerate)
       start_cont_traffic(traffic, time, framerate)
index 52b1b4a..c174af0 100644 (file)
@@ -39,6 +39,7 @@ and is configured as follows:
     TRAFFIC = {
         'traffic_type' : 'rfc2544_throughput',
         'frame_rate' : 100,
+        'burst_size' : 100,
         'bidir' : 'True',  # will be passed as string in title format to tgen
         'multistream' : 0,
         'stream_type' : 'L4',
@@ -857,6 +858,21 @@ place. This can be adjusted with the following configurations:
     TRAFFICGEN_TREX_LEARNING_MODE=True
     TRAFFICGEN_TREX_LEARNING_DURATION=5
 
+Latency measurements have impact on T-Rex performance. Thus vswitchperf uses a separate
+latency stream for each direction with limited speed. This workaround is used for RFC2544
+**Throughput** and **Continuous** traffic types. In case of **Burst** traffic type,
+the latency statistics are measured for all frames in the burst. Collection of latency
+statistics is driven by configuration option ``TRAFFICGEN_TREX_LATENCY_PPS`` as follows:
+
+    * value ``0`` - disables latency measurements
+    * non zero integer value - enables latency measurements; In case of Throughput
+        and Continuous traffic types, it specifies a speed of latency specific stream
+        in PPS. In case of burst traffic type, it enables latency measurements for all frames.
+
+.. code-block:: console
+
+    TRAFFICGEN_TREX_LATENCY_PPS = 1000
+
 SR-IOV and Multistream layer 2
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 T-Rex by default only accepts packets on the receive side if the destination mac matches the
index 3dc5448..b9aaeb8 100755 (executable)
@@ -25,6 +25,7 @@ own.
 
 import json
 
+from collections import OrderedDict
 from conf import settings
 from conf import merge_spec
 from tools.pkt_gen import trafficgen
@@ -108,41 +109,41 @@ class Dummy(trafficgen.ITrafficGenerator):
         """
         pass
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+    def send_burst_traffic(self, traffic=None, duration=20):
         """
         Send a burst of traffic.
         """
         traffic_ = self.traffic_defaults.copy()
-        result = {}
+        result = OrderedDict()
 
         if traffic:
             traffic_ = merge_spec(traffic_, traffic)
 
         results = get_user_traffic(
             'burst',
-            '%dpkts, %dmS' % (numpkts, duration),
+            '%dpkts, %dmS' % (traffic['burst_size'], duration),
             traffic_,
             ('frames rx', 'payload errors', 'sequence errors'))
 
         # builds results by using user-supplied values where possible
         # and guessing remainder using available info
-        result[ResultsConstants.TX_FRAMES] = numpkts
+        result[ResultsConstants.TX_FRAMES] = traffic['burst_size']
         result[ResultsConstants.RX_FRAMES] = results[0]
         result[ResultsConstants.TX_BYTES] = traffic_['l2']['framesize'] \
-                                            * numpkts
+                                            * traffic['burst_size']
         result[ResultsConstants.RX_BYTES] = traffic_['l2']['framesize'] \
                                             * results[0]
         result[ResultsConstants.PAYLOAD_ERR] = results[1]
         result[ResultsConstants.SEQ_ERR] = results[2]
 
-        return results
+        return result
 
     def send_cont_traffic(self, traffic=None, duration=30):
         """
         Send a continuous flow of traffic.
         """
         traffic_ = self.traffic_defaults.copy()
-        result = {}
+        result = OrderedDict()
 
         if traffic:
             traffic_ = merge_spec(traffic_, traffic)
@@ -179,7 +180,7 @@ class Dummy(trafficgen.ITrafficGenerator):
         Send traffic per RFC2544 throughput test specifications.
         """
         traffic_ = self.traffic_defaults.copy()
-        result = {}
+        result = OrderedDict()
 
         if traffic:
             traffic_ = merge_spec(traffic_, traffic)
@@ -216,7 +217,7 @@ class Dummy(trafficgen.ITrafficGenerator):
         Send traffic per RFC2544 back2back test specifications.
         """
         traffic_ = self.traffic_defaults.copy()
-        result = {}
+        result = OrderedDict()
 
         if traffic:
             traffic_ = merge_spec(traffic_, traffic)
index d4ca56f..7dccfd5 100755 (executable)
@@ -242,11 +242,11 @@ class Ixia(trafficgen.ITrafficGenerator):
 
         return result
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+    def send_burst_traffic(self, traffic=None, duration=20):
         """See ITrafficGenerator for description
         """
         flow = {
-            'numpkts': numpkts,
+            'numpkts': traffic['burst_size'],
             'duration': duration,
             'type': 'stopStream',
             'framerate': traffic['frame_rate'],
index d1ba909..bdf7882 100755 (executable)
@@ -528,7 +528,7 @@ class IxNet(trafficgen.ITrafficGenerator):
 
         return parse_ixnet_rfc_results(parse_result_string(output[0]))
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+    def send_burst_traffic(self, traffic=None, duration=20):
         return NotImplementedError('IxNet does not implement send_burst_traffic')
 
 if __name__ == '__main__':
index 570720e..1f332e8 100644 (file)
@@ -240,14 +240,13 @@ class Moongen(ITrafficGenerator):
         """
         self._logger.info("MOONGEN: In moongen disconnect method")
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+    def send_burst_traffic(self, traffic=None, duration=20):
         """Send a burst of traffic.
 
-        Send a ``numpkts`` packets of traffic, using ``traffic``
+        Send a ``traffic['burst_traffic']`` packets of traffic, using ``traffic``
         configuration, with a timeout of ``time``.
 
         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
-        :param numpkts: Number of packets to send
         :param duration: Time to wait to receive packets
 
         :returns: dictionary of strings with following data:
index 9980ae7..858e2d7 100644 (file)
@@ -182,7 +182,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
         """
         pass
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+    def send_burst_traffic(self, traffic=None, duration=20):
         """
         Do nothing.
         """
index 262df71..a6f7edc 100755 (executable)
@@ -81,15 +81,14 @@ class ITrafficGenerator(object):
         """
         raise NotImplementedError('Please call an implementation.')
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+    def send_burst_traffic(self, traffic=None, duration=20):
         """Send a burst of traffic.
 
-        Send a ``numpkts`` packets of traffic, using ``traffic``
+        Send a ``traffic['burst_size']`` packets of traffic, using ``traffic``
         configuration, for ``duration`` seconds.
 
         Attributes:
         :param traffic: Detailed "traffic" spec, see design docs for details
-        :param numpkts: Number of packets to send
         :param duration: Time to wait to receive packets
 
         :returns: dictionary of strings with following data:
index e0ce4c4..d3a7ea8 100644 (file)
@@ -248,22 +248,48 @@ class Trex(ITrafficGenerator):
             pkt_a = STLPktBuilder(pkt=base_pkt_a / payload_a)
             pkt_b = STLPktBuilder(pkt=base_pkt_b / payload_b)
 
-        stream_1 = STLStream(packet=pkt_a,
-                             name='stream_1',
-                             mode=STLTXCont(percentage=traffic['frame_rate']))
-        stream_2 = STLStream(packet=pkt_b,
-                             name='stream_2',
-                             mode=STLTXCont(percentage=traffic['frame_rate']))
         lat_pps = settings.getValue('TRAFFICGEN_TREX_LATENCY_PPS')
-        if lat_pps > 0:
-            stream_1_lat = STLStream(packet=pkt_a,
+        if traffic['traffic_type'] == 'burst':
+            if lat_pps > 0:
+                # latency statistics are requested; in case of frame burst we can enable
+                # statistics for all frames
+                stream_1 = STLStream(packet=pkt_a,
                                      flow_stats=STLFlowLatencyStats(pg_id=0),
-                                     name='stream_1_lat',
-                                     mode=STLTXCont(pps=lat_pps))
-            stream_2_lat = STLStream(packet=pkt_b,
+                                     name='stream_1',
+                                     mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
+                                                           total_pkts=traffic['burst_size']))
+                stream_2 = STLStream(packet=pkt_b,
                                      flow_stats=STLFlowLatencyStats(pg_id=1),
-                                     name='stream_2_lat',
-                                     mode=STLTXCont(pps=lat_pps))
+                                     name='stream_2',
+                                     mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
+                                                           total_pkts=traffic['burst_size']))
+            else:
+                stream_1 = STLStream(packet=pkt_a,
+                                     name='stream_1',
+                                     mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
+                                                           total_pkts=traffic['burst_size']))
+                stream_2 = STLStream(packet=pkt_b,
+                                     name='stream_2',
+                                     mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
+                                                           total_pkts=traffic['burst_size']))
+        else:
+            stream_1 = STLStream(packet=pkt_a,
+                                 name='stream_1',
+                                 mode=STLTXCont(percentage=traffic['frame_rate']))
+            stream_2 = STLStream(packet=pkt_b,
+                                 name='stream_2',
+                                 mode=STLTXCont(percentage=traffic['frame_rate']))
+            # workaround for latency statistics, which can't be enabled for streams
+            # with high framerate due to the huge performance impact
+            if lat_pps > 0:
+                stream_1_lat = STLStream(packet=pkt_a,
+                                         flow_stats=STLFlowLatencyStats(pg_id=0),
+                                         name='stream_1_lat',
+                                         mode=STLTXCont(pps=lat_pps))
+                stream_2_lat = STLStream(packet=pkt_b,
+                                         flow_stats=STLFlowLatencyStats(pg_id=1),
+                                         name='stream_2_lat',
+                                         mode=STLTXCont(pps=lat_pps))
 
         return (stream_1, stream_2, stream_1_lat, stream_2_lat)
 
@@ -293,7 +319,7 @@ class Trex(ITrafficGenerator):
             # since we can only control both ports at once take the lower of the two
             max_speed = min(max_speed_1, max_speed_2)
         gbps_speed = (max_speed / 1000) * (float(traffic['frame_rate']) / 100.0)
-        self._logger.debug('Starting traffic at %s Gpbs speed', gbps_speed)
+        self._logger.debug('Starting traffic at %s Gbps speed', gbps_speed)
 
         # for SR-IOV
         if settings.getValue('TRAFFICGEN_TREX_PROMISCUOUS'):
@@ -382,20 +408,29 @@ class Trex(ITrafficGenerator):
             result[ResultsConstants.FRAME_LOSS_PERCENT] = 100
 
         if settings.getValue('TRAFFICGEN_TREX_LATENCY_PPS') > 0 and stats['latency']:
-            result[ResultsConstants.MIN_LATENCY_NS] = (
-                '{:.3f}'.format(
-                    (float(min(stats["latency"][0]["latency"]["total_min"],
-                               stats["latency"][1]["latency"]["total_min"])))))
-
-            result[ResultsConstants.MAX_LATENCY_NS] = (
-                '{:.3f}'.format(
-                    (float(max(stats["latency"][0]["latency"]["total_max"],
-                               stats["latency"][1]["latency"]["total_max"])))))
-
-            result[ResultsConstants.AVG_LATENCY_NS] = (
-                '{:.3f}'.format(
-                    float((stats["latency"][0]["latency"]["average"]+
-                           stats["latency"][1]["latency"]["average"])/2)))
+            try:
+                result[ResultsConstants.MIN_LATENCY_NS] = (
+                    '{:.3f}'.format(
+                        (float(min(stats["latency"][0]["latency"]["total_min"],
+                                   stats["latency"][1]["latency"]["total_min"])))))
+            except TypeError:
+                result[ResultsConstants.MIN_LATENCY_NS] = 'Unknown'
+
+            try:
+                result[ResultsConstants.MAX_LATENCY_NS] = (
+                    '{:.3f}'.format(
+                        (float(max(stats["latency"][0]["latency"]["total_max"],
+                                   stats["latency"][1]["latency"]["total_max"])))))
+            except TypeError:
+                result[ResultsConstants.MAX_LATENCY_NS] = 'Unknown'
+
+            try:
+                result[ResultsConstants.AVG_LATENCY_NS] = (
+                    '{:.3f}'.format(
+                        float((stats["latency"][0]["latency"]["average"]+
+                               stats["latency"][1]["latency"]["average"])/2)))
+            except TypeError:
+                result[ResultsConstants.AVG_LATENCY_NS] = 'Unknown'
 
         else:
             result[ResultsConstants.MIN_LATENCY_NS] = 'Unknown'
@@ -568,9 +603,25 @@ class Trex(ITrafficGenerator):
         raise NotImplementedError(
             'Trex wait rfc2544 throughput not implemented')
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=5):
-        raise NotImplementedError(
-            'Trex send burst traffic not implemented')
+    def send_burst_traffic(self, traffic=None, duration=20):
+        """See ITrafficGenerator for description
+        """
+        self._logger.info("In Trex send_burst_traffic method")
+        self._params.clear()
+
+        self._params['traffic'] = self.traffic_defaults.copy()
+        if traffic:
+            self._params['traffic'] = merge_spec(
+                self._params['traffic'], traffic)
+
+        if settings.getValue('TRAFFICGEN_TREX_LEARNING_MODE'):
+            self.learning_packets(traffic)
+        self._logger.info("T-Rex sending traffic")
+        stats = self.generate_traffic(traffic, duration)
+
+        time.sleep(3)  # allow packets to complete before reading stats
+
+        return self.calculate_results(stats)
 
     def send_rfc2544_back2back(self, traffic=None, tests=1, duration=30,
                                lossrate=0.0):
index 19b44f0..458ecd3 100755 (executable)
@@ -568,7 +568,7 @@ class Xena(ITrafficGenerator):
             self._xsocket.disconnect()
             self._xsocket = None
 
-    def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+    def send_burst_traffic(self, traffic=None, duration=20):
         """Send a burst of traffic.
 
         See ITrafficGenerator for description
@@ -579,7 +579,7 @@ class Xena(ITrafficGenerator):
         if traffic:
             self._params['traffic'] = merge_spec(self._params['traffic'],
                                                  traffic)
-        self._start_traffic_api(numpkts)
+        self._start_traffic_api(traffic['burst_size'])
         return self._stop_api_traffic()
 
     def send_cont_traffic(self, traffic=None, duration=20):