3 # Copyright (c) 2016-2017 Intel Corporation
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
22 from yardstick.error import IncorrectConfig, SSHError
23 from yardstick.error import IncorrectNodeSetup
24 from yardstick.error import IncorrectSetup
25 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkInterface
26 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkNode
27 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper
28 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelperException
29 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_KERNEL
30 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_DPDK
31 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_KERNEL
32 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_DPDK
33 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_OTHER
34 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_OTHER
40 class TestDpdkInterface(unittest.TestCase):
44 'address': '0a:de:ad:be:ef:f5',
48 'interface_name': 'enp11s0',
50 'pci_bus_id': '0000:0b:00.0',
51 'subsystem_device': '0x1533',
52 'subsystem_vendor': '0x15d9',
56 'address': '0a:de:ad:be:ef:f4',
60 'interface_name': 'lan',
62 'pci_bus_id': '0000:00:19.0',
63 'subsystem_device': '0x153a',
64 'subsystem_vendor': '0x15d9',
71 'address': 'fa:de:ad:be:ef:5b',
73 'driver': 'virtio_net',
75 'interface_name': 'eth1',
77 'pci_bus_id': '0000:00:04.0',
82 def test_parse_netdev_info(self):
84 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2
85 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5
86 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down
87 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086
88 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533
89 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9
90 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533
91 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb
92 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0
93 /sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3
94 /sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4
95 /sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up
96 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086
97 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a
98 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9
99 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a
100 /sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e
101 /sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0
103 res = DpdkBindHelper.parse_netdev_info(output)
104 self.assertDictEqual(res, self.SAMPLE_NETDEVS)
106 def test_parse_netdev_info_virtio(self):
108 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3
109 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b
110 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down
111 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4
112 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001
113 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net
115 res = DpdkBindHelper.parse_netdev_info(output)
116 self.assertDictEqual(res, self.SAMPLE_VM_NETDEVS)
118 def test_probe_missing_values(self):
119 mock_dpdk_node = mock.Mock()
120 mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy()
122 interface = {'local_mac': '0a:de:ad:be:ef:f5'}
123 dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
125 dpdk_intf.probe_missing_values()
126 self.assertEqual(interface['vpci'], '0000:0b:00.0')
128 interface['local_mac'] = '0a:de:ad:be:ef:f4'
129 dpdk_intf.probe_missing_values()
130 self.assertEqual(interface['vpci'], '0000:00:19.0')
132 def test_probe_missing_values_no_update(self):
133 mock_dpdk_node = mock.Mock()
134 mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy()
135 del mock_dpdk_node.netdevs['enp11s0']['driver']
136 del mock_dpdk_node.netdevs['lan']['driver']
138 interface = {'local_mac': '0a:de:ad:be:ef:f5'}
139 dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
141 dpdk_intf.probe_missing_values()
142 self.assertNotIn('vpci', interface)
143 self.assertNotIn('driver', interface)
145 def test_probe_missing_values_negative(self):
146 mock_dpdk_node = mock.Mock()
147 mock_dpdk_node.netdevs.values.side_effect = IncorrectNodeSetup
149 interface = {'local_mac': '0a:de:ad:be:ef:f5'}
150 dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
152 with self.assertRaises(IncorrectConfig):
153 dpdk_intf.probe_missing_values()
156 class TestDpdkNode(unittest.TestCase):
160 'virtual-interface': {
165 'virtual-interface': {
170 'virtual-interface': {
176 def test_probe_dpdk_drivers(self):
177 mock_ssh_helper = mock.Mock()
178 mock_ssh_helper.execute.return_value = 0, '', ''
182 'virtual-interface': {
187 'virtual-interface': {
192 'virtual-interface': {
198 dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper)
199 dpdk_helper = dpdk_node.dpdk_helper
201 dpdk_helper.probe_real_kernel_drivers = mock.Mock()
202 dpdk_helper.real_kernel_interface_driver_map = {
210 dpdk_node._probe_dpdk_drivers()
211 self.assertNotIn('driver', interfaces[0]['virtual-interface'])
212 self.assertEqual(interfaces[1]['virtual-interface']['driver'], 'driver2')
213 self.assertEqual(interfaces[2]['virtual-interface']['driver'], 'driver1')
215 def test_check(self):
217 if not mock_force_rebind.called:
218 raise IncorrectConfig
220 interfaces[0]['virtual-interface'].update({
221 'vpci': '0000:01:02.1',
222 'local_ip': '10.20.30.40',
223 'netmask': '255.255.0.0',
227 mock_ssh_helper = mock.Mock()
228 mock_ssh_helper.execute.return_value = 0, '', ''
232 'virtual-interface': {
237 dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper)
238 dpdk_node._probe_missing_values = mock_probe_missing = mock.Mock(side_effect=update)
239 dpdk_node._force_rebind = mock_force_rebind = mock.Mock()
241 self.assertIsNone(dpdk_node.check())
242 self.assertEqual(mock_probe_missing.call_count, 2)
244 @mock.patch('yardstick.network_services.helpers.dpdkbindnic_helper.DpdkInterface')
245 def test_check_negative(self, mock_intf_type):
246 mock_ssh_helper = mock.Mock()
247 mock_ssh_helper.execute.return_value = 0, '', ''
249 mock_intf_type().check.side_effect = SSHError
251 dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
253 with self.assertRaises(IncorrectSetup):
256 def test_probe_netdevs(self):
257 mock_ssh_helper = mock.Mock()
258 mock_ssh_helper.execute.return_value = 0, '', ''
260 expected = {'key1': 500, 'key2': 'hello world'}
261 update = {'key1': 1000, 'key3': []}
263 dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
264 dpdk_helper = dpdk_node.dpdk_helper
265 dpdk_helper.find_net_devices = mock.Mock(side_effect=[expected, update])
267 self.assertDictEqual(dpdk_node.netdevs, {})
268 dpdk_node._probe_netdevs()
269 self.assertDictEqual(dpdk_node.netdevs, expected)
271 expected = {'key1': 1000, 'key2': 'hello world', 'key3': []}
272 dpdk_node._probe_netdevs()
273 self.assertDictEqual(dpdk_node.netdevs, expected)
275 def test_probe_netdevs_setup_negative(self):
276 mock_ssh_helper = mock.Mock()
277 mock_ssh_helper.execute.return_value = 0, '', ''
279 dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
280 dpdk_helper = dpdk_node.dpdk_helper
281 dpdk_helper.find_net_devices = mock.Mock(side_effect=DpdkBindHelperException)
283 with self.assertRaises(DpdkBindHelperException):
284 dpdk_node._probe_netdevs()
286 def test_force_rebind(self):
287 mock_ssh_helper = mock.Mock()
288 mock_ssh_helper.execute.return_value = 0, '', ''
290 dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
291 dpdk_helper = dpdk_node.dpdk_helper
292 dpdk_helper.force_dpdk_rebind = mock_helper_func = mock.Mock()
294 dpdk_node._force_rebind()
295 self.assertEqual(mock_helper_func.call_count, 1)
298 class TestDpdkBindHelper(unittest.TestCase):
299 bin_path = "/opt/nsb_bin"
302 Network devices using DPDK-compatible driver
303 ============================================
304 0000:00:04.0 'Virtio network device' drv=igb_uio unused=
305 0000:00:05.0 'Virtio network device' drv=igb_uio unused=
307 Network devices using kernel driver
308 ===================================
309 0000:00:03.0 'Virtio network device' if=ens3 drv=virtio-pci unused=igb_uio *Active*
311 Other network devices
312 =====================
315 Crypto devices using DPDK-compatible driver
316 ===========================================
319 Crypto devices using kernel driver
320 ==================================
331 'dev_type': 'Virtio network device',
335 'vpci': '0000:00:04.0',
338 'dev_type': 'Virtio network device',
342 'vpci': '0000:00:05.0',
347 'dev_type': 'Virtio network device',
348 'driver': 'virtio-pci',
351 'vpci': '0000:00:03.0',
369 ONE_INPUT_LINE = ("0000:00:03.0 'Virtio network device' if=ens3 "
370 "drv=virtio-pci unused=igb_uio *Active*")
372 ONE_INPUT_LINE_PARSED = [{
373 'vpci': '0000:00:03.0',
374 'dev_type': 'Virtio network device',
376 'driver': 'virtio-pci',
381 def test___init__(self):
383 conn.provision_tool = mock.Mock(return_value='path_to_tool')
384 conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
386 dpdk_bind_helper = DpdkBindHelper(conn)
388 self.assertEqual(conn, dpdk_bind_helper.ssh_helper)
389 self.assertEqual(self.CLEAN_STATUS, dpdk_bind_helper.dpdk_status)
390 self.assertIsNone(dpdk_bind_helper.status_nic_row_re)
391 self.assertEqual(dpdk_bind_helper.dpdk_devbind,
392 os.path.join(self.bin_path, dpdk_bind_helper.DPDK_DEVBIND))
393 self.assertIsNone(dpdk_bind_helper._status_cmd_attr)
395 def test__dpdk_execute(self):
397 conn.execute = mock.Mock(return_value=(0, 'output', 'error'))
398 conn.provision_tool = mock.Mock(return_value='tool_path')
399 dpdk_bind_helper = DpdkBindHelper(conn)
400 self.assertEqual((0, 'output', 'error'), dpdk_bind_helper._dpdk_execute('command'))
402 def test__dpdk_execute_failure(self):
404 conn.execute = mock.Mock(return_value=(1, 'output', 'error'))
405 conn.provision_tool = mock.Mock(return_value='tool_path')
406 dpdk_bind_helper = DpdkBindHelper(conn)
407 with self.assertRaises(DpdkBindHelperException):
408 dpdk_bind_helper._dpdk_execute('command')
410 def test__addline(self):
413 dpdk_bind_helper = DpdkBindHelper(conn)
415 dpdk_bind_helper._add_line(NETWORK_KERNEL, self.ONE_INPUT_LINE)
417 self.assertIsNotNone(dpdk_bind_helper.dpdk_status)
418 self.assertEqual(self.ONE_INPUT_LINE_PARSED, dpdk_bind_helper.dpdk_status[NETWORK_KERNEL])
420 def test__switch_active_dict_by_header(self):
421 line = "Crypto devices using DPDK-compatible driver"
423 self.assertEqual(CRYPTO_DPDK, DpdkBindHelper._switch_active_dict(line, olddict))
425 def test__switch_active_dict_by_header_empty(self):
428 self.assertEqual(olddict, DpdkBindHelper._switch_active_dict(line, olddict))
430 def test_parse_dpdk_status_output(self):
433 dpdk_bind_helper = DpdkBindHelper(conn)
435 dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
438 self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.dpdk_status)
440 def test_kernel_bound_pci_addresses(self):
441 mock_ssh_helper = mock.Mock()
442 mock_ssh_helper.execute.return_value = 0, '', ''
444 expected = ['a', 'b', 3]
446 dpdk_helper = DpdkBindHelper(mock_ssh_helper)
447 dpdk_helper.dpdk_status = {
448 NETWORK_DPDK: [{'vpci': 4}, {'vpci': 5}, {'vpci': 'g'}],
449 NETWORK_KERNEL: [{'vpci': 'a'}, {'vpci': 'b'}, {'vpci': 3}],
453 result = dpdk_helper.kernel_bound_pci_addresses
454 self.assertEqual(result, expected)
456 def test_find_net_devices_negative(self):
457 mock_ssh_helper = mock.Mock()
458 mock_ssh_helper.execute.return_value = 1, 'error', 'debug'
460 dpdk_helper = DpdkBindHelper(mock_ssh_helper)
462 self.assertDictEqual(dpdk_helper.find_net_devices(), {})
464 def test_read_status(self):
466 conn.execute = mock.Mock(return_value=(0, self.EXAMPLE_OUTPUT, ''))
467 conn.provision_tool = mock.Mock(return_value='path_to_tool')
469 dpdk_bind_helper = DpdkBindHelper(conn)
471 self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.read_status())
473 def test__get_bound_pci_addresses(self):
476 dpdk_bind_helper = DpdkBindHelper(conn)
478 dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
480 self.assertEqual(['0000:00:04.0', '0000:00:05.0'],
481 dpdk_bind_helper._get_bound_pci_addresses(NETWORK_DPDK))
482 self.assertEqual(['0000:00:03.0'],
483 dpdk_bind_helper._get_bound_pci_addresses(NETWORK_KERNEL))
485 def test_interface_driver_map(self):
488 dpdk_bind_helper = DpdkBindHelper(conn)
490 dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
492 self.assertEqual({'0000:00:04.0': 'igb_uio',
493 '0000:00:03.0': 'virtio-pci',
494 '0000:00:05.0': 'igb_uio',
496 dpdk_bind_helper.interface_driver_map)
500 conn.execute = mock.Mock(return_value=(0, '', ''))
501 conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
503 dpdk_bind_helper = DpdkBindHelper(conn)
504 dpdk_bind_helper.read_status = mock.Mock()
506 dpdk_bind_helper.bind(['0000:00:03.0', '0000:00:04.0'], 'my_driver')
508 conn.execute.assert_called_with('sudo /opt/nsb_bin/dpdk-devbind.py --force '
509 '-b my_driver 0000:00:03.0 0000:00:04.0')
510 dpdk_bind_helper.read_status.assert_called_once()
512 def test_bind_single_pci(self):
514 conn.execute = mock.Mock(return_value=(0, '', ''))
515 conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
517 dpdk_bind_helper = DpdkBindHelper(conn)
518 dpdk_bind_helper.read_status = mock.Mock()
520 dpdk_bind_helper.bind('0000:00:03.0', 'my_driver')
522 conn.execute.assert_called_with('sudo /opt/nsb_bin/dpdk-devbind.py --force '
523 '-b my_driver 0000:00:03.0')
524 dpdk_bind_helper.read_status.assert_called_once()
526 def test_rebind_drivers(self):
529 dpdk_bind_helper = DpdkBindHelper(conn)
531 dpdk_bind_helper.bind = mock.Mock()
532 dpdk_bind_helper.used_drivers = {
533 'd1': ['0000:05:00.0'],
534 'd3': ['0000:05:01.0', '0000:05:02.0'],
537 dpdk_bind_helper.rebind_drivers()
539 dpdk_bind_helper.bind.assert_any_call(['0000:05:00.0'], 'd1', True)
540 dpdk_bind_helper.bind.assert_any_call(['0000:05:01.0', '0000:05:02.0'], 'd3', True)
542 def test_save_used_drivers(self):
544 dpdk_bind_helper = DpdkBindHelper(conn)
545 dpdk_bind_helper.dpdk_status = self.PARSED_EXAMPLE
547 dpdk_bind_helper.save_used_drivers()
550 'igb_uio': ['0000:00:04.0', '0000:00:05.0'],
551 'virtio-pci': ['0000:00:03.0'],
554 self.assertDictEqual(expected, dpdk_bind_helper.used_drivers)
556 def test_force_dpdk_rebind(self):
557 mock_ssh_helper = mock.Mock()
558 mock_ssh_helper.execute.return_value = 0, '', ''
560 dpdk_helper = DpdkBindHelper(mock_ssh_helper, 'driver2')
561 dpdk_helper.dpdk_status = {
577 dpdk_helper.real_kernel_interface_driver_map = {
578 'pci1': 'real_driver1',
579 'pci2': 'real_driver2',
580 'pci3': 'real_driver1',
581 'pci4': 'real_driver4',
582 'pci6': 'real_driver6',
584 dpdk_helper.load_dpdk_driver = mock.Mock()
585 dpdk_helper.read_status = mock.Mock()
586 dpdk_helper.save_real_kernel_interface_driver_map = mock.Mock()
587 dpdk_helper.save_used_drivers = mock.Mock()
588 dpdk_helper.bind = mock_bind = mock.Mock()
590 dpdk_helper.force_dpdk_rebind()
591 self.assertEqual(mock_bind.call_count, 2)
593 def test_save_real_kernel_drivers(self):
594 mock_ssh_helper = mock.Mock()
595 mock_ssh_helper.execute.return_value = 0, '', ''
597 dpdk_helper = DpdkBindHelper(mock_ssh_helper)
598 dpdk_helper.real_kernel_drivers = {
601 dpdk_helper.real_kernel_interface_driver_map = {
608 # save_used_drivers must be called before save_real_kernel_drivers can be
609 with self.assertRaises(AttributeError):
610 dpdk_helper.save_real_kernel_drivers()
612 dpdk_helper.save_used_drivers()
614 expected_used_drivers = {
615 'AAA': ['abc', 'abs'],
619 dpdk_helper.save_real_kernel_drivers()
620 self.assertDictEqual(dpdk_helper.used_drivers, expected_used_drivers)
621 self.assertDictEqual(dpdk_helper.real_kernel_drivers, {})
623 def test_get_real_kernel_driver(self):
624 mock_ssh_helper = mock.Mock()
625 mock_ssh_helper.execute.side_effect = [
626 (0, 'non-matching text', ''),
627 (0, 'pre Kernel modules: real_driver1', ''),
628 (0, 'before Ethernet middle Virtio network device after', ''),
631 dpdk_helper = DpdkBindHelper(mock_ssh_helper)
633 self.assertIsNone(dpdk_helper.get_real_kernel_driver('abc'))
634 self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), 'real_driver1')
635 self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), DpdkBindHelper.VIRTIO_DRIVER)