1 # Copyright (c) 2016-2019 Intel Corporation
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.
18 from yardstick.common import utils
19 from yardstick.network_services.traffic_profile import base as tp_base
20 from yardstick.network_services.traffic_profile import trex_traffic_profile
23 LOG = logging.getLogger(__name__)
26 class IXIARFC2544Profile(trex_traffic_profile.TrexProfile):
30 DROP_PERCENT_ROUND = 6
32 STATUS_SUCCESS = "Success"
33 STATUS_FAIL = "Failure"
35 def __init__(self, yaml_data):
36 super(IXIARFC2544Profile, self).__init__(yaml_data)
37 self.rate = self.config.frame_rate
38 self.rate_unit = self.config.rate_unit
39 self.full_profile = {}
41 def _get_ip_and_mask(self, ip_range):
42 _ip_range = ip_range.split('-')
43 if len(_ip_range) == 1:
44 return _ip_range[0], None
46 mask = utils.get_mask_from_ip_range(_ip_range[0], _ip_range[1])
47 return _ip_range[0], mask
49 def _get_fixed_and_mask(self, port_range):
50 _port_range = str(port_range).split('-')
51 if len(_port_range) == 1:
52 return int(_port_range[0]), 0
54 return int(_port_range[0]), int(_port_range[1])
56 def _get_ixia_traffic_profile(self, profile_data, mac=None):
57 mac = {} if mac is None else mac
59 for traffickey, values in profile_data.items():
60 if not traffickey.startswith((self.UPLINK, self.DOWNLINK)):
63 # values should be single-item dict, so just grab the first item
65 key, value = next(iter(values.items()))
67 result[traffickey] = {}
70 port_id = value.get('id', 1)
71 port_index = port_id - 1
73 result[traffickey] = {
77 'rate_unit': self.rate_unit,
83 frame_rate = value.get('frame_rate')
85 flow_rate, flow_rate_unit = self.config.parse_rate(frame_rate)
86 result[traffickey]['rate'] = flow_rate
87 result[traffickey]['rate_unit'] = flow_rate_unit
89 outer_l2 = value.get('outer_l2')
91 result[traffickey]['outer_l2'].update({
92 'framesize': outer_l2.get('framesize'),
93 'framesPerSecond': True,
94 'QinQ': outer_l2.get('QinQ'),
95 'srcmac': mac.get('src_mac_{}'.format(port_index)),
96 'dstmac': mac.get('dst_mac_{}'.format(port_index)),
99 if value.get('outer_l3v4'):
100 outer_l3 = value['outer_l3v4']
101 src_key, dst_key = 'srcip4', 'dstip4'
103 outer_l3 = value.get('outer_l3v6')
104 src_key, dst_key = 'srcip6', 'dstip6'
106 srcip = srcmask = dstip = dstmask = None
107 if outer_l3.get(src_key):
108 srcip, srcmask = self._get_ip_and_mask(outer_l3[src_key])
109 if outer_l3.get(dst_key):
110 dstip, dstmask = self._get_ip_and_mask(outer_l3[dst_key])
112 result[traffickey]['outer_l3'].update({
113 'count': outer_l3.get('count', 1),
114 'dscp': outer_l3.get('dscp'),
115 'ttl': outer_l3.get('ttl'),
116 'srcseed': outer_l3.get('srcseed', 1),
117 'dstseed': outer_l3.get('dstseed', 1),
123 'proto': outer_l3.get('proto'),
124 'priority': outer_l3.get('priority')
127 outer_l4 = value.get('outer_l4')
129 src_port = src_port_mask = dst_port = dst_port_mask = None
130 if outer_l4.get('srcport'):
131 src_port, src_port_mask = (
132 self._get_fixed_and_mask(outer_l4['srcport']))
134 if outer_l4.get('dstport'):
135 dst_port, dst_port_mask = (
136 self._get_fixed_and_mask(outer_l4['dstport']))
138 result[traffickey]['outer_l4'].update({
141 'srcportmask': src_port_mask,
142 'dstportmask': dst_port_mask,
143 'count': outer_l4.get('count', 1),
144 'seed': outer_l4.get('seed', 1),
149 def _ixia_traffic_generate(self, traffic, ixia_obj, traffic_gen):
150 ixia_obj.update_frame(traffic, self.config.duration)
151 ixia_obj.update_ip_packet(traffic)
152 ixia_obj.update_l4(traffic)
153 self._update_traffic_tracking_options(traffic_gen)
154 ixia_obj.start_traffic()
156 def _update_traffic_tracking_options(self, traffic_gen):
157 traffic_gen.update_tracking_options()
159 def update_traffic_profile(self, traffic_generator):
160 def port_generator():
161 for vld_id, intfs in sorted(traffic_generator.networks.items()):
162 if not vld_id.startswith((self.UPLINK, self.DOWNLINK)):
164 profile_data = self.params.get(vld_id)
167 self.profile_data = profile_data
168 self.full_profile.update({vld_id: self.profile_data})
170 yield traffic_generator.vnfd_helper.port_num(intf)
172 self.ports = [port for port in port_generator()]
174 def _get_next_rate(self):
175 rate = round(float(self.max_rate + self.min_rate)/2.0, self.RATE_ROUND)
178 def _get_framesize(self):
180 traffic = self._get_ixia_traffic_profile(self.full_profile)
181 for v in traffic.values():
182 framesize = v['outer_l2']['framesize']
183 for size in (s for s, w in framesize.items() if int(w) != 0):
184 framesizes.append(size)
185 if len(set(framesizes)) == 0:
187 elif len(set(framesizes)) == 1:
191 def execute_traffic(self, traffic_generator, ixia_obj=None, mac=None):
192 mac = {} if mac is None else mac
193 first_run = self.first_run
195 self.first_run = False
197 self.max_rate = self.rate
200 self.rate = self._get_next_rate()
202 traffic = self._get_ixia_traffic_profile(self.full_profile, mac)
203 self._ixia_traffic_generate(traffic, ixia_obj, traffic_generator)
206 # pylint: disable=unused-argument
207 def get_drop_percentage(self, samples, tol_min, tolerance, precision,
208 resolution, first_run=False, tc_rfc2544_opts=None):
211 num_ifaces = len(samples)
212 duration = self.config.duration
213 in_packets_sum = sum(
214 [samples[iface]['in_packets'] for iface in samples])
215 out_packets_sum = sum(
216 [samples[iface]['out_packets'] for iface in samples])
217 rx_throughput = round(float(in_packets_sum) / duration, 3)
218 tx_throughput = round(float(out_packets_sum) / duration, 3)
219 packet_drop = abs(out_packets_sum - in_packets_sum)
222 drop_percent = round(
223 (packet_drop / float(out_packets_sum)) * 100,
224 self.DROP_PERCENT_ROUND)
225 except ZeroDivisionError:
226 LOG.info('No traffic is flowing')
229 completed = True if drop_percent <= tolerance else False
231 self.rate_unit == tp_base.TrafficProfileConfig.RATE_FPS):
232 self.rate = float(out_packets_sum) / duration / num_ifaces
234 if drop_percent > tolerance:
235 self.max_rate = self.rate
236 elif drop_percent < tol_min:
237 self.min_rate = self.rate
241 last_rate = self.rate
242 next_rate = self._get_next_rate()
243 if abs(next_rate - self.rate) < resolution:
244 LOG.debug("rate=%s, next_rate=%s, resolution=%s", self.rate,
245 next_rate, resolution)
246 # stop test if the difference between the rate transmission
247 # in two iterations is smaller than the value of the resolution
250 LOG.debug("tolerance=%s, tolerance_precision=%s drop_percent=%s "
251 "completed=%s", tolerance, precision, drop_percent,
254 latency_ns_avg = float(
255 sum([samples[iface]['Store-Forward_Avg_latency_ns']
256 for iface in samples])) / num_ifaces
257 latency_ns_min = float(
258 sum([samples[iface]['Store-Forward_Min_latency_ns']
259 for iface in samples])) / num_ifaces
260 latency_ns_max = float(
261 sum([samples[iface]['Store-Forward_Max_latency_ns']
262 for iface in samples])) / num_ifaces
264 samples['Status'] = self.STATUS_FAIL
265 if round(drop_percent, precision) <= tolerance:
266 samples['Status'] = self.STATUS_SUCCESS
268 samples['TxThroughput'] = tx_throughput
269 samples['RxThroughput'] = rx_throughput
270 samples['DropPercentage'] = drop_percent
271 samples['latency_ns_avg'] = latency_ns_avg
272 samples['latency_ns_min'] = latency_ns_min
273 samples['latency_ns_max'] = latency_ns_max
274 samples['Rate'] = last_rate
275 samples['PktSize'] = self._get_framesize()
277 return completed, samples
280 class IXIARFC2544PppoeScenarioProfile(IXIARFC2544Profile):
281 """Class handles BNG PPPoE scenario tests traffic profile"""
283 def __init__(self, yaml_data):
284 super(IXIARFC2544PppoeScenarioProfile, self).__init__(yaml_data)
285 self.full_profile = collections.OrderedDict()
287 def _get_flow_groups_params(self):
288 flows_data = [key for key in self.params.keys()
289 if key.split('_')[0] in [self.UPLINK, self.DOWNLINK]]
290 for i in range(len(flows_data)):
291 uplink = '_'.join([self.UPLINK, str(i)])
292 downlink = '_'.join([self.DOWNLINK, str(i)])
293 if uplink in flows_data:
294 self.full_profile.update({uplink: self.params[uplink]})
295 if downlink in flows_data:
296 self.full_profile.update({downlink: self.params[downlink]})
298 def update_traffic_profile(self, traffic_generator):
300 networks = collections.OrderedDict()
302 # Sort network interfaces pairs
303 for i in range(len(traffic_generator.networks)):
304 uplink = '_'.join([self.UPLINK, str(i)])
305 downlink = '_'.join([self.DOWNLINK, str(i)])
306 if uplink in traffic_generator.networks:
307 networks[uplink] = traffic_generator.networks[uplink]
308 if downlink in traffic_generator.networks:
309 networks[downlink] = traffic_generator.networks[downlink]
311 def port_generator():
312 for intfs in networks.values():
314 yield traffic_generator.vnfd_helper.port_num(intf)
316 self._get_flow_groups_params()
317 self.ports = [port for port in port_generator()]
319 def _get_prio_flows_drop_percentage(self, stats):
321 for prio_id in stats:
322 prio_flow = stats[prio_id]
323 sum_packet_drop = abs(prio_flow['out_packets'] - prio_flow['in_packets'])
325 drop_percent = round(
326 (sum_packet_drop / float(prio_flow['out_packets'])) * 100,
327 self.DROP_PERCENT_ROUND)
328 except ZeroDivisionError:
329 LOG.info('No traffic is flowing')
330 prio_flow['DropPercentage'] = drop_percent
333 def _get_summary_pppoe_subs_counters(self, samples):
335 keys = ['sessions_up',
337 'sessions_not_started',
341 sum([samples[port][key] for port in samples
342 if key in samples[port]])
345 def get_drop_percentage(self, samples, tol_min, tolerance, precision,
346 resolution, first_run=False, tc_rfc2544_opts=None):
348 sum_drop_percent = 100
349 num_ifaces = len(samples)
350 duration = self.config.duration
351 last_rate = self.rate
352 priority_stats = samples.pop('priority_stats')
353 priority_stats = self._get_prio_flows_drop_percentage(priority_stats)
354 summary_subs_stats = self._get_summary_pppoe_subs_counters(samples)
355 in_packets_sum = sum(
356 [samples[iface]['in_packets'] for iface in samples])
357 out_packets_sum = sum(
358 [samples[iface]['out_packets'] for iface in samples])
359 rx_throughput = round(float(in_packets_sum) / duration, 3)
360 tx_throughput = round(float(out_packets_sum) / duration, 3)
361 sum_packet_drop = abs(out_packets_sum - in_packets_sum)
364 sum_drop_percent = round(
365 (sum_packet_drop / float(out_packets_sum)) * 100,
366 self.DROP_PERCENT_ROUND)
367 except ZeroDivisionError:
368 LOG.info('No traffic is flowing')
370 latency_ns_avg = float(
371 sum([samples[iface]['Store-Forward_Avg_latency_ns']
372 for iface in samples])) / num_ifaces
373 latency_ns_min = float(
374 sum([samples[iface]['Store-Forward_Min_latency_ns']
375 for iface in samples])) / num_ifaces
376 latency_ns_max = float(
377 sum([samples[iface]['Store-Forward_Max_latency_ns']
378 for iface in samples])) / num_ifaces
380 samples['TxThroughput'] = tx_throughput
381 samples['RxThroughput'] = rx_throughput
382 samples['DropPercentage'] = sum_drop_percent
383 samples['latency_ns_avg'] = latency_ns_avg
384 samples['latency_ns_min'] = latency_ns_min
385 samples['latency_ns_max'] = latency_ns_max
386 samples['priority'] = priority_stats
387 samples['Rate'] = last_rate
388 samples['PktSize'] = self._get_framesize()
389 samples.update(summary_subs_stats)
392 priority = tc_rfc2544_opts.get('priority')
394 drop_percent = samples['priority'][priority]['DropPercentage']
396 drop_percent = sum_drop_percent
398 drop_percent = sum_drop_percent
401 completed = True if drop_percent <= tolerance else False
403 self.rate_unit == tp_base.TrafficProfileConfig.RATE_FPS):
404 self.rate = float(out_packets_sum) / duration / num_ifaces
406 if drop_percent > tolerance:
407 self.max_rate = self.rate
408 elif drop_percent < tol_min:
409 self.min_rate = self.rate
413 next_rate = self._get_next_rate()
414 if abs(next_rate - self.rate) < resolution:
415 LOG.debug("rate=%s, next_rate=%s, resolution=%s", self.rate,
416 next_rate, resolution)
417 # stop test if the difference between the rate transmission
418 # in two iterations is smaller than the value of the resolution
421 LOG.debug("tolerance=%s, tolerance_precision=%s drop_percent=%s "
422 "completed=%s", tolerance, precision, drop_percent,
425 samples['Status'] = self.STATUS_FAIL
426 if round(drop_percent, precision) <= tolerance:
427 samples['Status'] = self.STATUS_SUCCESS
429 return completed, samples