diff options
Diffstat (limited to 'tools/pkt_gen')
-rwxr-xr-x | tools/pkt_gen/dummy/dummy.py | 10 | ||||
-rwxr-xr-x | tools/pkt_gen/ixia/ixia.py | 6 | ||||
-rwxr-xr-x | tools/pkt_gen/ixia/pass_fail.tcl | 5 | ||||
-rwxr-xr-x | tools/pkt_gen/ixnet/ixnet.py | 20 | ||||
-rw-r--r-- | tools/pkt_gen/ixnet/ixnetrfc2544.tcl | 11 | ||||
-rwxr-xr-x | tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl | 11 | ||||
-rw-r--r-- | tools/pkt_gen/moongen/moongen.py | 167 | ||||
-rw-r--r-- | tools/pkt_gen/testcenter/testcenter.py | 4 | ||||
-rwxr-xr-x | tools/pkt_gen/trafficgen/trafficgen.py | 12 | ||||
-rw-r--r-- | tools/pkt_gen/xena/XenaDriver.py | 16 | ||||
-rwxr-xr-x | tools/pkt_gen/xena/xena.py | 138 | ||||
-rw-r--r-- | tools/pkt_gen/xena/xena_json.py | 16 |
12 files changed, 254 insertions, 162 deletions
diff --git a/tools/pkt_gen/dummy/dummy.py b/tools/pkt_gen/dummy/dummy.py index d3d79974..3324824c 100755 --- a/tools/pkt_gen/dummy/dummy.py +++ b/tools/pkt_gen/dummy/dummy.py @@ -146,8 +146,8 @@ class Dummy(trafficgen.ITrafficGenerator): results = get_user_traffic( 'continuous', '%dmpps, multistream %s, duration %d' % (traffic['frame_rate'], - traffic['multistream'], - duration), traffic_, + traffic['multistream'], + duration), traffic_, ('frames tx', 'frames rx', 'tx rate %', 'rx rate %', 'min latency', 'max latency', 'avg latency', 'frameloss %')) @@ -169,7 +169,7 @@ class Dummy(trafficgen.ITrafficGenerator): result[ResultsConstants.FRAME_LOSS_PERCENT] = float(results[7]) return result - def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """ Send traffic per RFC2544 throughput test specifications. @@ -182,8 +182,8 @@ class Dummy(trafficgen.ITrafficGenerator): results = get_user_traffic( 'throughput', - '%d trials, %d seconds iterations, %f packet loss, multistream ' - '%s' % (trials, duration, lossrate, traffic['multistream']), + '%d tests, %d seconds iterations, %f packet loss, multistream ' + '%s' % (tests, duration, lossrate, traffic['multistream']), traffic_, ('frames tx', 'frames rx', 'tx rate %', 'rx rate %', 'min latency', 'max latency', 'avg latency', 'frameloss %')) diff --git a/tools/pkt_gen/ixia/ixia.py b/tools/pkt_gen/ixia/ixia.py index ae5da6d2..cd14a2a7 100755 --- a/tools/pkt_gen/ixia/ixia.py +++ b/tools/pkt_gen/ixia/ixia.py @@ -38,9 +38,9 @@ import tkinter import logging import os +from collections import OrderedDict from tools.pkt_gen import trafficgen from conf import settings -from collections import OrderedDict from core.results.results_constants import ResultsConstants _ROOT_DIR = os.path.dirname(os.path.realpath(__file__)) @@ -252,13 +252,13 @@ class Ixia(trafficgen.ITrafficGenerator): """ return self.run_tcl('stopTraffic') - def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20, lossrate=0.0): + def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """See ITrafficGenerator for description """ params = {} params['config'] = { - 'trials': trials, + 'tests': tests, 'duration': duration, 'lossrate': lossrate, 'multipleStreams': traffic['multistream'], diff --git a/tools/pkt_gen/ixia/pass_fail.tcl b/tools/pkt_gen/ixia/pass_fail.tcl index acb4443f..79b7f10d 100755 --- a/tools/pkt_gen/ixia/pass_fail.tcl +++ b/tools/pkt_gen/ixia/pass_fail.tcl @@ -675,7 +675,10 @@ proc rfcThroughputTest { testSpec trafficSpec } { # testSpec - set numTrials [dict get $testSpec trials] ;# we don't use this yet + # RFC2544 to IXIA terminology mapping (it affects Ixia configuration below): + # Test => Trial + # Trial => Iteration + set numTrials [dict get $testSpec tests] ;# we don't use this yet set duration [dict get $testSpec duration] set lossRate [dict get $testSpec lossrate] set multipleStream [dict get $testSpec multipleStreams] ;# we don't use this yet diff --git a/tools/pkt_gen/ixnet/ixnet.py b/tools/pkt_gen/ixnet/ixnet.py index aadadf94..5e4ae569 100755 --- a/tools/pkt_gen/ixnet/ixnet.py +++ b/tools/pkt_gen/ixnet/ixnet.py @@ -19,8 +19,6 @@ This requires the following settings in your config file: * TRAFFICGEN_IXNET_LIB_PATH IxNetwork libraries path -* TRAFFICGEN_IXNET_HOST - IxNetwork host IP address * TRAFFICGEN_IXNET_PORT IxNetwork host port number * TRAFFICGEN_IXNET_USER @@ -32,7 +30,7 @@ This requires the following settings in your config file: as the previous one The following settings are also required. These can likely be shared -an 'Ixia' traffic generator instance: +with an 'Ixia' traffic generator instance: * TRAFFICGEN_IXIA_HOST IXIA chassis IP address @@ -255,15 +253,15 @@ class IxNet(trafficgen.ITrafficGenerator): """ return self._wait_result() - def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """See ITrafficGenerator for description """ - self.start_rfc2544_throughput(traffic, trials, duration, lossrate) + self.start_rfc2544_throughput(traffic, tests, duration, lossrate) return self.wait_rfc2544_throughput() - def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Start transmission. """ @@ -272,7 +270,7 @@ class IxNet(trafficgen.ITrafficGenerator): self._params['config'] = { 'binary': True, - 'trials': trials, + 'tests': tests, 'duration': duration, 'lossrate': lossrate, 'multipleStreams': traffic['multistream'], @@ -389,18 +387,18 @@ class IxNet(trafficgen.ITrafficGenerator): # the results file return parse_ixnet_rfc_results(parse_result_string(output[0])) - def send_rfc2544_back2back(self, traffic=None, trials=50, duration=2, + def send_rfc2544_back2back(self, traffic=None, tests=1, duration=2, lossrate=0.0): """See ITrafficGenerator for description """ # NOTE 2 seconds is the recommended duration for a back 2 back # test in RFC2544. 50 trials is the recommended number from the # RFC also. - self.start_rfc2544_back2back(traffic, trials, duration, lossrate) + self.start_rfc2544_back2back(traffic, tests, duration, lossrate) return self.wait_rfc2544_back2back() - def start_rfc2544_back2back(self, traffic=None, trials=50, duration=2, + def start_rfc2544_back2back(self, traffic=None, tests=1, duration=2, lossrate=0.0): """Start transmission. """ @@ -409,7 +407,7 @@ class IxNet(trafficgen.ITrafficGenerator): self._params['config'] = { 'binary': True, - 'trials': trials, + 'tests': tests, 'duration': duration, 'lossrate': lossrate, 'multipleStreams': traffic['multistream'], diff --git a/tools/pkt_gen/ixnet/ixnetrfc2544.tcl b/tools/pkt_gen/ixnet/ixnetrfc2544.tcl index 233db040..e70ca874 100644 --- a/tools/pkt_gen/ixnet/ixnetrfc2544.tcl +++ b/tools/pkt_gen/ixnet/ixnetrfc2544.tcl @@ -83,13 +83,16 @@ proc startRfc2544Test { testSpec trafficSpec } { set duration [dict get $testSpec duration] + # RFC2544 to IXIA terminology mapping (it affects Ixia configuration inside this script): + # Test => Trial + # Trial => Iteration if {$binary} { - set numTrials [dict get $testSpec trials] + set numTests [dict get $testSpec tests] set frameRate 100 set tolerance [dict get $testSpec lossrate] set loadType binary } else { - set numTrials 1 + set numTests 1 set frameRate [dict get $testSpec framerate] set tolerance 0.0 set loadType custom @@ -7778,7 +7781,7 @@ proc startRfc2544Test { testSpec trafficSpec } { -framesize $frameSize \ -reportTputRateUnit mbps \ -duration $duration \ - -numtrials $numTrials \ + -numtrials $numTests \ -trafficType constantLoading \ -burstSize 1 \ -framesPerBurstGap 1 \ @@ -7951,7 +7954,7 @@ proc startRfc2544Test { testSpec trafficSpec } { -rfc2889ordering noOrdering \ -floodedFramesEnabled False \ -duration $duration \ - -numtrials $numTrials \ + -numtrials $numTests \ -trafficType constantLoading \ -burstSize 1 \ -framesPerBurstGap 1 \ diff --git a/tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl b/tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl index 0bdba9cd..539c5a5b 100755 --- a/tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl +++ b/tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl @@ -83,13 +83,16 @@ proc startRfc2544Test { testSpec trafficSpec } { set duration [dict get $testSpec duration] + # RFC2544 to IXIA terminology mapping (it affects Ixia configuration inside this script): + # Test => Trial + # Trial => Iteration if {$binary} { - set numTrials [dict get $testSpec trials] + set numTests [dict get $testSpec tests] set frameRate 100 set tolerance [dict get $testSpec lossrate] set loadType binary } else { - set numTrials 1 + set numTests 1 set frameRate [dict get $testSpec framerate] set tolerance 0.0 set loadType custom @@ -3218,7 +3221,7 @@ proc startRfc2544Test { testSpec trafficSpec } { -framesize $frameSize \ -reportTputRateUnit mbps \ -duration $duration \ - -numtrials $numTrials \ + -numtrials $numTests \ -trafficType constantLoading \ -burstSize 1 \ -framesPerBurstGap 1 \ @@ -3391,7 +3394,7 @@ proc startRfc2544Test { testSpec trafficSpec } { -rfc2889ordering noOrdering \ -floodedFramesEnabled False \ -duration $duration \ - -numtrials $numTrials \ + -numtrials $numTests \ -trafficType constantLoading \ -burstSize 1 \ -framesPerBurstGap 1 \ diff --git a/tools/pkt_gen/moongen/moongen.py b/tools/pkt_gen/moongen/moongen.py index d6c09e5d..790286d8 100644 --- a/tools/pkt_gen/moongen/moongen.py +++ b/tools/pkt_gen/moongen/moongen.py @@ -20,10 +20,11 @@ Moongen Traffic Generator Model """ # python imports -import logging from collections import OrderedDict -import subprocess +import logging +import math import re +import subprocess # VSPerf imports from conf import settings @@ -49,6 +50,13 @@ class Moongen(ITrafficGenerator): self._moongen_user = settings.getValue('TRAFFICGEN_MOONGEN_USER') self._moongen_ports = settings.getValue('TRAFFICGEN_MOONGEN_PORTS') + if settings.getValue('TRAFFICGEN_MOONGEN_LINE_SPEED_GBPS') == '10': + self._moongen_line_speed = math.pow(10, 10) + else: + raise RuntimeError( + 'MOONGEN: Invalid line speed in configuration ' + \ + 'file (today 10Gbps supported)') + @property def traffic_defaults(self): """Default traffic values. @@ -58,12 +66,12 @@ class Moongen(ITrafficGenerator): will likely break traffic generator implementations or tests respectively. """ - self._logger.info("In moongen traffic_defaults method") + self._logger.info("In Moongen traffic_defaults method") return self._traffic_defaults def create_moongen_cfg_file(self, traffic, duration=60, acceptable_loss_pct=1, one_shot=0): - """Create the MoonGen configuration file from VSPERF's traffic profile + """Create the Moongen configuration file from VSPERF's traffic profile :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags :param duration: The length of time to generate packet throughput :param acceptable_loss: Maximum packet loss acceptable @@ -138,8 +146,9 @@ class Moongen(ITrafficGenerator): out_file.write("dstIp = \"" + \ str(traffic['l3']['dstip']) + "\",\n") - out_file.write("vlanId = " + \ - str(traffic['vlan']['id']) + ",\n") + if traffic['vlan']['enabled']: + out_file.write("vlanId = " + \ + str(traffic['vlan']['id']) + ",\n") out_file.write("searchRunTime = " + \ str(duration) + ",\n") @@ -156,10 +165,17 @@ class Moongen(ITrafficGenerator): if one_shot: out_file.write("oneShot = true,\n") - # Assume 10G line rates at the moment. Need to convert VSPERF - # frame_rate (percentage of line rate) to Mpps for MoonGen + # Need to convert VSPERF frame_rate (percentage of line rate) + # to Mpps for Moongen + start_rate = str( + (traffic['frame_rate'] / 100) * (self._moongen_line_speed / \ + (8 * (traffic['l2']['framesize'] + 20)) / math.pow(10, 6))) + + logging.debug("startRate = " + start_rate) + + out_file.write("startRate = " + \ + start_rate + "\n") - out_file.write("startRate = " + str((traffic['frame_rate'] / 100) * 14.88) + "\n") out_file.write("}" + "\n") out_file.close() @@ -181,17 +197,17 @@ class Moongen(ITrafficGenerator): raise RuntimeError('MOONGEN: Error copying configuration file') def connect(self): - """Connect to MoonGen traffic generator + """Connect to Moongen traffic generator - Verify that MoonGen is on the system indicated by + Verify that Moongen is on the system indicated by the configuration file """ - self._logger.info("MOONGEN: In MoonGen connect method...") + self._logger.info("MOONGEN: In Moongen connect method...") if self._moongen_host_ip_addr: cmd_ping = "ping -c1 " + self._moongen_host_ip_addr else: - raise RuntimeError('MOONGEN: MoonGen host not defined') + raise RuntimeError('MOONGEN: Moongen host not defined') ping = subprocess.Popen(cmd_ping, shell=True, stderr=subprocess.PIPE) output, error = ping.communicate() @@ -199,7 +215,7 @@ class Moongen(ITrafficGenerator): if ping.returncode: self._logger.error(error) self._logger.error(output) - raise RuntimeError('MOONGEN: Cannot ping MoonGen host at ' + \ + raise RuntimeError('MOONGEN: Cannot ping Moongen host at ' + \ self._moongen_host_ip_addr) connect_moongen = "ssh " + self._moongen_user + \ @@ -218,10 +234,10 @@ class Moongen(ITrafficGenerator): self._logger.error(error) self._logger.error(output) raise RuntimeError( - 'MOONGEN: Cannot locate MoonGen program at %s within %s' \ + 'MOONGEN: Cannot locate Moongen program at %s within %s' \ % (self._moongen_host_ip_addr, self._moongen_base_dir)) - self._logger.info("MOONGEN: MoonGen host successfully found...") + self._logger.info("MOONGEN: Moongen host successfully found...") def disconnect(self): """Disconnect from the traffic generator. @@ -252,7 +268,7 @@ class Moongen(ITrafficGenerator): - List of List of Rx Bytes, - Payload Errors and Sequence Errors. """ - self._logger.info("In moongen send_burst_traffic method") + self._logger.info("In Moongen send_burst_traffic method") return NotImplementedError('Moongen Burst traffic not implemented') def send_cont_traffic(self, traffic=None, duration=20): @@ -274,7 +290,7 @@ class Moongen(ITrafficGenerator): - Max Latency (ns), - Avg Latency (ns) """ - self._logger.info("In moongen send_cont_traffic method") + self._logger.info("In Moongen send_cont_traffic method") self._params.clear() self._params['traffic'] = self.traffic_defaults.copy() @@ -316,31 +332,31 @@ class Moongen(ITrafficGenerator): results = OrderedDict() results[ResultsConstants.THROUGHPUT_RX_FPS] = ( - '{:,.6f}'.format(total_throughput_rx_fps)) + '{:.6f}'.format(total_throughput_rx_fps)) results[ResultsConstants.THROUGHPUT_RX_MBPS] = ( - '{:,.3f}'.format(total_throughput_rx_mbps)) + '{:.3f}'.format(total_throughput_rx_mbps)) results[ResultsConstants.THROUGHPUT_RX_PERCENT] = ( - '{:,.3f}'.format(total_throughput_rx_pct)) + '{:.3f}'.format(total_throughput_rx_pct)) results[ResultsConstants.TX_RATE_FPS] = ( - '{:,.6f}'.format(total_throughput_tx_fps)) + '{:.6f}'.format(total_throughput_tx_fps)) results[ResultsConstants.TX_RATE_MBPS] = ( - '{:,.3f}'.format(total_throughput_tx_mbps)) + '{:.3f}'.format(total_throughput_tx_mbps)) results[ResultsConstants.TX_RATE_PERCENT] = ( - '{:,.3f}'.format(total_throughput_tx_pct)) + '{:.3f}'.format(total_throughput_tx_pct)) results[ResultsConstants.MIN_LATENCY_NS] = ( - '{:,.3f}'.format(total_min_latency_ns)) + '{:.3f}'.format(total_min_latency_ns)) results[ResultsConstants.MAX_LATENCY_NS] = ( - '{:,.3f}'.format(total_max_latency_ns)) + '{:.3f}'.format(total_max_latency_ns)) results[ResultsConstants.AVG_LATENCY_NS] = ( - '{:,.3f}'.format(total_avg_latency_ns)) + '{:.3f}'.format(total_avg_latency_ns)) return results @@ -352,18 +368,18 @@ class Moongen(ITrafficGenerator): :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags :param duration: Time to wait to receive packets (secs) """ - self._logger.info("In moongen start_cont_traffic method") - return NotImplementedError('Moongen continuous traffic not implemented') + self._logger.info("In Moongen start_cont_traffic method") + return NotImplementedError('moongen continuous traffic not implemented') def stop_cont_traffic(self): # Stop continuous transmission and return results. - self._logger.info("In moongen stop_cont_traffic method") + self._logger.info("In Moongen stop_cont_traffic method") def run_moongen_and_collect_results(self, test_run=1): - """Execute MoonGen and transform results into VSPERF format + """Execute Moongen and transform results into VSPERF format :param test_run: The number of tests to run """ - # Start MoonGen and create logfile of the run + # Start Moongen and create logfile of the run connect_moongen = "ssh " + self._moongen_user + "@" + \ self._moongen_host_ip_addr @@ -381,7 +397,7 @@ class Moongen(ITrafficGenerator): logging.debug(error) logging.debug(output) raise RuntimeError( - 'MOONGEN: Error starting MoonGen program at %s within %s' \ + 'MOONGEN: Error starting Moongen program at %s within %s' \ % (self._moongen_host_ip_addr, self._moongen_base_dir)) cmd_moongen = "mkdir -p /tmp/moongen/" + str(test_run) @@ -396,7 +412,7 @@ class Moongen(ITrafficGenerator): logging.debug(error) logging.debug(output) raise RuntimeError( - 'MOONGEN: Error obtaining MoonGen log from %s within %s' \ + 'MOONGEN: Error obtaining Moongen log from %s within %s' \ % (self._moongen_host_ip_addr, self._moongen_base_dir)) cmd_moongen = " scp " + self._moongen_user + "@" + \ @@ -414,7 +430,7 @@ class Moongen(ITrafficGenerator): logging.debug(error) logging.debug(output) raise RuntimeError( - 'MOONGEN: Error obtaining MoonGen log from %s within %s' \ + 'MOONGEN: Error obtaining Moongen log from %s within %s' \ % (self._moongen_host_ip_addr, self._moongen_base_dir)) log_file = "/tmp/moongen/" + str(test_run) + "/moongen-run.log" @@ -443,7 +459,7 @@ class Moongen(ITrafficGenerator): if not results_match: logging.error('There was a problem parsing ' +\ - 'MoonGen REPORT section of MoonGen log file') + 'Moongen REPORT section of Moongen log file') moongen_results = OrderedDict() moongen_results[ResultsConstants.THROUGHPUT_RX_FPS] = 0 @@ -468,14 +484,25 @@ class Moongen(ITrafficGenerator): if parameters_match: frame_size = int(parameters_match.group(1)) else: - logging.error('There was a problem parsing MoonGen ' +\ - 'PARAMETERS section of MoonGen log file') + logging.error('There was a problem parsing Moongen ' +\ + 'PARAMETERS section of Moongen log file') frame_size = 0 - if results_match and parameters_match: + # Each packet stream in the MoonGen report is prefaced with the + # words '[REPORT]Device'. Count the instances of this string to + # get the total aggregrate throughput. For example: + # + # - If num_traffic_streams = 1, there is a single + # unidirectional stream + # + # - If num_traffic_streams = 2, there is a bidirectional + # traffic stream + num_traffic_streams = mytext.count('[REPORT]Device') + + if results_match and parameters_match and num_traffic_streams: # Assume for now 10G link speed - max_theoretical_mfps = ( - (10000000000 / 8) / (frame_size + 20)) + max_theoretical_fps = ( + num_traffic_streams * (self._moongen_line_speed / 8) / (frame_size + 20)) moongen_results[ResultsConstants.THROUGHPUT_RX_FPS] = ( float(results_match.group(6)) * 1000000) @@ -484,8 +511,7 @@ class Moongen(ITrafficGenerator): (float(results_match.group(6)) * frame_size + 20) * 8) moongen_results[ResultsConstants.THROUGHPUT_RX_PERCENT] = ( - float(results_match.group(6)) * \ - 1000000 / max_theoretical_mfps * 100) + (100 * float(results_match.group(6)) * 1000000) / max_theoretical_fps) moongen_results[ResultsConstants.TX_RATE_FPS] = ( float(results_match.group(5)) * 1000000) @@ -494,8 +520,7 @@ class Moongen(ITrafficGenerator): float(results_match.group(5)) * (frame_size + 20) * 8) moongen_results[ResultsConstants.TX_RATE_PERCENT] = ( - float(results_match.group(5)) * - 1000000 / max_theoretical_mfps * 100) + (100 * float(results_match.group(5)) * 1000000) / max_theoretical_fps) moongen_results[ResultsConstants.B2B_TX_COUNT] = ( float(results_match.group(1))) @@ -512,7 +537,7 @@ class Moongen(ITrafficGenerator): return moongen_results def send_rfc2544_throughput(self, traffic=None, duration=20, - lossrate=0.0, trials=1): + lossrate=0.0, tests=1): # # Send traffic per RFC2544 throughput test specifications. # @@ -521,7 +546,7 @@ class Moongen(ITrafficGenerator): # detected is found. # # :param traffic: Detailed "traffic" spec, see design docs for details - # :param trials: Number of trials to execute + # :param tests: Number of tests to execute # :param duration: Per iteration duration # :param lossrate: Acceptable lossrate percentage # :returns: dictionary of strings with following data: @@ -557,7 +582,7 @@ class Moongen(ITrafficGenerator): total_max_latency_ns = 0 total_avg_latency_ns = 0 - for test_run in range(1, trials+1): + for test_run in range(1, tests+1): collected_results = ( Moongen.run_moongen_and_collect_results(self, test_run=test_run)) @@ -586,35 +611,35 @@ class Moongen(ITrafficGenerator): results = OrderedDict() results[ResultsConstants.THROUGHPUT_RX_FPS] = ( - '{:,.6f}'.format(total_throughput_rx_fps / trials)) + '{:.6f}'.format(total_throughput_rx_fps / tests)) results[ResultsConstants.THROUGHPUT_RX_MBPS] = ( - '{:,.3f}'.format(total_throughput_rx_mbps / trials)) + '{:.3f}'.format(total_throughput_rx_mbps / tests)) results[ResultsConstants.THROUGHPUT_RX_PERCENT] = ( - '{:,.3f}'.format(total_throughput_rx_pct / trials)) + '{:.3f}'.format(total_throughput_rx_pct / tests)) results[ResultsConstants.TX_RATE_FPS] = ( - '{:,.6f}'.format(total_throughput_tx_fps / trials)) + '{:.6f}'.format(total_throughput_tx_fps / tests)) results[ResultsConstants.TX_RATE_MBPS] = ( - '{:,.3f}'.format(total_throughput_tx_mbps / trials)) + '{:.3f}'.format(total_throughput_tx_mbps / tests)) results[ResultsConstants.TX_RATE_PERCENT] = ( - '{:,.3f}'.format(total_throughput_tx_pct / trials)) + '{:.3f}'.format(total_throughput_tx_pct / tests)) results[ResultsConstants.MIN_LATENCY_NS] = ( - '{:,.3f}'.format(total_min_latency_ns / trials)) + '{:.3f}'.format(total_min_latency_ns / tests)) results[ResultsConstants.MAX_LATENCY_NS] = ( - '{:,.3f}'.format(total_max_latency_ns / trials)) + '{:.3f}'.format(total_max_latency_ns / tests)) results[ResultsConstants.AVG_LATENCY_NS] = ( - '{:,.3f}'.format(total_avg_latency_ns / trials)) + '{:.3f}'.format(total_avg_latency_ns / tests)) return results - def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Non-blocking version of 'send_rfc2544_throughput'. @@ -630,14 +655,14 @@ class Moongen(ITrafficGenerator): self._logger.info('In moongen wait_rfc2544_throughput') def send_rfc2544_back2back(self, traffic=None, duration=60, - lossrate=0.0, trials=1): + lossrate=0.0, tests=1): """Send traffic per RFC2544 back2back test specifications. Send packets at a fixed rate, using ``traffic`` configuration, for duration seconds. :param traffic: Detailed "traffic" spec, see design docs for details - :param trials: Number of trials to execute + :param tests: Number of tests to execute :param duration: Per iteration duration :param lossrate: Acceptable loss percentage @@ -671,7 +696,7 @@ class Moongen(ITrafficGenerator): results[ResultsConstants.SCAL_STREAM_TYPE] = 0 results[ResultsConstants.SCAL_PRE_INSTALLED_FLOWS] = 0 - for test_run in range(1, trials+1): + for test_run in range(1, tests+1): collected_results = ( Moongen.run_moongen_and_collect_results(self, test_run=test_run)) @@ -701,28 +726,28 @@ class Moongen(ITrafficGenerator): # Calculate average results results[ResultsConstants.B2B_RX_FPS] = ( - results[ResultsConstants.B2B_RX_FPS] / trials) + results[ResultsConstants.B2B_RX_FPS] / tests) results[ResultsConstants.B2B_RX_PERCENT] = ( - results[ResultsConstants.B2B_RX_PERCENT] / trials) + results[ResultsConstants.B2B_RX_PERCENT] / tests) results[ResultsConstants.B2B_TX_FPS] = ( - results[ResultsConstants.B2B_TX_FPS] / trials) + results[ResultsConstants.B2B_TX_FPS] / tests) results[ResultsConstants.B2B_TX_PERCENT] = ( - results[ResultsConstants.B2B_TX_PERCENT] / trials) + results[ResultsConstants.B2B_TX_PERCENT] / tests) results[ResultsConstants.B2B_TX_COUNT] = ( - results[ResultsConstants.B2B_TX_COUNT] / trials) + results[ResultsConstants.B2B_TX_COUNT] / tests) results[ResultsConstants.B2B_FRAMES] = ( - results[ResultsConstants.B2B_FRAMES] / trials) + results[ResultsConstants.B2B_FRAMES] / tests) results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = ( - results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] / trials) + results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] / tests) results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = ( - results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] / trials) + results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] / tests) results[ResultsConstants.SCAL_STREAM_COUNT] = 0 results[ResultsConstants.SCAL_STREAM_TYPE] = 0 @@ -730,14 +755,14 @@ class Moongen(ITrafficGenerator): return results - def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20, + def start_rfc2544_back2back(self, traffic=None, tests=1, duration=20, lossrate=0.0): # # Non-blocking version of 'send_rfc2544_back2back'. # # Start transmission and immediately return. Do not wait for results. # - self._logger.info("In moongen start_rfc2544_back2back method") + self._logger.info("In Moongen start_rfc2544_back2back method") return NotImplementedError( 'Moongen start back2back traffic not implemented') diff --git a/tools/pkt_gen/testcenter/testcenter.py b/tools/pkt_gen/testcenter/testcenter.py index a1f38d8b..c242269a 100644 --- a/tools/pkt_gen/testcenter/testcenter.py +++ b/tools/pkt_gen/testcenter/testcenter.py @@ -211,7 +211,7 @@ class TestCenter(trafficgen.ITrafficGenerator): return self.get_rfc2544_results(filec) - def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """ Send traffic per RFC2544 throughput test specifications. @@ -243,7 +243,7 @@ class TestCenter(trafficgen.ITrafficGenerator): return self.get_rfc2544_results(filec) - def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20, + def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20, lossrate=0.0): """ Send traffic per RFC2544 BacktoBack test specifications. diff --git a/tools/pkt_gen/trafficgen/trafficgen.py b/tools/pkt_gen/trafficgen/trafficgen.py index 3953bbb1..fb40cd92 100755 --- a/tools/pkt_gen/trafficgen/trafficgen.py +++ b/tools/pkt_gen/trafficgen/trafficgen.py @@ -133,7 +133,7 @@ class ITrafficGenerator(object): """ raise NotImplementedError('Please call an implementation.') - def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Send traffic per RFC2544 throughput test specifications. @@ -142,7 +142,7 @@ class ITrafficGenerator(object): detected is found. :param traffic: Detailed "traffic" spec, see design docs for details - :param trials: Number of trials to execute + :param tests: Number of tests to execute :param duration: Per iteration duration :param lossrate: Acceptable lossrate percentage :returns: dictionary of strings with following data: @@ -158,7 +158,7 @@ class ITrafficGenerator(object): """ raise NotImplementedError('Please call an implementation.') - def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Non-blocking version of 'send_rfc2544_throughput'. @@ -172,7 +172,7 @@ class ITrafficGenerator(object): """ raise NotImplementedError('Please call an implementation.') - def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20, + def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Send traffic per RFC2544 back2back test specifications. @@ -180,7 +180,7 @@ class ITrafficGenerator(object): configuration, for duration seconds. :param traffic: Detailed "traffic" spec, see design docs for details - :param trials: Number of trials to execute + :param tests: Number of tests to execute :param duration: Per iteration duration :param lossrate: Acceptable loss percentage @@ -191,7 +191,7 @@ class ITrafficGenerator(object): """ raise NotImplementedError('Please call an implementation.') - def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20, + def start_rfc2544_back2back(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Non-blocking version of 'send_rfc2544_back2back'. diff --git a/tools/pkt_gen/xena/XenaDriver.py b/tools/pkt_gen/xena/XenaDriver.py index aa8443c9..d3862312 100644 --- a/tools/pkt_gen/xena/XenaDriver.py +++ b/tools/pkt_gen/xena/XenaDriver.py @@ -1001,9 +1001,21 @@ class XenaTXStats(object): mydict = statdict return mydict - def aggregate_stats(stat1, stat2): """ + Judge whether stat1 and stat2 both have same key, if both have same key, + call the aggregate fuction, else use the stat1's value + """ + newstat = dict() + for keys in stat1.keys(): + if keys in stat2 and isinstance(stat1[keys], dict): + newstat[keys] = aggregate(stat1[keys], stat2[keys]) + else: + newstat[keys] = stat1[keys] + return newstat + +def aggregate(stat1, stat2): + """ Recursive function to aggregate two sets of statistics. This is used when bi directional traffic is done and statistics need to be calculated based on two sets of statistics. @@ -1014,7 +1026,7 @@ def aggregate_stats(stat1, stat2): newstat = dict() for (keys1, keys2) in zip(stat1.keys(), stat2.keys()): if isinstance(stat1[keys1], dict): - newstat[keys1] = aggregate_stats(stat1[keys1], stat2[keys2]) + newstat[keys1] = aggregate(stat1[keys1], stat2[keys2]) else: if not isinstance(stat1[keys1], int) and not isinstance( [keys1], float): diff --git a/tools/pkt_gen/xena/xena.py b/tools/pkt_gen/xena/xena.py index 7dd4b90b..8d45053e 100755 --- a/tools/pkt_gen/xena/xena.py +++ b/tools/pkt_gen/xena/xena.py @@ -25,6 +25,7 @@ Xena Traffic Generator Model # python imports import binascii import logging +import os import subprocess import sys from time import sleep @@ -50,6 +51,7 @@ from tools.pkt_gen.xena.XenaDriver import ( XenaManager, ) + class Xena(ITrafficGenerator): """ Xena Traffic generator wrapper class @@ -65,6 +67,19 @@ class Xena(ITrafficGenerator): self._duration = None self.tx_stats = None self.rx_stats = None + self._log_handle = None + + user_home = os.path.expanduser('~') + self._log_path = '{}/Xena/Xena2544-2G/Logs/xena2544.log'.format( + user_home) + + # make the folder and log file if they doesn't exist + if not os.path.exists(self._log_path): + os.makedirs(os.path.dirname(self._log_path)) + + # empty the file contents + open(self._log_path, 'w').close() + @property def traffic_defaults(self): @@ -99,7 +114,7 @@ class Xena(ITrafficGenerator): root[0][1][0][0].get('PortRxBpsL1')) + float( root[0][1][0][1].get('PortRxBpsL1')))/ 1000000 results[ResultsConstants.THROUGHPUT_RX_PERCENT] = ( - 100 - int(root[0][1][0].get('TotalLossRatioPcnt'))) * float( + 100 - float(root[0][1][0].get('TotalLossRatioPcnt'))) * float( root[0][1][0].get('TotalTxRatePcnt'))/100 results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get( 'TotalTxRateFps') @@ -260,10 +275,10 @@ class Xena(ITrafficGenerator): return result_dict - def _setup_json_config(self, trials, loss_rate, testtype=None): + def _setup_json_config(self, tests, loss_rate, testtype=None): """ Create a 2bUsed json file that will be used for xena2544.exe execution. - :param trials: Number of trials + :param tests: Number of tests :param loss_rate: The acceptable loss rate as float :param testtype: Either '2544_b2b' or '2544_throughput' as string :return: None @@ -290,15 +305,26 @@ class Xena(ITrafficGenerator): if testtype == '2544_throughput': j_file.set_test_options_tput( packet_sizes=self._params['traffic']['l2']['framesize'], - iterations=trials, loss_rate=loss_rate, + iterations=tests, loss_rate=loss_rate, duration=self._duration, micro_tpld=True if self._params[ 'traffic']['l2']['framesize'] == 64 else False) j_file.enable_throughput_test() + j_file.modify_2544_tput_options( + settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE'), + settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE'), + settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE'), + settings.getValue( + 'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION'), + settings.getValue( + 'TRAFFICGEN_XENA_2544_TPUT_USEPASS_THRESHHOLD'), + settings.getValue( + 'TRAFFICGEN_XENA_2544_TPUT_PASS_THRESHHOLD') + ) elif testtype == '2544_b2b': j_file.set_test_options_back2back( packet_sizes=self._params['traffic']['l2']['framesize'], - iterations=trials, duration=self._duration, + iterations=tests, duration=self._duration, startvalue=self._params['traffic']['frame_rate'], endvalue=self._params['traffic']['frame_rate'], micro_tpld=True if self._params[ @@ -451,6 +477,44 @@ class Xena(ITrafficGenerator): self.rx_stats = self.xmanager.ports[1].get_rx_stats() sleep(1) + def _start_xena_2544(self): + """ + Start the xena2544 exe. + :return: None + """ + args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c", + "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r", + "./tools/pkt_gen/xena", "-u", + settings.getValue('TRAFFICGEN_XENA_USER')] + # Sometimes Xena2544.exe completes, but mono holds the process without + # releasing it, this can cause a deadlock of the main thread. Use the + # xena log file as a way to detect this. + self._log_handle = open(self._log_path, 'r') + # read the contents of the log before we start so the next read in the + # wait method are only looking at the text from this test instance + self._log_handle.read() + self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout) + + def _wait_xena_2544_complete(self): + """ + Wait for Xena2544.exe completion. + :return: None + """ + data = '' + while True: + try: + self.mono_pipe.wait(60) + self._log_handle.close() + break + except subprocess.TimeoutExpired: + # check the log to see if Xena2544 has completed and mono is + # deadlocked. + data += self._log_handle.read() + if 'TestCompletedSuccessfully' in data: + self._log_handle.close() + self.mono_pipe.terminate() + break + def _stop_api_traffic(self): """ Stop traffic through the socket API @@ -495,13 +559,11 @@ class Xena(ITrafficGenerator): See ITrafficGenerator for description """ self._duration = duration - self._params.clear() self._params['traffic'] = self.traffic_defaults.copy() if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) - self._start_traffic_api(numpkts) return self._stop_api_traffic() @@ -517,7 +579,6 @@ class Xena(ITrafficGenerator): if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) - self._start_traffic_api(-1) return self._stop_api_traffic() @@ -533,7 +594,6 @@ class Xena(ITrafficGenerator): if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) - self._start_traffic_api(-1) def stop_cont_traffic(self): @@ -541,7 +601,7 @@ class Xena(ITrafficGenerator): """ return self._stop_api_traffic() - def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Send traffic per RFC2544 throughput test specifications. @@ -554,19 +614,14 @@ class Xena(ITrafficGenerator): if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) + self._setup_json_config(tests, lossrate, '2544_throughput') + self._start_xena_2544() + self._wait_xena_2544_complete() - self._setup_json_config(trials, lossrate, '2544_throughput') - - args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c", - "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r", - "./tools/pkt_gen/xena", "-u", - settings.getValue('TRAFFICGEN_XENA_USER')] - self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout) - self.mono_pipe.communicate() root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot() return Xena._create_throughput_result(root) - def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20, + def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Non-blocking version of 'send_rfc2544_throughput'. @@ -578,26 +633,19 @@ class Xena(ITrafficGenerator): if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) - - self._setup_json_config(trials, lossrate, '2544_throughput') - - args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c", - "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r", - "./tools/pkt_gen/xena", "-u", - settings.getValue('TRAFFICGEN_XENA_USER')] - self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout) + self._setup_json_config(tests, lossrate, '2544_throughput') + self._start_xena_2544() def wait_rfc2544_throughput(self): """Wait for and return results of RFC2544 test. See ITrafficGenerator for description """ - self.mono_pipe.communicate() - sleep(2) + self._wait_xena_2544_complete() root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot() return Xena._create_throughput_result(root) - def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20, + def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Send traffic per RFC2544 back2back test specifications. @@ -610,47 +658,31 @@ class Xena(ITrafficGenerator): if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) - - self._setup_json_config(trials, lossrate, '2544_b2b') - - args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c", - "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r", - "./tools/pkt_gen/xena", "-u", - settings.getValue('TRAFFICGEN_XENA_USER')] - self.mono_pipe = subprocess.Popen( - args, stdout=sys.stdout) - self.mono_pipe.communicate() + self._setup_json_config(tests, lossrate, '2544_b2b') + self._start_xena_2544() + self._wait_xena_2544_complete() root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot() return Xena._create_throughput_result(root) - def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20, + def start_rfc2544_back2back(self, traffic=None, tests=1, duration=20, lossrate=0.0): """Non-blocking version of 'send_rfc2544_back2back'. See ITrafficGenerator for description """ self._duration = duration - self._params.clear() self._params['traffic'] = self.traffic_defaults.copy() if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) - - self._setup_json_config(trials, lossrate, '2544_b2b') - - args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c", - "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r", - "./tools/pkt_gen/xena", "-u", - settings.getValue('TRAFFICGEN_XENA_USER')] - self.mono_pipe = subprocess.Popen( - args, stdout=sys.stdout) + self._setup_json_config(tests, lossrate, '2544_b2b') + self._start_xena_2544() def wait_rfc2544_back2back(self): """Wait and set results of RFC2544 test. """ - self.mono_pipe.communicate() - sleep(2) + self._wait_xena_2544_complete() root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot() return Xena._create_throughput_result(root) diff --git a/tools/pkt_gen/xena/xena_json.py b/tools/pkt_gen/xena/xena_json.py index 2a15a932..1ce7b46f 100644 --- a/tools/pkt_gen/xena/xena_json.py +++ b/tools/pkt_gen/xena/xena_json.py @@ -233,6 +233,22 @@ class XenaJSON(object): self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][ 'Enabled'] = 'true' + def modify_2544_tput_options(self, initial_value, minimum_value, + maximum_value, value_resolution, + use_pass_threshhold, pass_threshhold): + self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][ + 'RateIterationOptions']['InitialValue'] = initial_value + self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][ + 'RateIterationOptions']['MinimumValue'] = minimum_value + self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][ + 'RateIterationOptions']['MaximumValue'] = maximum_value + self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][ + 'RateIterationOptions']['ValueResolution'] = value_resolution + self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][ + 'RateIterationOptions']['UsePassThreshold'] = use_pass_threshhold + self.json_data['TestOptions']['TestTypeOptionMap']['Throughput'][ + 'RateIterationOptions']['PassThreshold'] = pass_threshhold + def set_chassis_info(self, hostname, pwd): """ Set the chassis info |