Merge "pkt_gen: Remove commas from MoonGen results"
[vswitchperf.git] / tools / pkt_gen / moongen / moongen.py
1 # Copyright 2016 Red Hat Inc
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 # Contributors:
16 #   Bill Michalowski, Red Hat Inc.
17 #   Andrew Theurer, Red Hat Inc.
18 """
19 Moongen Traffic Generator Model
20 """
21
22 # python imports
23 import logging
24 from collections import OrderedDict
25 import subprocess
26 import re
27
28 # VSPerf imports
29 from conf import settings
30 from core.results.results_constants import ResultsConstants
31 from tools.pkt_gen.trafficgen.trafficgenhelper import (
32     TRAFFIC_DEFAULTS,
33     merge_spec)
34 from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
35
36 class Moongen(ITrafficGenerator):
37     """Moongen Traffic generator wrapper."""
38     _traffic_defaults = TRAFFIC_DEFAULTS.copy()
39     _logger = logging.getLogger(__name__)
40
41     def __init__(self):
42         """Moongen class constructor."""
43         self._logger.info("In moongen __init__ method")
44         self._params = {}
45         self._moongen_host_ip_addr = (
46             settings.getValue('TRAFFICGEN_MOONGEN_HOST_IP_ADDR'))
47         self._moongen_base_dir = (
48             settings.getValue('TRAFFICGEN_MOONGEN_BASE_DIR'))
49         self._moongen_user = settings.getValue('TRAFFICGEN_MOONGEN_USER')
50         self._moongen_ports = settings.getValue('TRAFFICGEN_MOONGEN_PORTS')
51
52     @property
53     def traffic_defaults(self):
54         """Default traffic values.
55
56         These can be expected to be constant across traffic generators,
57         so no setter is provided. Changes to the structure or contents
58         will likely break traffic generator implementations or tests
59         respectively.
60         """
61         self._logger.info("In Moongen traffic_defaults method")
62         return self._traffic_defaults
63
64     def create_moongen_cfg_file(self, traffic, duration=60,
65                                 acceptable_loss_pct=1, one_shot=0):
66         """Create the Moongen configuration file from VSPERF's traffic profile
67         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
68         :param duration: The length of time to generate packet throughput
69         :param acceptable_loss: Maximum packet loss acceptable
70         :param one_shot: No RFC 2544 binary search,
71                         just packet flow at traffic specifics
72         """
73         logging.debug("traffic['frame_rate'] = " + \
74             str(traffic['frame_rate']))
75
76         logging.debug("traffic['multistream'] = " + \
77             str(traffic['multistream']))
78
79         logging.debug("traffic['stream_type'] = " + \
80             str(traffic['stream_type']))
81
82         logging.debug("traffic['l2']['srcmac'] = " + \
83             str(traffic['l2']['srcmac']))
84
85         logging.debug("traffic['l2']['dstmac'] = " + \
86             str(traffic['l2']['dstmac']))
87
88         logging.debug("traffic['l3']['proto'] = " + \
89             str(traffic['l3']['proto']))
90
91         logging.debug("traffic['l3']['srcip'] = " + \
92             str(traffic['l3']['srcip']))
93
94         logging.debug("traffic['l3']['dstip'] = " + \
95             str(traffic['l3']['dstip']))
96
97         logging.debug("traffic['l4']['srcport'] = " + \
98             str(traffic['l4']['srcport']))
99
100         logging.debug("traffic['l4']['dstport'] = " + \
101             str(traffic['l4']['dstport']))
102
103         logging.debug("traffic['vlan']['enabled'] = " + \
104             str(traffic['vlan']['enabled']))
105
106         logging.debug("traffic['vlan']['id'] = " + \
107             str(traffic['vlan']['id']))
108
109         logging.debug("traffic['vlan']['priority'] = " + \
110             str(traffic['vlan']['priority']))
111
112         logging.debug("traffic['vlan']['cfi'] = " + \
113             str(traffic['vlan']['cfi']))
114
115         logging.debug(traffic['l2']['framesize'])
116
117         out_file = open("opnfv-vsperf-cfg.lua", "wt")
118
119         out_file.write("VSPERF {\n")
120
121         out_file.write("testType = \"throughput\",\n")
122
123         out_file.write("runBidirec = " + \
124             traffic['bidir'].lower() + ",\n")
125
126         out_file.write("frameSize = " + \
127             str(traffic['l2']['framesize']) + ",\n")
128
129         out_file.write("srcMac = \"" + \
130             str(traffic['l2']['srcmac']) + "\",\n")
131
132         out_file.write("dstMac = \"" + \
133             str(traffic['l2']['dstmac']) + "\",\n")
134
135         out_file.write("srcIp = \"" + \
136             str(traffic['l3']['srcip']) + "\",\n")
137
138         out_file.write("dstIp = \"" + \
139             str(traffic['l3']['dstip']) + "\",\n")
140
141         if traffic['vlan']['enabled']:
142             out_file.write("vlanId = " + \
143                 str(traffic['vlan']['id']) + ",\n")
144
145         out_file.write("searchRunTime = " + \
146             str(duration) + ",\n")
147
148         out_file.write("validationRunTime = " + \
149             str(duration) + ",\n")
150
151         out_file.write("acceptableLossPct = " + \
152             str(acceptable_loss_pct) + ",\n")
153
154         out_file.write("ports = " +\
155             str(self._moongen_ports) +  ",\n")
156
157         if one_shot:
158             out_file.write("oneShot = true,\n")
159
160         # Assume 10G line rates at the moment.  Need to convert VSPERF
161         # frame_rate (percentage of line rate) to Mpps for Moongen
162
163         out_file.write("startRate = " + str((traffic['frame_rate'] / 100) * 14.88) + "\n")
164         out_file.write("}" + "\n")
165         out_file.close()
166
167         copy_moongen_cfg = "scp opnfv-vsperf-cfg.lua " + \
168                             self._moongen_user + "@" + \
169                             self._moongen_host_ip_addr + ":" + \
170                             self._moongen_base_dir + \
171                             "/. && rm opnfv-vsperf-cfg.lua"
172
173         find_moongen = subprocess.Popen(copy_moongen_cfg,
174                                         shell=True,
175                                         stderr=subprocess.PIPE)
176
177         output, error = find_moongen.communicate()
178
179         if error:
180             logging.error(output)
181             logging.error(error)
182             raise RuntimeError('MOONGEN: Error copying configuration file')
183
184     def connect(self):
185         """Connect to Moongen traffic generator
186
187         Verify that Moongen is on the system indicated by
188         the configuration file
189         """
190         self._logger.info("MOONGEN:  In Moongen connect method...")
191
192         if self._moongen_host_ip_addr:
193             cmd_ping = "ping -c1 " + self._moongen_host_ip_addr
194         else:
195             raise RuntimeError('MOONGEN: Moongen host not defined')
196
197         ping = subprocess.Popen(cmd_ping, shell=True, stderr=subprocess.PIPE)
198         output, error = ping.communicate()
199
200         if ping.returncode:
201             self._logger.error(error)
202             self._logger.error(output)
203             raise RuntimeError('MOONGEN: Cannot ping Moongen host at ' + \
204                                self._moongen_host_ip_addr)
205
206         connect_moongen = "ssh " + self._moongen_user + \
207                           "@" + self._moongen_host_ip_addr
208
209         cmd_find_moongen = connect_moongen + " ls " + \
210                            self._moongen_base_dir + "/examples/opnfv-vsperf.lua"
211
212         find_moongen = subprocess.Popen(cmd_find_moongen,
213                                         shell=True,
214                                         stderr=subprocess.PIPE)
215
216         output, error = find_moongen.communicate()
217
218         if find_moongen.returncode:
219             self._logger.error(error)
220             self._logger.error(output)
221             raise RuntimeError(
222                 'MOONGEN: Cannot locate Moongen program at %s within %s' \
223                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
224
225         self._logger.info("MOONGEN: Moongen host successfully found...")
226
227     def disconnect(self):
228         """Disconnect from the traffic generator.
229
230         As with :func:`connect`, this function is optional.
231
232         Where implemented, this function should raise an exception on
233         failure.
234
235         :returns: None
236         """
237         self._logger.info("MOONGEN: In moongen disconnect method")
238
239     def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
240         """Send a burst of traffic.
241
242         Send a ``numpkts`` packets of traffic, using ``traffic``
243         configuration, with a timeout of ``time``.
244
245         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
246         :param numpkts: Number of packets to send
247         :param duration: Time to wait to receive packets
248
249         :returns: dictionary of strings with following data:
250             - List of Tx Frames,
251             - List of Rx Frames,
252             - List of Tx Bytes,
253             - List of List of Rx Bytes,
254             - Payload Errors and Sequence Errors.
255         """
256         self._logger.info("In Moongen send_burst_traffic method")
257         return NotImplementedError('Moongen Burst traffic not implemented')
258
259     def send_cont_traffic(self, traffic=None, duration=20):
260         """Send a continuous flow of traffic
261
262         Send packets at ``frame rate``, using ``traffic`` configuration,
263         until timeout ``time`` occurs.
264
265         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
266         :param duration: Time to wait to receive packets (secs)
267         :returns: dictionary of strings with following data:
268             - Tx Throughput (fps),
269             - Rx Throughput (fps),
270             - Tx Throughput (mbps),
271             - Rx Throughput (mbps),
272             - Tx Throughput (% linerate),
273             - Rx Throughput (% linerate),
274             - Min Latency (ns),
275             - Max Latency (ns),
276             - Avg Latency (ns)
277         """
278         self._logger.info("In Moongen send_cont_traffic method")
279
280         self._params.clear()
281         self._params['traffic'] = self.traffic_defaults.copy()
282
283         if traffic:
284             self._params['traffic'] = merge_spec(self._params['traffic'],
285                                                  traffic)
286
287         Moongen.create_moongen_cfg_file(self,
288                                         traffic,
289                                         duration=duration,
290                                         acceptable_loss_pct=100.0,
291                                         one_shot=1)
292
293         collected_results = Moongen.run_moongen_and_collect_results(self,
294                                                                     test_run=1)
295
296         total_throughput_rx_fps = (
297             float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS]))
298
299         total_throughput_rx_mbps = (
300             float(collected_results[ResultsConstants.THROUGHPUT_RX_MBPS]))
301
302         total_throughput_rx_pct = (
303             float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT]))
304
305         total_throughput_tx_fps = (
306             float(collected_results[ResultsConstants.TX_RATE_FPS]))
307
308         total_throughput_tx_mbps = (
309             float(collected_results[ResultsConstants.TX_RATE_MBPS]))
310
311         total_throughput_tx_pct = (
312             float(collected_results[ResultsConstants.TX_RATE_PERCENT]))
313
314         total_min_latency_ns = 0
315         total_max_latency_ns = 0
316         total_avg_latency_ns = 0
317
318         results = OrderedDict()
319         results[ResultsConstants.THROUGHPUT_RX_FPS] = (
320             '{:.6f}'.format(total_throughput_rx_fps))
321
322         results[ResultsConstants.THROUGHPUT_RX_MBPS] = (
323             '{:.3f}'.format(total_throughput_rx_mbps))
324
325         results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
326             '{:.3f}'.format(total_throughput_rx_pct))
327
328         results[ResultsConstants.TX_RATE_FPS] = (
329             '{:.6f}'.format(total_throughput_tx_fps))
330
331         results[ResultsConstants.TX_RATE_MBPS] = (
332             '{:.3f}'.format(total_throughput_tx_mbps))
333
334         results[ResultsConstants.TX_RATE_PERCENT] = (
335             '{:.3f}'.format(total_throughput_tx_pct))
336
337         results[ResultsConstants.MIN_LATENCY_NS] = (
338             '{:.3f}'.format(total_min_latency_ns))
339
340         results[ResultsConstants.MAX_LATENCY_NS] = (
341             '{:.3f}'.format(total_max_latency_ns))
342
343         results[ResultsConstants.AVG_LATENCY_NS] = (
344             '{:.3f}'.format(total_avg_latency_ns))
345
346         return results
347
348     def start_cont_traffic(self, traffic=None, duration=20):
349         """ Non-blocking version of 'send_cont_traffic'.
350
351         Start transmission and immediately return. Do not wait for
352         results.
353         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
354         :param duration: Time to wait to receive packets (secs)
355         """
356         self._logger.info("In Moongen start_cont_traffic method")
357         return NotImplementedError('moongen continuous traffic not implemented')
358
359     def stop_cont_traffic(self):
360         # Stop continuous transmission and return results.
361         self._logger.info("In Moongen stop_cont_traffic method")
362
363     def run_moongen_and_collect_results(self, test_run=1):
364         """Execute Moongen and transform results into VSPERF format
365         :param test_run: The number of tests to run
366         """
367         # Start Moongen and create logfile of the run
368         connect_moongen = "ssh " + self._moongen_user + "@" + \
369             self._moongen_host_ip_addr
370
371         cmd_moongen = " 'cd " + self._moongen_base_dir + \
372             "; ./build/MoonGen examples/opnfv-vsperf.lua | tee moongen_log.txt'"
373
374         cmd_start_moongen = connect_moongen + cmd_moongen
375
376         start_moongen = subprocess.Popen(cmd_start_moongen,
377                                          shell=True, stderr=subprocess.PIPE)
378
379         output, error = start_moongen.communicate()
380
381         if start_moongen.returncode:
382             logging.debug(error)
383             logging.debug(output)
384             raise RuntimeError(
385                 'MOONGEN: Error starting Moongen program at %s within %s' \
386                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
387
388         cmd_moongen = "mkdir -p /tmp/moongen/" + str(test_run)
389
390         moongen_create_log_dir = subprocess.Popen(cmd_moongen,
391                                                   shell=True,
392                                                   stderr=subprocess.PIPE)
393
394         output, error = moongen_create_log_dir.communicate()
395
396         if moongen_create_log_dir.returncode:
397             logging.debug(error)
398             logging.debug(output)
399             raise RuntimeError(
400                 'MOONGEN: Error obtaining Moongen log from %s within %s' \
401                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
402
403         cmd_moongen = " scp " + self._moongen_user + "@" + \
404             self._moongen_host_ip_addr + ":" + \
405             self._moongen_base_dir + "/moongen_log.txt /tmp/moongen/" + \
406             str(test_run) + "/moongen-run.log"
407
408         copy_moongen_log = subprocess.Popen(cmd_moongen,
409                                             shell=True,
410                                             stderr=subprocess.PIPE)
411
412         output, error = copy_moongen_log.communicate()
413
414         if copy_moongen_log.returncode:
415             logging.debug(error)
416             logging.debug(output)
417             raise RuntimeError(
418                 'MOONGEN: Error obtaining Moongen log from %s within %s' \
419                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
420
421         log_file = "/tmp/moongen/" + str(test_run) + "/moongen-run.log"
422
423         with open(log_file, 'r') as logfile_handle:
424             mytext = logfile_handle.read()
425
426              # REPORT results line
427              # match.group(1) = Tx frames
428              # match.group(2) = Rx frames
429              # match.group(3) = Frame loss (count)
430              # match.group(4) = Frame loss (percentage)
431              # match.group(5) = Tx Mpps
432              # match.group(6) = Rx Mpps
433             search_pattern = re.compile(
434                 r'\[REPORT\]\s+total\:\s+'
435                 r'Tx\s+frames\:\s+(\d+)\s+'
436                 r'Rx\s+Frames\:\s+(\d+)\s+'
437                 r'frame\s+loss\:\s+(\d+)\,'
438                 r'\s+(\d+\.\d+|\d+)%\s+'
439                 r'Tx\s+Mpps\:\s+(\d+.\d+|\d+)\s+'
440                 r'Rx\s+Mpps\:\s+(\d+\.\d+|\d+)',
441                 re.IGNORECASE)
442
443             results_match = search_pattern.search(mytext)
444
445             if not results_match:
446                 logging.error('There was a problem parsing ' +\
447                     'Moongen REPORT section of Moongen log file')
448
449             moongen_results = OrderedDict()
450             moongen_results[ResultsConstants.THROUGHPUT_RX_FPS] = 0
451             moongen_results[ResultsConstants.THROUGHPUT_RX_MBPS] = 0
452             moongen_results[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0
453             moongen_results[ResultsConstants.TX_RATE_FPS] = 0
454             moongen_results[ResultsConstants.TX_RATE_MBPS] = 0
455             moongen_results[ResultsConstants.TX_RATE_PERCENT] = 0
456             moongen_results[ResultsConstants.B2B_TX_COUNT] = 0
457             moongen_results[ResultsConstants.B2B_FRAMES] = 0
458             moongen_results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = 0
459             moongen_results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = 0
460
461             # find PARAMETERS line
462             # parameters_match.group(1) = Frame size
463
464             search_pattern = re.compile(
465                 r'\[PARAMETERS\]\s+.*frameSize\:\s+(\d+)',
466                 flags=re.IGNORECASE)
467             parameters_match = search_pattern.search(mytext)
468
469             if parameters_match:
470                 frame_size = int(parameters_match.group(1))
471             else:
472                 logging.error('There was a problem parsing Moongen ' +\
473                     'PARAMETERS section of Moongen log file')
474                 frame_size = 0
475
476         if results_match and parameters_match:
477             # Assume for now 10G link speed
478             max_theoretical_mfps = (
479                 (10000000000 / 8) / (frame_size + 20))
480
481             moongen_results[ResultsConstants.THROUGHPUT_RX_FPS] = (
482                 float(results_match.group(6)) * 1000000)
483
484             moongen_results[ResultsConstants.THROUGHPUT_RX_MBPS] = (
485                 (float(results_match.group(6)) * frame_size + 20) * 8)
486
487             moongen_results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
488                 float(results_match.group(6)) * \
489                       1000000 / max_theoretical_mfps * 100)
490
491             moongen_results[ResultsConstants.TX_RATE_FPS] = (
492                 float(results_match.group(5)) * 1000000)
493
494             moongen_results[ResultsConstants.TX_RATE_MBPS] = (
495                 float(results_match.group(5)) * (frame_size + 20) * 8)
496
497             moongen_results[ResultsConstants.TX_RATE_PERCENT] = (
498                 float(results_match.group(5)) *
499                 1000000 / max_theoretical_mfps * 100)
500
501             moongen_results[ResultsConstants.B2B_TX_COUNT] = (
502                 float(results_match.group(1)))
503
504             moongen_results[ResultsConstants.B2B_FRAMES] = (
505                 float(results_match.group(2)))
506
507             moongen_results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = (
508                 float(results_match.group(3)))
509
510             moongen_results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = (
511                 float(results_match.group(4)))
512
513         return moongen_results
514
515     def send_rfc2544_throughput(self, traffic=None, duration=20,
516                                 lossrate=0.0, trials=1):
517         #
518         # Send traffic per RFC2544 throughput test specifications.
519         #
520         # Send packets at a variable rate, using ``traffic``
521         # configuration, until minimum rate at which no packet loss is
522         # detected is found.
523         #
524         # :param traffic: Detailed "traffic" spec, see design docs for details
525         # :param trials: Number of trials to execute
526         # :param duration: Per iteration duration
527         # :param lossrate: Acceptable lossrate percentage
528         # :returns: dictionary of strings with following data:
529         #     - Tx Throughput (fps),
530         #     - Rx Throughput (fps),
531         #     - Tx Throughput (mbps),
532         #     - Rx Throughput (mbps),
533         #     - Tx Throughput (% linerate),
534         #     - Rx Throughput (% linerate),
535         #     - Min Latency (ns),
536         #     - Max Latency (ns),
537         #     - Avg Latency (ns)
538         #
539         self._logger.info("In moongen send_rfc2544_throughput method")
540         self._params.clear()
541         self._params['traffic'] = self.traffic_defaults.copy()
542
543         if traffic:
544             self._params['traffic'] = merge_spec(self._params['traffic'],
545                                                  traffic)
546         Moongen.create_moongen_cfg_file(self,
547                                         traffic,
548                                         duration=duration,
549                                         acceptable_loss_pct=lossrate)
550
551         total_throughput_rx_fps = 0
552         total_throughput_rx_mbps = 0
553         total_throughput_rx_pct = 0
554         total_throughput_tx_fps = 0
555         total_throughput_tx_mbps = 0
556         total_throughput_tx_pct = 0
557         total_min_latency_ns = 0
558         total_max_latency_ns = 0
559         total_avg_latency_ns = 0
560
561         for test_run in range(1, trials+1):
562             collected_results = (
563                 Moongen.run_moongen_and_collect_results(self, test_run=test_run))
564
565             total_throughput_rx_fps += (
566                 float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS]))
567
568             total_throughput_rx_mbps += (
569                 float(collected_results[ResultsConstants.THROUGHPUT_RX_MBPS]))
570
571             total_throughput_rx_pct += (
572                 float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT]))
573
574             total_throughput_tx_fps += (
575                 float(collected_results[ResultsConstants.TX_RATE_FPS]))
576
577             total_throughput_tx_mbps += (
578                 float(collected_results[ResultsConstants.TX_RATE_MBPS]))
579
580             total_throughput_tx_pct += (
581                 float(collected_results[ResultsConstants.TX_RATE_PERCENT]))
582
583             # Latency not supported now, leaving as placeholder
584             total_min_latency_ns = 0
585             total_max_latency_ns = 0
586             total_avg_latency_ns = 0
587
588         results = OrderedDict()
589         results[ResultsConstants.THROUGHPUT_RX_FPS] = (
590             '{:.6f}'.format(total_throughput_rx_fps / trials))
591
592         results[ResultsConstants.THROUGHPUT_RX_MBPS] = (
593             '{:.3f}'.format(total_throughput_rx_mbps / trials))
594
595         results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
596             '{:.3f}'.format(total_throughput_rx_pct / trials))
597
598         results[ResultsConstants.TX_RATE_FPS] = (
599             '{:.6f}'.format(total_throughput_tx_fps / trials))
600
601         results[ResultsConstants.TX_RATE_MBPS] = (
602             '{:.3f}'.format(total_throughput_tx_mbps / trials))
603
604         results[ResultsConstants.TX_RATE_PERCENT] = (
605             '{:.3f}'.format(total_throughput_tx_pct / trials))
606
607         results[ResultsConstants.MIN_LATENCY_NS] = (
608             '{:.3f}'.format(total_min_latency_ns / trials))
609
610         results[ResultsConstants.MAX_LATENCY_NS] = (
611             '{:.3f}'.format(total_max_latency_ns / trials))
612
613         results[ResultsConstants.AVG_LATENCY_NS] = (
614             '{:.3f}'.format(total_avg_latency_ns / trials))
615
616         return results
617
618     def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
619                                  lossrate=0.0):
620         """Non-blocking version of 'send_rfc2544_throughput'.
621
622         Start transmission and immediately return. Do not wait for
623         results.
624         """
625         self._logger.info(
626             "MOONGEN: In moongen start_rfc2544_throughput method")
627
628     def wait_rfc2544_throughput(self):
629         """Wait for and return results of RFC2544 test.
630         """
631         self._logger.info('In moongen wait_rfc2544_throughput')
632
633     def send_rfc2544_back2back(self, traffic=None, duration=60,
634                                lossrate=0.0, trials=1):
635         """Send traffic per RFC2544 back2back test specifications.
636
637         Send packets at a fixed rate, using ``traffic``
638         configuration, for duration seconds.
639
640         :param traffic: Detailed "traffic" spec, see design docs for details
641         :param trials: Number of trials to execute
642         :param duration: Per iteration duration
643         :param lossrate: Acceptable loss percentage
644
645         :returns: Named tuple of Rx Throughput (fps), Rx Throughput (mbps),
646             Tx Rate (% linerate), Rx Rate (% linerate), Tx Count (frames),
647             Back to Back Count (frames), Frame Loss (frames), Frame Loss (%)
648         :rtype: :class:`Back2BackResult`
649         """
650         self._params.clear()
651         self._params['traffic'] = self.traffic_defaults.copy()
652
653         if traffic:
654             self._params['traffic'] = merge_spec(self._params['traffic'],
655                                                  traffic)
656
657         Moongen.create_moongen_cfg_file(self,
658                                         traffic,
659                                         duration=duration,
660                                         acceptable_loss_pct=lossrate)
661
662         results = OrderedDict()
663         results[ResultsConstants.B2B_RX_FPS] = 0
664         results[ResultsConstants.B2B_TX_FPS] = 0
665         results[ResultsConstants.B2B_RX_PERCENT] = 0
666         results[ResultsConstants.B2B_TX_PERCENT] = 0
667         results[ResultsConstants.B2B_TX_COUNT] = 0
668         results[ResultsConstants.B2B_FRAMES] = 0
669         results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = 0
670         results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = 0
671         results[ResultsConstants.SCAL_STREAM_COUNT] = 0
672         results[ResultsConstants.SCAL_STREAM_TYPE] = 0
673         results[ResultsConstants.SCAL_PRE_INSTALLED_FLOWS] = 0
674
675         for test_run in range(1, trials+1):
676             collected_results = (
677                 Moongen.run_moongen_and_collect_results(self, test_run=test_run))
678
679             results[ResultsConstants.B2B_RX_FPS] += (
680                 float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS]))
681
682             results[ResultsConstants.B2B_RX_PERCENT] += (
683                 float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT]))
684
685             results[ResultsConstants.B2B_TX_FPS] += (
686                 float(collected_results[ResultsConstants.TX_RATE_FPS]))
687
688             results[ResultsConstants.B2B_TX_PERCENT] += (
689                 float(collected_results[ResultsConstants.TX_RATE_PERCENT]))
690
691             results[ResultsConstants.B2B_TX_COUNT] += (
692                 int(collected_results[ResultsConstants.B2B_TX_COUNT]))
693
694             results[ResultsConstants.B2B_FRAMES] += (
695                 int(collected_results[ResultsConstants.B2B_FRAMES]))
696
697             results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] += (
698                 int(collected_results[ResultsConstants.B2B_FRAME_LOSS_FRAMES]))
699
700             results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] += (
701                 int(collected_results[ResultsConstants.B2B_FRAME_LOSS_PERCENT]))
702
703         # Calculate average results
704         results[ResultsConstants.B2B_RX_FPS] = (
705             results[ResultsConstants.B2B_RX_FPS] / trials)
706
707         results[ResultsConstants.B2B_RX_PERCENT] = (
708             results[ResultsConstants.B2B_RX_PERCENT] / trials)
709
710         results[ResultsConstants.B2B_TX_FPS] = (
711             results[ResultsConstants.B2B_TX_FPS] / trials)
712
713         results[ResultsConstants.B2B_TX_PERCENT] = (
714             results[ResultsConstants.B2B_TX_PERCENT] / trials)
715
716         results[ResultsConstants.B2B_TX_COUNT] = (
717             results[ResultsConstants.B2B_TX_COUNT] / trials)
718
719         results[ResultsConstants.B2B_FRAMES] = (
720             results[ResultsConstants.B2B_FRAMES] / trials)
721
722         results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = (
723             results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] / trials)
724
725         results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = (
726             results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] / trials)
727
728         results[ResultsConstants.SCAL_STREAM_COUNT] = 0
729         results[ResultsConstants.SCAL_STREAM_TYPE] = 0
730         results[ResultsConstants.SCAL_PRE_INSTALLED_FLOWS] = 0
731
732         return results
733
734     def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
735                                 lossrate=0.0):
736         #
737         # Non-blocking version of 'send_rfc2544_back2back'.
738         #
739         # Start transmission and immediately return. Do not wait for results.
740         #
741         self._logger.info("In Moongen start_rfc2544_back2back method")
742         return NotImplementedError(
743             'Moongen start back2back traffic not implemented')
744
745     def wait_rfc2544_back2back(self):
746         self._logger.info("In moongen wait_rfc2544_back2back method")
747         #
748         # Wait and set results of RFC2544 test.
749         #
750         return NotImplementedError(
751             'Moongen wait back2back traffic not implemented')
752
753 if __name__ == "__main__":
754     pass