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, trials, loss_rate, testtype=None):
280 Create a 2bUsed json file that will be used for xena2544.exe execution.
281 :param trials: Number of trials
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=trials, 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()
313 elif testtype == '2544_b2b':
314 j_file.set_test_options_back2back(
315 packet_sizes=self._params['traffic']['l2']['framesize'],
316 iterations=trials, duration=self._duration,
317 startvalue=self._params['traffic']['frame_rate'],
318 endvalue=self._params['traffic']['frame_rate'],
319 micro_tpld=True if self._params[
320 'traffic']['l2']['framesize'] == 64 else False)
321 j_file.enable_back2back_test()
323 j_file.set_header_layer2(
324 dst_mac=self._params['traffic']['l2']['dstmac'],
325 src_mac=self._params['traffic']['l2']['srcmac'])
326 j_file.set_header_layer3(
327 src_ip=self._params['traffic']['l3']['srcip'],
328 dst_ip=self._params['traffic']['l3']['dstip'],
329 protocol=self._params['traffic']['l3']['proto'])
330 j_file.set_header_layer4_udp(
331 source_port=self._params['traffic']['l4']['srcport'],
332 destination_port=self._params['traffic']['l4']['dstport'])
333 if self._params['traffic']['vlan']['enabled']:
334 j_file.set_header_vlan(
335 vlan_id=self._params['traffic']['vlan']['id'],
336 id=self._params['traffic']['vlan']['cfi'],
337 prio=self._params['traffic']['vlan']['priority'])
338 j_file.add_header_segments(
339 flows=self._params['traffic']['multistream'],
340 multistream_layer=self._params['traffic']['stream_type'])
342 if self._params['traffic']['bidir'] == "True":
343 j_file.set_topology_mesh()
345 j_file.set_topology_blocks()
347 j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544')
348 except Exception as exc:
349 self._logger.exception("Error during Xena JSON setup: %s", exc)
352 def _start_traffic_api(self, packet_limit):
354 Start the Xena traffic using the socket API driver
355 :param packet_limit: packet limit for stream, set to -1 for no limit
358 if not self.xmanager:
359 self._xsocket = XenaSocketDriver(
360 settings.getValue('TRAFFICGEN_XENA_IP'))
361 self.xmanager = XenaManager(
362 self._xsocket, settings.getValue('TRAFFICGEN_XENA_USER'),
363 settings.getValue('TRAFFICGEN_XENA_PASSWORD'))
365 # for the report file version info ask the chassis directly for its
367 settings.setValue('XENA_VERSION', 'XENA Socket API - {}'.format(
368 self.xmanager.get_version()))
370 if not len(self.xmanager.ports):
371 self.xmanager.ports[0] = self.xmanager.add_module_port(
372 settings.getValue('TRAFFICGEN_XENA_MODULE1'),
373 settings.getValue('TRAFFICGEN_XENA_PORT1'))
374 if not self.xmanager.ports[0].reserve_port():
376 'Unable to reserve port 0. Please release Xena Port')
378 if len(self.xmanager.ports) < 2:
379 self.xmanager.ports[1] = self.xmanager.add_module_port(
380 settings.getValue('TRAFFICGEN_XENA_MODULE2'),
381 settings.getValue('TRAFFICGEN_XENA_PORT2'))
382 if not self.xmanager.ports[1].reserve_port():
384 'Unable to reserve port 1. Please release Xena Port')
386 # Clear port configuration for a clean start
387 self.xmanager.ports[0].reset_port()
388 self.xmanager.ports[1].reset_port()
389 self.xmanager.ports[0].clear_stats()
390 self.xmanager.ports[1].clear_stats()
392 # set the port IP from the conf file
393 self.xmanager.ports[0].set_port_ip(
394 settings.getValue('TRAFFICGEN_XENA_PORT0_IP'),
395 settings.getValue('TRAFFICGEN_XENA_PORT0_CIDR'),
396 settings.getValue('TRAFFICGEN_XENA_PORT0_GATEWAY'))
397 self.xmanager.ports[1].set_port_ip(
398 settings.getValue('TRAFFICGEN_XENA_PORT1_IP'),
399 settings.getValue('TRAFFICGEN_XENA_PORT1_CIDR'),
400 settings.getValue('TRAFFICGEN_XENA_PORT1_GATEWAY'))
402 def setup_stream(stream, port, payload_id, flip_addr=False):
404 Helper function to configure streams.
405 :param stream: Stream object from XenaDriver module
406 :param port: Port object from XenaDriver module
407 :param payload_id: payload ID as int
408 :param flip_addr: Boolean if the source and destination addresses
413 stream.set_packet_limit(packet_limit)
415 stream.set_rate_fraction(
416 10000 * self._params['traffic']['frame_rate'])
417 stream.set_packet_header(self._build_packet_header(
419 stream.set_header_protocol(
420 'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][
421 'enabled'] else 'ETHERNET IP UDP')
422 stream.set_packet_length(
423 'fixed', self._params['traffic']['l2']['framesize'], 16383)
424 stream.set_packet_payload('incrementing', '0x00')
425 stream.set_payload_id(payload_id)
426 port.set_port_time_limit(self._duration * 1000000)
428 if self._params['traffic']['l2']['framesize'] == 64:
430 port.micro_tpld_enable()
432 if self._params['traffic']['multistream']:
433 stream.enable_multistream(
434 flows=self._params['traffic']['multistream'],
435 layer=self._params['traffic']['stream_type'])
437 s1_p0 = self.xmanager.ports[0].add_stream()
438 setup_stream(s1_p0, self.xmanager.ports[0], 0)
440 if self._params['traffic']['bidir'] == 'True':
441 s1_p1 = self.xmanager.ports[1].add_stream()
442 setup_stream(s1_p1, self.xmanager.ports[1], 1, flip_addr=True)
444 if not self.xmanager.ports[0].traffic_on():
446 "Failure to start port 0. Check settings and retry.")
447 if self._params['traffic']['bidir'] == 'True':
448 if not self.xmanager.ports[1].traffic_on():
450 "Failure to start port 1. Check settings and retry.")
451 sleep(self._duration)
453 if self._params['traffic']['bidir'] == 'True':
454 # need to aggregate out both ports stats and assign that data
455 self.rx_stats = self.xmanager.ports[1].get_rx_stats()
456 self.tx_stats = self.xmanager.ports[0].get_tx_stats()
457 self.tx_stats.data = aggregate_stats(
459 self.xmanager.ports[1].get_tx_stats().data)
460 self.rx_stats.data = aggregate_stats(
462 self.xmanager.ports[0].get_rx_stats().data)
464 # no need to aggregate, just grab the appropriate port stats
465 self.tx_stats = self.xmanager.ports[0].get_tx_stats()
466 self.rx_stats = self.xmanager.ports[1].get_rx_stats()
469 def _start_xena_2544(self):
471 Start the xena2544 exe.
474 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
475 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
476 "./tools/pkt_gen/xena", "-u",
477 settings.getValue('TRAFFICGEN_XENA_USER')]
478 # Sometimes Xena2544.exe completes, but mono holds the process without
479 # releasing it, this can cause a deadlock of the main thread. Use the
480 # xena log file as a way to detect this.
481 self._log_handle = open(self._log_path, 'r')
482 # read the contents of the log before we start so the next read in the
483 # wait method are only looking at the text from this test instance
484 self._log_handle.read()
485 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
487 def _wait_xena_2544_complete(self):
489 Wait for Xena2544.exe completion.
495 self.mono_pipe.wait(60)
496 self._log_handle.close()
498 except subprocess.TimeoutExpired:
499 # check the log to see if Xena2544 has completed and mono is
501 data += self._log_handle.read()
502 if 'TestCompletedSuccessfully' in data:
503 self._log_handle.close()
504 self.mono_pipe.terminate()
507 def _stop_api_traffic(self):
509 Stop traffic through the socket API
510 :return: Return results from _create_api_result method
512 self.xmanager.ports[0].traffic_off()
513 if self._params['traffic']['bidir'] == 'True':
514 self.xmanager.ports[1].traffic_off()
517 stat = self._create_api_result()
522 self._logger.debug('Connect')
525 def disconnect(self):
526 """Disconnect from the traffic generator.
528 As with :func:`connect`, this function is optional.
531 Where implemented, this function should raise an exception on
536 self._logger.debug('disconnect')
538 self.xmanager.disconnect()
542 self._xsocket.disconnect()
545 def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
546 """Send a burst of traffic.
548 See ITrafficGenerator for description
550 self._duration = duration
552 self._params['traffic'] = self.traffic_defaults.copy()
554 self._params['traffic'] = merge_spec(self._params['traffic'],
556 self._start_traffic_api(numpkts)
557 return self._stop_api_traffic()
559 def send_cont_traffic(self, traffic=None, duration=20):
560 """Send a continuous flow of traffic.
562 See ITrafficGenerator for description
564 self._duration = duration
567 self._params['traffic'] = self.traffic_defaults.copy()
569 self._params['traffic'] = merge_spec(self._params['traffic'],
571 self._start_traffic_api(-1)
572 return self._stop_api_traffic()
574 def start_cont_traffic(self, traffic=None, duration=20):
575 """Non-blocking version of 'send_cont_traffic'.
577 See ITrafficGenerator for description
579 self._duration = duration
582 self._params['traffic'] = self.traffic_defaults.copy()
584 self._params['traffic'] = merge_spec(self._params['traffic'],
586 self._start_traffic_api(-1)
588 def stop_cont_traffic(self):
589 """Stop continuous transmission and return results.
591 return self._stop_api_traffic()
593 def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
595 """Send traffic per RFC2544 throughput test specifications.
597 See ITrafficGenerator for description
599 self._duration = duration
602 self._params['traffic'] = self.traffic_defaults.copy()
604 self._params['traffic'] = merge_spec(self._params['traffic'],
606 self._setup_json_config(trials, lossrate, '2544_throughput')
607 self._start_xena_2544()
608 self._wait_xena_2544_complete()
610 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
611 return Xena._create_throughput_result(root)
613 def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
615 """Non-blocking version of 'send_rfc2544_throughput'.
617 See ITrafficGenerator for description
619 self._duration = duration
621 self._params['traffic'] = self.traffic_defaults.copy()
623 self._params['traffic'] = merge_spec(self._params['traffic'],
625 self._setup_json_config(trials, lossrate, '2544_throughput')
626 self._start_xena_2544()
628 def wait_rfc2544_throughput(self):
629 """Wait for and return results of RFC2544 test.
631 See ITrafficGenerator for description
633 self._wait_xena_2544_complete()
634 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
635 return Xena._create_throughput_result(root)
637 def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
639 """Send traffic per RFC2544 back2back test specifications.
641 See ITrafficGenerator for description
643 self._duration = duration
646 self._params['traffic'] = self.traffic_defaults.copy()
648 self._params['traffic'] = merge_spec(self._params['traffic'],
650 self._setup_json_config(trials, lossrate, '2544_b2b')
651 self._start_xena_2544()
652 self._wait_xena_2544_complete()
653 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
654 return Xena._create_throughput_result(root)
656 def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
658 """Non-blocking version of 'send_rfc2544_back2back'.
660 See ITrafficGenerator for description
662 self._duration = duration
664 self._params['traffic'] = self.traffic_defaults.copy()
666 self._params['traffic'] = merge_spec(self._params['traffic'],
668 self._setup_json_config(trials, lossrate, '2544_b2b')
669 self._start_xena_2544()
671 def wait_rfc2544_back2back(self):
672 """Wait and set results of RFC2544 test.
674 self._wait_xena_2544_complete()
675 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
676 return Xena._create_throughput_result(root)
679 if __name__ == "__main__":