1 # Copyright 2016 Red Hat Inc & Xena Networks.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 # Rick Alongi, Red Hat Inc.
17 # Amit Supugade, Red Hat Inc.
18 # Dan Amzulescu, Xena Networks
19 # Christian Trautman, Red Hat Inc.
22 Xena Traffic Generator Model
31 from time import sleep
32 import xml.etree.ElementTree as ET
33 from collections import OrderedDict
35 import scapy.layers.inet as inet
38 from conf import settings
39 from core.results.results_constants import ResultsConstants
40 from tools.pkt_gen.trafficgen.trafficgenhelper import (
43 from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
46 from tools.pkt_gen.xena.xena_json import XenaJSON
47 from tools.pkt_gen.xena.XenaDriver import (
55 class Xena(ITrafficGenerator):
57 Xena Traffic generator wrapper class
59 _traffic_defaults = TRAFFIC_DEFAULTS.copy()
60 _logger = logging.getLogger(__name__)
70 self._log_handle = None
72 user_home = os.path.expanduser('~')
73 self._log_path = '{}/Xena/Xena2544-2G/Logs/xena2544.log'.format(
76 # make the folder and log file if they doesn't exist
77 if not os.path.exists(self._log_path):
78 os.makedirs(os.path.dirname(self._log_path))
80 # empty the file contents
81 open(self._log_path, 'w').close()
85 def traffic_defaults(self):
86 """Default traffic values.
88 These can be expected to be constant across traffic generators,
89 so no setter is provided. Changes to the structure or contents
90 will likely break traffic generator implementations or tests
93 return self._traffic_defaults
96 def _create_throughput_result(root):
98 Create the results based off the output xml file from the Xena2544.exe
100 :param root: root dictionary from xml import
101 :return: Results Ordered dictionary based off ResultsConstants
103 # get the test type from the report file
104 test_type = root[0][1].get('TestType')
105 # set the version from the report file
106 settings.setValue('XENA_VERSION', root[0][0][1].get('GeneratedBy'))
108 if test_type == 'Throughput':
109 results = OrderedDict()
110 results[ResultsConstants.THROUGHPUT_RX_FPS] = float(
111 root[0][1][0][0].get('PortRxPps')) + float(
112 root[0][1][0][1].get('PortRxPps'))
113 results[ResultsConstants.THROUGHPUT_RX_MBPS] = (float(
114 root[0][1][0][0].get('PortRxBpsL1')) + float(
115 root[0][1][0][1].get('PortRxBpsL1')))/ 1000000
116 results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
117 100 - float(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
118 root[0][1][0].get('TotalTxRatePcnt'))/100
119 results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
121 results[ResultsConstants.TX_RATE_MBPS] = float(
122 root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
123 results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
126 results[ResultsConstants.MIN_LATENCY_NS] = float(
127 root[0][1][0][0].get('MinLatency')) * 1000
129 # Stats for latency returned as N/A so just post them
130 results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
133 results[ResultsConstants.MAX_LATENCY_NS] = float(
134 root[0][1][0][0].get('MaxLatency')) * 1000
136 # Stats for latency returned as N/A so just post them
137 results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
140 results[ResultsConstants.AVG_LATENCY_NS] = float(
141 root[0][1][0][0].get('AvgLatency')) * 1000
143 # Stats for latency returned as N/A so just post them
144 results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
146 elif test_type == 'Back2Back':
147 results = OrderedDict()
149 # Just mimic what Ixia does and only return the b2b frame count.
150 # This may change later once its decided the common results stats
151 # to be returned should be.
152 results[ResultsConstants.B2B_FRAMES] = root[0][1][0][0].get(
153 'TotalTxBurstFrames')
155 raise NotImplementedError('Unknown test type in report file.')
159 def _build_packet_header(self, reverse=False):
161 Build a packet header based on traffic profile using scapy external
163 :param reverse: Swap source and destination info when building header
164 :return: packet header in hex
166 srcmac = self._params['traffic']['l2'][
167 'srcmac'] if not reverse else self._params['traffic']['l2'][
169 dstmac = self._params['traffic']['l2'][
170 'dstmac'] if not reverse else self._params['traffic']['l2'][
172 srcip = self._params['traffic']['l3'][
173 'srcip'] if not reverse else self._params['traffic']['l3']['dstip']
174 dstip = self._params['traffic']['l3'][
175 'dstip'] if not reverse else self._params['traffic']['l3']['srcip']
176 layer2 = inet.Ether(src=srcmac, dst=dstmac)
177 layer3 = inet.IP(src=srcip, dst=dstip,
178 proto=self._params['traffic']['l3']['proto'])
179 layer4 = inet.UDP(sport=self._params['traffic']['l4']['srcport'],
180 dport=self._params['traffic']['l4']['dstport'])
181 if self._params['traffic']['vlan']['enabled']:
182 vlan = inet.Dot1Q(vlan=self._params['traffic']['vlan']['id'],
183 prio=self._params['traffic']['vlan']['priority'],
184 id=self._params['traffic']['vlan']['cfi'])
187 packet = layer2/vlan/layer3/layer4 if vlan else layer2/layer3/layer4
188 packet_bytes = bytes(packet)
189 packet_hex = '0x' + binascii.hexlify(packet_bytes).decode('utf-8')
192 def _create_api_result(self):
194 Create result dictionary per trafficgen specifications from socket API
195 stats. If stats are not available return values of 0.
196 :return: ResultsConstants as dictionary
198 # Handle each case of statistics based on if the data is available.
199 # This prevents uncaught exceptions when the stats aren't available.
200 result_dict = OrderedDict()
201 if self.tx_stats.data.get(self.tx_stats.pt_stream_keys[0]):
202 result_dict[ResultsConstants.TX_FRAMES] = self.tx_stats.data[
203 self.tx_stats.pt_stream_keys[0]]['packets']
204 result_dict[ResultsConstants.TX_RATE_FPS] = self.tx_stats.data[
205 self.tx_stats.pt_stream_keys[0]]['pps']
206 result_dict[ResultsConstants.TX_RATE_MBPS] = self.tx_stats.data[
207 self.tx_stats.pt_stream_keys[0]]['bps'] / 1000000
208 result_dict[ResultsConstants.TX_BYTES] = self.tx_stats.data[
209 self.tx_stats.pt_stream_keys[0]]['bytes']
210 # tx rate percent may need to be halved if bi directional
211 result_dict[ResultsConstants.TX_RATE_PERCENT] = line_percentage(
212 self.xmanager.ports[0], self.tx_stats, self._duration,
213 self._params['traffic']['l2']['framesize']) if \
214 self._params['traffic']['bidir'] == 'False' else\
216 self.xmanager.ports[0], self.tx_stats, self._duration,
217 self._params['traffic']['l2']['framesize']) / 2
219 self._logger.error('Transmit stats not available.')
220 result_dict[ResultsConstants.TX_FRAMES] = 0
221 result_dict[ResultsConstants.TX_RATE_FPS] = 0
222 result_dict[ResultsConstants.TX_RATE_MBPS] = 0
223 result_dict[ResultsConstants.TX_BYTES] = 0
224 result_dict[ResultsConstants.TX_RATE_PERCENT] = 0
226 if self.rx_stats.data.get('pr_tpldstraffic'):
227 result_dict[ResultsConstants.RX_FRAMES] = self.rx_stats.data[
228 'pr_tpldstraffic']['0']['packets']
230 ResultsConstants.THROUGHPUT_RX_FPS] = self.rx_stats.data[
231 'pr_tpldstraffic']['0']['pps']
233 ResultsConstants.THROUGHPUT_RX_MBPS] = self.rx_stats.data[
234 'pr_tpldstraffic']['0']['bps'] / 1000000
235 result_dict[ResultsConstants.RX_BYTES] = self.rx_stats.data[
236 'pr_tpldstraffic']['0']['bytes']
237 # throughput percent may need to be halved if bi directional
239 ResultsConstants.THROUGHPUT_RX_PERCENT] = line_percentage(
240 self.xmanager.ports[1], self.rx_stats, self._duration,
241 self._params['traffic']['l2']['framesize']) if \
242 self._params['traffic']['bidir'] == 'False' else \
244 self.xmanager.ports[1], self.rx_stats, self._duration,
245 self._params['traffic']['l2']['framesize']) / 2
248 self._logger.error('Receive stats not available.')
249 result_dict[ResultsConstants.RX_FRAMES] = 0
250 result_dict[ResultsConstants.THROUGHPUT_RX_FPS] = 0
251 result_dict[ResultsConstants.THROUGHPUT_RX_MBPS] = 0
252 result_dict[ResultsConstants.RX_BYTES] = 0
253 result_dict[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0
255 if self.rx_stats.data.get('pr_tplderrors'):
256 result_dict[ResultsConstants.PAYLOAD_ERR] = self.rx_stats.data[
257 'pr_tplderrors']['0']['pld']
258 result_dict[ResultsConstants.SEQ_ERR] = self.rx_stats.data[
259 'pr_tplderrors']['0']['seq']
261 result_dict[ResultsConstants.PAYLOAD_ERR] = 0
262 result_dict[ResultsConstants.SEQ_ERR] = 0
264 if self.rx_stats.data.get('pr_tpldlatency'):
265 result_dict[ResultsConstants.MIN_LATENCY_NS] = self.rx_stats.data[
266 'pr_tpldlatency']['0']['min']
267 result_dict[ResultsConstants.MAX_LATENCY_NS] = self.rx_stats.data[
268 'pr_tpldlatency']['0']['max']
269 result_dict[ResultsConstants.AVG_LATENCY_NS] = self.rx_stats.data[
270 'pr_tpldlatency']['0']['avg']
272 result_dict[ResultsConstants.MIN_LATENCY_NS] = 0
273 result_dict[ResultsConstants.MAX_LATENCY_NS] = 0
274 result_dict[ResultsConstants.AVG_LATENCY_NS] = 0
278 def _setup_json_config(self, tests, loss_rate, testtype=None):
280 Create a 2bUsed json file that will be used for xena2544.exe execution.
281 :param tests: Number of tests
282 :param loss_rate: The acceptable loss rate as float
283 :param testtype: Either '2544_b2b' or '2544_throughput' as string
287 j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544')
288 j_file.set_chassis_info(
289 settings.getValue('TRAFFICGEN_XENA_IP'),
290 settings.getValue('TRAFFICGEN_XENA_PASSWORD')
292 j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'),
293 settings.getValue('TRAFFICGEN_XENA_PORT1'))
294 j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'),
295 settings.getValue('TRAFFICGEN_XENA_PORT2'))
296 j_file.set_port_ip_v4(
297 0, settings.getValue("TRAFFICGEN_XENA_PORT0_IP"),
298 settings.getValue("TRAFFICGEN_XENA_PORT0_CIDR"),
299 settings.getValue("TRAFFICGEN_XENA_PORT0_GATEWAY"))
300 j_file.set_port_ip_v4(
301 1, settings.getValue("TRAFFICGEN_XENA_PORT1_IP"),
302 settings.getValue("TRAFFICGEN_XENA_PORT1_CIDR"),
303 settings.getValue("TRAFFICGEN_XENA_PORT1_GATEWAY"))
305 if testtype == '2544_throughput':
306 j_file.set_test_options_tput(
307 packet_sizes=self._params['traffic']['l2']['framesize'],
308 iterations=tests, loss_rate=loss_rate,
309 duration=self._duration, micro_tpld=True if self._params[
310 'traffic']['l2']['framesize'] == 64 else False)
311 j_file.enable_throughput_test()
312 j_file.modify_2544_tput_options(
313 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE'),
314 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE'),
315 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE'),
317 'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION'),
319 'TRAFFICGEN_XENA_2544_TPUT_USEPASS_THRESHHOLD'),
321 'TRAFFICGEN_XENA_2544_TPUT_PASS_THRESHHOLD')
324 elif testtype == '2544_b2b':
325 j_file.set_test_options_back2back(
326 packet_sizes=self._params['traffic']['l2']['framesize'],
327 iterations=tests, duration=self._duration,
328 startvalue=self._params['traffic']['frame_rate'],
329 endvalue=self._params['traffic']['frame_rate'],
330 micro_tpld=True if self._params[
331 'traffic']['l2']['framesize'] == 64 else False)
332 j_file.enable_back2back_test()
334 j_file.set_header_layer2(
335 dst_mac=self._params['traffic']['l2']['dstmac'],
336 src_mac=self._params['traffic']['l2']['srcmac'])
337 j_file.set_header_layer3(
338 src_ip=self._params['traffic']['l3']['srcip'],
339 dst_ip=self._params['traffic']['l3']['dstip'],
340 protocol=self._params['traffic']['l3']['proto'])
341 j_file.set_header_layer4_udp(
342 source_port=self._params['traffic']['l4']['srcport'],
343 destination_port=self._params['traffic']['l4']['dstport'])
344 if self._params['traffic']['vlan']['enabled']:
345 j_file.set_header_vlan(
346 vlan_id=self._params['traffic']['vlan']['id'],
347 id=self._params['traffic']['vlan']['cfi'],
348 prio=self._params['traffic']['vlan']['priority'])
349 j_file.add_header_segments(
350 flows=self._params['traffic']['multistream'],
351 multistream_layer=self._params['traffic']['stream_type'])
353 if self._params['traffic']['bidir'] == "True":
354 j_file.set_topology_mesh()
356 j_file.set_topology_blocks()
358 j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544')
359 except Exception as exc:
360 self._logger.exception("Error during Xena JSON setup: %s", exc)
363 def _start_traffic_api(self, packet_limit):
365 Start the Xena traffic using the socket API driver
366 :param packet_limit: packet limit for stream, set to -1 for no limit
369 if not self.xmanager:
370 self._xsocket = XenaSocketDriver(
371 settings.getValue('TRAFFICGEN_XENA_IP'))
372 self.xmanager = XenaManager(
373 self._xsocket, settings.getValue('TRAFFICGEN_XENA_USER'),
374 settings.getValue('TRAFFICGEN_XENA_PASSWORD'))
376 # for the report file version info ask the chassis directly for its
378 settings.setValue('XENA_VERSION', 'XENA Socket API - {}'.format(
379 self.xmanager.get_version()))
381 if not len(self.xmanager.ports):
382 self.xmanager.ports[0] = self.xmanager.add_module_port(
383 settings.getValue('TRAFFICGEN_XENA_MODULE1'),
384 settings.getValue('TRAFFICGEN_XENA_PORT1'))
385 if not self.xmanager.ports[0].reserve_port():
387 'Unable to reserve port 0. Please release Xena Port')
389 if len(self.xmanager.ports) < 2:
390 self.xmanager.ports[1] = self.xmanager.add_module_port(
391 settings.getValue('TRAFFICGEN_XENA_MODULE2'),
392 settings.getValue('TRAFFICGEN_XENA_PORT2'))
393 if not self.xmanager.ports[1].reserve_port():
395 'Unable to reserve port 1. Please release Xena Port')
397 # Clear port configuration for a clean start
398 self.xmanager.ports[0].reset_port()
399 self.xmanager.ports[1].reset_port()
400 self.xmanager.ports[0].clear_stats()
401 self.xmanager.ports[1].clear_stats()
403 # set the port IP from the conf file
404 self.xmanager.ports[0].set_port_ip(
405 settings.getValue('TRAFFICGEN_XENA_PORT0_IP'),
406 settings.getValue('TRAFFICGEN_XENA_PORT0_CIDR'),
407 settings.getValue('TRAFFICGEN_XENA_PORT0_GATEWAY'))
408 self.xmanager.ports[1].set_port_ip(
409 settings.getValue('TRAFFICGEN_XENA_PORT1_IP'),
410 settings.getValue('TRAFFICGEN_XENA_PORT1_CIDR'),
411 settings.getValue('TRAFFICGEN_XENA_PORT1_GATEWAY'))
413 def setup_stream(stream, port, payload_id, flip_addr=False):
415 Helper function to configure streams.
416 :param stream: Stream object from XenaDriver module
417 :param port: Port object from XenaDriver module
418 :param payload_id: payload ID as int
419 :param flip_addr: Boolean if the source and destination addresses
424 stream.set_packet_limit(packet_limit)
426 stream.set_rate_fraction(
427 10000 * self._params['traffic']['frame_rate'])
428 stream.set_packet_header(self._build_packet_header(
430 stream.set_header_protocol(
431 'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][
432 'enabled'] else 'ETHERNET IP UDP')
433 stream.set_packet_length(
434 'fixed', self._params['traffic']['l2']['framesize'], 16383)
435 stream.set_packet_payload('incrementing', '0x00')
436 stream.set_payload_id(payload_id)
437 port.set_port_time_limit(self._duration * 1000000)
439 if self._params['traffic']['l2']['framesize'] == 64:
441 port.micro_tpld_enable()
443 if self._params['traffic']['multistream']:
444 stream.enable_multistream(
445 flows=self._params['traffic']['multistream'],
446 layer=self._params['traffic']['stream_type'])
448 s1_p0 = self.xmanager.ports[0].add_stream()
449 setup_stream(s1_p0, self.xmanager.ports[0], 0)
451 if self._params['traffic']['bidir'] == 'True':
452 s1_p1 = self.xmanager.ports[1].add_stream()
453 setup_stream(s1_p1, self.xmanager.ports[1], 1, flip_addr=True)
455 if not self.xmanager.ports[0].traffic_on():
457 "Failure to start port 0. Check settings and retry.")
458 if self._params['traffic']['bidir'] == 'True':
459 if not self.xmanager.ports[1].traffic_on():
461 "Failure to start port 1. Check settings and retry.")
462 sleep(self._duration)
464 if self._params['traffic']['bidir'] == 'True':
465 # need to aggregate out both ports stats and assign that data
466 self.rx_stats = self.xmanager.ports[1].get_rx_stats()
467 self.tx_stats = self.xmanager.ports[0].get_tx_stats()
468 self.tx_stats.data = aggregate_stats(
470 self.xmanager.ports[1].get_tx_stats().data)
471 self.rx_stats.data = aggregate_stats(
473 self.xmanager.ports[0].get_rx_stats().data)
475 # no need to aggregate, just grab the appropriate port stats
476 self.tx_stats = self.xmanager.ports[0].get_tx_stats()
477 self.rx_stats = self.xmanager.ports[1].get_rx_stats()
480 def _start_xena_2544(self):
482 Start the xena2544 exe.
485 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
486 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
487 "./tools/pkt_gen/xena", "-u",
488 settings.getValue('TRAFFICGEN_XENA_USER')]
489 # Sometimes Xena2544.exe completes, but mono holds the process without
490 # releasing it, this can cause a deadlock of the main thread. Use the
491 # xena log file as a way to detect this.
492 self._log_handle = open(self._log_path, 'r')
493 # read the contents of the log before we start so the next read in the
494 # wait method are only looking at the text from this test instance
495 self._log_handle.read()
496 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
498 def _wait_xena_2544_complete(self):
500 Wait for Xena2544.exe completion.
506 self.mono_pipe.wait(60)
507 self._log_handle.close()
509 except subprocess.TimeoutExpired:
510 # check the log to see if Xena2544 has completed and mono is
512 data += self._log_handle.read()
513 if 'TestCompletedSuccessfully' in data:
514 self._log_handle.close()
515 self.mono_pipe.terminate()
518 def _stop_api_traffic(self):
520 Stop traffic through the socket API
521 :return: Return results from _create_api_result method
523 self.xmanager.ports[0].traffic_off()
524 if self._params['traffic']['bidir'] == 'True':
525 self.xmanager.ports[1].traffic_off()
528 stat = self._create_api_result()
533 self._logger.debug('Connect')
536 def disconnect(self):
537 """Disconnect from the traffic generator.
539 As with :func:`connect`, this function is optional.
542 Where implemented, this function should raise an exception on
547 self._logger.debug('disconnect')
549 self.xmanager.disconnect()
553 self._xsocket.disconnect()
556 def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
557 """Send a burst of traffic.
559 See ITrafficGenerator for description
561 self._duration = duration
563 self._params['traffic'] = self.traffic_defaults.copy()
565 self._params['traffic'] = merge_spec(self._params['traffic'],
567 self._start_traffic_api(numpkts)
568 return self._stop_api_traffic()
570 def send_cont_traffic(self, traffic=None, duration=20):
571 """Send a continuous flow of traffic.
573 See ITrafficGenerator for description
575 self._duration = duration
578 self._params['traffic'] = self.traffic_defaults.copy()
580 self._params['traffic'] = merge_spec(self._params['traffic'],
582 self._start_traffic_api(-1)
583 return self._stop_api_traffic()
585 def start_cont_traffic(self, traffic=None, duration=20):
586 """Non-blocking version of 'send_cont_traffic'.
588 See ITrafficGenerator for description
590 self._duration = duration
593 self._params['traffic'] = self.traffic_defaults.copy()
595 self._params['traffic'] = merge_spec(self._params['traffic'],
597 self._start_traffic_api(-1)
599 def stop_cont_traffic(self):
600 """Stop continuous transmission and return results.
602 return self._stop_api_traffic()
604 def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
606 """Send traffic per RFC2544 throughput test specifications.
608 See ITrafficGenerator for description
610 self._duration = duration
613 self._params['traffic'] = self.traffic_defaults.copy()
615 self._params['traffic'] = merge_spec(self._params['traffic'],
617 self._setup_json_config(tests, lossrate, '2544_throughput')
618 self._start_xena_2544()
619 self._wait_xena_2544_complete()
621 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
622 return Xena._create_throughput_result(root)
624 def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
626 """Non-blocking version of 'send_rfc2544_throughput'.
628 See ITrafficGenerator for description
630 self._duration = duration
632 self._params['traffic'] = self.traffic_defaults.copy()
634 self._params['traffic'] = merge_spec(self._params['traffic'],
636 self._setup_json_config(tests, lossrate, '2544_throughput')
637 self._start_xena_2544()
639 def wait_rfc2544_throughput(self):
640 """Wait for and return results of RFC2544 test.
642 See ITrafficGenerator for description
644 self._wait_xena_2544_complete()
645 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
646 return Xena._create_throughput_result(root)
648 def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
650 """Send traffic per RFC2544 back2back test specifications.
652 See ITrafficGenerator for description
654 self._duration = duration
657 self._params['traffic'] = self.traffic_defaults.copy()
659 self._params['traffic'] = merge_spec(self._params['traffic'],
661 self._setup_json_config(tests, lossrate, '2544_b2b')
662 self._start_xena_2544()
663 self._wait_xena_2544_complete()
664 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
665 return Xena._create_throughput_result(root)
667 def start_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
669 """Non-blocking version of 'send_rfc2544_back2back'.
671 See ITrafficGenerator for description
673 self._duration = duration
675 self._params['traffic'] = self.traffic_defaults.copy()
677 self._params['traffic'] = merge_spec(self._params['traffic'],
679 self._setup_json_config(tests, lossrate, '2544_b2b')
680 self._start_xena_2544()
682 def wait_rfc2544_back2back(self):
683 """Wait and set results of RFC2544 test.
685 self._wait_xena_2544_complete()
686 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
687 return Xena._create_throughput_result(root)
690 if __name__ == "__main__":