diff options
-rw-r--r-- | tests/unit/benchmark/contexts/nodes_duplicate_sample_new.yaml | 112 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/nodes_sample_new.yaml | 96 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/sriov_sample_password.yaml | 52 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/sriov_sample_ssh_key.yaml | 54 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/sriov_sample_write_to_file.txt | 1 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/test_sriov.py | 423 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/test_standalone.py | 194 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/sriov.py | 432 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/standalone.py | 54 |
9 files changed, 1381 insertions, 37 deletions
diff --git a/tests/unit/benchmark/contexts/nodes_duplicate_sample_new.yaml b/tests/unit/benchmark/contexts/nodes_duplicate_sample_new.yaml new file mode 100644 index 000000000..48f4065a2 --- /dev/null +++ b/tests/unit/benchmark/contexts/nodes_duplicate_sample_new.yaml @@ -0,0 +1,112 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +nodes: +- + name: trafficgen_1 + role: TrafficGen + ip: 10.123.123.123 + user: root + auth_type: password + password: password + interfaces: + xe0: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.0" + driver: ixgbe + dpdk_port_num: 0 + local_ip: "152.16.100.20" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" + xe1: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.1" + driver: ixgbe + dpdk_port_num: 1 + local_ip: "152.16.100.21" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" +- + name: sriov + role: Sriov + ip: 10.123.123.122 + user: root + auth_type: password + password: password + vf_macs: + - "00:00:00:00:00:00" + - "00:00:00:00:00:00" + phy_ports: # Physical ports to configure sriov + - "0000:06:00.0" + - "0000:06:00.1" + phy_driver: i40e # kernel driver + images: "/var/lib/libvirt/images/ubuntu1.img" + +- + name: sriov + role: Sriov + ip: 10.123.123.111 + user: root + auth_type: password + password: password + vf_macs: + - "00:00:00:00:00:00" + - "00:00:00:00:00:00" + phy_ports: # Physical ports to configure sriov + - "0000:06:00.0" + - "0000:06:00.1" + phy_driver: i40e # kernel driver + images: "/var/lib/libvirt/images/ubuntu1.img" + +- + name: vnf + role: vnf + ip: 10.123.123.121 + user: root + auth_type: password + password: password + host: 10.123.123.121 #BM host == ip, SRIOV & ovs-dpdk host == compute node. + interfaces: + xe0: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:06:00.0" + driver: i40e + dpdk_port_num: 0 + local_ip: "152.16.100.19" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" + + xe1: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:06:00.1" + driver: i40e + dpdk_port_num: 1 + local_ip: "152.16.40.19" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" + routing_table: + - network: "152.16.100.20" + netmask: "255.255.255.0" + gateway: "152.16.100.20" + if: "xe0" + - network: "152.16.40.20" + netmask: "255.255.255.0" + gateway: "152.16.40.20" + if: "xe1" + nd_route_tbl: + - network: "0064:ff9b:0:0:0:0:9810:6414" + netmask: "112" + gateway: "0064:ff9b:0:0:0:0:9810:6414" + if: "xe0" + - network: "0064:ff9b:0:0:0:0:9810:2814" + netmask: "112" + gateway: "0064:ff9b:0:0:0:0:9810:2814" + if: "xe1" + diff --git a/tests/unit/benchmark/contexts/nodes_sample_new.yaml b/tests/unit/benchmark/contexts/nodes_sample_new.yaml new file mode 100644 index 000000000..a400bec03 --- /dev/null +++ b/tests/unit/benchmark/contexts/nodes_sample_new.yaml @@ -0,0 +1,96 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +nodes: +- + name: trafficgen_1 + role: TrafficGen + ip: 10.123.123.123 + user: root + auth_type: password + password: password + interfaces: + xe0: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.0" + driver: ixgbe + dpdk_port_num: 0 + local_ip: "152.16.100.20" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" + xe1: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.1" + driver: ixgbe + dpdk_port_num: 1 + local_ip: "152.16.100.21" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" +- + name: sriov + role: Sriov + ip: 10.123.123.122 + user: root + auth_type: password + password: password + vf_macs: + - "00:00:00:00:00:00" + - "00:00:00:00:00:00" + phy_ports: # Physical ports to configure sriov + - "0000:06:00.0" + - "0000:06:00.1" + phy_driver: i40e # kernel driver + images: "/var/lib/libvirt/images/ubuntu1.img" + +- + name: vnf + role: vnf + ip: 10.123.123.121 + user: root + auth_type: password + password: password + host: 10.123.123.121 #BM host == ip, SRIOV & ovs-dpdk host == compute node. + interfaces: + xe0: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:06:00.0" + driver: i40e + dpdk_port_num: 0 + local_ip: "152.16.100.19" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" + + xe1: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:06:00.1" + driver: i40e + dpdk_port_num: 1 + local_ip: "152.16.40.19" + netmask: "255.255.255.0" + local_mac: "00:00:00:00:00:00" + routing_table: + - network: "152.16.100.20" + netmask: "255.255.255.0" + gateway: "152.16.100.20" + if: "xe0" + - network: "152.16.40.20" + netmask: "255.255.255.0" + gateway: "152.16.40.20" + if: "xe1" + nd_route_tbl: + - network: "0064:ff9b:0:0:0:0:9810:6414" + netmask: "112" + gateway: "0064:ff9b:0:0:0:0:9810:6414" + if: "xe0" + - network: "0064:ff9b:0:0:0:0:9810:2814" + netmask: "112" + gateway: "0064:ff9b:0:0:0:0:9810:2814" + if: "xe1" + diff --git a/tests/unit/benchmark/contexts/sriov_sample_password.yaml b/tests/unit/benchmark/contexts/sriov_sample_password.yaml new file mode 100644 index 000000000..4f60e46d5 --- /dev/null +++ b/tests/unit/benchmark/contexts/sriov_sample_password.yaml @@ -0,0 +1,52 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +nodes: +- + name: trafficgen_1 + role: TrafficGen + ip: 10.10.10.10 + auth_type: password + user: root + password: password + interfaces: + xe0: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.0" + driver: ixgbe + dpdk_port_num: 0 + local_ip: "152.16.100.20" + netmask: "255.255.255.0" + local_mac: "90:e2:ba:77:ce:68" + xe1: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.1" + driver: ixgbe + dpdk_port_num: 1 + local_ip: "152.16.100.21" + netmask: "255.255.255.0" + local_mac: "90:e2:ba:77:ce:69" +- + name: sriov + role: Sriov + ip: 10.10.10.11 + auth_type: password + user: root + password: password + vf_macs: + - "00:00:00:71:7d:25" + - "00:00:00:71:7d:26" + phy_ports: # Physical ports to configure sriov + - "0000:06:00.0" + - "0000:06:00.1" + phy_driver: i40e # kernel driver + images: "/var/lib/libvirt/images/ubuntu1.img" diff --git a/tests/unit/benchmark/contexts/sriov_sample_ssh_key.yaml b/tests/unit/benchmark/contexts/sriov_sample_ssh_key.yaml new file mode 100644 index 000000000..faa496771 --- /dev/null +++ b/tests/unit/benchmark/contexts/sriov_sample_ssh_key.yaml @@ -0,0 +1,54 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +nodes: +- + name: trafficgen_1 + role: TrafficGen + ip: 10.10.10.10 + auth_type: ssh_key + user: root + ssh_port: 22 + key_filename: /root/.ssh/id_rsa + interfaces: + xe0: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.0" + driver: ixgbe + dpdk_port_num: 0 + local_ip: "152.16.100.20" + netmask: "255.255.255.0" + local_mac: "90:e2:ba:77:ce:68" + xe1: # logical name from topology.yaml and vnfd.yaml + vpci: "0000:03:00.1" + driver: ixgbe + dpdk_port_num: 1 + local_ip: "152.16.100.21" + netmask: "255.255.255.0" + local_mac: "90:e2:ba:77:ce:69" +- + name: sriov + role: Sriov + ip: 10.10.10.11 + auth_type: ssh_key + user: root + ssh_port: 22 + key_filename: /root/.ssh/id_rsa + vf_macs: + - "00:00:00:71:7d:25" + - "00:00:00:71:7d:26" + phy_ports: # Physical ports to configure sriov + - "0000:06:00.0" + - "0000:06:00.1" + phy_driver: i40e # kernel driver + images: "/var/lib/libvirt/images/ubuntu1.img" diff --git a/tests/unit/benchmark/contexts/sriov_sample_write_to_file.txt b/tests/unit/benchmark/contexts/sriov_sample_write_to_file.txt new file mode 100644 index 000000000..f0eec86f6 --- /dev/null +++ b/tests/unit/benchmark/contexts/sriov_sample_write_to_file.txt @@ -0,0 +1 @@ +some content
\ No newline at end of file diff --git a/tests/unit/benchmark/contexts/test_sriov.py b/tests/unit/benchmark/contexts/test_sriov.py new file mode 100644 index 000000000..e4d8f5e1a --- /dev/null +++ b/tests/unit/benchmark/contexts/test_sriov.py @@ -0,0 +1,423 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +import os +import mock +import unittest + +from yardstick.benchmark.contexts import sriov + +NIC_INPUT = { + 'interface': {}, + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'pci': ['0000:06:00.0', '0000:06:00.1'], + 'phy_driver': 'i40e'} +DRIVER = "i40e" +NIC_DETAILS = { + 'interface': {0: 'enp6s0f0', 1: 'enp6s0f1'}, + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'pci': ['0000:06:00.0', '0000:06:00.1'], + 'phy_driver': 'i40e'} + +CORRECT_FILE_PATH = "/etc/yardstick/nodes/pod_sriov.yaml" +WRONG_FILE_PATH = "/etc/yardstick/wrong.yaml" +SAMPLE_FILE = "sriov_sample_write_to_file.txt" + +SRIOV = [{ + 'auth_type': 'ssh_key', + 'name': 'sriov', + 'ssh_port': 22, + 'ip': '10.10.10.11', + 'key_filename': '/root/.ssh/id_rsa', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] + +SRIOV_PASSWORD = [{ + 'auth_type': 'password', + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.10.10.11', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] + +vfnic = "i40evf" +PCIS = ['0000:06:00.0', '0000:06:00.1'] + + +class SriovTestCase(unittest.TestCase): + + NODES_SAMPLE_SSH = "sriov_sample_ssh_key.yaml" + NODES_SAMPLE_PASSWORD = "sriov_sample_password.yaml" + + def setUp(self): + self.test_context = sriov.Sriov() + + def test_construct(self): + self.assertIsNone(self.test_context.name) + self.assertIsNone(self.test_context.file_path) + self.assertEqual(self.test_context.nodes, []) + self.assertEqual(self.test_context.sriov, []) + self.assertFalse(self.test_context.vm_deploy) + self.assertTrue(self.test_context.first_run) + self.assertEqual(self.test_context.user, "") + self.assertEqual(self.test_context.ssh_ip, "") + self.assertEqual(self.test_context.passwd, "") + self.assertEqual(self.test_context.ssh_port, "") + self.assertEqual(self.test_context.auth_type, "") + + def test_init(self): + self.test_context.parse_pod_and_get_data = mock.Mock() + self.test_context.file_path = CORRECT_FILE_PATH + self.test_context.init() + self.assertIsNone(self.test_context.init()) + + def test_successful_init_with_ssh(self): + CORRECT_FILE_PATH = self._get_file_abspath(self.NODES_SAMPLE_SSH) + self.test_context.parse_pod_and_get_data(CORRECT_FILE_PATH) + + def test_successful_init_with_password(self): + CORRECT_FILE_PATH = self._get_file_abspath(self.NODES_SAMPLE_PASSWORD) + self.test_context.parse_pod_and_get_data(CORRECT_FILE_PATH) + + def test_unsuccessful_init(self): + self.assertRaises( + IOError, + lambda: self.test_context.parse_pod_and_get_data(WRONG_FILE_PATH)) + + @mock.patch('yardstick.network_services.utils.provision_tool', return_value="a") + def test_ssh_connection(self, mock_prov): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(1, "a", "")) + ssh.return_value = ssh_mock + mock_prov.provision_tool = mock.Mock() + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + sriov_obj.sriov = SRIOV_PASSWORD + self.assertIsNone(sriov_obj.ssh_remote_machine()) + + @mock.patch('yardstick.network_services.utils.provision_tool', return_value="a") + def test_ssh_connection_ssh_key(self, mock_prov): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(1, "a", "")) + ssh.return_value = ssh_mock + mock_prov.provision_tool = mock.Mock() + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + sriov_obj.sriov = SRIOV + sriov_obj.key_filename = '/root/.ssh/id_rsa' + self.assertIsNone(sriov_obj.ssh_remote_machine()) + + def test_get_nic_details(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, "eth0 eth1", "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.sriov = SRIOV + sriov_obj.connection = ssh_mock + self.assertIsNotNone(sriov_obj.get_nic_details()) + + def test_install_req_libs(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.first_run = True + sriov_obj.connection = ssh_mock + self.assertIsNone(sriov_obj.install_req_libs()) + + def test_configure_nics_for_sriov(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + nic_details = { + 'interface': {0: 'enp6s0f0', 1: 'enp6s0f1'}, + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'pci': ['0000:06:00.0', '0000:06:00.1'], + 'phy_driver': 'i40e', + 'vf_pci': [{}, {}]} + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock((DRIVER), return_value=(0, "0 driver", "")) + ssh.return_value = ssh_mock + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + for i in range(len(NIC_DETAILS['pci'])): + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + ssh_mock.execute = \ + mock.Mock(return_value=( + 0, + "{'0':'06:02:00','1':'06:06:00'}", + "")) + sriov_obj.get_vf_datas = mock.Mock(return_value={ + '0000:06:00.0': '0000:06:02.0'}) + nic_details['vf_pci'][i] = sriov_obj.get_vf_datas.return_value + vf_pci = [[], []] + vf_pci[i] = sriov_obj.get_vf_datas.return_value + self.assertIsNotNone( + sriov_obj.configure_nics_for_sriov(DRIVER, NIC_DETAILS)) + + def test_setup_sriov_context(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + nic_details = { + 'interface': {0: 'enp6s0f0', 1: 'enp6s0f1'}, + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'pci': ['0000:06:00.0', '0000:06:00.1'], + 'phy_driver': 'i40e', + 'vf_pci': [{'vf_pci': '06:02.00'}, {'vf_pci': '06:06.00'}]} + vf = [{'vf_pci': '06:02.00'}, {'vf_pci': '06:06.00'}] + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + sriov_obj.sriov = SRIOV + blacklist = "/etc/modprobe.d/blacklist.conf" + self.assertEqual(vfnic, "i40evf") + mock_sriov = mock.Mock() + mock_sriov.sriov_obj.read_from_file(blacklist) + sriov_obj.read_from_file = mock.Mock( + return_value="some random text") + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + sriov_obj.configure_nics_for_sriov = mock.Mock( + return_value=nic_details) + nic_details = sriov_obj.configure_nics_for_sriov.return_value + self.assertEqual(vf, nic_details['vf_pci']) + vf = [ + {'vf_pci': '06:02.00', 'mac': '00:00:00:00:00:0a'}, + {'vf_pci': '06:06.00', 'mac': '00:00:00:00:00:0b'}] + sriov_obj.add_sriov_interface = mock.Mock() + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh_mock.put = mock.Mock() + sriov_obj.check_output = mock.Mock(return_value=(1, {})) + self.assertIsNone( + sriov_obj.setup_sriov_context(PCIS, nic_details, DRIVER)) + + def test_setup_sriov_context_vm_already_present(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + nic_details = { + 'interface': {0: 'enp6s0f0', 1: 'enp6s0f1'}, + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'pci': ['0000:06:00.0', '0000:06:00.1'], + 'phy_driver': 'i40e', + 'vf_pci': [{'vf_pci': '06:02.00'}, {'vf_pci': '06:06.00'}]} + vf = [{'vf_pci': '06:02.00'}, {'vf_pci': '06:06.00'}] + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + sriov_obj.sriov = SRIOV + blacklist = "/etc/modprobe.d/blacklist.conf" + self.assertEqual(vfnic, "i40evf") + mock_sriov = mock.Mock() + mock_sriov.sriov_obj.read_from_file(blacklist) + sriov_obj.read_from_file = mock.Mock( + return_value="some random text") + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + sriov_obj.configure_nics_for_sriov = mock.Mock( + return_value=nic_details) + nic_details = sriov_obj.configure_nics_for_sriov.return_value + self.assertEqual(vf, nic_details['vf_pci']) + vf = [ + {'vf_pci': '06:02.00', 'mac': '00:00:00:00:00:0a'}, + {'vf_pci': '06:06.00', 'mac': '00:00:00:00:00:0b'}] + sriov_obj.add_sriov_interface = mock.Mock() + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh_mock.put = mock.Mock() + sriov_obj.check_output = mock.Mock(return_value=(0, "vm1")) + self.assertIsNone(sriov_obj.setup_sriov_context( + PCIS, + nic_details, + DRIVER)) + + @mock.patch( + 'yardstick.benchmark.contexts.sriov', + return_value="Domain vm1 created from /tmp/vm_sriov.xml") + def test_is_vm_created(self, NIC_INPUT): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + mock_sriov = mock.Mock() + pcis = NIC_DETAILS['pci'] + driver = NIC_DETAILS['phy_driver'] + self.assertIsNotNone( + mock_sriov.sriov_obj.setup_sriov_context( + pcis, + NIC_DETAILS, + driver)) + + def test_add_sriov_interface(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + with mock.patch("xml.etree.ElementTree.parse") as parse: + with mock.patch("re.search") as re: + with mock.patch("xml.etree.ElementTree.SubElement") \ + as elem: + parse = mock.Mock(return_value="root") + re = mock.Mock() + elem = mock.Mock() + print("{0} {1} {2}".format(parse, re, elem)) + self.assertIsNone(sriov_obj.add_sriov_interface( + 0, + "0000:06:02.0", + "00:00:00:00:00:0a", + "/tmp/vm_sriov.xml")) + + def test_get_virtual_devices(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + pci_out = " \ + PCI_CLASS=20000 \ + PCI_ID=8086:154C \ + PCI_SUBSYS_ID=8086:0000 \ + PCI_SLOT_NAME=0000:06:02.0 \ + MODALIAS= \ + pci:v00008086d0000154Csv00008086sd00000000bc02sc00i00" + pci = "0000:06:00.0" + sriov_obj.check_output = mock.Mock(return_value=(0, pci_out)) + with mock.patch("re.search") as re: + re = mock.Mock(return_value="a") + print("{0}".format(re)) + self.assertIsNotNone(sriov_obj.get_virtual_devices(pci)) + + def test_get_vf_datas(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + sriov_obj.get_virtual_devices = mock.Mock( + return_value={'0000:06:00.0': '0000:06:02.0'}) + with mock.patch("re.search") as re: + re = mock.Mock() + print("{0}".format(re)) + self.assertIsNotNone(sriov_obj.get_vf_datas( + 'vf_pci', + {'0000:06:00.0': '0000:06:02.0'}, + "00:00:00:00:00:0a")) + + def test_check_output(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + cmd = "command" + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + self.assertIsNotNone(sriov_obj.check_output(cmd, None)) + + def test_split_cpu_list_available(self): + with mock.patch("itertools.chain") as iter1: + iter1 = mock.Mock() + print("{0}".format(iter1)) + sriov_obj = sriov.Sriov() + self.assertIsNotNone(sriov_obj.split_cpu_list('0,5')) + + def test_split_cpu_list_null(self): + with mock.patch("itertools.chain") as iter1: + iter1 = mock.Mock() + print("{0}".format(iter1)) + sriov_obj = sriov.Sriov() + self.assertEqual(sriov_obj.split_cpu_list([]), []) + + def test_destroy_vm_successful(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + sriov_obj.sriov = SRIOV + sriov_obj.check_output = mock.Mock(return_value=(0, "vm1")) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh_mock.execute = \ + mock.Mock(return_value=(0, "0 i40e")) + ssh_mock.execute = \ + mock.Mock(return_value=(0, "0 i40e")) + self.assertIsNone(sriov_obj.destroy_vm()) + + def test_destroy_vm_unsuccessful(self): + with mock.patch("yardstick.ssh.SSH") as ssh: + ssh_mock = mock.Mock(autospec=ssh.SSH) + ssh_mock.execute = \ + mock.Mock(return_value=(0, {}, "")) + ssh.return_value = ssh_mock + sriov_obj = sriov.Sriov() + sriov_obj.connection = ssh_mock + sriov_obj.sriov = SRIOV + sriov_obj.check_output = mock.Mock(return_value=(1, {})) + self.assertIsNone(sriov_obj.destroy_vm()) + + def test_read_from_file(self): + CORRECT_FILE_PATH = self._get_file_abspath(self.NODES_SAMPLE_PASSWORD) + sriov_obj = sriov.Sriov() + self.assertIsNotNone(sriov_obj.read_from_file(CORRECT_FILE_PATH)) + + def test_write_to_file(self): + sriov_obj = sriov.Sriov() + self.assertIsNone(sriov_obj.write_to_file(SAMPLE_FILE, "some content")) + + def _get_file_abspath(self, filename): + curr_path = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(curr_path, filename) + return file_path + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/benchmark/contexts/test_standalone.py b/tests/unit/benchmark/contexts/test_standalone.py index a6fd776e8..ee25bb33b 100644 --- a/tests/unit/benchmark/contexts/test_standalone.py +++ b/tests/unit/benchmark/contexts/test_standalone.py @@ -20,111 +20,235 @@ from __future__ import absolute_import import os import unittest - +import mock from yardstick.benchmark.contexts import standalone +from yardstick.benchmark.contexts import sriov + +MOCKS = { + 'yardstick.benchmark.contexts': mock.MagicMock(), + 'yardstick.benchmark.contexts.sriov': mock.MagicMock(), + 'yardstick.benchmark.contexts.standalone': mock.MagicMock(), +} class StandaloneContextTestCase(unittest.TestCase): - NODES_SAMPLE = "standalone_sample.yaml" - NODES_DUPLICATE_SAMPLE = "standalone_duplicate_sample.yaml" + NODES_SAMPLE = "nodes_sample_new.yaml" + NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample_new.yaml" def setUp(self): self.test_context = standalone.StandaloneContext() def test_construct(self): - self.assertIsNone(self.test_context.name) self.assertIsNone(self.test_context.file_path) self.assertEqual(self.test_context.nodes, []) self.assertEqual(self.test_context.nfvi_node, []) def test_unsuccessful_init(self): - attrs = { 'name': 'foo', 'file': self._get_file_abspath("error_file") } - self.assertRaises(IOError, self.test_context.init, attrs) def test_successful_init(self): - attrs = { - 'name': 'foo', + 'name': 'sriov', 'file': self._get_file_abspath(self.NODES_SAMPLE) } + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] + self.test_context.get_nfvi_obj = mock.Mock() self.test_context.init(attrs) - - self.assertEqual(self.test_context.name, "foo") + self.assertEqual(self.test_context.name, "sriov") self.assertEqual(len(self.test_context.nodes), 3) - self.assertEqual(len(self.test_context.nfvi_node), 1) - self.assertEqual(self.test_context.nfvi_node[0]["name"], "node2") + self.assertEqual(len(self.test_context.nfvi_node), 2) + self.assertEqual(self.test_context.nfvi_node[0]["name"], "sriov") def test__get_server_with_dic_attr_name(self): - attrs = { 'name': 'foo', 'file': self._get_file_abspath(self.NODES_SAMPLE) } - + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] self.test_context.init(attrs) - attr_name = {'name': 'foo.bar'} result = self.test_context._get_server(attr_name) - self.assertEqual(result, None) def test__get_server_not_found(self): - attrs = { 'name': 'foo', 'file': self._get_file_abspath(self.NODES_SAMPLE) } - + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] self.test_context.init(attrs) - attr_name = 'bar.foo' result = self.test_context._get_server(attr_name) - self.assertEqual(result, None) def test__get_server_duplicate(self): - attrs = { 'name': 'foo', 'file': self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE) } - + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] self.test_context.init(attrs) - - attr_name = 'node2.foo' - - self.assertRaises(ValueError, self.test_context._get_server, attr_name) + attr_name = 'sriov.foo' + self.assertRaises( + ValueError, + self.test_context._get_server, + attr_name) def test__get_server_found(self): - attrs = { - 'name': 'foo', + 'name': 'sriov', 'file': self._get_file_abspath(self.NODES_SAMPLE) } - + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] self.test_context.init(attrs) - - attr_name = 'node1.foo' + attr_name = 'sriov.sriov' result = self.test_context._get_server(attr_name) - - self.assertEqual(result['ip'], '1.1.1.1') - self.assertEqual(result['name'], 'node1.foo') + self.assertEqual(result['ip'], '10.123.123.122') + self.assertEqual(result['name'], 'sriov.sriov') self.assertEqual(result['user'], 'root') def test_deploy(self): + attrs = { + 'name': 'foo', + 'file': self._get_file_abspath(self.NODES_SAMPLE) + } + + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] + self.test_context.get_nfvi_obj = mock.MagicMock() + self.test_context.init(attrs) + self.test_context.nfvi_obj.ssh_remote_machine = mock.Mock() + self.test_context.nfvi_obj.first_run = True + self.test_context.nfvi_obj.get_nic_details = mock.Mock() + PORTS = ['0000:06:00.0', '0000:06:00.1'] + NIC_DETAILS = { + 'interface': {0: 'enp6s0f0', 1: 'enp6s0f1'}, + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'pci': ['0000:06:00.0', '0000:06:00.1'], + 'phy_driver': 'i40e'} + DRIVER = 'i40e' + result = self.test_context.nfvi_obj.setup_sriov_context( + PORTS, + NIC_DETAILS, + DRIVER) + print("{0}".format(result)) self.assertIsNone(self.test_context.deploy()) def test_undeploy(self): + attrs = { + 'name': 'foo', + 'file': self._get_file_abspath(self.NODES_SAMPLE) + } + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] + self.test_context.get_nfvi_obj = mock.MagicMock() + self.test_context.init(attrs) + self.test_context.nfvi_obj.destroy_vm = mock.Mock() self.assertIsNone(self.test_context.undeploy()) + def test_get_nfvi_obj(self): + with mock.patch('yardstick.benchmark.contexts.sriov'): + attrs = { + 'name': 'sriov', + 'file': self._get_file_abspath(self.NODES_SAMPLE) + } + self.test_context.init(attrs) + self.test_context.nfvi_obj.file_path = self._get_file_abspath( + self.NODES_SAMPLE) + self.test_context.nfvi_node = [{ + 'name': 'sriov', + 'vf_macs': ['00:00:00:71:7d:25', '00:00:00:71:7d:26'], + 'ip': '10.123.123.122', + 'role': 'Sriov', + 'user': 'root', + 'images': '/var/lib/libvirt/images/ubuntu1.img', + 'phy_driver': 'i40e', + 'password': 'password', + 'phy_ports': ['0000:06:00.0', '0000:06:00.1']}] + self.test_context.get_nfvi_obj = mock.MagicMock() + self.test_context.init(attrs) + self.test_context.get_context_impl = mock.Mock( + return_value=sriov.Sriov) + self.assertIsNotNone(self.test_context.get_nfvi_obj()) + + def test_get_context_impl_correct_obj(self): + with mock.patch.dict("sys.modules", MOCKS): + self.assertIsNotNone(self.test_context.get_context_impl('Sriov')) + + def test_get_context_impl_wrong_obj(self): + with mock.patch.dict("sys.modules", MOCKS): + self.assertRaises( + ValueError, + lambda: self.test_context.get_context_impl('wrong_object')) + def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) file_path = os.path.join(curr_path, filename) @@ -174,3 +298,5 @@ class StandaloneContextTestCase(unittest.TestCase): expected = network1 result = self.test_context._get_network(attr_name) self.assertDictEqual(result, expected) +if __name__ == '__main__': + unittest.main() diff --git a/yardstick/benchmark/contexts/sriov.py b/yardstick/benchmark/contexts/sriov.py new file mode 100644 index 000000000..5dc27bfae --- /dev/null +++ b/yardstick/benchmark/contexts/sriov.py @@ -0,0 +1,432 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +import os +import yaml +import re +import time +import glob +import uuid +import random +import logging +import itertools +import xml.etree.ElementTree as ET +from yardstick import ssh +from yardstick.network_services.utils import get_nsb_option +from yardstick.network_services.utils import provision_tool +from yardstick.benchmark.contexts.standalone import StandaloneContext + +log = logging.getLogger(__name__) + +VM_TEMPLATE = """ +<domain type="kvm"> + <name>vm1</name> + <uuid>{random_uuid}</uuid> + <memory unit="KiB">102400</memory> + <currentMemory unit="KiB">102400</currentMemory> + <memoryBacking> + <hugepages /> + </memoryBacking> + <vcpu placement="static">20</vcpu> + <os> + <type arch="x86_64" machine="pc-i440fx-utopic">hvm</type> + <boot dev="hd" /> + </os> + <features> + <acpi /> + <apic /> + <pae /> + </features> + <cpu match="exact" mode="custom"> + <model fallback="allow">SandyBridge</model> + <topology cores="10" sockets="1" threads="2" /> + </cpu> + <clock offset="utc"> + <timer name="rtc" tickpolicy="catchup" /> + <timer name="pit" tickpolicy="delay" /> + <timer name="hpet" present="no" /> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/bin/kvm-spice</emulator> + <disk device="disk" type="file"> + <driver name="qemu" type="qcow2" /> + <source file="{vm_image}"/> + <target bus="virtio" dev="vda" /> + <address bus="0x00" domain="0x0000" +function="0x0" slot="0x04" type="pci" /> + </disk> + <controller index="0" model="ich9-ehci1" type="usb"> + <address bus="0x00" domain="0x0000" +function="0x7" slot="0x05" type="pci" /> + </controller> + <controller index="0" model="ich9-uhci1" type="usb"> + <master startport="0" /> + <address bus="0x00" domain="0x0000" function="0x0" +multifunction="on" slot="0x05" type="pci" /> + </controller> + <controller index="0" model="ich9-uhci2" type="usb"> + <master startport="2" /> + <address bus="0x00" domain="0x0000" +function="0x1" slot="0x05" type="pci" /> + </controller> + <controller index="0" model="ich9-uhci3" type="usb"> + <master startport="4" /> + <address bus="0x00" domain="0x0000" +function="0x2" slot="0x05" type="pci" /> + </controller> + <controller index="0" model="pci-root" type="pci" /> + <serial type="pty"> + <target port="0" /> + </serial> + <console type="pty"> + <target port="0" type="serial" /> + </console> + <input bus="usb" type="tablet" /> + <input bus="ps2" type="mouse" /> + <input bus="ps2" type="keyboard" /> + <graphics autoport="yes" listen="0.0.0.0" port="-1" type="vnc" /> + <video> + <model heads="1" type="cirrus" vram="16384" /> + <address bus="0x00" domain="0x0000" +function="0x0" slot="0x02" type="pci" /> + </video> + <memballoon model="virtio"> + <address bus="0x00" domain="0x0000" +function="0x0" slot="0x06" type="pci" /> + </memballoon> + <interface type="bridge"> + <mac address="{mac_addr}" /> + <source bridge="virbr0" /> + </interface> + </devices> +</domain> +""" + + +class Sriov(StandaloneContext): + def __init__(self): + self.name = None + self.file_path = None + self.nodes = [] + self.vm_deploy = False + self.sriov = [] + self.first_run = True + self.dpdk_nic_bind = "" + self.user = "" + self.ssh_ip = "" + self.passwd = "" + self.ssh_port = "" + self.auth_type = "" + + def init(self): + self.parse_pod_and_get_data(self.file_path) + + def parse_pod_and_get_data(self, file_path): + self.file_path = file_path + log.debug("parsing pod file: {0}".format(self.file_path)) + try: + with open(self.file_path) as stream: + cfg = yaml.load(stream) + except IOError: + log.error("File {0} does not exist".format(self.file_path)) + raise + + self.nodes.extend([node for node in cfg["nodes"] + if node["role"] != "Sriov"]) + self.sriov.extend([node for node in cfg["nodes"] + if node["role"] == "Sriov"]) + self.user = self.sriov[0]['user'] + self.ssh_ip = self.sriov[0]['ip'] + if self.sriov[0]['auth_type'] == "password": + self.passwd = self.sriov[0]['password'] + else: + self.ssh_port = self.sriov[0]['ssh_port'] + self.key_filename = self.sriov[0]['key_filename'] + + def ssh_remote_machine(self): + if self.sriov[0]['auth_type'] == "password": + self.connection = ssh.SSH( + self.user, + self.ssh_ip, + password=self.passwd) + self.connection.wait() + else: + if self.ssh_port is not None: + ssh_port = self.ssh_port + else: + ssh_port = ssh.DEFAULT_PORT + self.connection = ssh.SSH( + self.user, + self.ssh_ip, + port=ssh_port, + key_filename=self.key_filename) + self.connection.wait() + self.dpdk_nic_bind = provision_tool( + self.connection, + os.path.join(get_nsb_option("bin_path"), "dpdk_nic_bind.py")) + + def get_nic_details(self): + nic_details = {} + nic_details = { + 'interface': {}, + 'pci': self.sriov[0]['phy_ports'], + 'phy_driver': self.sriov[0]['phy_driver'], + 'vf_macs': self.sriov[0]['vf_macs'] + } + # Make sure that ports are bound to kernel drivers e.g. i40e/ixgbe + for i, _ in enumerate(nic_details['pci']): + err, out, _ = self.connection.execute( + "{dpdk_nic_bind} --force -b {driver} {port}".format( + dpdk_nic_bind=self.dpdk_nic_bind, + driver=self.sriov[0]['phy_driver'], + port=self.sriov[0]['phy_ports'][i])) + err, out, _ = self.connection.execute( + "lshw -c network -businfo | grep '{port}'".format( + port=self.sriov[0]['phy_ports'][i])) + a = out.split()[1] + err, out, _ = self.connection.execute( + "ip -s link show {interface}".format( + interface=out.split()[1])) + nic_details['interface'][i] = str(a) + log.info("{0}".format(nic_details)) + return nic_details + + def install_req_libs(self): + if self.first_run: + log.info("Installing required libraries...") + err, out, _ = self.connection.execute("apt-get update") + log.debug("{0}".format(out)) + err, out, _ = self.connection.execute( + "apt-get -y install qemu-kvm libvirt-bin") + log.debug("{0}".format(out)) + err, out, _ = self.connection.execute( + "apt-get -y install libvirt-dev bridge-utils numactl") + log.debug("{0}".format(out)) + self.first_run = False + + def configure_nics_for_sriov(self, host_driver, nic_details): + vf_pci = [[], []] + self.connection.execute( + "rmmod {0}".format(host_driver))[1].splitlines() + self.connection.execute( + "modprobe {0} num_vfs=1".format(host_driver))[1].splitlines() + nic_details['vf_pci'] = {} + for i in range(len(nic_details['pci'])): + self.connection.execute( + "echo 1 > /sys/bus/pci/devices/{0}/sriov_numvfs".format( + nic_details['pci'][i])) + err, out, _ = self.connection.execute( + "ip link set {interface} vf 0 mac {mac}".format( + interface=nic_details['interface'][i], + mac=nic_details['vf_macs'][i])) + time.sleep(3) + vf_pci[i] = self.get_vf_datas( + 'vf_pci', + nic_details['pci'][i], + nic_details['vf_macs'][i]) + nic_details['vf_pci'][i] = vf_pci[i] + log.debug("NIC DETAILS : {0}".format(nic_details)) + return nic_details + + def setup_sriov_context(self, pcis, nic_details, host_driver): + blacklist = "/etc/modprobe.d/blacklist.conf" + + # 1 : Blacklist the vf driver in /etc/modprobe.d/blacklist.conf + vfnic = "{0}vf".format(host_driver) + lines = self.read_from_file(blacklist) + if vfnic not in lines: + vfblacklist = "blacklist {vfnic}".format(vfnic=vfnic) + self.connection.execute( + "echo {vfblacklist} >> {blacklist}".format( + vfblacklist=vfblacklist, + blacklist=blacklist)) + + # 2 : modprobe host_driver with num_vfs + nic_details = self.configure_nics_for_sriov(host_driver, nic_details) + + # 3: Setup vm_sriov.xml to launch VM + cfg_sriov = '/tmp/vm_sriov.xml' + mac = [0x00, 0x24, 0x81, + random.randint(0x00, 0x7f), + random.randint(0x00, 0xff), + random.randint(0x00, 0xff)] + mac_address = ':'.join(map(lambda x: "%02x" % x, mac)) + vm_sriov_xml = VM_TEMPLATE.format( + random_uuid=uuid.uuid4(), + mac_addr=mac_address, + vm_image=self.sriov[0]["images"]) + with open(cfg_sriov, 'w') as f: + f.write(vm_sriov_xml) + + vf = nic_details['vf_pci'] + for index in range(len(nic_details['vf_pci'])): + self.add_sriov_interface( + index, + vf[index]['vf_pci'], + mac_address, + "/tmp/vm_sriov.xml") + self.connection.execute( + "ifconfig {interface} up".format( + interface=nic_details['interface'][index])) + + # 4: Create and start the VM + self.connection.put(cfg_sriov, cfg_sriov) + time.sleep(10) + err, out = self.check_output("virsh list --name | grep -i vm1") + try: + if out == "vm1": + log.info("VM is already present") + else: + # FIXME: launch through libvirt + log.info("virsh create ...") + err, out, _ = self.connection.execute( + "virsh create /tmp/vm_sriov.xml") + time.sleep(10) + log.error("err : {0}".format(err)) + log.error("{0}".format(_)) + log.debug("out : {0}".format(out)) + except ValueError: + raise + + # 5: Tunning for better performace + self.pin_vcpu(pcis) + self.connection.execute( + "echo 1 > /sys/module/kvm/parameters/" + "allow_unsafe_assigned_interrupts") + self.connection.execute( + "echo never > /sys/kernel/mm/transparent_hugepage/enabled") + + def add_sriov_interface(self, index, vf_pci, vfmac, xml): + root = ET.parse(xml) + pattern = "0000:(\d+):(\d+).(\d+)" + m = re.search(pattern, vf_pci, re.MULTILINE) + device = root.find('devices') + + interface = ET.SubElement(device, 'interface') + interface.set('managed', 'yes') + interface.set('type', 'hostdev') + + mac = ET.SubElement(interface, 'mac') + mac.set('address', vfmac) + source = ET.SubElement(interface, 'source') + + addr = ET.SubElement(source, "address") + addr.set('domain', "0x0") + addr.set('bus', "{0}".format(m.group(1))) + addr.set('function', "{0}".format(m.group(3))) + addr.set('slot', "{0}".format(m.group(2))) + addr.set('type', "pci") + + vf_pci = ET.SubElement(interface, 'address') + vf_pci.set('type', 'pci') + vf_pci.set('domain', '0x0000') + vf_pci.set('bus', '0x00') + vf_pci.set('slot', '0x0{0}'.format(index + 7)) + vf_pci.set('function', '0x00') + + root.write(xml) + + # This is roughly compatible with check_output function in subprocess + # module which is only available in python 2.7 + def check_output(self, cmd, stderr=None): + # Run a command and capture its output + err, out, _ = self.connection.execute(cmd) + return err, out + + def get_virtual_devices(self, pci): + pf_vfs = {} + err, extra_info = self.check_output( + "cat /sys/bus/pci/devices/{0}/virtfn0/uevent".format(pci)) + pattern = "PCI_SLOT_NAME=(?P<name>[0-9:.\s.]+)" + m = re.search(pattern, extra_info, re.MULTILINE) + + if m: + pf_vfs.update({pci: str(m.group(1).rstrip())}) + log.info("pf_vfs : {0}".format(pf_vfs)) + return pf_vfs + + def get_vf_datas(self, key, value, vfmac): + vfret = {} + pattern = "0000:(\d+):(\d+).(\d+)" + + vfret["mac"] = vfmac + vfs = self.get_virtual_devices(value) + log.info("vfs: {0}".format(vfs)) + for k, v in vfs.items(): + m = re.search(pattern, k, re.MULTILINE) + m1 = re.search(pattern, value, re.MULTILINE) + if m.group(1) == m1.group(1): + vfret["vf_pci"] = str(v) + break + + return vfret + + def read_from_file(self, filename): + data = "" + with open(filename, 'r') as the_file: + data = the_file.read() + return data + + def write_to_file(self, filename, content): + with open(filename, 'w') as the_file: + the_file.write(content) + + def pin_vcpu(self, pcis): + nodes = self.get_numa_nodes() + log.info("{0}".format(nodes)) + num_nodes = len(nodes) + for i in range(0, 10): + self.connection.execute( + "virsh vcpupin vm1 {0} {1}".format( + i, nodes[str(num_nodes - 1)][i])) + + def get_numa_nodes(self): + nodes_sysfs = glob.iglob("/sys/devices/system/node/node*") + nodes = {} + for node_sysfs in nodes_sysfs: + num = os.path.basename(node_sysfs).replace("node", "") + with open(os.path.join(node_sysfs, "cpulist")) as cpulist_file: + cpulist = cpulist_file.read().strip() + nodes[num] = self.split_cpu_list(cpulist) + log.info("nodes: {0}".format(nodes)) + return nodes + + def split_cpu_list(self, cpu_list): + if cpu_list: + ranges = cpu_list.split(',') + bounds = ([int(b) for b in r.split('-')] for r in ranges) + range_objects =\ + (range(bound[0], bound[1] + 1 if len(bound) == 2 + else bound[0] + 1) for bound in bounds) + + return sorted(itertools.chain.from_iterable(range_objects)) + else: + return [] + + def destroy_vm(self): + host_driver = self.sriov[0]["phy_driver"] + err, out = self.check_output("virsh list --name | grep -i vm1") + log.info("{0}".format(out)) + if err == 0: + self.connection.execute("virsh shutdown vm1") + self.connection.execute("virsh destroy vm1") + self.check_output("rmmod {0}".format(host_driver))[1].splitlines() + self.check_output("modprobe {0}".format(host_driver))[ + 1].splitlines() + else: + log.error("error : {0}".format(err)) diff --git a/yardstick/benchmark/contexts/standalone.py b/yardstick/benchmark/contexts/standalone.py index 8614f0cac..e921437d6 100644 --- a/yardstick/benchmark/contexts/standalone.py +++ b/yardstick/benchmark/contexts/standalone.py @@ -21,6 +21,7 @@ import yaml from yardstick.benchmark.contexts.base import Context from yardstick.common.constants import YARDSTICK_ROOT_PATH +from yardstick.common.utils import import_modules_from_package, itersubclasses LOG = logging.getLogger(__name__) @@ -38,7 +39,8 @@ class StandaloneContext(Context): self.nodes = [] self.networks = {} self.nfvi_node = [] - super(StandaloneContext, self).__init__() + self.nfvi_obj = None + super(self.__class__, self).__init__() def read_config_file(self): """Read from config file""" @@ -48,6 +50,14 @@ class StandaloneContext(Context): cfg = yaml.load(stream) return cfg + def get_nfvi_obj(self): + print("{0}".format(self.nfvi_node[0]['role'])) + context_type = self.get_context_impl(self.nfvi_node[0]['role']) + nfvi_obj = context_type() + nfvi_obj.__init__() + nfvi_obj.parse_pod_and_get_data(self.file_path) + return nfvi_obj + def init(self, attrs): """initializes itself from the supplied arguments""" @@ -69,6 +79,15 @@ class StandaloneContext(Context): if node["role"] == "nfvi_node"]) # add optional static network definition self.networks.update(cfg.get("networks", {})) + for node in cfg["nodes"]: + if str(node["role"]) == "Sriov": + self.nfvi_node.extend([node for node in cfg["nodes"] + if str(node["role"]) == "Sriov"]) + if str(node["role"]) == "ovs-dpdk": + LOG.info("{0}".format(node["role"])) + else: + LOG.debug("Node role is other than SRIOV and OVS") + self.nfvi_obj = self.get_nfvi_obj() LOG.debug("Nodes: %r", self.nodes) LOG.debug("NFVi Node: %r", self.nfvi_node) LOG.debug("Networks: %r", self.networks) @@ -77,13 +96,26 @@ class StandaloneContext(Context): """don't need to deploy""" # Todo: NFVi deploy (sriov, vswitch, ovs etc) based on the config. + self.nfvi_obj.ssh_remote_machine() + if self.nfvi_obj.first_run is True: + self.nfvi_obj.install_req_libs() + + nic_details = self.nfvi_obj.get_nic_details() + print("{0}".format(nic_details)) + self.nfvi_obj.setup_sriov_context( + self.nfvi_obj.sriov[0]['phy_ports'], + nic_details, + self.nfvi_obj.sriov[0]['phy_driver']) pass def undeploy(self): """don't need to undeploy""" # Todo: NFVi undeploy (sriov, vswitch, ovs etc) based on the config. - super(StandaloneContext, self).undeploy() + # self.nfvi_obj = self.get_nfvi_obj() + self.nfvi_obj.ssh_remote_machine() + self.nfvi_obj.destroy_vm() + pass def _get_server(self, attr_name): """lookup server info by name from context @@ -95,7 +127,7 @@ class StandaloneContext(Context): if isinstance(attr_name, collections.Mapping): return None - if self.name.split("-")[0] != attr_name.split(".")[1]: + if self.name != attr_name.split(".")[1]: return None node_name = attr_name.split(".")[0] @@ -146,3 +178,19 @@ class StandaloneContext(Context): "physical_network": network.get("physical_network"), } return result + + def get_context_impl(self, nfvi_type): + """ Find the implementing class from vnf_model["vnf"]["name"] field + + :param vnf_model: dictionary containing a parsed vnfd + :return: subclass of GenericVNF + """ + import_modules_from_package( + "yardstick.benchmark.contexts") + expected_name = nfvi_type + impl = [c for c in itersubclasses(StandaloneContext) + if c.__name__ == expected_name] + try: + return next(iter(impl)) + except StopIteration: + raise ValueError("No implementation for %s", expected_name) |