From e9ff0fdf355d26d0c171c6c1137c4beb12561233 Mon Sep 17 00:00:00 2001 From: Martin Klozik 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 Reviewed-by: Al Morton Reviewed-by: Christian Trautman Reviewed-by: Sridhar Rao Reviewed-by: Richard Elias --- 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') 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 1.2.3-korg