1 # Copyright 2015 Intel Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 """Automation of system configuration for DPDK use.
17 Parts of this based on ``tools/dpdk_nic_bind.py`` script from Intel(R)
21 from sys import platform as _platform
29 from tools import tasks
30 from conf import settings
31 from tools.module_manager import ModuleManager
33 _LOGGER = logging.getLogger(__name__)
34 RTE_PCI_TOOL = os.path.join(
35 settings.getValue('RTE_SDK'), 'tools', 'dpdk_nic_bind.py')
37 _DPDK_MODULE_MANAGER = ModuleManager()
45 """Setup system for DPDK.
48 _LOGGER.error('Not running on a compatible Linux version. Exiting...')
58 """Setup system for DPDK.
61 _LOGGER.error('Not running on a compatible Linux version. Exiting...')
71 # vhost specific modules management
75 def insert_vhost_modules():
76 """Inserts VHOST related kernel modules
78 mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
81 _insert_module_group('VHOST_MODULE', mod_path_prefix)
84 def remove_vhost_modules():
85 """Removes all VHOST related kernel modules
87 _remove_module_group('VHOST_MODULE')
90 # basic compatibility test
95 """Check if running on Linux.
97 Many of the functions in this file rely on features commonly found
98 only on Linux (i.e. ``/proc`` is not present on FreeBSD). Hence, this
99 check is important to ensure someone doesn't run this on an incompatible
102 return _platform.startswith('linux') and os.path.isdir('/proc')
105 # hugepage management
109 def _is_hugepage_available():
110 """Check if hugepages are available on the system.
112 hugepage_re = re.compile(r'^HugePages_Free:\s+(?P<num_hp>\d+)$')
115 with open('/proc/meminfo') as mem_file:
116 mem_info = mem_file.readlines()
118 # first check if module is loaded
119 for line in mem_info:
120 result = hugepage_re.match(line)
124 num_huge = result.group('num_hp')
126 _LOGGER.info('No free hugepages.')
128 _LOGGER.info('Found \'%s\' free hugepage(s).', num_huge)
134 def _is_hugepage_mounted():
135 """Check if hugepages are mounted.
137 output = subprocess.check_output(['mount'], shell=True)
138 my_encoding = locale.getdefaultlocale()[1]
139 for line in output.decode(my_encoding).split('\n'):
140 if 'hugetlbfs' in line:
146 def _mount_hugepages():
147 """Ensure hugepages are mounted.
149 if not _is_hugepage_available():
152 if _is_hugepage_mounted():
155 if not os.path.exists(settings.getValue('HUGEPAGE_DIR')):
156 os.makedirs(settings.getValue('HUGEPAGE_DIR'))
158 tasks.run_task(['sudo', 'mount', '-t', 'hugetlbfs', 'nodev',
159 settings.getValue('HUGEPAGE_DIR')],
160 _LOGGER, 'Mounting hugepages...', True)
161 except subprocess.CalledProcessError:
162 _LOGGER.error('Unable to mount hugepages.')
165 def _umount_hugepages():
166 """Ensure hugepages are unmounted.
168 if not _is_hugepage_mounted():
172 tasks.run_task(['sudo', 'umount', settings.getValue('HUGEPAGE_DIR')],
173 _LOGGER, 'Unmounting hugepages...', True)
174 except subprocess.CalledProcessError:
175 _LOGGER.error('Unable to umount hugepages.')
182 def _is_module_inserted(module):
183 """Check if a module is inserted on system.
185 with open('/proc/modules') as mod_file:
186 loaded_mods = mod_file.readlines()
188 # first check if module is loaded
189 for line in loaded_mods:
190 if line.startswith(module):
195 def _insert_modules():
196 """Ensure required modules are inserted on system.
199 _DPDK_MODULE_MANAGER.insert_modules(settings.getValue('SYS_MODULES'))
201 mod_path_prefix = settings.getValue('OVS_DIR')
202 _insert_module_group('OVS_MODULES', mod_path_prefix)
203 mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
204 settings.getValue('RTE_TARGET'))
205 _insert_module_group('DPDK_MODULES', mod_path_prefix)
208 def _insert_module_group(module_group, group_path_prefix):
209 """Ensure all modules in a group are inserted into the system.
211 :param module_group: A name of configuration item containing a list
214 for module in settings.getValue(module_group):
215 # first check if module is loaded
216 if _is_module_inserted(module[1]):
220 mod_path = os.path.join(group_path_prefix, module[0],
222 tasks.run_task(['sudo', 'insmod', mod_path], _LOGGER,
223 'Inserting module \'%s\'...' % module[1], True)
224 except subprocess.CalledProcessError:
225 _LOGGER.error('Unable to insert module \'%s\'.', module[1])
226 raise # fail catastrophically
229 def _remove_modules():
230 """Ensure required modules are removed from system.
232 _remove_module_group('OVS_MODULES')
233 _remove_module_group('DPDK_MODULES')
235 _DPDK_MODULE_MANAGER.remove_modules()
237 def _remove_module_group(module_group):
238 """Ensure all modules in a group are removed from the system.
240 :param module_group: A name of configuration item containing a list
243 for module in settings.getValue(module_group):
244 # first check if module is loaded
245 if not _is_module_inserted(module[1]):
249 tasks.run_task(['sudo', 'rmmod', module[1]], _LOGGER,
250 'Removing module \'%s\'...' % module[1], True)
251 except subprocess.CalledProcessError:
252 _LOGGER.error('Unable to remove module \'%s\'.', module[1])
257 # 'vhost-net' module management
260 def _remove_vhost_net():
261 """Remove vhost-net driver and file.
263 if _is_module_inserted('vhost_net'):
265 tasks.run_task(['sudo', 'rmmod', 'vhost_net'], _LOGGER,
266 'Removing \'/dev/vhost-net\' directory...', True)
267 except subprocess.CalledProcessError:
268 _LOGGER.error('Unable to remove module \'vhost_net\'.')
271 tasks.run_task(['sudo', 'rm', '-f', '/dev/vhost-net'], _LOGGER,
272 'Removing \'/dev/vhost-net\' directory...', True)
273 except subprocess.CalledProcessError:
274 _LOGGER.error('Unable to remove directory \'/dev/vhost-net\'.')
282 """Bind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
285 tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind', 'igb_uio'] +
286 settings.getValue('WHITELIST_NICS'), _LOGGER,
287 'Binding NICs %s...' %
288 settings.getValue('WHITELIST_NICS'),
290 except subprocess.CalledProcessError:
291 _LOGGER.error('Unable to bind NICs %s',
292 str(settings.getValue('WHITELIST_NICS')))
294 def _unbind_nics_get_driver():
295 """Check what driver the NICs should be bound to
296 after unbinding them from DPDK.
299 _output = subprocess.check_output([os.path.expanduser(RTE_PCI_TOOL), '--status'])
300 _my_encoding = locale.getdefaultlocale()[1]
301 for line in _output.decode(_my_encoding).split('\n'):
302 for nic in settings.getValue('WHITELIST_NICS'):
304 _driver_list.append((line.split("unused=", 1)[1]))
308 """Unbind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
310 nic_drivers = _unbind_nics_get_driver()
312 tasks.run_task(['sudo', RTE_PCI_TOOL, '--unbind'] +
313 settings.getValue('WHITELIST_NICS'), _LOGGER,
314 'Unbinding NICs %s...' %
315 str(settings.getValue('WHITELIST_NICS')),
317 except subprocess.CalledProcessError:
318 _LOGGER.error('Unable to unbind NICs %s',
319 str(settings.getValue('WHITELIST_NICS')))
320 # Rebind NICs to their original drivers
321 # using the Intel DPDK ``dpdk_nic_bind.py`` tool.
322 for i, nic in enumerate(settings.getValue('WHITELIST_NICS')):
324 if nic_drivers[i] != '':
325 tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind',
326 nic_drivers[i], nic],
327 _LOGGER, 'Binding NIC %s...' %
330 except subprocess.CalledProcessError:
331 _LOGGER.error('Unable to bind NICs %s to drivers %s',
332 str(settings.getValue('WHITELIST_NICS')),
341 def _vhost_user_cleanup():
342 """Remove files created by vhost-user tests.
344 for sock in settings.getValue('VHOST_USER_SOCKS'):
345 if os.path.exists(sock):
347 tasks.run_task(['sudo', 'rm', sock],
349 'Deleting vhost-user socket \'%s\'...' %
353 except subprocess.CalledProcessError:
354 _LOGGER.error('Unable to delete vhost-user socket \'%s\'.',
360 """A context manager for the system init/cleanup.
363 _LOGGER.info('Setting up DPDK')
367 def __exit__(self, type_, value, traceback):
368 _LOGGER.info('Cleaning up DPDK')