xena_burst: Add Xena Burst traffic
[vswitchperf.git] / tools / pkt_gen / xena / xena.py
1 # Copyright 2016 Red Hat Inc & Xena Networks.
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 #   Rick Alongi, Red Hat Inc.
17 #   Amit Supugade, Red Hat Inc.
18 #   Dan Amzulescu, Xena Networks
19 #   Christian Trautman, Red Hat Inc.
20
21 """
22 Xena Traffic Generator Model
23 """
24
25 # python imports
26 import binascii
27 import logging
28 import subprocess
29 import sys
30 from time import sleep
31 import xml.etree.ElementTree as ET
32 from collections import OrderedDict
33
34 # VSPerf imports
35 from conf import settings
36 from core.results.results_constants import ResultsConstants
37 from tools.pkt_gen.trafficgen.trafficgenhelper import (
38     TRAFFIC_DEFAULTS,
39     merge_spec)
40 from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
41
42 # Xena module imports
43 from tools.pkt_gen.xena.xena_json import XenaJSON
44 from tools.pkt_gen.xena.XenaDriver import (
45     aggregate_stats,
46     line_percentage,
47     XenaSocketDriver,
48     XenaManager,
49     )
50
51 # scapy imports
52 import scapy.layers.inet as inet
53
54
55 class Xena(ITrafficGenerator):
56     """
57     Xena Traffic generator wrapper class
58     """
59     _traffic_defaults = TRAFFIC_DEFAULTS.copy()
60     _logger = logging.getLogger(__name__)
61
62     def __init__(self):
63         self.mono_pipe = None
64         self.xmanager = None
65         self._params = {}
66         self._xsocket = None
67         self._duration = None
68         self.tx_stats = None
69         self.rx_stats = None
70
71     @property
72     def traffic_defaults(self):
73         """Default traffic values.
74
75         These can be expected to be constant across traffic generators,
76         so no setter is provided. Changes to the structure or contents
77         will likely break traffic generator implementations or tests
78         respectively.
79         """
80         return self._traffic_defaults
81
82     @staticmethod
83     def _create_throughput_result(root):
84         """
85         Create the results based off the output xml file from the Xena2544.exe
86         execution
87         :param root: root dictionary from xml import
88         :return: Results Ordered dictionary based off ResultsConstants
89         """
90         # get the test type from the report file
91         test_type = root[0][1].get('TestType')
92         # set the version from the report file
93         settings.setValue('XENA_VERSION', root[0][0][1].get('GeneratedBy'))
94
95         if test_type == 'Throughput':
96             results = OrderedDict()
97             results[ResultsConstants.THROUGHPUT_RX_FPS] = int(
98                 root[0][1][0][0].get('PortRxPps')) + int(
99                     root[0][1][0][1].get('PortRxPps'))
100             results[ResultsConstants.THROUGHPUT_RX_MBPS] = (int(
101                 root[0][1][0][0].get('PortRxBpsL1')) + int(
102                     root[0][1][0][1].get('PortRxBpsL1')))/ 1000000
103             results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
104                 100 - int(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
105                     root[0][1][0].get('TotalTxRatePcnt'))/100
106             results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
107                 'TotalTxRateFps')
108             results[ResultsConstants.TX_RATE_MBPS] = float(
109                 root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
110             results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
111                 'TotalTxRatePcnt')
112             try:
113                 results[ResultsConstants.MIN_LATENCY_NS] = float(
114                     root[0][1][0][0].get('MinLatency')) * 1000
115             except ValueError:
116                 # Stats for latency returned as N/A so just post them
117                 results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
118                     'MinLatency')
119             try:
120                 results[ResultsConstants.MAX_LATENCY_NS] = float(
121                     root[0][1][0][0].get('MaxLatency')) * 1000
122             except ValueError:
123                 # Stats for latency returned as N/A so just post them
124                 results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
125                     'MaxLatency')
126             try:
127                 results[ResultsConstants.AVG_LATENCY_NS] = float(
128                     root[0][1][0][0].get('AvgLatency')) * 1000
129             except ValueError:
130                 # Stats for latency returned as N/A so just post them
131                 results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
132                     'AvgLatency')
133         elif test_type == 'Back2Back':
134             results = OrderedDict()
135
136             # Just mimic what Ixia does and only return the b2b frame count.
137             # This may change later once its decided the common results stats
138             # to be returned should be.
139             results[ResultsConstants.B2B_FRAMES] = root[0][1][0][0].get(
140                 'TotalTxBurstFrames')
141         else:
142             raise NotImplementedError('Unknown test type in report file.')
143
144         return results
145
146     def _build_packet_header(self, reverse=False):
147         """
148         Build a packet header based on traffic profile using scapy external
149         libraries.
150         :param reverse: Swap source and destination info when building header
151         :return: packet header in hex
152         """
153         srcmac = self._params['traffic']['l2'][
154             'srcmac'] if not reverse else self._params['traffic']['l2'][
155                 'dstmac']
156         dstmac = self._params['traffic']['l2'][
157             'dstmac'] if not reverse else self._params['traffic']['l2'][
158                 'srcmac']
159         srcip = self._params['traffic']['l3'][
160             'srcip'] if not reverse else self._params['traffic']['l3']['dstip']
161         dstip = self._params['traffic']['l3'][
162             'dstip'] if not reverse else self._params['traffic']['l3']['srcip']
163         layer2 = inet.Ether(src=srcmac, dst=dstmac)
164         layer3 = inet.IP(src=srcip, dst=dstip,
165                          proto=self._params['traffic']['l3']['proto'])
166         layer4 = inet.UDP(sport=self._params['traffic']['l4']['srcport'],
167                           dport=self._params['traffic']['l4']['dstport'])
168         if self._params['traffic']['vlan']['enabled']:
169             vlan = inet.Dot1Q(vlan=self._params['traffic']['vlan']['id'],
170                               prio=self._params['traffic']['vlan']['priority'],
171                               id=self._params['traffic']['vlan']['cfi'])
172         else:
173             vlan = None
174         packet = layer2/vlan/layer3/layer4 if vlan else layer2/layer3/layer4
175         packet_bytes = bytes(packet)
176         packet_hex = '0x' + binascii.hexlify(packet_bytes).decode('utf-8')
177         return packet_hex
178
179     def _create_api_result(self):
180         """
181         Create result dictionary per trafficgen specifications from socket API
182         stats. If stats are not available return values of 0.
183         :return: ResultsConstants as dictionary
184         """
185         # Handle each case of statistics based on if the data is available.
186         # This prevents uncaught exceptions when the stats aren't available.
187         result_dict = OrderedDict()
188         if self.tx_stats.data.get(self.tx_stats.pt_stream_keys[0]):
189             result_dict[ResultsConstants.TX_FRAMES] = self.tx_stats.data[
190                 self.tx_stats.pt_stream_keys[0]]['packets']
191             result_dict[ResultsConstants.TX_RATE_FPS] = self.tx_stats.data[
192                 self.tx_stats.pt_stream_keys[0]]['pps']
193             result_dict[ResultsConstants.TX_RATE_MBPS] = self.tx_stats.data[
194                 self.tx_stats.pt_stream_keys[0]]['bps'] / 1000000
195             result_dict[ResultsConstants.TX_BYTES] = self.tx_stats.data[
196                 self.tx_stats.pt_stream_keys[0]]['bytes']
197             # tx rate percent may need to be halved if bi directional
198             result_dict[ResultsConstants.TX_RATE_PERCENT] = line_percentage(
199                 self.xmanager.ports[0], self.tx_stats, self._duration,
200                 self._params['traffic']['l2']['framesize']) if \
201                 self._params['traffic']['bidir'] == 'False' else\
202                 line_percentage(
203                     self.xmanager.ports[0], self.tx_stats, self._duration,
204                     self._params['traffic']['l2']['framesize']) / 2
205         else:
206             self._logger.error('Transmit stats not available.')
207             result_dict[ResultsConstants.TX_FRAMES] = 0
208             result_dict[ResultsConstants.TX_RATE_FPS] = 0
209             result_dict[ResultsConstants.TX_RATE_MBPS] = 0
210             result_dict[ResultsConstants.TX_BYTES] = 0
211             result_dict[ResultsConstants.TX_RATE_PERCENT] = 0
212
213         if self.rx_stats.data.get('pr_tpldstraffic'):
214             result_dict[ResultsConstants.RX_FRAMES] = self.rx_stats.data[
215                 'pr_tpldstraffic']['0']['packets']
216             result_dict[
217                 ResultsConstants.THROUGHPUT_RX_FPS] = self.rx_stats.data[
218                     'pr_tpldstraffic']['0']['pps']
219             result_dict[
220                 ResultsConstants.THROUGHPUT_RX_MBPS] = self.rx_stats.data[
221                     'pr_tpldstraffic']['0']['bps'] / 1000000
222             result_dict[ResultsConstants.RX_BYTES] = self.rx_stats.data[
223                 'pr_tpldstraffic']['0']['bytes']
224             # throughput percent may need to be halved if bi directional
225             result_dict[
226                 ResultsConstants.THROUGHPUT_RX_PERCENT] = line_percentage(
227                     self.xmanager.ports[1], self.rx_stats, self._duration,
228                     self._params['traffic']['l2']['framesize']) if \
229                 self._params['traffic']['bidir'] == 'False' else \
230                 line_percentage(
231                     self.xmanager.ports[1], self.rx_stats, self._duration,
232                     self._params['traffic']['l2']['framesize']) / 2
233
234         else:
235             self._logger.error('Receive stats not available.')
236             result_dict[ResultsConstants.RX_FRAMES] = 0
237             result_dict[ResultsConstants.THROUGHPUT_RX_FPS] = 0
238             result_dict[ResultsConstants.THROUGHPUT_RX_MBPS] = 0
239             result_dict[ResultsConstants.RX_BYTES] = 0
240             result_dict[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0
241
242         if self.rx_stats.data.get('pr_tplderrors'):
243             result_dict[ResultsConstants.PAYLOAD_ERR] = self.rx_stats.data[
244                 'pr_tplderrors']['0']['pld']
245             result_dict[ResultsConstants.SEQ_ERR] = self.rx_stats.data[
246                 'pr_tplderrors']['0']['seq']
247         else:
248             result_dict[ResultsConstants.PAYLOAD_ERR] = 0
249             result_dict[ResultsConstants.SEQ_ERR] = 0
250
251         if self.rx_stats.data.get('pr_tpldlatency'):
252             result_dict[ResultsConstants.MIN_LATENCY_NS] = self.rx_stats.data[
253                 'pr_tpldlatency']['0']['min']
254             result_dict[ResultsConstants.MAX_LATENCY_NS] = self.rx_stats.data[
255                 'pr_tpldlatency']['0']['max']
256             result_dict[ResultsConstants.AVG_LATENCY_NS] = self.rx_stats.data[
257                 'pr_tpldlatency']['0']['avg']
258         else:
259             result_dict[ResultsConstants.MIN_LATENCY_NS] = 0
260             result_dict[ResultsConstants.MAX_LATENCY_NS] = 0
261             result_dict[ResultsConstants.AVG_LATENCY_NS] = 0
262
263         return result_dict
264
265     def _setup_json_config(self, trials, loss_rate, testtype=None):
266         """
267         Create a 2bUsed json file that will be used for xena2544.exe execution.
268         :param trials: Number of trials
269         :param loss_rate: The acceptable loss rate as float
270         :param testtype: Either '2544_b2b' or '2544_throughput' as string
271         :return: None
272         """
273         try:
274             j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544')
275             j_file.set_chassis_info(
276                 settings.getValue('TRAFFICGEN_XENA_IP'),
277                 settings.getValue('TRAFFICGEN_XENA_PASSWORD')
278             )
279             j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'),
280                             settings.getValue('TRAFFICGEN_XENA_PORT1'))
281             j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'),
282                             settings.getValue('TRAFFICGEN_XENA_PORT2'))
283             j_file.set_port_ip_v4(
284                 0, settings.getValue("TRAFFICGEN_XENA_PORT0_IP"),
285                 settings.getValue("TRAFFICGEN_XENA_PORT0_CIDR"),
286                 settings.getValue("TRAFFICGEN_XENA_PORT0_GATEWAY"))
287             j_file.set_port_ip_v4(
288                 1, settings.getValue("TRAFFICGEN_XENA_PORT1_IP"),
289                 settings.getValue("TRAFFICGEN_XENA_PORT1_CIDR"),
290                 settings.getValue("TRAFFICGEN_XENA_PORT1_GATEWAY"))
291             j_file.set_test_options(
292                 packet_sizes=self._params['traffic']['l2']['framesize'],
293                 iterations=trials, loss_rate=loss_rate,
294                 duration=self._duration, micro_tpld=True if self._params[
295                     'traffic']['l2']['framesize'] == 64 else False)
296             if testtype == '2544_throughput':
297                 j_file.enable_throughput_test()
298             elif testtype == '2544_b2b':
299                 j_file.enable_back2back_test()
300
301             j_file.set_header_layer2(
302                 dst_mac=self._params['traffic']['l2']['dstmac'],
303                 src_mac=self._params['traffic']['l2']['srcmac'])
304             j_file.set_header_layer3(
305                 src_ip=self._params['traffic']['l3']['srcip'],
306                 dst_ip=self._params['traffic']['l3']['dstip'],
307                 protocol=self._params['traffic']['l3']['proto'])
308             j_file.set_header_layer4_udp(
309                 source_port=self._params['traffic']['l4']['srcport'],
310                 destination_port=self._params['traffic']['l4']['dstport'])
311             if self._params['traffic']['vlan']['enabled']:
312                 j_file.set_header_vlan(
313                     vlan_id=self._params['traffic']['vlan']['id'],
314                     id=self._params['traffic']['vlan']['cfi'],
315                     prio=self._params['traffic']['vlan']['priority'])
316             j_file.add_header_segments(
317                 flows=self._params['traffic']['multistream'],
318                 multistream_layer=self._params['traffic']['stream_type'])
319             # set duplex mode
320             if self._params['traffic']['bidir'] == "True":
321                 j_file.set_topology_mesh()
322             else:
323                 j_file.set_topology_blocks()
324
325             j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544')
326         except Exception as exc:
327             self._logger.exception("Error during Xena JSON setup: %s", exc)
328             raise
329
330     def _start_traffic_api(self, packet_limit):
331         """
332         Start the Xena traffic using the socket API driver
333         :param packet_limit: packet limit for stream, set to -1 for no limit
334         :return: None
335         """
336         if not self.xmanager:
337             self._xsocket = XenaSocketDriver(
338                 settings.getValue('TRAFFICGEN_XENA_IP'))
339             self.xmanager = XenaManager(
340                 self._xsocket, settings.getValue('TRAFFICGEN_XENA_USER'),
341                 settings.getValue('TRAFFICGEN_XENA_PASSWORD'))
342
343         # for the report file version info ask the chassis directly for its
344         # software versions
345         settings.setValue('XENA_VERSION', 'XENA Socket API - {}'.format(
346             self.xmanager.get_version()))
347
348         if not len(self.xmanager.ports):
349             self.xmanager.ports[0] = self.xmanager.add_module_port(
350                 settings.getValue('TRAFFICGEN_XENA_MODULE1'),
351                 settings.getValue('TRAFFICGEN_XENA_PORT1'))
352             if not self.xmanager.ports[0].reserve_port():
353                 self._logger.error(
354                     'Unable to reserve port 0. Please release Xena Port')
355
356         if len(self.xmanager.ports) < 2:
357             self.xmanager.ports[1] = self.xmanager.add_module_port(
358                 settings.getValue('TRAFFICGEN_XENA_MODULE2'),
359                 settings.getValue('TRAFFICGEN_XENA_PORT2'))
360             if not self.xmanager.ports[1].reserve_port():
361                 self._logger.error(
362                     'Unable to reserve port 1. Please release Xena Port')
363
364         # Clear port configuration for a clean start
365         self.xmanager.ports[0].reset_port()
366         self.xmanager.ports[1].reset_port()
367         self.xmanager.ports[0].clear_stats()
368         self.xmanager.ports[1].clear_stats()
369
370         # set the port IP from the conf file
371         self.xmanager.ports[0].set_port_ip(
372             settings.getValue('TRAFFICGEN_XENA_PORT0_IP'),
373             settings.getValue('TRAFFICGEN_XENA_PORT0_CIDR'),
374             settings.getValue('TRAFFICGEN_XENA_PORT0_GATEWAY'))
375         self.xmanager.ports[1].set_port_ip(
376             settings.getValue('TRAFFICGEN_XENA_PORT1_IP'),
377             settings.getValue('TRAFFICGEN_XENA_PORT1_CIDR'),
378             settings.getValue('TRAFFICGEN_XENA_PORT1_GATEWAY'))
379
380         def setup_stream(stream, port, payload_id, flip_addr=False):
381             """
382             Helper function to configure streams.
383             :param stream: Stream object from XenaDriver module
384             :param port: Port object from XenaDriver module
385             :param payload_id: payload ID as int
386             :param flip_addr: Boolean if the source and destination addresses
387             should be flipped.
388             :return: None
389             """
390             stream.set_on()
391             stream.set_packet_limit(packet_limit)
392
393             stream.set_rate_fraction(
394                 10000 * self._params['traffic']['frame_rate'])
395             stream.set_packet_header(self._build_packet_header(
396                 reverse=flip_addr))
397             stream.set_header_protocol(
398                 'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][
399                     'enabled'] else 'ETHERNET IP UDP')
400             stream.set_packet_length(
401                 'fixed', self._params['traffic']['l2']['framesize'], 16383)
402             stream.set_packet_payload('incrementing', '0x00')
403             stream.set_payload_id(payload_id)
404             port.set_port_time_limit(self._duration * 1000000)
405
406             if self._params['traffic']['l2']['framesize'] == 64:
407                 # set micro tpld
408                 port.micro_tpld_enable()
409
410             if self._params['traffic']['multistream']:
411                 stream.enable_multistream(
412                     flows=self._params['traffic']['multistream'],
413                     layer=self._params['traffic']['stream_type'])
414
415         s1_p0 = self.xmanager.ports[0].add_stream()
416         setup_stream(s1_p0, self.xmanager.ports[0], 0)
417
418         if self._params['traffic']['bidir'] == 'True':
419             s1_p1 = self.xmanager.ports[1].add_stream()
420             setup_stream(s1_p1, self.xmanager.ports[1], 1, flip_addr=True)
421
422         if not self.xmanager.ports[0].traffic_on():
423             self._logger.error(
424                 "Failure to start port 0. Check settings and retry.")
425         if self._params['traffic']['bidir'] == 'True':
426             if not self.xmanager.ports[1].traffic_on():
427                 self._logger.error(
428                     "Failure to start port 1. Check settings and retry.")
429         sleep(self._duration)
430         # getting results
431         if self._params['traffic']['bidir'] == 'True':
432             # need to aggregate out both ports stats and assign that data
433             self.rx_stats = self.xmanager.ports[1].get_rx_stats()
434             self.tx_stats = self.xmanager.ports[0].get_tx_stats()
435             self.tx_stats.data = aggregate_stats(
436                 self.tx_stats.data,
437                 self.xmanager.ports[1].get_tx_stats().data)
438             self.rx_stats.data = aggregate_stats(
439                 self.rx_stats.data,
440                 self.xmanager.ports[0].get_rx_stats().data)
441         else:
442             # no need to aggregate, just grab the appropriate port stats
443             self.tx_stats = self.xmanager.ports[0].get_tx_stats()
444             self.rx_stats = self.xmanager.ports[1].get_rx_stats()
445         sleep(1)
446
447     def _stop_api_traffic(self):
448         """
449         Stop traffic through the socket API
450         :return: Return results from _create_api_result method
451         """
452         self.xmanager.ports[0].traffic_off()
453         if self._params['traffic']['bidir'] == 'True':
454             self.xmanager.ports[1].traffic_off()
455         sleep(5)
456
457         stat = self._create_api_result()
458         self.disconnect()
459         return stat
460
461     def connect(self):
462         self._logger.debug('Connect')
463         return self
464
465     def disconnect(self):
466         """Disconnect from the traffic generator.
467
468         As with :func:`connect`, this function is optional.
469
470
471         Where implemented, this function should raise an exception on
472         failure.
473
474         :returns: None
475         """
476         self._logger.debug('disconnect')
477         if self.xmanager:
478             self.xmanager.disconnect()
479             self.xmanager = None
480
481         if self._xsocket:
482             self._xsocket.disconnect()
483             self._xsocket = None
484
485     def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
486         """Send a burst of traffic.
487
488         See ITrafficGenerator for description
489         """
490         self._duration = duration
491
492         self._params.clear()
493         self._params['traffic'] = self.traffic_defaults.copy()
494         if traffic:
495             self._params['traffic'] = merge_spec(self._params['traffic'],
496                                                  traffic)
497
498         self._start_traffic_api(numpkts)
499         return self._stop_api_traffic()
500
501     def send_cont_traffic(self, traffic=None, duration=20):
502         """Send a continuous flow of traffic.
503
504         See ITrafficGenerator for description
505         """
506         self._duration = duration
507
508         self._params.clear()
509         self._params['traffic'] = self.traffic_defaults.copy()
510         if traffic:
511             self._params['traffic'] = merge_spec(self._params['traffic'],
512                                                  traffic)
513
514         self._start_traffic_api(-1)
515         return self._stop_api_traffic()
516
517     def start_cont_traffic(self, traffic=None, duration=20):
518         """Non-blocking version of 'send_cont_traffic'.
519
520         See ITrafficGenerator for description
521         """
522         self._duration = duration
523
524         self._params.clear()
525         self._params['traffic'] = self.traffic_defaults.copy()
526         if traffic:
527             self._params['traffic'] = merge_spec(self._params['traffic'],
528                                                  traffic)
529
530         self._start_traffic_api(-1)
531
532     def stop_cont_traffic(self):
533         """Stop continuous transmission and return results.
534         """
535         return self._stop_api_traffic()
536
537     def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
538                                 lossrate=0.0):
539         """Send traffic per RFC2544 throughput test specifications.
540
541         See ITrafficGenerator for description
542         """
543         self._duration = duration
544
545         self._params.clear()
546         self._params['traffic'] = self.traffic_defaults.copy()
547         if traffic:
548             self._params['traffic'] = merge_spec(self._params['traffic'],
549                                                  traffic)
550
551         self._setup_json_config(trials, lossrate, '2544_throughput')
552
553         args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
554                 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
555                 "./tools/pkt_gen/xena", "-u",
556                 settings.getValue('TRAFFICGEN_XENA_USER')]
557         self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
558         self.mono_pipe.communicate()
559         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
560         return Xena._create_throughput_result(root)
561
562     def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
563                                  lossrate=0.0):
564         """Non-blocking version of 'send_rfc2544_throughput'.
565
566         See ITrafficGenerator for description
567         """
568         self._duration = duration
569         self._params.clear()
570         self._params['traffic'] = self.traffic_defaults.copy()
571         if traffic:
572             self._params['traffic'] = merge_spec(self._params['traffic'],
573                                                  traffic)
574
575         self._setup_json_config(trials, lossrate, '2544_throughput')
576
577         args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
578                 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
579                 "./tools/pkt_gen/xena", "-u",
580                 settings.getValue('TRAFFICGEN_XENA_USER')]
581         self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
582
583     def wait_rfc2544_throughput(self):
584         """Wait for and return results of RFC2544 test.
585
586         See ITrafficGenerator for description
587         """
588         self.mono_pipe.communicate()
589         sleep(2)
590         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
591         return Xena._create_throughput_result(root)
592
593     def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
594                                lossrate=0.0):
595         """Send traffic per RFC2544 back2back test specifications.
596
597         See ITrafficGenerator for description
598         """
599         self._duration = duration
600
601         self._params.clear()
602         self._params['traffic'] = self.traffic_defaults.copy()
603         if traffic:
604             self._params['traffic'] = merge_spec(self._params['traffic'],
605                                                  traffic)
606
607         self._setup_json_config(trials, lossrate, '2544_b2b')
608
609         args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
610                 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
611                 "./tools/pkt_gen/xena", "-u",
612                 settings.getValue('TRAFFICGEN_XENA_USER')]
613         self.mono_pipe = subprocess.Popen(
614             args, stdout=sys.stdout)
615         self.mono_pipe.communicate()
616         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
617         return Xena._create_throughput_result(root)
618
619     def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
620                                 lossrate=0.0):
621         """Non-blocking version of 'send_rfc2544_back2back'.
622
623         See ITrafficGenerator for description
624         """
625         self._duration = duration
626
627         self._params.clear()
628         self._params['traffic'] = self.traffic_defaults.copy()
629         if traffic:
630             self._params['traffic'] = merge_spec(self._params['traffic'],
631                                                  traffic)
632
633         self._setup_json_config(trials, lossrate, '2544_b2b')
634
635         args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
636                 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
637                 "./tools/pkt_gen/xena", "-u",
638                 settings.getValue('TRAFFICGEN_XENA_USER')]
639         self.mono_pipe = subprocess.Popen(
640             args, stdout=sys.stdout)
641
642     def wait_rfc2544_back2back(self):
643         """Wait and set results of RFC2544 test.
644         """
645         self.mono_pipe.communicate()
646         sleep(2)
647         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
648         return Xena._create_throughput_result(root)
649
650
651 if __name__ == "__main__":
652     pass
653