summaryrefslogtreecommitdiffstats
path: root/tools/pkt_gen
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pkt_gen')
-rwxr-xr-xtools/pkt_gen/ixia/ixia.py8
-rwxr-xr-xtools/pkt_gen/ixnet/ixnet.py8
-rw-r--r--tools/pkt_gen/trex/trex.py205
3 files changed, 177 insertions, 44 deletions
diff --git a/tools/pkt_gen/ixia/ixia.py b/tools/pkt_gen/ixia/ixia.py
index e768be06..d4ca56f2 100755
--- a/tools/pkt_gen/ixia/ixia.py
+++ b/tools/pkt_gen/ixia/ixia.py
@@ -111,6 +111,11 @@ def _build_set_cmds(values, prefix='dict set'):
yield subkey
continue
+ if isinstance(value, list):
+ value = '{{{}}}'.format(' '.join(str(x) for x in value))
+ yield ' '.join([prefix, 'set', key, value]).strip()
+ continue
+
# tcl doesn't recognise the strings "True" or "False", only "1"
# or "0". Special case to convert them
if isinstance(value, bool):
@@ -118,6 +123,9 @@ def _build_set_cmds(values, prefix='dict set'):
else:
value = str(value)
+ if isinstance(value, str) and not value:
+ value = '{}'
+
if prefix:
yield ' '.join([prefix, key, value]).strip()
else:
diff --git a/tools/pkt_gen/ixnet/ixnet.py b/tools/pkt_gen/ixnet/ixnet.py
index b8fb1879..d1ba9096 100755
--- a/tools/pkt_gen/ixnet/ixnet.py
+++ b/tools/pkt_gen/ixnet/ixnet.py
@@ -127,6 +127,11 @@ def _build_set_cmds(values, prefix='dict set'):
yield subkey
continue
+ if isinstance(value, list):
+ value = '{{{}}}'.format(' '.join(str(x) for x in value))
+ yield ' '.join([prefix, 'set', key, value]).strip()
+ continue
+
# tcl doesn't recognise the strings "True" or "False", only "1"
# or "0". Special case to convert them
if isinstance(value, bool):
@@ -134,6 +139,9 @@ def _build_set_cmds(values, prefix='dict set'):
else:
value = str(value)
+ if isinstance(value, str) and not value:
+ value = '{}'
+
if prefix:
yield ' '.join([prefix, key, value]).strip()
else:
diff --git a/tools/pkt_gen/trex/trex.py b/tools/pkt_gen/trex/trex.py
index acdaf287..cfe54b78 100644
--- a/tools/pkt_gen/trex/trex.py
+++ b/tools/pkt_gen/trex/trex.py
@@ -19,6 +19,8 @@ Trex Traffic Generator Model
import logging
import subprocess
import sys
+import time
+import os
from collections import OrderedDict
# pylint: disable=unused-import
import netaddr
@@ -81,6 +83,7 @@ class Trex(ITrafficGenerator):
settings.getValue('TRAFFICGEN_TREX_BASE_DIR'))
self._trex_user = settings.getValue('TRAFFICGEN_TREX_USER')
self._stlclient = None
+ self._verification_params = None
def connect(self):
'''Connect to Trex traffic generator
@@ -89,11 +92,11 @@ class Trex(ITrafficGenerator):
the configuration file
'''
self._stlclient = STLClient()
- self._logger.info("TREX: In Trex connect method...")
+ self._logger.info("T-Rex: In Trex connect method...")
if self._trex_host_ip_addr:
cmd_ping = "ping -c1 " + self._trex_host_ip_addr
else:
- raise RuntimeError('TREX: Trex host not defined')
+ raise RuntimeError('T-Rex: Trex host not defined')
ping = subprocess.Popen(cmd_ping, shell=True, stderr=subprocess.PIPE)
output, error = ping.communicate()
@@ -101,7 +104,7 @@ class Trex(ITrafficGenerator):
if ping.returncode:
self._logger.error(error)
self._logger.error(output)
- raise RuntimeError('TREX: Cannot ping Trex host at ' + \
+ raise RuntimeError('T-Rex: Cannot ping Trex host at ' + \
self._trex_host_ip_addr)
connect_trex = "ssh " + self._trex_user + \
@@ -120,13 +123,18 @@ class Trex(ITrafficGenerator):
self._logger.error(error)
self._logger.error(output)
raise RuntimeError(
- 'TREX: Cannot locate Trex program at %s within %s' \
+ 'T-Rex: Cannot locate Trex program at %s within %s' \
% (self._trex_host_ip_addr, self._trex_base_dir))
- self._stlclient = STLClient(username=self._trex_user, server=self._trex_host_ip_addr,
- verbose_level=0)
- self._stlclient.connect()
- self._logger.info("TREX: Trex host successfully found...")
+ try:
+ self._stlclient = STLClient(username=self._trex_user, server=self._trex_host_ip_addr,
+ verbose_level=0)
+ self._stlclient.connect()
+ except STLError:
+ raise RuntimeError('T-Rex: Cannot connect to T-Rex server. Please check if it is '
+ 'running and that firewall allows connection to TCP port 4501.')
+
+ self._logger.info("T-Rex: Trex host successfully found...")
def disconnect(self):
"""Disconnect from the traffic generator.
@@ -138,7 +146,7 @@ class Trex(ITrafficGenerator):
:returns: None
"""
- self._logger.info("TREX: In trex disconnect method")
+ self._logger.info("T-Rex: In trex disconnect method")
self._stlclient.disconnect(stop_traffic=True, release_ports=True)
@staticmethod
@@ -243,11 +251,16 @@ class Trex(ITrafficGenerator):
return (stream_1, stream_2, stream_1_lat, stream_2_lat)
- def generate_traffic(self, traffic, duration):
+ def generate_traffic(self, traffic, duration, disable_capture=False):
"""The method that generate a stream
"""
my_ports = [0, 1]
+
+ # initialize ports
self._stlclient.reset(my_ports)
+ self._stlclient.remove_all_captures()
+ self._stlclient.set_service_mode(ports=my_ports, enabled=False)
+
ports_info = self._stlclient.get_port_info(my_ports)
# for SR-IOV
if settings.getValue('TRAFFICGEN_TREX_PROMISCUOUS'):
@@ -262,10 +275,35 @@ class Trex(ITrafficGenerator):
self._stlclient.add_streams(stream_1_lat, ports=[0])
self._stlclient.add_streams(stream_2_lat, ports=[1])
+ # enable traffic capture if requested
+ pcap_id = {}
+ if traffic['capture']['enabled'] and not disable_capture:
+ for ports in ['tx_ports', 'rx_ports']:
+ if traffic['capture'][ports]:
+ pcap_dir = ports[:2]
+ self._logger.info("T-Rex starting %s traffic capture", pcap_dir.upper())
+ capture = {ports : traffic['capture'][ports],
+ 'limit' : traffic['capture']['count'],
+ 'bpf_filter' : traffic['capture']['filter']}
+ self._stlclient.set_service_mode(ports=traffic['capture'][ports], enabled=True)
+ pcap_id[pcap_dir] = self._stlclient.start_capture(**capture)
+
self._stlclient.clear_stats()
- self._stlclient.start(ports=[0, 1], force=True, duration=duration)
- self._stlclient.wait_on_traffic(ports=[0, 1])
+ self._stlclient.start(ports=my_ports, force=True, duration=duration)
+ self._stlclient.wait_on_traffic(ports=my_ports)
stats = self._stlclient.get_stats(sync_now=True)
+
+ # export captured data into pcap file if possible
+ if pcap_id:
+ for pcap_dir in pcap_id:
+ pcap_file = 'capture_{}.pcap'.format(pcap_dir)
+ self._stlclient.stop_capture(pcap_id[pcap_dir]['id'],
+ os.path.join(settings.getValue('RESULTS_PATH'), pcap_file))
+ stats['capture_{}'.format(pcap_dir)] = pcap_file
+ self._logger.info("T-Rex writing %s traffic capture into %s", pcap_dir.upper(), pcap_file)
+ # disable service mode for all ports used by Trex
+ self._stlclient.set_service_mode(ports=my_ports, enabled=False)
+
return stats
@staticmethod
@@ -323,8 +361,78 @@ class Trex(ITrafficGenerator):
result[ResultsConstants.MIN_LATENCY_NS] = 'Unknown'
result[ResultsConstants.MAX_LATENCY_NS] = 'Unknown'
result[ResultsConstants.AVG_LATENCY_NS] = 'Unknown'
+
+ if 'capture_tx' in stats:
+ result[ResultsConstants.CAPTURE_TX] = stats['capture_tx']
+ if 'capture_rx' in stats:
+ result[ResultsConstants.CAPTURE_RX] = stats['capture_rx']
return result
+ def learning_packets(self, traffic):
+ """
+ Send learning packets before testing
+ :param traffic: traffic structure as per send_cont_traffic guidelines
+ :return: None
+ """
+ self._logger.info("T-Rex sending learning packets")
+ learning_thresh_traffic = copy.deepcopy(traffic)
+ learning_thresh_traffic["frame_rate"] = 1
+ self.generate_traffic(learning_thresh_traffic,
+ settings.getValue("TRAFFICGEN_TREX_LEARNING_DURATION"),
+ disable_capture=True)
+ self._logger.info("T-Rex finished learning packets")
+ time.sleep(3) # allow packets to complete before starting test traffic
+
+ def run_trials(self, traffic, boundaries, duration, lossrate):
+ """
+ Run rfc2544 trial loop
+ :param traffic: traffic profile dictionary
+ :param boundaries: A dictionary of three keys left, right, center to dictate
+ the highest, lowest, and starting point of the binary search.
+ Values are percentages of line rates for each key.
+ :param duration: length in seconds for trials
+ :param lossrate: loweset loss rate percentage calculated from
+ comparision between received and sent packets
+ :return: passing stats as dictionary
+ """
+ threshold = settings.getValue('TRAFFICGEN_TREX_RFC2544_TPUT_THRESHOLD')
+ stats_ok = _EMPTY_STATS
+ new_params = copy.deepcopy(traffic)
+ iteration = 1
+ left = boundaries['left']
+ right = boundaries['right']
+ center = boundaries['center']
+ self._logger.info('Starting RFC2544 trials')
+ while (right - left) > threshold:
+ stats = self.generate_traffic(new_params, duration)
+ test_lossrate = ((stats["total"]["opackets"] - stats[
+ "total"]["ipackets"]) * 100) / stats["total"]["opackets"]
+ if stats["total"]["ipackets"] == 0:
+ self._logger.error('No packets recieved. Test failed')
+ return _EMPTY_STATS
+ if settings.getValue('TRAFFICGEN_TREX_VERIFICATION_MODE'):
+ if test_lossrate <= lossrate:
+ # save the last passing trial for verification
+ self._verification_params = copy.deepcopy(new_params)
+ self._logger.debug("Iteration: %s, frame rate: %s, throughput_rx_fps: %s, frame_loss_percent: %s",
+ iteration, "{:.3f}".format(new_params['frame_rate']), stats['total']['rx_pps'],
+ "{:.3f}".format(test_lossrate))
+ if test_lossrate == 0.0 and new_params['frame_rate'] == traffic['frame_rate']:
+ return copy.deepcopy(stats)
+ elif test_lossrate > lossrate:
+ right = center
+ center = (left + right) / 2
+ new_params = copy.deepcopy(traffic)
+ new_params['frame_rate'] = center
+ else:
+ stats_ok = copy.deepcopy(stats)
+ left = center
+ center = (left + right) / 2
+ new_params = copy.deepcopy(traffic)
+ new_params['frame_rate'] = center
+ iteration += 1
+ return stats_ok
+
def send_cont_traffic(self, traffic=None, duration=30):
"""See ITrafficGenerator for description
"""
@@ -336,6 +444,9 @@ class Trex(ITrafficGenerator):
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)
return self.calculate_results(stats)
@@ -356,45 +467,51 @@ class Trex(ITrafficGenerator):
"""
self._logger.info("In Trex send_rfc2544_throughput method")
self._params.clear()
- threshold = settings.getValue('TRAFFICGEN_TREX_RFC2544_TPUT_THRESHOLD')
- test_lossrate = 0
- left = 0
- iteration = 1
- stats_ok = _EMPTY_STATS
self._params['traffic'] = self.traffic_defaults.copy()
if traffic:
self._params['traffic'] = merge_spec(
self._params['traffic'], traffic)
- new_params = copy.deepcopy(traffic)
- stats = self.generate_traffic(traffic, duration)
- right = traffic['frame_rate']
- center = traffic['frame_rate']
+ if settings.getValue('TRAFFICGEN_TREX_LEARNING_MODE'):
+ self.learning_packets(traffic)
+ self._verification_params = copy.deepcopy(traffic)
- # Loops until the preconfigured difference between frame rate
+ binary_bounds = {'right' : traffic['frame_rate'],
+ 'left' : 0,
+ 'center': traffic['frame_rate'],}
+
+ # Loops until the preconfigured differencde between frame rate
# of successful and unsuccessful iterations is reached
- while (right - left) > threshold:
- test_lossrate = ((stats["total"]["opackets"] - stats["total"]
- ["ipackets"]) * 100) / stats["total"]["opackets"]
- self._logger.debug("Iteration: %s, frame rate: %s, throughput_rx_fps: %s, frame_loss_percent: %s",
- iteration, "{:.3f}".format(new_params['frame_rate']), stats['total']['rx_pps'],
- "{:.3f}".format(test_lossrate))
- if test_lossrate == 0.0 and new_params['frame_rate'] == traffic['frame_rate']:
- stats_ok = copy.deepcopy(stats)
- break
- elif test_lossrate > lossrate:
- right = center
- center = (left+right) / 2
- new_params = copy.deepcopy(traffic)
- new_params['frame_rate'] = center
- stats = self.generate_traffic(new_params, duration)
+ stats_ok = self.run_trials(boundaries=binary_bounds, duration=duration,
+ lossrate=lossrate, traffic=traffic)
+ if settings.getValue('TRAFFICGEN_TREX_VERIFICATION_MODE'):
+ verification_iterations = 1
+ while verification_iterations <= settings.getValue('TRAFFICGEN_TREX_MAXIMUM_VERIFICATION_TRIALS'):
+ self._logger.info('Starting Trex Verification trial for %s seconds at frame rate %s',
+ settings.getValue('TRAFFICGEN_TREX_VERIFICATION_DURATION'),
+ self._verification_params['frame_rate'])
+ stats = self.generate_traffic(self._verification_params,
+ settings.getValue('TRAFFICGEN_TREX_VERIFICATION_DURATION'))
+ verification_lossrate = ((stats["total"]["opackets"] - stats[
+ "total"]["ipackets"]) * 100) / stats["total"]["opackets"]
+ if verification_lossrate <= lossrate:
+ self._logger.info('Trex Verification passed, %s packets were lost',
+ stats["total"]["opackets"] - stats["total"]["ipackets"])
+ stats_ok = copy.deepcopy(stats)
+ break
+ else:
+ self._logger.info('Trex Verification failed, %s packets were lost',
+ stats["total"]["opackets"] - stats["total"]["ipackets"])
+ new_right = self._verification_params['frame_rate'] - settings.getValue(
+ 'TRAFFICGEN_TREX_RFC2544_TPUT_THRESHOLD')
+ self._verification_params['frame_rate'] = new_right
+ binary_bounds = {'right': new_right,
+ 'left': 0,
+ 'center': new_right,}
+ stats_ok = self.run_trials(boundaries=binary_bounds, duration=duration,
+ lossrate=lossrate, traffic=self._verification_params)
+ verification_iterations += 1
else:
- stats_ok = copy.deepcopy(stats)
- left = center
- center = (left+right) / 2
- new_params = copy.deepcopy(traffic)
- new_params['frame_rate'] = center
- stats = self.generate_traffic(new_params, duration)
- iteration += 1
+ self._logger.error('Could not pass Trex Verification. Test failed')
return self.calculate_results(stats_ok)
def start_rfc2544_throughput(self, traffic=None, tests=1, duration=60,