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
30 from time import sleep
31 import xml.etree.ElementTree as ET
32 from collections import OrderedDict
35 from conf import settings
36 from core.results.results_constants import ResultsConstants
37 from tools.pkt_gen.trafficgen.trafficgenhelper import (
40 from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
43 from tools.pkt_gen.xena.xena_json import XenaJSON
46 class Xena(ITrafficGenerator):
48 Xena Traffic generator wrapper class
50 _traffic_defaults = TRAFFIC_DEFAULTS.copy()
51 _logger = logging.getLogger(__name__)
59 def traffic_defaults(self):
60 """Default traffic values.
62 These can be expected to be constant across traffic generators,
63 so no setter is provided. Changes to the structure or contents
64 will likely break traffic generator implementations or tests
67 return self._traffic_defaults
70 def _create_throughput_result(root):
72 Create the results based off the output xml file from the Xena2544.exe
74 :param root: root dictionary from xml import
75 :return: Results Ordered dictionary based off ResultsConstants
77 throughput_test = False
78 back2back_test = False
79 # get the calling method so we know how to return the stats
80 caller = inspect.stack()[1][3]
81 if 'throughput' in caller:
82 throughput_test = True
83 elif 'back2back' in caller:
86 raise NotImplementedError(
87 "Unknown implementation for result return")
90 results = OrderedDict()
91 results[ResultsConstants.THROUGHPUT_RX_FPS] = int(
92 root[0][1][0][1].get('PortRxPps'))
93 results[ResultsConstants.THROUGHPUT_RX_MBPS] = int(
94 root[0][1][0][1].get('PortRxBpsL1')) / 1000000
95 results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
96 100 - int(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
97 root[0][1][0].get('TotalTxRatePcnt'))/100
98 results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
100 results[ResultsConstants.TX_RATE_MBPS] = float(
101 root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
102 results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
105 results[ResultsConstants.MIN_LATENCY_NS] = float(
106 root[0][1][0][0].get('MinLatency')) * 1000
108 # Stats for latency returned as N/A so just post them
109 results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
112 results[ResultsConstants.MAX_LATENCY_NS] = float(
113 root[0][1][0][0].get('MaxLatency')) * 1000
115 # Stats for latency returned as N/A so just post them
116 results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
119 results[ResultsConstants.AVG_LATENCY_NS] = float(
120 root[0][1][0][0].get('AvgLatency')) * 1000
122 # Stats for latency returned as N/A so just post them
123 results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
126 raise NotImplementedError('Back to back results not implemented')
130 def _setup_json_config(self, trials, loss_rate, testtype=None):
132 Create a 2bUsed json file that will be used for xena2544.exe execution.
133 :param trials: Number of trials
134 :param loss_rate: The acceptable loss rate as float
135 :param testtype: Either '2544_b2b' or '2544_throughput' as string
139 j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544')
140 j_file.set_chassis_info(
141 settings.getValue('TRAFFICGEN_XENA_IP'),
142 settings.getValue('TRAFFICGEN_XENA_PASSWORD')
144 j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'),
145 settings.getValue('TRAFFICGEN_XENA_PORT1')
147 j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'),
148 settings.getValue('TRAFFICGEN_XENA_PORT2')
150 j_file.set_test_options(
151 packet_sizes=self._params['traffic']['l2']['framesize'],
152 iterations=trials, loss_rate=loss_rate,
153 duration=self._duration, micro_tpld=True if self._params[
154 'traffic']['l2']['framesize'] == 64 else False)
155 if testtype == '2544_throughput':
156 j_file.enable_throughput_test()
157 elif testtype == '2544_b2b':
158 j_file.enable_back2back_test()
160 j_file.set_header_layer2(
161 dst_mac=self._params['traffic']['l2']['dstmac'],
162 src_mac=self._params['traffic']['l2']['srcmac'])
163 j_file.set_header_layer3(
164 src_ip=self._params['traffic']['l3']['srcip'],
165 dst_ip=self._params['traffic']['l3']['dstip'],
166 protocol=self._params['traffic']['l3']['proto'])
167 j_file.set_header_layer4_udp(
168 source_port=self._params['traffic']['l4']['srcport'],
169 destination_port=self._params['traffic']['l4']['dstport'])
170 if self._params['traffic']['vlan']['enabled']:
171 j_file.set_header_vlan(
172 vlan_id=self._params['traffic']['vlan']['id'],
173 id=self._params['traffic']['vlan']['cfi'],
174 prio=self._params['traffic']['vlan']['priority'])
175 j_file.add_header_segments(
176 flows=self._params['traffic']['multistream'],
177 multistream_layer=self._params['traffic']['stream_type'])
179 if self._params['traffic']['bidir']:
180 j_file.set_topology_mesh()
182 j_file.set_topology_blocks()
184 j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544')
185 except Exception as exc:
186 self._logger.exception("Error during Xena JSON setup: %s", exc)
190 """Connect to the traffic generator.
192 This is an optional function, designed for traffic generators
193 which must be "connected to" (i.e. via SSH or an API) before
194 they can be used. If not required, simply do nothing here.
196 Where implemented, this function should raise an exception on
203 def disconnect(self):
204 """Disconnect from the traffic generator.
206 As with :func:`connect`, this function is optional.
208 Where implemented, this function should raise an exception on
215 def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
216 """Send a burst of traffic.
218 Send a ``numpkts`` packets of traffic, using ``traffic``
219 configuration, with a timeout of ``time``.
222 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
223 :param numpkts: Number of packets to send
224 :param duration: Time to wait to receive packets
226 :returns: dictionary of strings with following data:
230 - List of List of Rx Bytes,
231 - Payload Errors and Sequence Errors.
233 raise NotImplementedError('Xena burst traffic not implemented')
235 def send_cont_traffic(self, traffic=None, duration=20):
236 """Send a continuous flow of traffic.r
238 Send packets at ``framerate``, using ``traffic`` configuration,
239 until timeout ``time`` occurs.
241 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
242 :param duration: Time to wait to receive packets (secs)
243 :returns: dictionary of strings with following data:
244 - Tx Throughput (fps),
245 - Rx Throughput (fps),
246 - Tx Throughput (mbps),
247 - Rx Throughput (mbps),
248 - Tx Throughput (% linerate),
249 - Rx Throughput (% linerate),
254 raise NotImplementedError('Xena continuous traffic not implemented')
256 def start_cont_traffic(self, traffic=None, duration=20):
257 """Non-blocking version of 'send_cont_traffic'.
259 Start transmission and immediately return. Do not wait for
261 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
262 :param duration: Time to wait to receive packets (secs)
264 raise NotImplementedError('Xena continuous traffic not implemented')
266 def stop_cont_traffic(self):
267 """Stop continuous transmission and return results.
269 raise NotImplementedError('Xena continuous traffic not implemented')
271 def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
273 """Send traffic per RFC2544 throughput test specifications.
275 See ITrafficGenerator for description
277 self._duration = duration
280 self._params['traffic'] = self.traffic_defaults.copy()
282 self._params['traffic'] = merge_spec(self._params['traffic'],
285 self._setup_json_config(trials, lossrate, '2544_throughput')
287 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
288 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
289 "./tools/pkt_gen/xena", "-u",
290 settings.getValue('TRAFFICGEN_XENA_USER')]
291 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
292 self.mono_pipe.communicate()
293 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
294 return Xena._create_throughput_result(root)
296 def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
298 """Non-blocking version of 'send_rfc2544_throughput'.
300 See ITrafficGenerator for description
302 self._duration = duration
304 self._params['traffic'] = self.traffic_defaults.copy()
306 self._params['traffic'] = merge_spec(self._params['traffic'],
309 self._setup_json_config(trials, lossrate, '2544_throughput')
311 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
312 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
313 "./tools/pkt_gen/xena", "-u",
314 settings.getValue('TRAFFICGEN_XENA_USER')]
315 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
317 def wait_rfc2544_throughput(self):
318 """Wait for and return results of RFC2544 test.
320 See ITrafficGenerator for description
322 self.mono_pipe.communicate()
324 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
325 return Xena._create_throughput_result(root)
327 def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
329 """Send traffic per RFC2544 back2back test specifications.
331 Send packets at a fixed rate, using ``traffic``
332 configuration, until minimum time at which no packet loss is
335 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN
337 :param trials: Number of trials to execute
338 :param duration: Per iteration duration
339 :param lossrate: Acceptable loss percentage
341 :returns: Named tuple of Rx Throughput (fps), Rx Throughput (mbps),
342 Tx Rate (% linerate), Rx Rate (% linerate), Tx Count (frames),
343 Back to Back Count (frames), Frame Loss (frames), Frame Loss (%)
344 :rtype: :class:`Back2BackResult`
346 raise NotImplementedError('Xena back2back not implemented')
348 def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
350 """Non-blocking version of 'send_rfc2544_back2back'.
352 Start transmission and immediately return. Do not wait for
355 raise NotImplementedError('Xena back2back not implemented')
357 def wait_rfc2544_back2back(self):
358 """Wait and set results of RFC2544 test.
360 raise NotImplementedError('Xena back2back not implemented')
363 if __name__ == "__main__":