Add send socket commands function
[yardstick.git] / yardstick / tests / unit / network_services / helpers / test_dpdkbindnic_helper.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 mock
16 import unittest
17
18 import os
19
20 from yardstick.common import exceptions
21 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkInterface
22 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkNode
23 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper
24 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelperException
25 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_KERNEL
26 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_DPDK
27 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_KERNEL
28 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_DPDK
29 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_OTHER
30 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_OTHER
31
32
33 NAME = "tg_0"
34
35
36 class TestDpdkInterface(unittest.TestCase):
37
38     SAMPLE_NETDEVS = {
39         'enp11s0': {
40             'address': '0a:de:ad:be:ef:f5',
41             'device': '0x1533',
42             'driver': 'igb',
43             'ifindex': '2',
44             'interface_name': 'enp11s0',
45             'operstate': 'down',
46             'pci_bus_id': '0000:0b:00.0',
47             'subsystem_device': '0x1533',
48             'subsystem_vendor': '0x15d9',
49             'vendor': '0x8086'
50         },
51         'lan': {
52             'address': '0a:de:ad:be:ef:f4',
53             'device': '0x153a',
54             'driver': 'e1000e',
55             'ifindex': '3',
56             'interface_name': 'lan',
57             'operstate': 'up',
58             'pci_bus_id': '0000:00:19.0',
59             'subsystem_device': '0x153a',
60             'subsystem_vendor': '0x15d9',
61             'vendor': '0x8086'
62         }
63     }
64
65     SAMPLE_VM_NETDEVS = {
66         'eth1': {
67             'address': 'fa:de:ad:be:ef:5b',
68             'device': '0x0001',
69             'driver': 'virtio_net',
70             'ifindex': '3',
71             'interface_name': 'eth1',
72             'operstate': 'down',
73             'pci_bus_id': '0000:00:04.0',
74             'vendor': '0x1af4'
75         }
76     }
77
78     def test_parse_netdev_info(self):
79         output = """\
80 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2
81 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5
82 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down
83 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086
84 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533
85 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9
86 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533
87 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb
88 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0
89 /sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3
90 /sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4
91 /sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up
92 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086
93 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a
94 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9
95 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a
96 /sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e
97 /sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0
98 """
99         res = DpdkBindHelper.parse_netdev_info(output)
100         self.assertDictEqual(res, self.SAMPLE_NETDEVS)
101
102     def test_parse_netdev_info_virtio(self):
103         output = """\
104 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3
105 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b
106 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down
107 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4
108 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001
109 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net
110 """
111         res = DpdkBindHelper.parse_netdev_info(output)
112         self.assertDictEqual(res, self.SAMPLE_VM_NETDEVS)
113
114     def test_probe_missing_values(self):
115         mock_dpdk_node = mock.Mock()
116         mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy()
117
118         interface = {'local_mac': '0a:de:ad:be:ef:f5'}
119         dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
120
121         dpdk_intf.probe_missing_values()
122         self.assertEqual(interface['vpci'], '0000:0b:00.0')
123
124         interface['local_mac'] = '0a:de:ad:be:ef:f4'
125         dpdk_intf.probe_missing_values()
126         self.assertEqual(interface['vpci'], '0000:00:19.0')
127
128     def test_probe_missing_values_no_update(self):
129         mock_dpdk_node = mock.Mock()
130         mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy()
131         del mock_dpdk_node.netdevs['enp11s0']['driver']
132         del mock_dpdk_node.netdevs['lan']['driver']
133
134         interface = {'local_mac': '0a:de:ad:be:ef:f5'}
135         dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
136
137         dpdk_intf.probe_missing_values()
138         self.assertNotIn('vpci', interface)
139         self.assertNotIn('driver', interface)
140
141     def test_probe_missing_values_negative(self):
142         mock_dpdk_node = mock.Mock()
143         mock_dpdk_node.netdevs.values.side_effect = (
144             exceptions.IncorrectNodeSetup(error_msg=''))
145
146         interface = {'local_mac': '0a:de:ad:be:ef:f5'}
147         dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
148
149         with self.assertRaises(exceptions.IncorrectConfig):
150             dpdk_intf.probe_missing_values()
151
152
153 class TestDpdkNode(unittest.TestCase):
154
155     INTERFACES = [
156         {'name': 'name1',
157          'virtual-interface': {
158              'local_mac': 404,
159              'vpci': 'pci10',
160          }},
161         {'name': 'name2',
162          'virtual-interface': {
163              'local_mac': 404,
164              'vpci': 'pci2',
165          }},
166         {'name': 'name3',
167          'virtual-interface': {
168              'local_mac': 404,
169              'vpci': 'some-pci1',
170          }},
171     ]
172
173     def test_probe_dpdk_drivers(self):
174         mock_ssh_helper = mock.Mock()
175         mock_ssh_helper.execute.return_value = 0, '', ''
176
177         interfaces = [
178             {'name': 'name1',
179              'virtual-interface': {
180                  'local_mac': 404,
181                  'vpci': 'pci10',
182              }},
183             {'name': 'name2',
184              'virtual-interface': {
185                  'local_mac': 404,
186                  'vpci': 'pci2',
187              }},
188             {'name': 'name3',
189              'virtual-interface': {
190                  'local_mac': 404,
191                  'vpci': 'some-pci1',
192              }},
193         ]
194
195         dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper)
196         dpdk_helper = dpdk_node.dpdk_helper
197
198         dpdk_helper.probe_real_kernel_drivers = mock.Mock()
199         dpdk_helper.real_kernel_interface_driver_map = {
200             'pci1': 'driver1',
201             'pci2': 'driver2',
202             'pci3': 'driver3',
203             'pci4': 'driver1',
204             'pci6': 'driver3',
205         }
206
207         dpdk_node._probe_dpdk_drivers()
208         self.assertNotIn('driver', interfaces[0]['virtual-interface'])
209         self.assertEqual(interfaces[1]['virtual-interface']['driver'], 'driver2')
210         self.assertEqual(interfaces[2]['virtual-interface']['driver'], 'driver1')
211
212     def test_check(self):
213         def update():
214             if not mock_force_rebind.called:
215                 raise exceptions.IncorrectConfig(error_msg='')
216
217             interfaces[0]['virtual-interface'].update({
218                 'vpci': '0000:01:02.1',
219                 'local_ip': '10.20.30.40',
220                 'netmask': '255.255.0.0',
221                 'driver': 'ixgbe',
222             })
223
224         mock_ssh_helper = mock.Mock()
225         mock_ssh_helper.execute.return_value = 0, '', ''
226
227         interfaces = [
228             {'name': 'name1',
229              'virtual-interface': {
230                  'local_mac': 404,
231              }},
232         ]
233
234         dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper)
235         dpdk_node._probe_missing_values = mock_probe_missing = mock.Mock(side_effect=update)
236         dpdk_node._force_rebind = mock_force_rebind = mock.Mock()
237
238         self.assertIsNone(dpdk_node.check())
239         self.assertEqual(mock_probe_missing.call_count, 2)
240
241     @mock.patch('yardstick.network_services.helpers.dpdkbindnic_helper.DpdkInterface')
242     def test_check_negative(self, mock_intf_type):
243         mock_ssh_helper = mock.Mock()
244         mock_ssh_helper.execute.return_value = 0, '', ''
245
246         mock_intf_type().check.side_effect = exceptions.SSHError
247
248         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
249
250         with self.assertRaises(exceptions.IncorrectSetup):
251             dpdk_node.check()
252
253     def test_probe_netdevs(self):
254         mock_ssh_helper = mock.Mock()
255         mock_ssh_helper.execute.return_value = 0, '', ''
256
257         expected = {'key1': 500, 'key2': 'hello world'}
258         update = {'key1': 1000, 'key3': []}
259
260         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
261         dpdk_helper = dpdk_node.dpdk_helper
262         dpdk_helper.find_net_devices = mock.Mock(side_effect=[expected, update])
263
264         self.assertDictEqual(dpdk_node.netdevs, {})
265         dpdk_node._probe_netdevs()
266         self.assertDictEqual(dpdk_node.netdevs, expected)
267
268         expected = {'key1': 1000, 'key2': 'hello world', 'key3': []}
269         dpdk_node._probe_netdevs()
270         self.assertDictEqual(dpdk_node.netdevs, expected)
271
272     def test_probe_netdevs_setup_negative(self):
273         mock_ssh_helper = mock.Mock()
274         mock_ssh_helper.execute.return_value = 0, '', ''
275
276         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
277         dpdk_helper = dpdk_node.dpdk_helper
278         dpdk_helper.find_net_devices = mock.Mock(side_effect=DpdkBindHelperException)
279
280         with self.assertRaises(DpdkBindHelperException):
281             dpdk_node._probe_netdevs()
282
283     def test_force_rebind(self):
284         mock_ssh_helper = mock.Mock()
285         mock_ssh_helper.execute.return_value = 0, '', ''
286
287         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
288         dpdk_helper = dpdk_node.dpdk_helper
289         dpdk_helper.force_dpdk_rebind = mock_helper_func = mock.Mock()
290
291         dpdk_node._force_rebind()
292         self.assertEqual(mock_helper_func.call_count, 1)
293
294
295 class TestDpdkBindHelper(unittest.TestCase):
296     bin_path = "/opt/nsb_bin"
297     EXAMPLE_OUTPUT = """
298
299 Network devices using DPDK-compatible driver
300 ============================================
301 0000:00:04.0 'Virtio network device' drv=igb_uio unused=
302 0000:00:05.0 'Virtio network device' drv=igb_uio unused=
303
304 Network devices using kernel driver
305 ===================================
306 0000:00:03.0 'Virtio network device' if=ens3 drv=virtio-pci unused=igb_uio *Active*
307
308 Other network devices
309 =====================
310 <none>
311
312 Crypto devices using DPDK-compatible driver
313 ===========================================
314 <none>
315
316 Crypto devices using kernel driver
317 ==================================
318 <none>
319
320 Other crypto devices
321 ====================
322 <none>
323 """
324
325     PARSED_EXAMPLE = {
326         NETWORK_DPDK: [
327             {'active': False,
328              'dev_type': 'Virtio network device',
329              'driver': 'igb_uio',
330              'iface': None,
331              'unused': '',
332              'vpci': '0000:00:04.0',
333              },
334             {'active': False,
335              'dev_type': 'Virtio network device',
336              'driver': 'igb_uio',
337              'iface': None,
338              'unused': '',
339              'vpci': '0000:00:05.0',
340              }
341         ],
342         NETWORK_KERNEL: [
343             {'active': True,
344              'dev_type': 'Virtio network device',
345              'driver': 'virtio-pci',
346              'iface': 'ens3',
347              'unused': 'igb_uio',
348              'vpci': '0000:00:03.0',
349              }
350         ],
351         CRYPTO_KERNEL: [],
352         CRYPTO_DPDK: [],
353         NETWORK_OTHER: [],
354         CRYPTO_OTHER: [],
355     }
356
357     CLEAN_STATUS = {
358         NETWORK_KERNEL: [],
359         NETWORK_DPDK: [],
360         CRYPTO_KERNEL: [],
361         CRYPTO_DPDK: [],
362         NETWORK_OTHER: [],
363         CRYPTO_OTHER: [],
364     }
365
366     ONE_INPUT_LINE = ("0000:00:03.0 'Virtio network device' if=ens3 "
367                       "drv=virtio-pci unused=igb_uio *Active*")
368
369     ONE_INPUT_LINE_PARSED = [{
370         'vpci': '0000:00:03.0',
371         'dev_type': 'Virtio network device',
372         'iface': 'ens3',
373         'driver': 'virtio-pci',
374         'unused': 'igb_uio',
375         'active': True,
376     }]
377
378     def test___init__(self):
379         conn = mock.Mock()
380         conn.provision_tool = mock.Mock(return_value='path_to_tool')
381         conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
382
383         dpdk_bind_helper = DpdkBindHelper(conn)
384
385         self.assertEqual(conn, dpdk_bind_helper.ssh_helper)
386         self.assertEqual(self.CLEAN_STATUS, dpdk_bind_helper.dpdk_status)
387         self.assertIsNone(dpdk_bind_helper.status_nic_row_re)
388         self.assertEqual(dpdk_bind_helper.dpdk_devbind,
389                          os.path.join(self.bin_path, dpdk_bind_helper.DPDK_DEVBIND))
390         self.assertIsNone(dpdk_bind_helper._status_cmd_attr)
391
392     def test__dpdk_execute(self):
393         conn = mock.Mock()
394         conn.execute = mock.Mock(return_value=(0, 'output', 'error'))
395         conn.provision_tool = mock.Mock(return_value='tool_path')
396         dpdk_bind_helper = DpdkBindHelper(conn)
397         self.assertEqual((0, 'output', 'error'), dpdk_bind_helper._dpdk_execute('command'))
398
399     def test__dpdk_execute_failure(self):
400         conn = mock.Mock()
401         conn.execute = mock.Mock(return_value=(1, 'output', 'error'))
402         conn.provision_tool = mock.Mock(return_value='tool_path')
403         dpdk_bind_helper = DpdkBindHelper(conn)
404         with self.assertRaises(DpdkBindHelperException):
405             dpdk_bind_helper._dpdk_execute('command')
406
407     def test__addline(self):
408         conn = mock.Mock()
409
410         dpdk_bind_helper = DpdkBindHelper(conn)
411
412         dpdk_bind_helper._add_line(NETWORK_KERNEL, self.ONE_INPUT_LINE)
413
414         self.assertIsNotNone(dpdk_bind_helper.dpdk_status)
415         self.assertEqual(self.ONE_INPUT_LINE_PARSED, dpdk_bind_helper.dpdk_status[NETWORK_KERNEL])
416
417     def test__switch_active_dict_by_header(self):
418         line = "Crypto devices using DPDK-compatible driver"
419         olddict = 'olddict'
420         self.assertEqual(CRYPTO_DPDK, DpdkBindHelper._switch_active_dict(line, olddict))
421
422     def test__switch_active_dict_by_header_empty(self):
423         line = "<none>"
424         olddict = 'olddict'
425         self.assertEqual(olddict, DpdkBindHelper._switch_active_dict(line, olddict))
426
427     def test_parse_dpdk_status_output(self):
428         conn = mock.Mock()
429
430         dpdk_bind_helper = DpdkBindHelper(conn)
431
432         dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
433
434         self.maxDiff = None
435         self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.dpdk_status)
436
437     def test_kernel_bound_pci_addresses(self):
438         mock_ssh_helper = mock.Mock()
439         mock_ssh_helper.execute.return_value = 0, '', ''
440
441         expected = ['a', 'b', 3]
442
443         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
444         dpdk_helper.dpdk_status = {
445             NETWORK_DPDK: [{'vpci': 4}, {'vpci': 5}, {'vpci': 'g'}],
446             NETWORK_KERNEL: [{'vpci': 'a'}, {'vpci': 'b'}, {'vpci': 3}],
447             CRYPTO_DPDK: [],
448         }
449
450         result = dpdk_helper.kernel_bound_pci_addresses
451         self.assertEqual(result, expected)
452
453     def test_find_net_devices_negative(self):
454         mock_ssh_helper = mock.Mock()
455         mock_ssh_helper.execute.return_value = 1, 'error', 'debug'
456
457         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
458
459         self.assertDictEqual(dpdk_helper.find_net_devices(), {})
460
461     def test_read_status(self):
462         conn = mock.Mock()
463         conn.execute = mock.Mock(return_value=(0, self.EXAMPLE_OUTPUT, ''))
464         conn.provision_tool = mock.Mock(return_value='path_to_tool')
465
466         dpdk_bind_helper = DpdkBindHelper(conn)
467
468         self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.read_status())
469
470     def test__get_bound_pci_addresses(self):
471         conn = mock.Mock()
472
473         dpdk_bind_helper = DpdkBindHelper(conn)
474
475         dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
476
477         self.assertEqual(['0000:00:04.0', '0000:00:05.0'],
478                           dpdk_bind_helper._get_bound_pci_addresses(NETWORK_DPDK))
479         self.assertEqual(['0000:00:03.0'],
480                           dpdk_bind_helper._get_bound_pci_addresses(NETWORK_KERNEL))
481
482     def test_interface_driver_map(self):
483         conn = mock.Mock()
484
485         dpdk_bind_helper = DpdkBindHelper(conn)
486
487         dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
488
489         self.assertEqual({'0000:00:04.0': 'igb_uio',
490                           '0000:00:03.0': 'virtio-pci',
491                           '0000:00:05.0': 'igb_uio',
492                           },
493                          dpdk_bind_helper.interface_driver_map)
494
495     def test_bind(self):
496         conn = mock.Mock()
497         conn.execute = mock.Mock(return_value=(0, '', ''))
498         conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
499
500         dpdk_bind_helper = DpdkBindHelper(conn)
501         dpdk_bind_helper.read_status = mock.Mock()
502
503         dpdk_bind_helper.bind(['0000:00:03.0', '0000:00:04.0'], 'my_driver')
504
505         conn.execute.assert_called_with('sudo /opt/nsb_bin/dpdk-devbind.py --force '
506                                         '-b my_driver 0000:00:03.0 0000:00:04.0')
507         dpdk_bind_helper.read_status.assert_called_once()
508
509     def test_bind_single_pci(self):
510         conn = mock.Mock()
511         conn.execute = mock.Mock(return_value=(0, '', ''))
512         conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
513
514         dpdk_bind_helper = DpdkBindHelper(conn)
515         dpdk_bind_helper.read_status = mock.Mock()
516
517         dpdk_bind_helper.bind('0000:00:03.0', 'my_driver')
518
519         conn.execute.assert_called_with('sudo /opt/nsb_bin/dpdk-devbind.py --force '
520                                         '-b my_driver 0000:00:03.0')
521         dpdk_bind_helper.read_status.assert_called_once()
522
523     def test_rebind_drivers(self):
524         conn = mock.Mock()
525
526         dpdk_bind_helper = DpdkBindHelper(conn)
527
528         dpdk_bind_helper.bind = mock.Mock()
529         dpdk_bind_helper.used_drivers = {
530             'd1': ['0000:05:00.0'],
531             'd3': ['0000:05:01.0', '0000:05:02.0'],
532         }
533
534         dpdk_bind_helper.rebind_drivers()
535
536         dpdk_bind_helper.bind.assert_any_call(['0000:05:00.0'], 'd1', True)
537         dpdk_bind_helper.bind.assert_any_call(['0000:05:01.0', '0000:05:02.0'], 'd3', True)
538
539     def test_save_used_drivers(self):
540         conn = mock.Mock()
541         dpdk_bind_helper = DpdkBindHelper(conn)
542         dpdk_bind_helper.dpdk_status = self.PARSED_EXAMPLE
543
544         dpdk_bind_helper.save_used_drivers()
545
546         expected = {
547             'igb_uio': ['0000:00:04.0', '0000:00:05.0'],
548             'virtio-pci': ['0000:00:03.0'],
549         }
550
551         self.assertDictEqual(expected, dpdk_bind_helper.used_drivers)
552
553     def test_force_dpdk_rebind(self):
554         mock_ssh_helper = mock.Mock()
555         mock_ssh_helper.execute.return_value = 0, '', ''
556
557         dpdk_helper = DpdkBindHelper(mock_ssh_helper, 'driver2')
558         dpdk_helper.dpdk_status = {
559             NETWORK_DPDK: [
560                 {
561                     'vpci': 'pci1',
562                 },
563                 {
564                     'vpci': 'pci3',
565                 },
566                 {
567                     'vpci': 'pci6',
568                 },
569                 {
570                     'vpci': 'pci3',
571                 },
572             ]
573         }
574         dpdk_helper.real_kernel_interface_driver_map = {
575             'pci1': 'real_driver1',
576             'pci2': 'real_driver2',
577             'pci3': 'real_driver1',
578             'pci4': 'real_driver4',
579             'pci6': 'real_driver6',
580         }
581         dpdk_helper.load_dpdk_driver = mock.Mock()
582         dpdk_helper.read_status = mock.Mock()
583         dpdk_helper.save_real_kernel_interface_driver_map = mock.Mock()
584         dpdk_helper.save_used_drivers = mock.Mock()
585         dpdk_helper.bind = mock_bind = mock.Mock()
586
587         dpdk_helper.force_dpdk_rebind()
588         self.assertEqual(mock_bind.call_count, 2)
589
590     def test_save_real_kernel_drivers(self):
591         mock_ssh_helper = mock.Mock()
592         mock_ssh_helper.execute.return_value = 0, '', ''
593
594         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
595         dpdk_helper.real_kernel_drivers = {
596             'abc': '123',
597         }
598         dpdk_helper.real_kernel_interface_driver_map = {
599             'abc': 'AAA',
600             'def': 'DDD',
601             'abs': 'AAA',
602             'ghi': 'GGG',
603         }
604
605         # save_used_drivers must be called before save_real_kernel_drivers can be
606         with self.assertRaises(AttributeError):
607             dpdk_helper.save_real_kernel_drivers()
608
609         dpdk_helper.save_used_drivers()
610
611         expected_used_drivers = {
612             'AAA': ['abc', 'abs'],
613             'DDD': ['def'],
614             'GGG': ['ghi'],
615         }
616         dpdk_helper.save_real_kernel_drivers()
617         self.assertDictEqual(dpdk_helper.used_drivers, expected_used_drivers)
618         self.assertDictEqual(dpdk_helper.real_kernel_drivers, {})
619
620     def test_get_real_kernel_driver(self):
621         mock_ssh_helper = mock.Mock()
622         mock_ssh_helper.execute.side_effect = [
623             (0, 'non-matching text', ''),
624             (0, 'pre Kernel modules: real_driver1', ''),
625             (0, 'before Ethernet middle Virtio network device after', ''),
626         ]
627
628         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
629
630         self.assertIsNone(dpdk_helper.get_real_kernel_driver('abc'))
631         self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), 'real_driver1')
632         self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), DpdkBindHelper.VIRTIO_DRIVER)