Merge "Adding trex trafficgen example."
[yardstick.git] / tests / unit / benchmark / scenarios / networking / test_vnf_generic.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2016-2017 Intel Corporation
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 # Unittest for yardstick.benchmark.scenarios.networking.test_vnf_generic
19
20 from __future__ import absolute_import
21 import unittest
22 import mock
23 import os
24
25 from yardstick.benchmark.scenarios.networking.vnf_generic import \
26     ssh_manager, NetworkServiceTestCase, IncorrectConfig, IncorrectSetup
27 from yardstick.network_services.collector.subscriber import Collector
28 from yardstick.network_services.vnf_generic.vnf.base import \
29     GenericTrafficGen, GenericVNF
30
31 COMPLETE_TREX_VNFD = \
32     {'vnfd:vnfd-catalog':
33      {'vnfd':
34       [{'benchmark':
35         {'kpi':
36          ['rx_throughput_fps',
37           'tx_throughput_fps',
38           'tx_throughput_mbps',
39           'rx_throughput_mbps',
40           'tx_throughput_pc_linerate',
41           'rx_throughput_pc_linerate',
42           'min_latency',
43           'max_latency',
44           'avg_latency']},
45         'connection-point': [{'name': 'xe0',
46                               'type': 'VPORT'},
47                              {'name': 'xe1',
48                               'type': 'VPORT'}],
49         'description': 'TRex stateless traffic generator for RFC2544',
50         'id': 'TrexTrafficGen',
51         'mgmt-interface': {'ip': '1.1.1.1',
52                            'password': 'berta',
53                            'user': 'berta',
54                            'vdu-id': 'trexgen-baremetal'},
55         'name': 'trexgen',
56         'short-name': 'trexgen',
57         'vdu': [{'description': 'TRex stateless traffic generator for RFC2544',
58                  'external-interface':
59                  [{'name': 'xe0',
60                    'virtual-interface': {'bandwidth': '10 Gbps',
61                                          'dst_ip': '1.1.1.1',
62                                          'dst_mac': '00:01:02:03:04:05',
63                                          'local_ip': '1.1.1.2',
64                                          'local_mac': '00:01:02:03:05:05',
65                                          'type': 'PCI-PASSTHROUGH',
66                                          'netmask': "255.255.255.0",
67                                          'driver': 'i40',
68                                          'vpci': '0000:00:10.2'},
69                    'vnfd-connection-point-ref': 'xe0'},
70                   {'name': 'xe1',
71                    'virtual-interface': {'bandwidth': '10 Gbps',
72                                          'dst_ip': '2.1.1.1',
73                                          'dst_mac': '00:01:02:03:04:06',
74                                          'local_ip': '2.1.1.2',
75                                          'local_mac': '00:01:02:03:05:06',
76                                          'type': 'PCI-PASSTHROUGH',
77                                          'netmask': "255.255.255.0",
78                                          'driver': 'i40',
79                                          'vpci': '0000:00:10.1'},
80                    'vnfd-connection-point-ref': 'xe1'}],
81                  'id': 'trexgen-baremetal',
82                  'name': 'trexgen-baremetal'}]}]}}
83
84 IP_ADDR_SHOW = """
85 28: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP """
86 """group default qlen 1000
87     link/ether 90:e2:ba:a7:6a:c8 brd ff:ff:ff:ff:ff:ff
88     inet 1.1.1.1/8 brd 1.255.255.255 scope global eth1
89     inet6 fe80::92e2:baff:fea7:6ac8/64 scope link
90        valid_lft forever preferred_lft forever
91 29: eth5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP """
92 """group default qlen 1000
93     link/ether 90:e2:ba:a7:6a:c9 brd ff:ff:ff:ff:ff:ff
94     inet 2.1.1.1/8 brd 2.255.255.255 scope global eth5
95     inet6 fe80::92e2:baff:fea7:6ac9/64 scope link tentative
96        valid_lft forever preferred_lft forever
97 """
98
99 SYS_CLASS_NET = """
100 lrwxrwxrwx 1 root root 0 sie 10 14:16 eth1 -> """
101 """../../devices/pci0000:80/0000:80:02.2/0000:84:00.1/net/eth1
102 lrwxrwxrwx 1 root root 0 sie  3 10:37 eth2 -> """
103 """../../devices/pci0000:00/0000:00:01.1/0000:84:00.2/net/eth5
104 """
105
106 TRAFFIC_PROFILE = {
107         "schema": "isb:traffic_profile:0.1",
108         "name": "fixed",
109         "description": "Fixed traffic profile to run UDP traffic",
110         "traffic_profile": {
111             "traffic_type": "FixedTraffic",
112             "frame_rate": 100,  # pps
113             "flow_number": 10,
114             "frame_size": 64}}
115
116
117 class TestNetworkServiceTestCase(unittest.TestCase):
118     def setUp(self):
119         self.context_cfg = \
120             {'nodes':
121              {'trexgen__1': {'role': 'TrafficGen',
122                              'name': 'trafficgen_1.yardstick',
123                              'ip': '10.10.10.11',
124                              'interfaces':
125                              {'xe0':
126                               {'netmask': '255.255.255.0',
127                                'local_ip': '152.16.100.20',
128                                'local_mac': '00:00:00:00:00:01',
129                                'driver': 'i40e',
130                                'vpci': '0000:07:00.0',
131                                'dpdk_port_num': 0},
132                               'xe1':
133                               {'netmask': '255.255.255.0',
134                                'local_ip': '152.16.40.20',
135                                'local_mac': '00:00:00:00:00:02',
136                                'driver': 'i40e',
137                                'vpci': '0000:07:00.1',
138                                'dpdk_port_num': 1}},
139                              'password': 'r00t',
140                              'user': 'root'},
141               'trexvnf__1': {'name': 'vnf.yardstick',
142                              'ip': '10.10.10.12',
143                              'interfaces':
144                              {'xe0':
145                               {'netmask': '255.255.255.0',
146                                'local_ip': '152.16.100.19',
147                                'local_mac': '00:00:00:00:00:03',
148                                'driver': 'i40e',
149                                'vpci': '0000:07:00.0',
150                                'dpdk_port_num': 0},
151                               'xe1': {'netmask': '255.255.255.0',
152                                       'local_ip': '152.16.40.19',
153                                       'local_mac': '00:00:00:00:00:04',
154                                       'driver': 'i40e',
155                                       'vpci': '0000:07:00.1',
156                                       'dpdk_port_num': 1}},
157                              'routing_table': [{'netmask': '255.255.255.0',
158                                                 'gateway': '152.16.100.20',
159                                                 'network': '152.16.100.20',
160                                                 'if': 'xe0'},
161                                                {'netmask': '255.255.255.0',
162                                                 'gateway': '152.16.40.20',
163                                                 'network': '152.16.40.20',
164                                                 'if': 'xe1'}],
165                              'host': '10.223.197.164',
166                              'role': 'vnf',
167                              'user': 'root',
168                              'nd_route_tbl':
169                              [{'netmask': '112',
170                                'gateway': '0064:ff9b:0:0:0:0:9810:6414',
171                                'network': '0064:ff9b:0:0:0:0:9810:6414',
172                                'if': 'xe0'},
173                               {'netmask': '112',
174                                'gateway': '0064:ff9b:0:0:0:0:9810:2814',
175                                'network': '0064:ff9b:0:0:0:0:9810:2814',
176                                'if': 'xe1'}],
177                              'password': 'r00t'}}}
178
179         self.topology = \
180             {'short-name': 'trex-tg-topology',
181              'constituent-vnfd':
182              [{'member-vnf-index': '1',
183                'VNF model': 'tg_trex_tpl.yaml',
184                'vnfd-id-ref': 'trexgen__1'},
185               {'member-vnf-index': '2',
186                'VNF model': 'tg_trex_tpl.yaml',
187                'vnfd-id-ref': 'trexvnf__1'}],
188              'description': 'trex-tg-topology',
189              'name': 'trex-tg-topology',
190              'vld': [{'vnfd-connection-point-ref': [
191                  {'vnfd-connection-point-ref': 'xe0',
192                   'member-vnf-index-ref': '1',
193                   'vnfd-id-ref': 'trexgen'},
194                  {'vnfd-connection-point-ref': 'xe0',
195                   'member-vnf-index-ref': '2',
196                   'vnfd-id-ref': 'trexgen'}],
197                       'type': 'ELAN',
198                       'id': 'private',
199                       'name': 'trexgen__1 to trexvnf__1 link 1'},
200                      {'vnfd-connection-point-ref': [
201                          {'vnfd-connection-point-ref': 'xe1',
202                           'member-vnf-index-ref': '1',
203                           'vnfd-id-ref': 'trexgen'},
204                          {'vnfd-connection-point-ref': 'xe1',
205                           'member-vnf-index-ref': '2',
206                           'vnfd-id-ref': 'trexgen'}],
207                       'type': 'ELAN',
208                       'id': 'public',
209                       'name': 'trexvnf__1 to trexgen__1 link 2'}],
210              'id': 'trex-tg-topology'}
211
212         self.scenario_cfg = {'tc_options':
213                              {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}},
214                              'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
215                              'tc': 'tc_ipv4_1Mflow_64B_packetsize',
216                              'runner': {'object': 'NetworkServiceTestCase',
217                                         'interval': 35,
218                                         'output_filename': 'yardstick.out',
219                                         'runner_id': 74476,
220                                         'duration': 400, 'type': 'Duration'},
221                              'traffic_profile': 'ipv4_throughput_vpe.yaml',
222                              'traffic_options':
223                              {'flow': 'ipv4_1flow_Packets_vpe.yaml',
224                               'imix': 'imix_voice.yaml'},
225                              'type': 'ISB',
226                              'nodes': {'tg__2': 'trafficgen_2.yardstick',
227                                        'tg__1': 'trafficgen_1.yardstick',
228                                        'vnf__1': 'vnf.yardstick'},
229                              'topology': 'vpe_vnf_topology.yaml'}
230
231         self.scenario_cfg["topology"] = \
232             self._get_file_abspath("vpe_vnf_topology.yaml")
233         self.s = NetworkServiceTestCase(self.scenario_cfg, self.context_cfg)
234
235     def _get_file_abspath(self, filename):
236         curr_path = os.path.dirname(os.path.abspath(__file__))
237         file_path = os.path.join(curr_path, filename)
238         return file_path
239
240     def test_ssh_manager(self):
241         with mock.patch("yardstick.ssh.SSH") as ssh:
242             ssh_mock = mock.Mock(autospec=ssh.SSH)
243             ssh_mock.execute = \
244                 mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, ""))
245             ssh.return_value = ssh_mock
246             for node, node_dict in self.context_cfg["nodes"].items():
247                 with ssh_manager(node_dict) as conn:
248                     self.assertIsNotNone(conn)
249
250     def test___init__(self):
251         assert self.topology
252
253     def test___get_traffic_flow(self):
254         self.scenario_cfg["traffic_options"]["flow"] = \
255             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
256         result = {'flow': {'dstip4_range': '152.40.0.20',
257                            'srcip4_range': '152.16.0.20', 'count': 1}}
258         self.assertEqual(result, self.s._get_traffic_flow(self.scenario_cfg))
259
260     def test___get_traffic_flow_error(self):
261         self.scenario_cfg["traffic_options"]["flow"] = \
262             "ipv4_1flow_Packets_vpe.yaml1"
263         self.assertEqual({}, self.s._get_traffic_flow(self.scenario_cfg))
264
265     def test_get_vnf_imp(self):
266         vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]
267         self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
268
269     def test_load_vnf_models_invalid(self):
270         self.context_cfg["nodes"]['trexgen__1']['VNF model'] = \
271             self._get_file_abspath("tg_trex_tpl.yaml")
272         self.context_cfg["nodes"]['trexvnf__1']['VNF model'] = \
273             self._get_file_abspath("tg_trex_tpl.yaml")
274
275         vnf = mock.Mock(autospec=GenericVNF)
276         self.s.get_vnf_impl = mock.Mock(return_value=vnf)
277
278         self.assertIsNotNone(self.s.load_vnf_models(self.context_cfg))
279
280     def test_map_topology_to_infrastructure(self):
281         with mock.patch("yardstick.ssh.SSH") as ssh:
282             ssh_mock = mock.Mock(autospec=ssh.SSH)
283             ssh_mock.execute = \
284                 mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, ""))
285             ssh.return_value = ssh_mock
286             self.s.map_topology_to_infrastructure(self.context_cfg,
287                                                   self.topology)
288         self.assertEqual("tg_trex_tpl.yaml",
289                          self.context_cfg["nodes"]['trexgen__1']['VNF model'])
290         self.assertEqual("tg_trex_tpl.yaml",
291                          self.context_cfg["nodes"]['trexvnf__1']['VNF model'])
292
293     def test_map_topology_to_infrastructure_insufficient_nodes(self):
294         del self.context_cfg['nodes']['trexvnf__1']
295         with mock.patch("yardstick.ssh.SSH") as ssh:
296             ssh_mock = mock.Mock(autospec=ssh.SSH)
297             ssh_mock.execute = \
298                 mock.Mock(return_value=(1, SYS_CLASS_NET+IP_ADDR_SHOW, ""))
299             ssh.return_value = ssh_mock
300
301             self.assertRaises(IncorrectSetup,
302                               self.s.map_topology_to_infrastructure,
303                               self.context_cfg, self.topology)
304
305     def test_map_topology_to_infrastructure_config_invalid(self):
306         del self.context_cfg\
307             ['nodes']['trexvnf__1']['interfaces']['xe0']['local_mac']
308         with mock.patch("yardstick.ssh.SSH") as ssh:
309             ssh_mock = mock.Mock(autospec=ssh.SSH)
310             ssh_mock.execute = \
311                 mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, ""))
312             ssh.return_value = ssh_mock
313
314             self.assertRaises(IncorrectConfig,
315                               self.s.map_topology_to_infrastructure,
316                               self.context_cfg, self.topology)
317
318     def test__resolve_topology_invalid_config(self):
319         with mock.patch("yardstick.ssh.SSH") as ssh:
320             ssh_mock = mock.Mock(autospec=ssh.SSH)
321             ssh_mock.execute = \
322                 mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, ""))
323             ssh.return_value = ssh_mock
324
325             del self.context_cfg['nodes']
326             self.assertRaises(IncorrectConfig, self.s._resolve_topology,
327                               self.context_cfg, self.topology)
328
329             self.topology['vld'][0]['vnfd-connection-point-ref'].append(
330                 self.topology['vld'][0]['vnfd-connection-point-ref'])
331             self.assertRaises(IncorrectConfig, self.s._resolve_topology,
332                               self.context_cfg, self.topology)
333
334     def test_run(self):
335         tgen = mock.Mock(autospec=GenericTrafficGen)
336         tgen.traffic_finished = True
337         verified_dict = {"verified": True}
338         tgen.verify_traffic = lambda x: verified_dict
339         tgen.name = "tgen__1"
340         vnf = mock.Mock(autospec=GenericVNF)
341         vnf.runs_traffic = False
342         self.s.vnfs = [tgen, vnf]
343         self.s.traffic_profile = mock.Mock()
344         self.s.collector = mock.Mock(autospec=Collector)
345         self.s.collector.get_kpi = \
346             mock.Mock(return_value={tgen.name: verified_dict})
347         result = {}
348         self.s.run(result)
349         self.assertDictEqual(result, {tgen.name: verified_dict})
350
351     def test_setup(self):
352         with mock.patch("yardstick.ssh.SSH") as ssh:
353             ssh_mock = mock.Mock(autospec=ssh.SSH)
354             ssh_mock.execute = \
355                 mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, ""))
356             ssh.return_value = ssh_mock
357
358             tgen = mock.Mock(autospec=GenericTrafficGen)
359             tgen.traffic_finished = True
360             verified_dict = {"verified": True}
361             tgen.verify_traffic = lambda x: verified_dict
362             tgen.terminate = mock.Mock(return_value=True)
363             tgen.name = "tgen__1"
364             vnf = mock.Mock(autospec=GenericVNF)
365             vnf.runs_traffic = False
366             vnf.terminate = mock.Mock(return_value=True)
367             self.s.vnfs = [tgen, vnf]
368             self.s.traffic_profile = mock.Mock()
369             self.s.collector = mock.Mock(autospec=Collector)
370             self.s.collector.get_kpi = \
371                 mock.Mock(return_value={tgen.name: verified_dict})
372             self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
373             self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
374             self.s._fill_traffic_profile = \
375                 mock.Mock(return_value=TRAFFIC_PROFILE)
376             self.assertEqual(None, self.s.setup())
377
378     def test__get_traffic_profile(self):
379         self.scenario_cfg["traffic_profile"] = \
380             self._get_file_abspath("ipv4_throughput_vpe.yaml")
381         self.assertIsNotNone(self.s._get_traffic_profile(self.scenario_cfg,
382                                                          self.context_cfg))
383
384     def test__get_traffic_profile_exception(self):
385         self.assertRaises(IOError, self.s._get_traffic_profile,
386                           self.scenario_cfg, self.context_cfg)
387
388     def test___get_traffic_imix_exception(self):
389         self.assertEqual({}, self.s._get_traffic_imix(self.scenario_cfg))
390
391     def test__fill_traffic_profile(self):
392         self.scenario_cfg["traffic_profile"] = \
393             self._get_file_abspath("ipv4_throughput_vpe.yaml")
394         self.scenario_cfg["traffic_options"]["flow"] = \
395             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
396         self.scenario_cfg["traffic_options"]["imix"] = \
397             self._get_file_abspath("imix_voice.yaml")
398         self.assertIsNotNone(self.s._fill_traffic_profile(self.scenario_cfg,
399                                                           self.context_cfg))
400
401     def test_teardown(self):
402         vnf = mock.Mock(autospec=GenericVNF)
403         vnf.terminate = \
404             mock.Mock(return_value=True)
405         self.s.vnfs = [vnf]
406         self.s.traffic_profile = mock.Mock()
407         self.s.collector = mock.Mock(autospec=Collector)
408         self.s.collector.stop = \
409             mock.Mock(return_value=True)
410         self.assertIsNone(self.s.teardown())