Merge "Add pod.yaml files for Apex"
[yardstick.git] / yardstick / network_services / libs / ixia_libs / IxNet / IxNet.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 import re
18 from itertools import product
19 import IxNetwork
20
21
22 log = logging.getLogger(__name__)
23
24 IP_VERSION_4 = 4
25 IP_VERSION_6 = 6
26
27
28 class TrafficStreamHelper(object):
29
30     TEMPLATE = '{0.traffic_item}/{0.stream}:{0.param_id}/{1}'
31
32     def __init__(self, traffic_item, stream, param_id):
33         super(TrafficStreamHelper, self).__init__()
34         self.traffic_item = traffic_item
35         self.stream = stream
36         self.param_id = param_id
37
38     def __getattr__(self, item):
39         return self.TEMPLATE.format(self, item)
40
41
42 class FramesizeHelper(object):
43
44     def __init__(self):
45         super(FramesizeHelper, self).__init__()
46         self.weighted_pairs = []
47         self.weighted_range_pairs = []
48
49     @property
50     def weighted_pairs_arg(self):
51         return '-weightedPairs', self.weighted_pairs
52
53     @property
54     def weighted_range_pairs_arg(self):
55         return '-weightedRangePairs', self.weighted_range_pairs
56
57     def make_args(self, *args):
58         return self.weighted_pairs_arg + self.weighted_range_pairs_arg + args
59
60     def populate_data(self, framesize_data):
61         for key, value in framesize_data.items():
62             if value == '0':
63                 continue
64
65             replaced = re.sub('[Bb]', '', key)
66             self.weighted_pairs.extend([
67                 replaced,
68                 value,
69             ])
70             pairs = [
71                 replaced,
72                 replaced,
73                 value,
74             ]
75             self.weighted_range_pairs.append(pairs)
76
77
78 class IxNextgen(object):
79
80     STATS_NAME_MAP = {
81         "traffic_item": 'Traffic Item',
82         "Tx_Frames": 'Tx Frames',
83         "Rx_Frames": 'Rx Frames',
84         "Tx_Frame_Rate": 'Tx Frame Rate',
85         "Rx_Frame_Rate": 'Tx Frame Rate',
86         "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
87         "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
88         "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
89     }
90
91     PORT_STATS_NAME_MAP = {
92         "stat_name": 'Stat Name',
93         "Frames_Tx": 'Frames Tx.',
94         "Valid_Frames_Rx": 'Valid Frames Rx.',
95         "Frames_Tx_Rate": 'Frames Tx. Rate',
96         "Valid_Frames_Rx_Rate": 'Valid Frames Rx. Rate',
97         "Tx_Rate_Kbps": 'Tx. Rate (Kbps)',
98         "Rx_Rate_Kbps": 'Rx. Rate (Kbps)',
99         "Tx_Rate_Mbps": 'Tx. Rate (Mbps)',
100         "Rx_Rate_Mbps": 'Rx. Rate (Mbps)',
101     }
102
103     LATENCY_NAME_MAP = {
104         "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
105         "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
106         "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
107     }
108
109     RANDOM_MASK_MAP = {
110         IP_VERSION_4: '0.0.0.255',
111         IP_VERSION_6: '0:0:0:0:0:0:0:ff',
112     }
113
114     MODE_SEEDS_MAP = {
115         0: ('uplink', ['256', '2048']),
116     }
117
118     MODE_SEEDS_DEFAULT = 'downlink', ['2048', '256']
119
120     @staticmethod
121     def find_view_obj(view_name, views):
122         edited_view_name = '::ixNet::OBJ-/statistics/view:"{}"'.format(view_name)
123         return next((view for view in views if edited_view_name == view), '')
124
125     @staticmethod
126     def get_config(tg_cfg):
127         card = []
128         port = []
129         external_interface = tg_cfg["vdu"][0]["external-interface"]
130         for intf in external_interface:
131             card_port0 = intf["virtual-interface"]["vpci"]
132             card0, port0 = card_port0.split(':')[:2]
133             card.append(card0)
134             port.append(port0)
135
136         cfg = {
137             'machine': tg_cfg["mgmt-interface"]["ip"],
138             'port': tg_cfg["mgmt-interface"]["tg-config"]["tcl_port"],
139             'chassis': tg_cfg["mgmt-interface"]["tg-config"]["ixchassis"],
140             'cards': card,
141             'ports': port,
142             'output_dir': tg_cfg["mgmt-interface"]["tg-config"]["dut_result_dir"],
143             'version': tg_cfg["mgmt-interface"]["tg-config"]["version"],
144             'bidir': True,
145         }
146
147         return cfg
148
149     def __init__(self, ixnet=None):
150         self.ixnet = ixnet
151         self._objRefs = dict()
152         self._cfg = None
153         self._logger = logging.getLogger(__name__)
154         self._params = None
155         self._bidir = None
156
157     def iter_over_get_lists(self, x1, x2, y2, offset=0):
158         for x in self.ixnet.getList(x1, x2):
159             y_list = self.ixnet.getList(x, y2)
160             for i, y in enumerate(y_list, offset):
161                 yield x, y, i
162
163     def set_random_ip_multi_attribute(self, ipv4, seed, fixed_bits, random_mask, l3_count):
164         self.ixnet.setMultiAttribute(
165             ipv4,
166             '-seed', str(seed),
167             '-fixedBits', str(fixed_bits),
168             '-randomMask', str(random_mask),
169             '-valueType', 'random',
170             '-countValue', str(l3_count))
171
172     def set_random_ip_multi_attributes(self, ip, version, seeds, l3):
173         try:
174             random_mask = self.RANDOM_MASK_MAP[version]
175         except KeyError:
176             raise ValueError('Unknown version %s' % version)
177
178         l3_count = l3['count']
179         if "srcIp" in ip:
180             fixed_bits = l3['srcip4']
181             self.set_random_ip_multi_attribute(ip, seeds[0], fixed_bits, random_mask, l3_count)
182         if "dstIp" in ip:
183             fixed_bits = l3['dstip4']
184             self.set_random_ip_multi_attribute(ip, seeds[1], fixed_bits, random_mask, l3_count)
185
186     def add_ip_header(self, params, version):
187         for _, ep, i in self.iter_over_get_lists('/traffic', 'trafficItem', "configElement", 1):
188             iter1 = (v['outer_l3'] for v in params.values() if str(v['id']) == str(i))
189             try:
190                 l3 = next(iter1, {})
191                 seeds = self.MODE_SEEDS_MAP.get(i, self.MODE_SEEDS_DEFAULT)[1]
192             except (KeyError, IndexError):
193                 continue
194
195             for _, ip_bits, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
196                 self.set_random_ip_multi_attributes(ip_bits, version, seeds, l3)
197
198         self.ixnet.commit()
199
200     def _connect(self, tg_cfg):
201         self._cfg = self.get_config(tg_cfg)
202         self.ixnet = IxNetwork.IxNet()
203
204         machine = self._cfg['machine']
205         port = str(self._cfg['port'])
206         version = str(self._cfg['version'])
207         result = self.ixnet.connect(machine, '-port', port, '-version', version)
208         return result
209
210     def clear_ixia_config(self):
211         self.ixnet.execute('newConfig')
212
213     def load_ixia_profile(self, profile):
214         self.ixnet.execute('loadConfig', self.ixnet.readFrom(profile))
215
216     def ix_load_config(self, profile):
217         self.clear_ixia_config()
218         self.load_ixia_profile(profile)
219
220     def ix_assign_ports(self):
221         vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport')
222         ports = []
223
224         chassis = self._cfg['chassis']
225         ports = [(chassis, card, port) for card, port in
226                  zip(self._cfg['cards'], self._cfg['ports'])]
227
228         vport_list = self.ixnet.getList("/", "vport")
229         self.ixnet.execute('assignPorts', ports, [], vport_list, True)
230         self.ixnet.commit()
231
232         for vport in vports:
233             if self.ixnet.getAttribute(vport, '-state') != 'up':
234                 log.error("Both thr ports are down...")
235
236     def ix_update_frame(self, params):
237         streams = ["configElement"]
238
239         for param in params.values():
240             framesize_data = FramesizeHelper()
241             traffic_items = self.ixnet.getList('/traffic', 'trafficItem')
242             param_id = param['id']
243             for traffic_item, stream in product(traffic_items, streams):
244                 helper = TrafficStreamHelper(traffic_item, stream, param_id)
245
246                 self.ixnet.setMultiAttribute(helper.transmissionControl,
247                                              '-type', '{0}'.format(param.get('traffic_type',
248                                                                              'continuous')),
249                                              '-duration', '{0}'.format(param.get('duration',
250                                                                                  "30")))
251
252                 stream_frame_rate_path = helper.frameRate
253                 self.ixnet.setMultiAttribute(stream_frame_rate_path, '-rate', param['iload'])
254                 if param['outer_l2']['framesPerSecond']:
255                     self.ixnet.setMultiAttribute(stream_frame_rate_path,
256                                                  '-type', 'framesPerSecond')
257
258                 framesize_data.populate_data(param['outer_l2']['framesize'])
259
260                 make_attr_args = framesize_data.make_args('-incrementFrom', '66',
261                                                           '-randomMin', '66',
262                                                           '-quadGaussian', [],
263                                                           '-type', 'weightedPairs',
264                                                           '-presetDistribution', 'cisco',
265                                                           '-incrementTo', '1518')
266
267                 self.ixnet.setMultiAttribute(helper.frameSize, *make_attr_args)
268
269                 self.ixnet.commit()
270
271     def update_ether_multi_attribute(self, ether, mac_addr):
272         self.ixnet.setMultiAttribute(ether,
273                                      '-singleValue', mac_addr,
274                                      '-fieldValue', mac_addr,
275                                      '-valueType', 'singleValue')
276
277     def update_ether_multi_attributes(self, ether, l2):
278         if "ethernet.header.destinationAddress" in ether:
279             self.update_ether_multi_attribute(ether, str(l2.get('dstmac', "00:00:00:00:00:02")))
280
281         if "ethernet.header.sourceAddress" in ether:
282             self.update_ether_multi_attribute(ether, str(l2.get('srcmac', "00:00:00:00:00:01")))
283
284     def ix_update_ether(self, params):
285         for _, ep, index in self.iter_over_get_lists('/traffic', 'trafficItem',
286                                                       "configElement", 1):
287             iter1 = (v['outer_l2'] for v in params.values() if str(v['id']) == str(index))
288             try:
289                 l2 = next(iter1, {})
290             except KeyError:
291                 continue
292
293             for _, ether, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
294                 self.update_ether_multi_attributes(ether, l2)
295
296         self.ixnet.commit()
297
298     def ix_update_udp(self, params):
299         pass
300
301     def ix_update_tcp(self, params):
302         pass
303
304     def ix_start_traffic(self):
305         tis = self.ixnet.getList('/traffic', 'trafficItem')
306         for ti in tis:
307             self.ixnet.execute('generate', [ti])
308             self.ixnet.execute('apply', '/traffic')
309             self.ixnet.execute('start', '/traffic')
310
311     def ix_stop_traffic(self):
312         tis = self.ixnet.getList('/traffic', 'trafficItem')
313         for _ in tis:
314             self.ixnet.execute('stop', '/traffic')
315
316     def build_stats_map(self, view_obj, name_map):
317         return {kl: self.execute_get_column_values(view_obj, kr) for kl, kr in name_map.items()}
318
319     def execute_get_column_values(self, view_obj, name):
320         return self.ixnet.execute('getColumnValues', view_obj, name)
321
322     def ix_get_statistics(self):
323         views = self.ixnet.getList('/statistics', 'view')
324         stats = {}
325         view_obj = self.find_view_obj("Traffic Item Statistics", views)
326         stats = self.build_stats_map(view_obj, self.STATS_NAME_MAP)
327
328         view_obj = self.find_view_obj("Port Statistics", views)
329         ports_stats = self.build_stats_map(view_obj, self.PORT_STATS_NAME_MAP)
330
331         view_obj = self.find_view_obj("Flow Statistics", views)
332         stats["latency"] = self.build_stats_map(view_obj, self.LATENCY_NAME_MAP)
333
334         return stats, ports_stats