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/pci_unbind.py`` script from Intel(R) DPDK.
20 from sys import platform as _platform
28 from tools import tasks
29 from conf import settings
31 _LOGGER = logging.getLogger(__name__)
32 RTE_PCI_TOOL = os.path.join(
33 settings.getValue('RTE_SDK'), 'tools', 'dpdk_nic_bind.py')
41 """Setup system for DPDK.
44 _LOGGER.error('Not running on a compatible Linux version. Exiting...')
51 _copy_dpdk_for_guest()
55 """Setup system for DPDK.
58 _LOGGER.error('Not running on a compatible Linux version. Exiting...')
68 # vhost specific modules management
72 def insert_vhost_modules():
73 """Inserts VHOST related kernel modules
75 mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
78 _insert_module_group('VHOST_MODULE', mod_path_prefix)
81 def remove_vhost_modules():
82 """Removes all VHOST related kernel modules
84 _remove_module_group('VHOST_MODULE')
87 # basic compatibility test
92 """Check if running on Linux.
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
99 return _platform.startswith('linux') and os.path.isdir('/proc')
102 # hugepage management
106 def _is_hugepage_available():
107 """Check if hugepages are available on the system.
109 hugepage_re = re.compile(r'^HugePages_Free:\s+(?P<num_hp>\d+)$')
112 with open('/proc/meminfo') as mem_file:
113 mem_info = mem_file.readlines()
115 # first check if module is loaded
116 for line in mem_info:
117 result = hugepage_re.match(line)
121 num_huge = result.group('num_hp')
123 _LOGGER.info('No free hugepages.')
125 _LOGGER.info('Found \'%s\' free hugepage(s).', num_huge)
131 def _is_hugepage_mounted():
132 """Check if hugepages are mounted.
134 output = subprocess.check_output(['mount'], shell=True)
135 my_encoding = locale.getdefaultlocale()[1]
136 for line in output.decode(my_encoding).split('\n'):
137 if 'hugetlbfs' in line:
143 def _mount_hugepages():
144 """Ensure hugepages are mounted.
146 if not _is_hugepage_available():
149 if _is_hugepage_mounted():
152 if not os.path.exists(settings.getValue('HUGEPAGE_DIR')):
153 os.makedirs(settings.getValue('HUGEPAGE_DIR'))
155 tasks.run_task(['sudo', 'mount', '-t', 'hugetlbfs', 'nodev',
156 settings.getValue('HUGEPAGE_DIR')],
157 _LOGGER, 'Mounting hugepages...', True)
158 except subprocess.CalledProcessError:
159 _LOGGER.error('Unable to mount hugepages.')
162 def _umount_hugepages():
163 """Ensure hugepages are unmounted.
165 if not _is_hugepage_mounted():
169 tasks.run_task(['sudo', 'umount', settings.getValue('HUGEPAGE_DIR')],
170 _LOGGER, 'Unmounting hugepages...', True)
171 except subprocess.CalledProcessError:
172 _LOGGER.error('Unable to umount hugepages.')
179 def _is_module_inserted(module):
180 """Check if a module is inserted on system.
182 with open('/proc/modules') as mod_file:
183 loaded_mods = mod_file.readlines()
185 # first check if module is loaded
186 for line in loaded_mods:
187 if line.startswith(module):
192 def _insert_modules():
193 """Ensure required modules are inserted on system.
195 for module in settings.getValue('SYS_MODULES'):
196 if _is_module_inserted(module):
200 tasks.run_task(['sudo', 'modprobe', module], _LOGGER,
201 'Inserting module \'%s\'...' % module, True)
202 except subprocess.CalledProcessError:
203 _LOGGER.error('Unable to insert module \'%s\'.', module)
204 raise # fail catastrophically
206 mod_path_prefix = settings.getValue('OVS_DIR')
207 _insert_module_group('OVS_MODULES', mod_path_prefix)
208 mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
209 settings.getValue('RTE_TARGET'))
210 _insert_module_group('DPDK_MODULES', mod_path_prefix)
213 def _insert_module_group(module_group, group_path_prefix):
214 """Ensure all modules in a group are inserted into the system.
216 :param module_group: A name of configuration item containing a list
219 for module in settings.getValue(module_group):
220 # first check if module is loaded
221 if _is_module_inserted(module[1]):
225 mod_path = os.path.join(group_path_prefix, module[0],
227 tasks.run_task(['sudo', 'insmod', mod_path], _LOGGER,
228 'Inserting module \'%s\'...' % module[1], True)
229 except subprocess.CalledProcessError:
230 _LOGGER.error('Unable to insert module \'%s\'.', module[1])
231 raise # fail catastrophically
234 def _remove_modules():
235 """Ensure required modules are removed from system.
237 _remove_module_group('OVS_MODULES')
238 _remove_module_group('DPDK_MODULES')
240 for module in settings.getValue('SYS_MODULES'):
241 # first check if module is loaded
242 if not _is_module_inserted(module):
246 tasks.run_task(['sudo', 'rmmod', module], _LOGGER,
247 'Removing module \'%s\'...' % module, True)
248 except subprocess.CalledProcessError:
249 _LOGGER.error('Unable to remove module \'%s\'.', module)
253 def _remove_module_group(module_group):
254 """Ensure all modules in a group are removed from the system.
256 :param module_group: A name of configuration item containing a list
259 for module in settings.getValue(module_group):
260 # first check if module is loaded
261 if not _is_module_inserted(module[1]):
265 tasks.run_task(['sudo', 'rmmod', module[1]], _LOGGER,
266 'Removing module \'%s\'...' % module[1], True)
267 except subprocess.CalledProcessError:
268 _LOGGER.error('Unable to remove module \'%s\'.', module[1])
273 # 'vhost-net' module management
276 def _remove_vhost_net():
277 """Remove vhost-net driver and file.
279 if _is_module_inserted('vhost_net'):
281 tasks.run_task(['sudo', 'rmmod', 'vhost_net'], _LOGGER,
282 'Removing \'/dev/vhost-net\' directory...', True)
283 except subprocess.CalledProcessError:
284 _LOGGER.error('Unable to remove module \'vhost_net\'.')
287 tasks.run_task(['sudo', 'rm', '-f', '/dev/vhost-net'], _LOGGER,
288 'Removing \'/dev/vhost-net\' directory...', True)
289 except subprocess.CalledProcessError:
290 _LOGGER.error('Unable to remove directory \'/dev/vhost-net\'.')
298 """Bind NICs using the Intel DPDK ``pci_unbind.py`` tool.
301 tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind', 'igb_uio'] +
302 settings.getValue('WHITELIST_NICS'), _LOGGER,
303 'Binding NICs %s...' %
304 settings.getValue('WHITELIST_NICS'),
306 except subprocess.CalledProcessError:
307 _LOGGER.error('Unable to bind NICs %s',
308 str(settings.getValue('WHITELIST_NICS')))
312 """Unbind NICs using the Intel DPDK ``pci_unbind.py`` tool.
315 tasks.run_task(['sudo', RTE_PCI_TOOL, '--unbind'] +
316 settings.getValue('WHITELIST_NICS'), _LOGGER,
317 'Unbinding NICs %s...' %
318 str(settings.getValue('WHITELIST_NICS')),
320 except subprocess.CalledProcessError:
321 _LOGGER.error('Unable to unbind NICs %s',
322 str(settings.getValue('WHITELIST_NICS')))
325 def _copy_dpdk_for_guest():
326 """Copy dpdk code to GUEST_SHARE_DIR for use by guests.
328 guest_share_dir = os.path.join(
329 settings.getValue('GUEST_SHARE_DIR'), 'DPDK')
331 if not os.path.exists(guest_share_dir):
332 os.makedirs(guest_share_dir)
335 tasks.run_task(['rsync', '-a', '-r', '-l', r'--exclude="\.git"',
336 os.path.join(settings.getValue('RTE_SDK'), ''),
339 'Copying DPDK to shared directory...',
341 except subprocess.CalledProcessError:
342 _LOGGER.error('Unable to copy DPDK to shared directory')
349 def _vhost_user_cleanup():
350 """Remove files created by vhost-user tests.
352 for sock in settings.getValue('VHOST_USER_SOCKS'):
353 if os.path.exists(sock):
355 tasks.run_task(['sudo', 'rm', sock],
357 'Deleting vhost-user socket \'%s\'...' %
361 except subprocess.CalledProcessError:
362 _LOGGER.error('Unable to delete vhost-user socket \'%s\'.',
368 """A context manager for the system init/cleanup.
371 _LOGGER.info('Setting up DPDK')
375 def __exit__(self, type_, value, traceback):
376 _LOGGER.info('Cleaning up DPDK')