From e9ff0fdf355d26d0c171c6c1137c4beb12561233 Mon Sep 17 00:00:00 2001
From: Martin Klozik <martinx.klozik@intel.com>
Date: Wed, 28 Feb 2018 06:34:23 -0800
Subject: trex: Add support for burst traffic type

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>
---
 tools/pkt_gen/dummy/dummy.py           |  19 +++---
 tools/pkt_gen/ixia/ixia.py             |   4 +-
 tools/pkt_gen/ixnet/ixnet.py           |   2 +-
 tools/pkt_gen/moongen/moongen.py       |   5 +-
 tools/pkt_gen/testcenter/testcenter.py |   2 +-
 tools/pkt_gen/trafficgen/trafficgen.py |   5 +-
 tools/pkt_gen/trex/trex.py             | 113 ++++++++++++++++++++++++---------
 tools/pkt_gen/xena/xena.py             |   4 +-
 8 files changed, 102 insertions(+), 52 deletions(-)

(limited to 'tools/pkt_gen')

diff --git a/tools/pkt_gen/dummy/dummy.py b/tools/pkt_gen/dummy/dummy.py
index 3dc5448e..b9aaeb8b 100755
--- a/tools/pkt_gen/dummy/dummy.py
+++ b/tools/pkt_gen/dummy/dummy.py
@@ -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)
diff --git a/tools/pkt_gen/ixia/ixia.py b/tools/pkt_gen/ixia/ixia.py
index d4ca56f2..7dccfd54 100755
--- a/tools/pkt_gen/ixia/ixia.py
+++ b/tools/pkt_gen/ixia/ixia.py
@@ -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'],
diff --git a/tools/pkt_gen/ixnet/ixnet.py b/tools/pkt_gen/ixnet/ixnet.py
index d1ba9096..bdf78828 100755
--- a/tools/pkt_gen/ixnet/ixnet.py
+++ b/tools/pkt_gen/ixnet/ixnet.py
@@ -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__':
diff --git a/tools/pkt_gen/moongen/moongen.py b/tools/pkt_gen/moongen/moongen.py
index 570720e8..1f332e87 100644
--- a/tools/pkt_gen/moongen/moongen.py
+++ b/tools/pkt_gen/moongen/moongen.py
@@ -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:
diff --git a/tools/pkt_gen/testcenter/testcenter.py b/tools/pkt_gen/testcenter/testcenter.py
index 9980ae7c..858e2d73 100644
--- a/tools/pkt_gen/testcenter/testcenter.py
+++ b/tools/pkt_gen/testcenter/testcenter.py
@@ -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.
         """
diff --git a/tools/pkt_gen/trafficgen/trafficgen.py b/tools/pkt_gen/trafficgen/trafficgen.py
index 262df71d..a6f7edcc 100755
--- a/tools/pkt_gen/trafficgen/trafficgen.py
+++ b/tools/pkt_gen/trafficgen/trafficgen.py
@@ -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:
diff --git a/tools/pkt_gen/trex/trex.py b/tools/pkt_gen/trex/trex.py
index e0ce4c48..d3a7ea89 100644
--- a/tools/pkt_gen/trex/trex.py
+++ b/tools/pkt_gen/trex/trex.py
@@ -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):
diff --git a/tools/pkt_gen/xena/xena.py b/tools/pkt_gen/xena/xena.py
index 19b44f0b..458ecd3e 100755
--- a/tools/pkt_gen/xena/xena.py
+++ b/tools/pkt_gen/xena/xena.py
@@ -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):
-- 
cgit