d6c09e5dc294064266d0b885529283d8df5e5481
[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         out_file.write("vlanId = " + \
142             str(traffic['vlan']['id']) + ",\n")
143
144         out_file.write("searchRunTime = " + \
145             str(duration) + ",\n")
146
147         out_file.write("validationRunTime = " + \
148             str(duration) + ",\n")
149
150         out_file.write("acceptableLossPct = " + \
151             str(acceptable_loss_pct) + ",\n")
152
153         out_file.write("ports = " +\
154             str(self._moongen_ports) +  ",\n")
155
156         if one_shot:
157             out_file.write("oneShot = true,\n")
158
159         # Assume 10G line rates at the moment.  Need to convert VSPERF
160         # frame_rate (percentage of line rate) to Mpps for MoonGen
161
162         out_file.write("startRate = " + str((traffic['frame_rate'] / 100) * 14.88) + "\n")
163         out_file.write("}" + "\n")
164         out_file.close()
165
166         copy_moongen_cfg = "scp opnfv-vsperf-cfg.lua " + \
167                             self._moongen_user + "@" + \
168                             self._moongen_host_ip_addr + ":" + \
169                             self._moongen_base_dir + \
170                             "/. && rm opnfv-vsperf-cfg.lua"
171
172         find_moongen = subprocess.Popen(copy_moongen_cfg,
173                                         shell=True,
174                                         stderr=subprocess.PIPE)
175
176         output, error = find_moongen.communicate()
177
178         if error:
179             logging.error(output)
180             logging.error(error)
181             raise RuntimeError('MOONGEN: Error copying configuration file')
182
183     def connect(self):
184         """Connect to MoonGen traffic generator
185
186         Verify that MoonGen is on the system indicated by
187         the configuration file
188         """
189         self._logger.info("MOONGEN:  In MoonGen connect method...")
190
191         if self._moongen_host_ip_addr:
192             cmd_ping = "ping -c1 " + self._moongen_host_ip_addr
193         else:
194             raise RuntimeError('MOONGEN: MoonGen host not defined')
195
196         ping = subprocess.Popen(cmd_ping, shell=True, stderr=subprocess.PIPE)
197         output, error = ping.communicate()
198
199         if ping.returncode:
200             self._logger.error(error)
201             self._logger.error(output)
202             raise RuntimeError('MOONGEN: Cannot ping MoonGen host at ' + \
203                                self._moongen_host_ip_addr)
204
205         connect_moongen = "ssh " + self._moongen_user + \
206                           "@" + self._moongen_host_ip_addr
207
208         cmd_find_moongen = connect_moongen + " ls " + \
209                            self._moongen_base_dir + "/examples/opnfv-vsperf.lua"
210
211         find_moongen = subprocess.Popen(cmd_find_moongen,
212                                         shell=True,
213                                         stderr=subprocess.PIPE)
214
215         output, error = find_moongen.communicate()
216
217         if find_moongen.returncode:
218             self._logger.error(error)
219             self._logger.error(output)
220             raise RuntimeError(
221                 'MOONGEN: Cannot locate MoonGen program at %s within %s' \
222                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
223
224         self._logger.info("MOONGEN: MoonGen host successfully found...")
225
226     def disconnect(self):
227         """Disconnect from the traffic generator.
228
229         As with :func:`connect`, this function is optional.
230
231         Where implemented, this function should raise an exception on
232         failure.
233
234         :returns: None
235         """
236         self._logger.info("MOONGEN: In moongen disconnect method")
237
238     def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
239         """Send a burst of traffic.
240
241         Send a ``numpkts`` packets of traffic, using ``traffic``
242         configuration, with a timeout of ``time``.
243
244         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
245         :param numpkts: Number of packets to send
246         :param duration: Time to wait to receive packets
247
248         :returns: dictionary of strings with following data:
249             - List of Tx Frames,
250             - List of Rx Frames,
251             - List of Tx Bytes,
252             - List of List of Rx Bytes,
253             - Payload Errors and Sequence Errors.
254         """
255         self._logger.info("In moongen send_burst_traffic method")
256         return NotImplementedError('Moongen Burst traffic not implemented')
257
258     def send_cont_traffic(self, traffic=None, duration=20):
259         """Send a continuous flow of traffic
260
261         Send packets at ``frame rate``, using ``traffic`` configuration,
262         until timeout ``time`` occurs.
263
264         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
265         :param duration: Time to wait to receive packets (secs)
266         :returns: dictionary of strings with following data:
267             - Tx Throughput (fps),
268             - Rx Throughput (fps),
269             - Tx Throughput (mbps),
270             - Rx Throughput (mbps),
271             - Tx Throughput (% linerate),
272             - Rx Throughput (% linerate),
273             - Min Latency (ns),
274             - Max Latency (ns),
275             - Avg Latency (ns)
276         """
277         self._logger.info("In moongen send_cont_traffic method")
278
279         self._params.clear()
280         self._params['traffic'] = self.traffic_defaults.copy()
281
282         if traffic:
283             self._params['traffic'] = merge_spec(self._params['traffic'],
284                                                  traffic)
285
286         Moongen.create_moongen_cfg_file(self,
287                                         traffic,
288                                         duration=duration,
289                                         acceptable_loss_pct=100.0,
290                                         one_shot=1)
291
292         collected_results = Moongen.run_moongen_and_collect_results(self,
293                                                                     test_run=1)
294
295         total_throughput_rx_fps = (
296             float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS]))
297
298         total_throughput_rx_mbps = (
299             float(collected_results[ResultsConstants.THROUGHPUT_RX_MBPS]))
300
301         total_throughput_rx_pct = (
302             float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT]))
303
304         total_throughput_tx_fps = (
305             float(collected_results[ResultsConstants.TX_RATE_FPS]))
306
307         total_throughput_tx_mbps = (
308             float(collected_results[ResultsConstants.TX_RATE_MBPS]))
309
310         total_throughput_tx_pct = (
311             float(collected_results[ResultsConstants.TX_RATE_PERCENT]))
312
313         total_min_latency_ns = 0
314         total_max_latency_ns = 0
315         total_avg_latency_ns = 0
316
317         results = OrderedDict()
318         results[ResultsConstants.THROUGHPUT_RX_FPS] = (
319             '{:,.6f}'.format(total_throughput_rx_fps))
320
321         results[ResultsConstants.THROUGHPUT_RX_MBPS] = (
322             '{:,.3f}'.format(total_throughput_rx_mbps))
323
324         results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
325             '{:,.3f}'.format(total_throughput_rx_pct))
326
327         results[ResultsConstants.TX_RATE_FPS] = (
328             '{:,.6f}'.format(total_throughput_tx_fps))
329
330         results[ResultsConstants.TX_RATE_MBPS] = (
331             '{:,.3f}'.format(total_throughput_tx_mbps))
332
333         results[ResultsConstants.TX_RATE_PERCENT] = (
334             '{:,.3f}'.format(total_throughput_tx_pct))
335
336         results[ResultsConstants.MIN_LATENCY_NS] = (
337             '{:,.3f}'.format(total_min_latency_ns))
338
339         results[ResultsConstants.MAX_LATENCY_NS] = (
340             '{:,.3f}'.format(total_max_latency_ns))
341
342         results[ResultsConstants.AVG_LATENCY_NS] = (
343             '{:,.3f}'.format(total_avg_latency_ns))
344
345         return results
346
347     def start_cont_traffic(self, traffic=None, duration=20):
348         """ Non-blocking version of 'send_cont_traffic'.
349
350         Start transmission and immediately return. Do not wait for
351         results.
352         :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
353         :param duration: Time to wait to receive packets (secs)
354         """
355         self._logger.info("In moongen start_cont_traffic method")
356         return NotImplementedError('Moongen continuous traffic not implemented')
357
358     def stop_cont_traffic(self):
359         # Stop continuous transmission and return results.
360         self._logger.info("In moongen stop_cont_traffic method")
361
362     def run_moongen_and_collect_results(self, test_run=1):
363         """Execute MoonGen and transform results into VSPERF format
364         :param test_run: The number of tests to run
365         """
366         # Start MoonGen and create logfile of the run
367         connect_moongen = "ssh " + self._moongen_user + "@" + \
368             self._moongen_host_ip_addr
369
370         cmd_moongen = " 'cd " + self._moongen_base_dir + \
371             "; ./build/MoonGen examples/opnfv-vsperf.lua | tee moongen_log.txt'"
372
373         cmd_start_moongen = connect_moongen + cmd_moongen
374
375         start_moongen = subprocess.Popen(cmd_start_moongen,
376                                          shell=True, stderr=subprocess.PIPE)
377
378         output, error = start_moongen.communicate()
379
380         if start_moongen.returncode:
381             logging.debug(error)
382             logging.debug(output)
383             raise RuntimeError(
384                 'MOONGEN: Error starting MoonGen program at %s within %s' \
385                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
386
387         cmd_moongen = "mkdir -p /tmp/moongen/" + str(test_run)
388
389         moongen_create_log_dir = subprocess.Popen(cmd_moongen,
390                                                   shell=True,
391                                                   stderr=subprocess.PIPE)
392
393         output, error = moongen_create_log_dir.communicate()
394
395         if moongen_create_log_dir.returncode:
396             logging.debug(error)
397             logging.debug(output)
398             raise RuntimeError(
399                 'MOONGEN: Error obtaining MoonGen log from %s within %s' \
400                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
401
402         cmd_moongen = " scp " + self._moongen_user + "@" + \
403             self._moongen_host_ip_addr + ":" + \
404             self._moongen_base_dir + "/moongen_log.txt /tmp/moongen/" + \
405             str(test_run) + "/moongen-run.log"
406
407         copy_moongen_log = subprocess.Popen(cmd_moongen,
408                                             shell=True,
409                                             stderr=subprocess.PIPE)
410
411         output, error = copy_moongen_log.communicate()
412
413         if copy_moongen_log.returncode:
414             logging.debug(error)
415             logging.debug(output)
416             raise RuntimeError(
417                 'MOONGEN: Error obtaining MoonGen log from %s within %s' \
418                 % (self._moongen_host_ip_addr, self._moongen_base_dir))
419
420         log_file = "/tmp/moongen/" + str(test_run) + "/moongen-run.log"
421
422         with open(log_file, 'r') as logfile_handle:
423             mytext = logfile_handle.read()
424
425              # REPORT results line
426              # match.group(1) = Tx frames
427              # match.group(2) = Rx frames
428              # match.group(3) = Frame loss (count)
429              # match.group(4) = Frame loss (percentage)
430              # match.group(5) = Tx Mpps
431              # match.group(6) = Rx Mpps
432             search_pattern = re.compile(
433                 r'\[REPORT\]\s+total\:\s+'
434                 r'Tx\s+frames\:\s+(\d+)\s+'
435                 r'Rx\s+Frames\:\s+(\d+)\s+'
436                 r'frame\s+loss\:\s+(\d+)\,'
437                 r'\s+(\d+\.\d+|\d+)%\s+'
438                 r'Tx\s+Mpps\:\s+(\d+.\d+|\d+)\s+'
439                 r'Rx\s+Mpps\:\s+(\d+\.\d+|\d+)',
440                 re.IGNORECASE)
441
442             results_match = search_pattern.search(mytext)
443
444             if not results_match:
445                 logging.error('There was a problem parsing ' +\
446                     'MoonGen REPORT section of MoonGen log file')
447
448             moongen_results = OrderedDict()
449             moongen_results[ResultsConstants.THROUGHPUT_RX_FPS] = 0
450             moongen_results[ResultsConstants.THROUGHPUT_RX_MBPS] = 0
451             moongen_results[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0
452             moongen_results[ResultsConstants.TX_RATE_FPS] = 0
453             moongen_results[ResultsConstants.TX_RATE_MBPS] = 0
454             moongen_results[ResultsConstants.TX_RATE_PERCENT] = 0
455             moongen_results[ResultsConstants.B2B_TX_COUNT] = 0
456             moongen_results[ResultsConstants.B2B_FRAMES] = 0
457             moongen_results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = 0
458             moongen_results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = 0
459
460             # find PARAMETERS line
461             # parameters_match.group(1) = Frame size
462
463             search_pattern = re.compile(
464                 r'\[PARAMETERS\]\s+.*frameSize\:\s+(\d+)',
465                 flags=re.IGNORECASE)
466             parameters_match = search_pattern.search(mytext)
467
468             if parameters_match:
469                 frame_size = int(parameters_match.group(1))
470             else:
471                 logging.error('There was a problem parsing MoonGen ' +\
472                     'PARAMETERS section of MoonGen log file')
473                 frame_size = 0
474
475         if results_match and parameters_match:
476             # Assume for now 10G link speed
477             max_theoretical_mfps = (
478                 (10000000000 / 8) / (frame_size + 20))
479
480             moongen_results[ResultsConstants.THROUGHPUT_RX_FPS] = (
481                 float(results_match.group(6)) * 1000000)
482
483             moongen_results[ResultsConstants.THROUGHPUT_RX_MBPS] = (
484                 (float(results_match.group(6)) * frame_size + 20) * 8)
485
486             moongen_results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
487                 float(results_match.group(6)) * \
488                       1000000 / max_theoretical_mfps * 100)
489
490             moongen_results[ResultsConstants.TX_RATE_FPS] = (
491                 float(results_match.group(5)) * 1000000)
492
493             moongen_results[ResultsConstants.TX_RATE_MBPS] = (
494                 float(results_match.group(5)) * (frame_size + 20) * 8)
495
496             moongen_results[ResultsConstants.TX_RATE_PERCENT] = (
497                 float(results_match.group(5)) *
498                 1000000 / max_theoretical_mfps * 100)
499
500             moongen_results[ResultsConstants.B2B_TX_COUNT] = (
501                 float(results_match.group(1)))
502
503             moongen_results[ResultsConstants.B2B_FRAMES] = (
504                 float(results_match.group(2)))
505
506             moongen_results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = (
507                 float(results_match.group(3)))
508
509             moongen_results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = (
510                 float(results_match.group(4)))
511
512         return moongen_results
513
514     def send_rfc2544_throughput(self, traffic=None, duration=20,
515                                 lossrate=0.0, trials=1):
516         #
517         # Send traffic per RFC2544 throughput test specifications.
518         #
519         # Send packets at a variable rate, using ``traffic``
520         # configuration, until minimum rate at which no packet loss is
521         # detected is found.
522         #
523         # :param traffic: Detailed "traffic" spec, see design docs for details
524         # :param trials: Number of trials to execute
525         # :param duration: Per iteration duration
526         # :param lossrate: Acceptable lossrate percentage
527         # :returns: dictionary of strings with following data:
528         #     - Tx Throughput (fps),
529         #     - Rx Throughput (fps),
530         #     - Tx Throughput (mbps),
531         #     - Rx Throughput (mbps),
532         #     - Tx Throughput (% linerate),
533         #     - Rx Throughput (% linerate),
534         #     - Min Latency (ns),
535         #     - Max Latency (ns),
536         #     - Avg Latency (ns)
537         #
538         self._logger.info("In moongen send_rfc2544_throughput method")
539         self._params.clear()
540         self._params['traffic'] = self.traffic_defaults.copy()
541
542         if traffic:
543             self._params['traffic'] = merge_spec(self._params['traffic'],
544                                                  traffic)
545         Moongen.create_moongen_cfg_file(self,
546                                         traffic,
547                                         duration=duration,
548                                         acceptable_loss_pct=lossrate)
549
550         total_throughput_rx_fps = 0
551         total_throughput_rx_mbps = 0
552         total_throughput_rx_pct = 0
553         total_throughput_tx_fps = 0
554         total_throughput_tx_mbps = 0
555         total_throughput_tx_pct = 0
556         total_min_latency_ns = 0
557         total_max_latency_ns = 0
558         total_avg_latency_ns = 0
559
560         for test_run in range(1, trials+1):
561             collected_results = (
562                 Moongen.run_moongen_and_collect_results(self, test_run=test_run))
563
564             total_throughput_rx_fps += (
565                 float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS]))
566
567             total_throughput_rx_mbps += (
568                 float(collected_results[ResultsConstants.THROUGHPUT_RX_MBPS]))
569
570             total_throughput_rx_pct += (
571                 float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT]))
572
573             total_throughput_tx_fps += (
574                 float(collected_results[ResultsConstants.TX_RATE_FPS]))
575
576             total_throughput_tx_mbps += (
577                 float(collected_results[ResultsConstants.TX_RATE_MBPS]))
578
579             total_throughput_tx_pct += (
580                 float(collected_results[ResultsConstants.TX_RATE_PERCENT]))
581
582             # Latency not supported now, leaving as placeholder
583             total_min_latency_ns = 0
584             total_max_latency_ns = 0
585             total_avg_latency_ns = 0
586
587         results = OrderedDict()
588         results[ResultsConstants.THROUGHPUT_RX_FPS] = (
589             '{:,.6f}'.format(total_throughput_rx_fps / trials))
590
591         results[ResultsConstants.THROUGHPUT_RX_MBPS] = (
592             '{:,.3f}'.format(total_throughput_rx_mbps / trials))
593
594         results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
595             '{:,.3f}'.format(total_throughput_rx_pct / trials))
596
597         results[ResultsConstants.TX_RATE_FPS] = (
598             '{:,.6f}'.format(total_throughput_tx_fps / trials))
599
600         results[ResultsConstants.TX_RATE_MBPS] = (
601             '{:,.3f}'.format(total_throughput_tx_mbps / trials))
602
603         results[ResultsConstants.TX_RATE_PERCENT] = (
604             '{:,.3f}'.format(total_throughput_tx_pct / trials))
605
606         results[ResultsConstants.MIN_LATENCY_NS] = (
607             '{:,.3f}'.format(total_min_latency_ns / trials))
608
609         results[ResultsConstants.MAX_LATENCY_NS] = (
610             '{:,.3f}'.format(total_max_latency_ns / trials))
611
612         results[ResultsConstants.AVG_LATENCY_NS] = (
613             '{:,.3f}'.format(total_avg_latency_ns / trials))
614
615         return results
616
617     def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
618                                  lossrate=0.0):
619         """Non-blocking version of 'send_rfc2544_throughput'.
620
621         Start transmission and immediately return. Do not wait for
622         results.
623         """
624         self._logger.info(
625             "MOONGEN: In moongen start_rfc2544_throughput method")
626
627     def wait_rfc2544_throughput(self):
628         """Wait for and return results of RFC2544 test.
629         """
630         self._logger.info('In moongen wait_rfc2544_throughput')
631
632     def send_rfc2544_back2back(self, traffic=None, duration=60,
633                                lossrate=0.0, trials=1):
634         """Send traffic per RFC2544 back2back test specifications.
635
636         Send packets at a fixed rate, using ``traffic``
637         configuration, for duration seconds.
638
639         :param traffic: Detailed "traffic" spec, see design docs for details
640         :param trials: Number of trials to execute
641         :param duration: Per iteration duration
642         :param lossrate: Acceptable loss percentage
643
644         :returns: Named tuple of Rx Throughput (fps), Rx Throughput (mbps),
645             Tx Rate (% linerate), Rx Rate (% linerate), Tx Count (frames),
646             Back to Back Count (frames), Frame Loss (frames), Frame Loss (%)
647         :rtype: :class:`Back2BackResult`
648         """
649         self._params.clear()
650         self._params['traffic'] = self.traffic_defaults.copy()
651
652         if traffic:
653             self._params['traffic'] = merge_spec(self._params['traffic'],
654                                                  traffic)
655
656         Moongen.create_moongen_cfg_file(self,
657                                         traffic,
658                                         duration=duration,
659                                         acceptable_loss_pct=lossrate)
660
661         results = OrderedDict()
662         results[ResultsConstants.B2B_RX_FPS] = 0
663         results[ResultsConstants.B2B_TX_FPS] = 0
664         results[ResultsConstants.B2B_RX_PERCENT] = 0
665         results[ResultsConstants.B2B_TX_PERCENT] = 0
666         results[ResultsConstants.B2B_TX_COUNT] = 0
667         results[ResultsConstants.B2B_FRAMES] = 0
668         results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = 0
669         results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = 0
670         results[ResultsConstants.SCAL_STREAM_COUNT] = 0
671         results[ResultsConstants.SCAL_STREAM_TYPE] = 0
672         results[ResultsConstants.SCAL_PRE_INSTALLED_FLOWS] = 0
673
674         for test_run in range(1, trials+1):
675             collected_results = (
676                 Moongen.run_moongen_and_collect_results(self, test_run=test_run))
677
678             results[ResultsConstants.B2B_RX_FPS] += (
679                 float(collected_results[ResultsConstants.THROUGHPUT_RX_FPS]))
680
681             results[ResultsConstants.B2B_RX_PERCENT] += (
682                 float(collected_results[ResultsConstants.THROUGHPUT_RX_PERCENT]))
683
684             results[ResultsConstants.B2B_TX_FPS] += (
685                 float(collected_results[ResultsConstants.TX_RATE_FPS]))
686
687             results[ResultsConstants.B2B_TX_PERCENT] += (
688                 float(collected_results[ResultsConstants.TX_RATE_PERCENT]))
689
690             results[ResultsConstants.B2B_TX_COUNT] += (
691                 int(collected_results[ResultsConstants.B2B_TX_COUNT]))
692
693             results[ResultsConstants.B2B_FRAMES] += (
694                 int(collected_results[ResultsConstants.B2B_FRAMES]))
695
696             results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] += (
697                 int(collected_results[ResultsConstants.B2B_FRAME_LOSS_FRAMES]))
698
699             results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] += (
700                 int(collected_results[ResultsConstants.B2B_FRAME_LOSS_PERCENT]))
701
702         # Calculate average results
703         results[ResultsConstants.B2B_RX_FPS] = (
704             results[ResultsConstants.B2B_RX_FPS] / trials)
705
706         results[ResultsConstants.B2B_RX_PERCENT] = (
707             results[ResultsConstants.B2B_RX_PERCENT] / trials)
708
709         results[ResultsConstants.B2B_TX_FPS] = (
710             results[ResultsConstants.B2B_TX_FPS] / trials)
711
712         results[ResultsConstants.B2B_TX_PERCENT] = (
713             results[ResultsConstants.B2B_TX_PERCENT] / trials)
714
715         results[ResultsConstants.B2B_TX_COUNT] = (
716             results[ResultsConstants.B2B_TX_COUNT] / trials)
717
718         results[ResultsConstants.B2B_FRAMES] = (
719             results[ResultsConstants.B2B_FRAMES] / trials)
720
721         results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = (
722             results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] / trials)
723
724         results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = (
725             results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] / trials)
726
727         results[ResultsConstants.SCAL_STREAM_COUNT] = 0
728         results[ResultsConstants.SCAL_STREAM_TYPE] = 0
729         results[ResultsConstants.SCAL_PRE_INSTALLED_FLOWS] = 0
730
731         return results
732
733     def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
734                                 lossrate=0.0):
735         #
736         # Non-blocking version of 'send_rfc2544_back2back'.
737         #
738         # Start transmission and immediately return. Do not wait for results.
739         #
740         self._logger.info("In moongen start_rfc2544_back2back method")
741         return NotImplementedError(
742             'Moongen start back2back traffic not implemented')
743
744     def wait_rfc2544_back2back(self):
745         self._logger.info("In moongen wait_rfc2544_back2back method")
746         #
747         # Wait and set results of RFC2544 test.
748         #
749         return NotImplementedError(
750             'Moongen wait back2back traffic not implemented')
751
752 if __name__ == "__main__":
753     pass