3ca0b9b8aba9a67e27c5d88be99a4365c79fc9ab
[yardstick.git] / yardstick / tests / unit / benchmark / contexts / standalone / test_ovs_dpdk.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 io
16 import os
17
18 import mock
19 import six
20 import unittest
21
22 from yardstick.benchmark.contexts.standalone import model
23 from yardstick.benchmark.contexts.standalone import ovs_dpdk
24 from yardstick.common import exceptions
25 from yardstick.network_services import utils
26
27
28 class OvsDpdkContextTestCase(unittest.TestCase):
29
30     NODES_SAMPLE = "nodes_sample.yaml"
31     NODES_ovs_dpdk_SAMPLE = "nodes_ovs_dpdk_sample.yaml"
32     NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample.yaml"
33
34     NETWORKS = {
35         'private_0': {
36             'phy_port': "0000:05:00.0",
37             'vpci': "0000:00:07.0",
38             'cidr': '152.16.100.10/24',
39             'interface': 'if0',
40             'mac': "00:00:00:00:00:01",
41             'vf_pci': {'vf_pci': 0},
42             'gateway_ip': '152.16.100.20'},
43         'public_0': {
44             'phy_port': "0000:05:00.1",
45             'vpci': "0000:00:08.0",
46             'cidr': '152.16.40.10/24',
47             'interface': 'if0',
48             'vf_pci': {'vf_pci': 0},
49             'mac': "00:00:00:00:00:01",
50             'gateway_ip': '152.16.100.20'},
51     }
52
53     def setUp(self):
54         self.attrs = {
55             'name': 'foo',
56             'task_id': '1234567890',
57             'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE)
58         }
59         self.ovs_dpdk = ovs_dpdk.OvsDpdkContext()
60         self.addCleanup(self._remove_contexts)
61
62     def _remove_contexts(self):
63         if self.ovs_dpdk in self.ovs_dpdk.list:
64             self.ovs_dpdk._delete_context()
65
66     @mock.patch('yardstick.benchmark.contexts.standalone.model.Server')
67     @mock.patch('yardstick.benchmark.contexts.standalone.model.StandaloneContextHelper')
68     def test___init__(self, mock_helper, mock_server):
69         self.ovs_dpdk.helper = mock_helper
70         self.ovs_dpdk.vnf_node = mock_server
71         self.assertIsNone(self.ovs_dpdk.file_path)
72         self.assertTrue(self.ovs_dpdk.first_run)
73
74     def test_init(self):
75         ATTRS = {
76             'name': 'StandaloneOvsDpdk',
77             'task_id': '1234567890',
78             'file': 'pod',
79             'flavor': {},
80             'servers': {},
81             'networks': {},
82         }
83
84         self.ovs_dpdk.helper.parse_pod_file = mock.Mock(
85             return_value=[{}, {}, {}])
86         self.assertIsNone(self.ovs_dpdk.init(ATTRS))
87
88     def test_setup_ovs(self):
89         fake_path = '/fake_path'
90         fake_dpdk_nic_bind = 'dpdk_tool.py'
91         self.ovs_dpdk.ovs_properties = {'vpath': fake_path}
92         self.ovs_dpdk.dpdk_devbind = fake_dpdk_nic_bind
93         self.ovs_dpdk.networks = self.NETWORKS
94         self.ovs_dpdk.connection = mock.Mock()
95         self.ovs_dpdk.connection.execute = mock.Mock(return_value=(0, 0, 0))
96         create_from = fake_path + '/etc/openvswitch/conf.db'
97         create_to = fake_path + '/share/openvswitch/vswitch.ovsschema'
98         cmd_list = [
99             'killall -r "ovs.*" -q | true',
100             'mkdir -p {0}/etc/openvswitch'.format(fake_path),
101             'mkdir -p {0}/var/run/openvswitch'.format(fake_path),
102             'rm {0}/etc/openvswitch/conf.db | true'.format(fake_path),
103             'ovsdb-tool create {0} {1}'.format(create_from, create_to),
104             'modprobe vfio-pci',
105             'chmod a+x /dev/vfio',
106             'chmod 0666 /dev/vfio/*',
107             '{0} --force -b vfio-pci {1}'.format(fake_dpdk_nic_bind,
108                 self.ovs_dpdk.networks['private_0']['phy_port']),
109             '{0} --force -b vfio-pci {1}'.format(fake_dpdk_nic_bind,
110                 self.ovs_dpdk.networks['public_0']['phy_port'])
111         ]
112         calls = [mock.call(cmd, timeout=self.ovs_dpdk.CMD_TIMEOUT)
113                  for cmd in cmd_list]
114
115         self.ovs_dpdk.setup_ovs()
116         self.ovs_dpdk.connection.execute.assert_has_calls(calls,
117                                                           any_order=True)
118
119     def test_setup_ovs_exception(self):
120         self.ovs_dpdk.networks = self.NETWORKS
121         self.ovs_dpdk.connection = mock.Mock()
122         self.ovs_dpdk.connection.execute = mock.Mock(return_value=(1, 0, 0))
123
124         with self.assertRaises(exceptions.OVSSetupError):
125             self.ovs_dpdk.setup_ovs()
126
127     def test_start_ovs_serverswitch(self):
128         with mock.patch("yardstick.ssh.SSH") as ssh:
129             ssh_mock = mock.Mock(autospec=ssh.SSH)
130             ssh_mock.execute = \
131                 mock.Mock(return_value=(0, "a", ""))
132             ssh.return_value = ssh_mock
133             self.ovs_dpdk.connection = ssh_mock
134             self.ovs_dpdk.networks = self.NETWORKS
135             self.ovs_dpdk.ovs_properties = {}
136             self.ovs_dpdk.wait_for_vswitchd = 0
137             self.assertIsNone(self.ovs_dpdk.start_ovs_serverswitch())
138
139     def test_setup_ovs_bridge_add_flows(self):
140         with mock.patch("yardstick.ssh.SSH") as ssh:
141             ssh_mock = mock.Mock(autospec=ssh.SSH)
142             ssh_mock.execute = \
143                 mock.Mock(return_value=(0, "a", ""))
144             ssh.return_value = ssh_mock
145             self.ovs_dpdk.connection = ssh_mock
146             self.ovs_dpdk.networks = self.NETWORKS
147             self.ovs_dpdk.ovs_properties = {
148                 'version': {'ovs': '2.7.0'}
149             }
150             self.ovs_dpdk.wait_for_vswitchd = 0
151             self.assertIsNone(self.ovs_dpdk.setup_ovs_bridge_add_flows())
152
153     @mock.patch("yardstick.ssh.SSH")
154     def test_cleanup_ovs_dpdk_env(self, mock_ssh):
155        mock_ssh.execute.return_value = 0, "a", ""
156        self.ovs_dpdk.connection = mock_ssh
157        self.ovs_dpdk.networks = self.NETWORKS
158        self.ovs_dpdk.ovs_properties = {
159            'version': {'ovs': '2.7.0'}
160        }
161        self.ovs_dpdk.wait_for_vswitchd = 0
162        self.assertIsNone(self.ovs_dpdk.cleanup_ovs_dpdk_env())
163
164     @mock.patch.object(ovs_dpdk.OvsDpdkContext, '_check_hugepages')
165     @mock.patch.object(utils, 'get_nsb_option')
166     @mock.patch.object(model.OvsDeploy, 'ovs_deploy')
167     def test_check_ovs_dpdk_env(self, mock_ovs_deploy, mock_get_nsb_option,
168                                 mock_check_hugepages):
169         self.ovs_dpdk.connection = mock.Mock()
170         self.ovs_dpdk.connection.execute = mock.Mock(
171             return_value=(1, 0, 0))
172         self.ovs_dpdk.networks = self.NETWORKS
173         self.ovs_dpdk.ovs_properties = {
174             'version': {'ovs': '2.7.0', 'dpdk': '16.11.1'}
175         }
176         self.ovs_dpdk.wait_for_vswitchd = 0
177         self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock()
178         mock_get_nsb_option.return_value = 'fake_path'
179
180         self.ovs_dpdk.check_ovs_dpdk_env()
181         mock_ovs_deploy.assert_called_once()
182         mock_check_hugepages.assert_called_once()
183         mock_get_nsb_option.assert_called_once_with('bin_path')
184
185     @mock.patch.object(ovs_dpdk.OvsDpdkContext, '_check_hugepages')
186     def test_check_ovs_dpdk_env_wrong_version(self, mock_check_hugepages):
187         self.ovs_dpdk.connection = mock.Mock()
188         self.ovs_dpdk.connection.execute = mock.Mock(
189             return_value=(1, 0, 0))
190         self.ovs_dpdk.networks = self.NETWORKS
191         self.ovs_dpdk.ovs_properties = {
192             'version': {'ovs': '0.0.1', 'dpdk': '9.8.7'}
193         }
194         self.ovs_dpdk.wait_for_vswitchd = 0
195         self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock()
196
197         with self.assertRaises(exceptions.OVSUnsupportedVersion):
198             self.ovs_dpdk.check_ovs_dpdk_env()
199         mock_check_hugepages.assert_called_once()
200
201     @mock.patch('yardstick.ssh.SSH')
202     def test_deploy(self, *args):
203         self.ovs_dpdk.vm_deploy = False
204         self.assertIsNone(self.ovs_dpdk.deploy())
205
206         self.ovs_dpdk.vm_deploy = True
207         self.ovs_dpdk.host_mgmt = {}
208         self.ovs_dpdk.install_req_libs = mock.Mock()
209         self.ovs_dpdk.helper.get_nic_details = mock.Mock(return_value={})
210         self.ovs_dpdk.check_ovs_dpdk_env = mock.Mock(return_value={})
211         self.ovs_dpdk.setup_ovs = mock.Mock(return_value={})
212         self.ovs_dpdk.start_ovs_serverswitch = mock.Mock(return_value={})
213         self.ovs_dpdk.setup_ovs_bridge_add_flows = mock.Mock(return_value={})
214         self.ovs_dpdk.setup_ovs_dpdk_context = mock.Mock(return_value={})
215         self.ovs_dpdk.wait_for_vnfs_to_start = mock.Mock(return_value={})
216         # TODO(elfoley): This test should check states/sideeffects instead of
217         # output.
218         self.assertIsNone(self.ovs_dpdk.deploy())
219
220     @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete')
221     def test_undeploy(self, mock_libvirt):
222         self.ovs_dpdk.vm_deploy = True
223         self.ovs_dpdk.connection = mock.Mock()
224         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
225         self.ovs_dpdk.drivers = ['vm_0', 'vm_1']
226         self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock()
227         self.ovs_dpdk.networks = self.NETWORKS
228         self.ovs_dpdk.undeploy()
229         mock_libvirt.assert_has_calls([
230             mock.call(self.ovs_dpdk.vm_names[0], self.ovs_dpdk.connection),
231             mock.call(self.ovs_dpdk.vm_names[1], self.ovs_dpdk.connection)
232         ])
233
234     def _get_file_abspath(self, filename):
235         curr_path = os.path.dirname(os.path.abspath(__file__))
236         file_path = os.path.join(curr_path, filename)
237         return file_path
238
239     def test__get_server_with_dic_attr_name(self):
240
241         self.ovs_dpdk.init(self.attrs)
242
243         attr_name = {'name': 'foo.bar'}
244         result = self.ovs_dpdk._get_server(attr_name)
245
246         self.assertEqual(result, None)
247
248     def test__get_server_not_found(self):
249
250         self.ovs_dpdk.helper.parse_pod_file = mock.Mock(
251             return_value=[{}, {}, {}])
252         self.ovs_dpdk.init(self.attrs)
253
254         attr_name = 'bar.foo'
255         result = self.ovs_dpdk._get_server(attr_name)
256
257         self.assertEqual(result, None)
258
259     def test__get_server_mismatch(self):
260
261         self.ovs_dpdk.init(self.attrs)
262
263         attr_name = 'bar.foo1'
264         result = self.ovs_dpdk._get_server(attr_name)
265
266         self.assertEqual(result, None)
267
268     def test__get_server_duplicate(self):
269
270         self.attrs['file'] = self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE)
271
272         self.ovs_dpdk.init(self.attrs)
273
274         attr_name = 'node1.foo-12345678'
275         with self.assertRaises(ValueError):
276             self.ovs_dpdk._get_server(attr_name)
277
278     def test__get_server_found(self):
279
280         self.ovs_dpdk.init(self.attrs)
281
282         attr_name = 'node1.foo-12345678'
283         result = self.ovs_dpdk._get_server(attr_name)
284
285         self.assertEqual(result['ip'], '10.229.47.137')
286         self.assertEqual(result['name'], 'node1.foo-12345678')
287         self.assertEqual(result['user'], 'root')
288         self.assertEqual(result['key_filename'], '/root/.yardstick_key')
289
290     # TODO(elfoley): Split this test for networks that exist and networks that
291     #                don't
292     def test__get_network(self):
293         network1 = {
294             'name': 'net_1',
295             'vld_id': 'vld111',
296             'segmentation_id': 'seg54',
297             'network_type': 'type_a',
298             'physical_network': 'phys',
299         }
300         network2 = {
301             'name': 'net_2',
302             'vld_id': 'vld999',
303         }
304         self.ovs_dpdk.networks = {
305             'a': network1,
306             'b': network2,
307         }
308
309         # Tests for networks that do not exist
310         attr_name = {}
311         self.assertIsNone(self.ovs_dpdk._get_network(attr_name))
312
313         attr_name = {'vld_id': 'vld777'}
314         self.assertIsNone(self.ovs_dpdk._get_network(attr_name))
315
316         self.assertIsNone(self.ovs_dpdk._get_network(None))
317
318         # TODO(elfoley): Split this test
319         attr_name = 'vld777'
320         self.assertIsNone(self.ovs_dpdk._get_network(attr_name))
321
322         # Tests for networks that exist
323         attr_name = {'vld_id': 'vld999'}
324         expected = {
325             "name": 'net_2',
326             "vld_id": 'vld999',
327             "segmentation_id": None,
328             "network_type": None,
329             "physical_network": None,
330         }
331         result = self.ovs_dpdk._get_network(attr_name)
332         self.assertDictEqual(result, expected)
333
334         attr_name = 'a'
335         expected = network1
336         result = self.ovs_dpdk._get_network(attr_name)
337         self.assertDictEqual(result, expected)
338
339     def test_configure_nics_for_ovs_dpdk(self):
340         with mock.patch("yardstick.ssh.SSH") as ssh:
341             ssh_mock = mock.Mock(autospec=ssh.SSH)
342             ssh_mock.execute = \
343                 mock.Mock(return_value=(0, "a", ""))
344             ssh.return_value = ssh_mock
345         self.ovs_dpdk.vm_deploy = True
346         self.ovs_dpdk.connection = ssh_mock
347         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
348         self.ovs_dpdk.drivers = []
349         self.ovs_dpdk.networks = self.NETWORKS
350         self.ovs_dpdk.helper.get_mac_address = mock.Mock(return_value="")
351         self.ovs_dpdk.get_vf_datas = mock.Mock(return_value="")
352         self.assertIsNone(self.ovs_dpdk.configure_nics_for_ovs_dpdk())
353
354     @mock.patch.object(model.Libvirt, 'add_ovs_interface')
355     def test__enable_interfaces(self, mock_add_ovs_interface):
356         self.ovs_dpdk.vm_deploy = True
357         self.ovs_dpdk.connection = mock.Mock()
358         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
359         self.ovs_dpdk.drivers = []
360         self.ovs_dpdk.networks = self.NETWORKS
361         self.ovs_dpdk.ovs_properties = {'vpath': 'fake_path'}
362         self.ovs_dpdk.get_vf_datas = mock.Mock(return_value="")
363         self.ovs_dpdk._enable_interfaces(0, ["private_0"], 'test')
364         mock_add_ovs_interface.assert_called_once_with(
365             'fake_path', 0, self.NETWORKS['private_0']['vpci'],
366             self.NETWORKS['private_0']['mac'], 'test')
367
368     @mock.patch.object(model.Libvirt, 'build_vm_xml')
369     @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete')
370     @mock.patch.object(model.Libvirt, 'virsh_create_vm')
371     def test_setup_ovs_dpdk_context(self, mock_create_vm, mock_check_if_exists,
372                                     mock_build_xml):
373         with mock.patch("yardstick.ssh.SSH") as ssh:
374             ssh_mock = mock.Mock(autospec=ssh.SSH)
375             ssh_mock.execute = \
376                 mock.Mock(return_value=(0, "a", ""))
377             ssh_mock.put = \
378                 mock.Mock(return_value=(0, "a", ""))
379             ssh.return_value = ssh_mock
380         self.ovs_dpdk.vm_deploy = True
381         self.ovs_dpdk.connection = ssh_mock
382         self.ovs_dpdk.vm_names = ['vm_0', 'vm_1']
383         self.ovs_dpdk.drivers = []
384         self.ovs_dpdk.servers = {
385             'vnf_0': {
386                 'network_ports': {
387                     'mgmt': {'cidr': '152.16.100.10/24'},
388                     'xe0': ['private_0'],
389                     'xe1': ['public_0']
390                 }
391             }
392         }
393         self.ovs_dpdk.networks = self.NETWORKS
394         self.ovs_dpdk.host_mgmt = {}
395         self.ovs_dpdk.flavor = {}
396         self.ovs_dpdk.configure_nics_for_ovs_dpdk = mock.Mock(return_value="")
397         mock_build_xml.return_value = [6, "00:00:00:00:00:01"]
398         self.ovs_dpdk._enable_interfaces = mock.Mock(return_value="")
399         vnf_instance = mock.Mock()
400         self.ovs_dpdk.vnf_node.generate_vnf_instance = mock.Mock(
401             return_value=vnf_instance)
402
403         self.assertEqual([vnf_instance],
404                          self.ovs_dpdk.setup_ovs_dpdk_context())
405         mock_create_vm.assert_called_once_with(
406             self.ovs_dpdk.connection, '/tmp/vm_ovs_0.xml')
407         mock_check_if_exists.assert_called_once_with(
408             'vm_0', self.ovs_dpdk.connection)
409         mock_build_xml.assert_called_once_with(
410             self.ovs_dpdk.connection, self.ovs_dpdk.vm_flavor,
411             '/tmp/vm_ovs_0.xml', 'vm_0', 0)
412
413     @mock.patch.object(io, 'BytesIO')
414     def test__check_hugepages(self, mock_bytesio):
415         data = six.BytesIO('HugePages_Total:      20\n'
416                            'HugePages_Free:       20\n'
417                            'HugePages_Rsvd:        0\n'
418                            'HugePages_Surp:        0\n'
419                            'Hugepagesize:    1048576 kB'.encode())
420         mock_bytesio.return_value = data
421         self.ovs_dpdk.connection = mock.Mock()
422         self.ovs_dpdk._check_hugepages()
423
424     @mock.patch.object(io, 'BytesIO')
425     def test__check_hugepages_no_info(self, mock_bytesio):
426         data = six.BytesIO(''.encode())
427         mock_bytesio.return_value = data
428         self.ovs_dpdk.connection = mock.Mock()
429         with self.assertRaises(exceptions.OVSHugepagesInfoError):
430             self.ovs_dpdk._check_hugepages()
431
432     @mock.patch.object(io, 'BytesIO')
433     def test__check_hugepages_no_total_hp(self, mock_bytesio):
434         data = six.BytesIO('HugePages_Total:       0\n'
435                            'HugePages_Free:        0\n'
436                            'HugePages_Rsvd:        0\n'
437                            'HugePages_Surp:        0\n'
438                            'Hugepagesize:    1048576 kB'.encode())
439         mock_bytesio.return_value = data
440         self.ovs_dpdk.connection = mock.Mock()
441         with self.assertRaises(exceptions.OVSHugepagesNotConfigured):
442             self.ovs_dpdk._check_hugepages()
443
444     @mock.patch.object(io, 'BytesIO')
445     def test__check_hugepages_no_free_hp(self, mock_bytesio):
446         data = six.BytesIO('HugePages_Total:      20\n'
447                            'HugePages_Free:        0\n'
448                            'HugePages_Rsvd:        0\n'
449                            'HugePages_Surp:        0\n'
450                            'Hugepagesize:    1048576 kB'.encode())
451         mock_bytesio.return_value = data
452         self.ovs_dpdk.connection = mock.Mock()
453         with self.assertRaises(exceptions.OVSHugepagesZeroFree) as exc:
454             self.ovs_dpdk._check_hugepages()
455         self.assertEqual('There are no HugePages free in this system. Total '
456                          'HugePages configured: 20', exc.exception.msg)