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