src: update make install for DPDK
[vswitchperf.git] / src / dpdk / dpdk.py
1 # Copyright 2015-2016 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 """Automation of system configuration for DPDK use.
16
17 Parts of this based on ``tools/dpdk_nic_bind.py`` script from Intel(R)
18 DPDK.
19 """
20
21 from sys import platform as _platform
22
23 import os
24 import subprocess
25 import logging
26 import locale
27
28 from tools import tasks
29 from conf import settings
30 from tools.module_manager import ModuleManager
31
32 _LOGGER = logging.getLogger(__name__)
33 RTE_PCI_TOOL = os.path.join(
34     settings.getValue('RTE_SDK'), 'tools', 'dpdk_nic_bind.py')
35
36 _DPDK_MODULE_MANAGER = ModuleManager()
37
38 #
39 # system management
40 #
41
42
43 def init():
44     """Setup system for DPDK.
45     """
46     if not _is_linux():
47         _LOGGER.error('Not running on a compatible Linux version. Exiting...')
48         return
49
50     _insert_modules()
51     _remove_vhost_net()
52     _bind_nics()
53
54
55 def cleanup():
56     """Setup system for DPDK.
57     """
58     if not _is_linux():
59         _LOGGER.error('Not running on a compatible Linux version. Exiting...')
60         return
61
62     _unbind_nics()
63     _remove_modules()
64     _vhost_user_cleanup()
65
66
67 #
68 # vhost specific modules management
69 #
70
71
72 def insert_vhost_modules():
73     """Inserts VHOST related kernel modules
74     """
75     mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
76                                    'lib',
77                                    'librte_vhost')
78     _insert_module_group('VHOST_MODULE', mod_path_prefix)
79
80
81 def remove_vhost_modules():
82     """Removes all VHOST related kernel modules
83     """
84     _remove_module_group('VHOST_MODULE')
85
86 #
87 # basic compatibility test
88 #
89
90
91 def _is_linux():
92     """Check if running on Linux.
93
94     Many of the functions in this file rely on features commonly found
95     only on Linux (i.e. ``/proc`` is not present on FreeBSD). Hence, this
96     check is important to ensure someone doesn't run this on an incompatible
97     OS or distro.
98     """
99     return _platform.startswith('linux') and os.path.isdir('/proc')
100
101 #
102 # module management
103 #
104
105
106 def _is_module_inserted(module):
107     """Check if a module is inserted on system.
108     """
109     with open('/proc/modules') as mod_file:
110         loaded_mods = mod_file.readlines()
111
112     # first check if module is loaded
113     for line in loaded_mods:
114         if line.startswith(module):
115             return True
116     return False
117
118
119 def _insert_modules():
120     """Ensure required modules are inserted on system.
121     """
122
123     _DPDK_MODULE_MANAGER.insert_modules(settings.getValue('SYS_MODULES'))
124
125     mod_path_prefix = settings.getValue('OVS_DIR')
126     _insert_module_group('OVS_MODULES', mod_path_prefix)
127     mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
128                                    settings.getValue('RTE_TARGET'))
129     _insert_module_group('DPDK_MODULES', mod_path_prefix)
130
131
132 def _insert_module_group(module_group, group_path_prefix):
133     """Ensure all modules in a group are inserted into the system.
134
135     :param module_group: A name of configuration item containing a list
136     of module names
137     """
138     for module in settings.getValue(module_group):
139         # first check if module is loaded
140         if _is_module_inserted(module[1]):
141             continue
142
143         try:
144             mod_path = os.path.join(group_path_prefix, module[0],
145                                     '%s.ko' % module[1])
146             tasks.run_task(['sudo', 'insmod', mod_path], _LOGGER,
147                            'Inserting module \'%s\'...' % module[1], True)
148         except subprocess.CalledProcessError:
149             _LOGGER.error('Unable to insert module \'%s\'.', module[1])
150             raise  # fail catastrophically
151
152
153 def _remove_modules():
154     """Ensure required modules are removed from system.
155     """
156     _remove_module_group('OVS_MODULES')
157     _remove_module_group('DPDK_MODULES')
158
159     _DPDK_MODULE_MANAGER.remove_modules()
160
161 def _remove_module_group(module_group):
162     """Ensure all modules in a group are removed from the system.
163
164     :param module_group: A name of configuration item containing a list
165     of module names
166     """
167     for module in settings.getValue(module_group):
168         # first check if module is loaded
169         if not _is_module_inserted(module[1]):
170             continue
171
172         try:
173             tasks.run_task(['sudo', 'rmmod', module[1]], _LOGGER,
174                            'Removing module \'%s\'...' % module[1], True)
175         except subprocess.CalledProcessError:
176             _LOGGER.error('Unable to remove module \'%s\'.', module[1])
177             continue
178
179
180 #
181 # 'vhost-net' module management
182 #
183
184 def _remove_vhost_net():
185     """Remove vhost-net driver and file.
186     """
187     if _is_module_inserted('vhost_net'):
188         try:
189             tasks.run_task(['sudo', 'rmmod', 'vhost_net'], _LOGGER,
190                            'Removing \'/dev/vhost-net\' directory...', True)
191         except subprocess.CalledProcessError:
192             _LOGGER.error('Unable to remove module \'vhost_net\'.')
193
194     try:
195         tasks.run_task(['sudo', 'rm', '-f', '/dev/vhost-net'], _LOGGER,
196                        'Removing \'/dev/vhost-net\' directory...', True)
197     except subprocess.CalledProcessError:
198         _LOGGER.error('Unable to remove directory \'/dev/vhost-net\'.')
199
200 #
201 # NIC management
202 #
203
204
205 def _bind_nics():
206     """Bind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
207     """
208     try:
209         tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind', 'igb_uio'] +
210                        settings.getValue('WHITELIST_NICS'), _LOGGER,
211                        'Binding NICs %s...' %
212                        settings.getValue('WHITELIST_NICS'),
213                        True)
214     except subprocess.CalledProcessError:
215         _LOGGER.error('Unable to bind NICs %s',
216                       str(settings.getValue('WHITELIST_NICS')))
217
218 def _unbind_nics_get_driver():
219     """Check what driver the NICs should be bound to
220        after unbinding them from DPDK.
221     """
222     _driver_list = []
223     _output = subprocess.check_output([os.path.expanduser(RTE_PCI_TOOL), '--status'])
224     _my_encoding = locale.getdefaultlocale()[1]
225     for line in _output.decode(_my_encoding).split('\n'):
226         for nic in settings.getValue('WHITELIST_NICS'):
227             if nic in line:
228                 _driver_list.append((line.split("unused=", 1)[1]))
229     return _driver_list
230
231 def _unbind_nics():
232     """Unbind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
233     """
234     nic_drivers = _unbind_nics_get_driver()
235     try:
236         tasks.run_task(['sudo', RTE_PCI_TOOL, '--unbind'] +
237                        settings.getValue('WHITELIST_NICS'), _LOGGER,
238                        'Unbinding NICs %s...' %
239                        str(settings.getValue('WHITELIST_NICS')),
240                        True)
241     except subprocess.CalledProcessError:
242         _LOGGER.error('Unable to unbind NICs %s',
243                       str(settings.getValue('WHITELIST_NICS')))
244     # Rebind NICs to their original drivers
245     # using the Intel DPDK ``dpdk_nic_bind.py`` tool.
246     for i, nic in enumerate(settings.getValue('WHITELIST_NICS')):
247         try:
248             if nic_drivers[i] != '':
249                 tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind',
250                                 nic_drivers[i], nic],
251                                _LOGGER, 'Binding NIC %s...' %
252                                nic,
253                                True)
254         except subprocess.CalledProcessError:
255             _LOGGER.error('Unable to bind NICs %s to drivers %s',
256                           str(settings.getValue('WHITELIST_NICS')),
257                           nic_drivers)
258
259
260
261 #
262 # Vhost-user cleanup
263 #
264
265 def _vhost_user_cleanup():
266     """Remove files created by vhost-user tests.
267     """
268     for sock in settings.getValue('VHOST_USER_SOCKS'):
269         if os.path.exists(sock):
270             try:
271                 tasks.run_task(['sudo', 'rm', sock],
272                                _LOGGER,
273                                'Deleting vhost-user socket \'%s\'...' %
274                                sock,
275                                True)
276
277             except subprocess.CalledProcessError:
278                 _LOGGER.error('Unable to delete vhost-user socket \'%s\'.',
279                               sock)
280                 continue
281
282
283 class Dpdk(object):
284     """A context manager for the system init/cleanup.
285     """
286     def __enter__(self):
287         _LOGGER.info('Setting up DPDK')
288         init()
289         return self
290
291     def __exit__(self, type_, value, traceback):
292         _LOGGER.info('Cleaning up DPDK')
293         cleanup()