X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=tools%2Fpkt_gen%2Fmoongen%2Fmoongen.py;h=7fd67661fe8a71a2afd77f3ff5ab2b1875306a4e;hb=fe97f17b0eed7e192b84edfa01177a23671887be;hp=d6c09e5dc294064266d0b885529283d8df5e5481;hpb=cead9a3d0571b8afc5ed680475e9bc3ea92c7d79;p=vswitchperf.git diff --git a/tools/pkt_gen/moongen/moongen.py b/tools/pkt_gen/moongen/moongen.py index d6c09e5d..7fd67661 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,14 +215,14 @@ 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 + \ "@" + self._moongen_host_ip_addr cmd_find_moongen = connect_moongen + " ls " + \ - self._moongen_base_dir + "/examples/opnfv-vsperf.lua" + self._moongen_base_dir + "/trafficgen.lua" find_moongen = subprocess.Popen(cmd_find_moongen, shell=True, @@ -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() @@ -292,55 +308,38 @@ class Moongen(ITrafficGenerator): collected_results = Moongen.run_moongen_and_collect_results(self, test_run=1) - total_throughput_rx_fps = ( - float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS])) - - total_throughput_rx_mbps = ( - float(collected_results[ResultsConstants.THROUGHPUT_RX_MBPS])) - - total_throughput_rx_pct = ( - float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT])) - - total_throughput_tx_fps = ( - float(collected_results[ResultsConstants.TX_RATE_FPS])) - - total_throughput_tx_mbps = ( - float(collected_results[ResultsConstants.TX_RATE_MBPS])) - - total_throughput_tx_pct = ( - float(collected_results[ResultsConstants.TX_RATE_PERCENT])) - - total_min_latency_ns = 0 - total_max_latency_ns = 0 - total_avg_latency_ns = 0 - results = OrderedDict() + results[ResultsConstants.THROUGHPUT_RX_FPS] = ( - '{:,.6f}'.format(total_throughput_rx_fps)) + '{:.6f}'.format( + float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS]))) results[ResultsConstants.THROUGHPUT_RX_MBPS] = ( - '{:,.3f}'.format(total_throughput_rx_mbps)) + '{:.3f}'.format( + float(collected_results[ResultsConstants.THROUGHPUT_RX_MBPS]))) results[ResultsConstants.THROUGHPUT_RX_PERCENT] = ( - '{:,.3f}'.format(total_throughput_rx_pct)) + '{:.3f}'.format( + float( + collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT]))) results[ResultsConstants.TX_RATE_FPS] = ( - '{:,.6f}'.format(total_throughput_tx_fps)) + '{:.3f}'.format( + float(collected_results[ResultsConstants.TX_RATE_FPS]))) results[ResultsConstants.TX_RATE_MBPS] = ( - '{:,.3f}'.format(total_throughput_tx_mbps)) + '{:.3f}'.format( + float(collected_results[ResultsConstants.TX_RATE_MBPS]))) results[ResultsConstants.TX_RATE_PERCENT] = ( - '{:,.3f}'.format(total_throughput_tx_pct)) + '{:.3f}'.format( + float(collected_results[ResultsConstants.TX_RATE_PERCENT]))) - results[ResultsConstants.MIN_LATENCY_NS] = ( - '{:,.3f}'.format(total_min_latency_ns)) + results[ResultsConstants.MIN_LATENCY_NS] = 0 - results[ResultsConstants.MAX_LATENCY_NS] = ( - '{:,.3f}'.format(total_max_latency_ns)) + results[ResultsConstants.MAX_LATENCY_NS] = 0 - results[ResultsConstants.AVG_LATENCY_NS] = ( - '{:,.3f}'.format(total_avg_latency_ns)) + results[ResultsConstants.AVG_LATENCY_NS] = 0 return results @@ -352,23 +351,23 @@ 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 cmd_moongen = " 'cd " + self._moongen_base_dir + \ - "; ./build/MoonGen examples/opnfv-vsperf.lua | tee moongen_log.txt'" + "; ./MoonGen/build/MoonGen trafficgen.lua | tee moongen_log.txt'" cmd_start_moongen = connect_moongen + cmd_moongen @@ -381,7 +380,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 +395,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 +413,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 +442,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,24 +467,34 @@ 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) moongen_results[ResultsConstants.THROUGHPUT_RX_MBPS] = ( - (float(results_match.group(6)) * frame_size + 20) * 8) + 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 +503,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 +520,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 +529,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: @@ -547,74 +555,79 @@ class Moongen(ITrafficGenerator): duration=duration, acceptable_loss_pct=lossrate) - total_throughput_rx_fps = 0 - total_throughput_rx_mbps = 0 - total_throughput_rx_pct = 0 - total_throughput_tx_fps = 0 - total_throughput_tx_mbps = 0 - total_throughput_tx_pct = 0 - total_min_latency_ns = 0 - total_max_latency_ns = 0 - total_avg_latency_ns = 0 - - for test_run in range(1, trials+1): + # Initialize RFC 2544 throughput specific results + results = OrderedDict() + results[ResultsConstants.THROUGHPUT_RX_FPS] = 0 + results[ResultsConstants.THROUGHPUT_RX_MBPS] = 0 + results[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0 + results[ResultsConstants.TX_RATE_FPS] = 0 + results[ResultsConstants.TX_RATE_MBPS] = 0 + results[ResultsConstants.TX_RATE_PERCENT] = 0 + results[ResultsConstants.MIN_LATENCY_NS] = 0 + results[ResultsConstants.MAX_LATENCY_NS] = 0 + results[ResultsConstants.AVG_LATENCY_NS] = 0 + + for test_run in range(1, tests+1): collected_results = ( Moongen.run_moongen_and_collect_results(self, test_run=test_run)) - total_throughput_rx_fps += ( + results[ResultsConstants.THROUGHPUT_RX_FPS] += ( float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS])) - total_throughput_rx_mbps += ( + results[ResultsConstants.THROUGHPUT_RX_MBPS] += ( float(collected_results[ResultsConstants.THROUGHPUT_RX_MBPS])) - total_throughput_rx_pct += ( + results[ResultsConstants.THROUGHPUT_RX_PERCENT] += ( float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT])) - total_throughput_tx_fps += ( + results[ResultsConstants.TX_RATE_FPS] += ( float(collected_results[ResultsConstants.TX_RATE_FPS])) - total_throughput_tx_mbps += ( + results[ResultsConstants.TX_RATE_MBPS] += ( float(collected_results[ResultsConstants.TX_RATE_MBPS])) - total_throughput_tx_pct += ( + results[ResultsConstants.TX_RATE_PERCENT] += ( float(collected_results[ResultsConstants.TX_RATE_PERCENT])) - # Latency not supported now, leaving as placeholder - total_min_latency_ns = 0 - total_max_latency_ns = 0 - total_avg_latency_ns = 0 - - results = OrderedDict() results[ResultsConstants.THROUGHPUT_RX_FPS] = ( - '{:,.6f}'.format(total_throughput_rx_fps / trials)) + '{:.6f}'.format(results[ResultsConstants.THROUGHPUT_RX_FPS] / + tests)) results[ResultsConstants.THROUGHPUT_RX_MBPS] = ( - '{:,.3f}'.format(total_throughput_rx_mbps / trials)) + '{:.3f}'.format(results[ResultsConstants.THROUGHPUT_RX_MBPS] / + tests)) results[ResultsConstants.THROUGHPUT_RX_PERCENT] = ( - '{:,.3f}'.format(total_throughput_rx_pct / trials)) + '{:.3f}'.format(results[ResultsConstants.THROUGHPUT_RX_PERCENT] / + tests)) results[ResultsConstants.TX_RATE_FPS] = ( - '{:,.6f}'.format(total_throughput_tx_fps / trials)) + '{:.6f}'.format(results[ResultsConstants.TX_RATE_FPS] / + tests)) results[ResultsConstants.TX_RATE_MBPS] = ( - '{:,.3f}'.format(total_throughput_tx_mbps / trials)) + '{:.3f}'.format(results[ResultsConstants.TX_RATE_MBPS] / + tests)) results[ResultsConstants.TX_RATE_PERCENT] = ( - '{:,.3f}'.format(total_throughput_tx_pct / trials)) + '{:.3f}'.format(results[ResultsConstants.TX_RATE_PERCENT] / + tests)) results[ResultsConstants.MIN_LATENCY_NS] = ( - '{:,.3f}'.format(total_min_latency_ns / trials)) + '{:.3f}'.format(results[ResultsConstants.MIN_LATENCY_NS] / + tests)) results[ResultsConstants.MAX_LATENCY_NS] = ( - '{:,.3f}'.format(total_max_latency_ns / trials)) + '{:.3f}'.format(results[ResultsConstants.MAX_LATENCY_NS] / + tests)) results[ResultsConstants.AVG_LATENCY_NS] = ( - '{:,.3f}'.format(total_avg_latency_ns / trials)) + '{:.3f}'.format(results[ResultsConstants.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 +643,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 @@ -646,6 +659,7 @@ class Moongen(ITrafficGenerator): Back to Back Count (frames), Frame Loss (frames), Frame Loss (%) :rtype: :class:`Back2BackResult` """ + self._logger.info("In moongen send_rfc2544_back2back method") self._params.clear() self._params['traffic'] = self.traffic_defaults.copy() @@ -658,6 +672,7 @@ class Moongen(ITrafficGenerator): duration=duration, acceptable_loss_pct=lossrate) + # Initialize RFC 2544 B2B specific results results = OrderedDict() results[ResultsConstants.B2B_RX_FPS] = 0 results[ResultsConstants.B2B_TX_FPS] = 0 @@ -671,7 +686,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 +716,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 +745,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')