Merge "Bugfix: pylint fix for yardstick/orchestrator/heat.py (no-value-for-parameter)"
[yardstick.git] / yardstick / network_services / traffic_profile / ixia_rfc2544.py
1 # Copyright (c) 2016-2017 Intel Corporation
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 import logging
16
17 from yardstick.common import utils
18 from yardstick.network_services.traffic_profile import base as tp_base
19 from yardstick.network_services.traffic_profile import trex_traffic_profile
20
21
22 LOG = logging.getLogger(__name__)
23
24
25 class IXIARFC2544Profile(trex_traffic_profile.TrexProfile):
26
27     UPLINK = 'uplink'
28     DOWNLINK = 'downlink'
29     DROP_PERCENT_ROUND = 6
30     RATE_ROUND = 5
31
32     def __init__(self, yaml_data):
33         super(IXIARFC2544Profile, self).__init__(yaml_data)
34         self.rate = self.config.frame_rate
35         self.rate_unit = self.config.rate_unit
36
37     def _get_ip_and_mask(self, ip_range):
38         _ip_range = ip_range.split('-')
39         if len(_ip_range) == 1:
40             return _ip_range[0], None
41
42         mask = utils.get_mask_from_ip_range(_ip_range[0], _ip_range[1])
43         return _ip_range[0], mask
44
45     def _get_fixed_and_mask(self, port_range):
46         _port_range = str(port_range).split('-')
47         if len(_port_range) == 1:
48             return int(_port_range[0]), 0
49
50         return int(_port_range[0]), int(_port_range[1])
51
52     def _get_ixia_traffic_profile(self, profile_data, mac=None):
53         mac = {} if mac is None else mac
54         result = {}
55         for traffickey, values in profile_data.items():
56             if not traffickey.startswith((self.UPLINK, self.DOWNLINK)):
57                 continue
58
59             try:
60                 # values should be single-item dict, so just grab the first item
61                 try:
62                     key, value = next(iter(values.items()))
63                 except StopIteration:
64                     result[traffickey] = {}
65                     continue
66
67                 port_id = value.get('id', 1)
68                 port_index = port_id - 1
69
70                 if value.get('outer_l3v4'):
71                     ip = value['outer_l3v4']
72                     src_key, dst_key = 'srcip4', 'dstip4'
73                 else:
74                     ip = value['outer_l3v6']
75                     src_key, dst_key = 'srcip6', 'dstip6'
76
77                 srcip, srcmask = self._get_ip_and_mask(ip[src_key])
78                 dstip, dstmask = self._get_ip_and_mask(ip[dst_key])
79
80                 outer_l4 = value.get('outer_l4')
81                 src_port, src_port_mask = self._get_fixed_and_mask(outer_l4['srcport'])
82                 dst_port, dst_port_mask = self._get_fixed_and_mask(outer_l4['dstport'])
83                 result[traffickey] = {
84                     'bidir': False,
85                     'id': port_id,
86                     'rate': self.rate,
87                     'rate_unit': self.rate_unit,
88                     'outer_l2': {
89                         'framesize': value['outer_l2']['framesize'],
90                         'framesPerSecond': True,
91                         'QinQ': value['outer_l2'].get('QinQ'),
92                         'srcmac': mac['src_mac_{}'.format(port_index)],
93                         'dstmac': mac['dst_mac_{}'.format(port_index)],
94                     },
95                     'outer_l3': {
96                         'count': ip['count'],
97                         'dscp': ip['dscp'],
98                         'ttl': ip['ttl'],
99                         'seed': ip['seed'],
100                         'srcip': srcip,
101                         'dstip': dstip,
102                         'srcmask': srcmask,
103                         'dstmask': dstmask,
104                         'type': key,
105                         'proto': ip['proto'],
106                     },
107                     'outer_l4': {
108                         'srcport': src_port,
109                         'dstport': dst_port,
110                         'srcportmask': src_port_mask,
111                         'dstportmask': dst_port_mask,
112                         'count': outer_l4['count'],
113                         'seed': outer_l4['seed'],
114                     }
115
116                 }
117             except KeyError:
118                 continue
119
120         return result
121
122     def _ixia_traffic_generate(self, traffic, ixia_obj):
123         ixia_obj.update_frame(traffic, self.config.duration)
124         ixia_obj.update_ip_packet(traffic)
125         ixia_obj.update_l4(traffic)
126         ixia_obj.start_traffic()
127
128     def update_traffic_profile(self, traffic_generator):
129         def port_generator():
130             for vld_id, intfs in sorted(traffic_generator.networks.items()):
131                 if not vld_id.startswith((self.UPLINK, self.DOWNLINK)):
132                     continue
133                 profile_data = self.params.get(vld_id)
134                 if not profile_data:
135                     continue
136                 self.profile_data = profile_data
137                 self.full_profile.update({vld_id: self.profile_data})
138                 for intf in intfs:
139                     yield traffic_generator.vnfd_helper.port_num(intf)
140
141         self.ports = [port for port in port_generator()]
142
143     def execute_traffic(self, traffic_generator, ixia_obj=None, mac=None):
144         mac = {} if mac is None else mac
145         first_run = self.first_run
146         if self.first_run:
147             self.first_run = False
148             self.full_profile = {}
149             self.pg_id = 0
150             self.update_traffic_profile(traffic_generator)
151             self.max_rate = self.rate
152             self.min_rate = 0.0
153         else:
154             self.rate = round(float(self.max_rate + self.min_rate) / 2.0,
155                               self.RATE_ROUND)
156
157         traffic = self._get_ixia_traffic_profile(self.full_profile, mac)
158         self._ixia_traffic_generate(traffic, ixia_obj)
159         return first_run
160
161     def get_drop_percentage(self, samples, tol_min, tolerance,
162                             first_run=False):
163         completed = False
164         drop_percent = 100
165         num_ifaces = len(samples)
166         duration = self.config.duration
167         in_packets_sum = sum(
168             [samples[iface]['in_packets'] for iface in samples])
169         out_packets_sum = sum(
170             [samples[iface]['out_packets'] for iface in samples])
171         rx_throughput = sum(
172             [samples[iface]['RxThroughput'] for iface in samples])
173         rx_throughput = round(float(rx_throughput), 2)
174         tx_throughput = sum(
175             [samples[iface]['TxThroughput'] for iface in samples])
176         tx_throughput = round(float(tx_throughput), 2)
177         packet_drop = abs(out_packets_sum - in_packets_sum)
178
179         try:
180             drop_percent = round(
181                 (packet_drop / float(out_packets_sum)) * 100,
182                 self.DROP_PERCENT_ROUND)
183         except ZeroDivisionError:
184             LOG.info('No traffic is flowing')
185
186         samples['TxThroughput'] = tx_throughput
187         samples['RxThroughput'] = rx_throughput
188         samples['DropPercentage'] = drop_percent
189
190         if first_run:
191             completed = True if drop_percent <= tolerance else False
192         if (first_run and
193                 self.rate_unit == tp_base.TrafficProfileConfig.RATE_FPS):
194             self.rate = float(out_packets_sum) / duration / num_ifaces
195
196         if drop_percent > tolerance:
197             self.max_rate = self.rate
198         elif drop_percent < tol_min:
199             self.min_rate = self.rate
200         else:
201             completed = True
202
203         return completed, samples