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