Merge "hugepage_doc: Add hugepage configuration info to installation doc"
[vswitchperf.git] / src / dpdk / dpdk.py
index 3f5333a..30f228f 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015 Intel Corporation.
+# Copyright 2015-2016 Intel Corporation.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -21,10 +21,8 @@ DPDK.
 from sys import platform as _platform
 
 import os
-import re
 import subprocess
 import logging
-import locale
 
 from tools import tasks
 from conf import settings
@@ -32,23 +30,28 @@ from tools.module_manager import ModuleManager
 
 _LOGGER = logging.getLogger(__name__)
 RTE_PCI_TOOL = os.path.join(
-    settings.getValue('RTE_SDK'), 'tools', 'dpdk_nic_bind.py')
+    settings.getValue('RTE_SDK_USER'), 'tools', 'dpdk_nic_bind.py')
 
 _DPDK_MODULE_MANAGER = ModuleManager()
 
+# declare global NIC variables only as their content might not be known yet
+_NICS = []
+_NICS_PCI = []
+
 #
 # system management
 #
 
-
 def init():
     """Setup system for DPDK.
     """
+    global _NICS
+    global _NICS_PCI
+    _NICS = settings.getValue('NICS')
+    _NICS_PCI = list(nic['pci'] for nic in _NICS)
     if not _is_linux():
         _LOGGER.error('Not running on a compatible Linux version. Exiting...')
         return
-
-    _mount_hugepages()
     _insert_modules()
     _remove_vhost_net()
     _bind_nics()
@@ -63,34 +66,12 @@ def cleanup():
 
     _unbind_nics()
     _remove_modules()
-    _umount_hugepages()
     _vhost_user_cleanup()
 
-
-#
-# vhost specific modules management
-#
-
-
-def insert_vhost_modules():
-    """Inserts VHOST related kernel modules
-    """
-    mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
-                                   'lib',
-                                   'librte_vhost')
-    _insert_module_group('VHOST_MODULE', mod_path_prefix)
-
-
-def remove_vhost_modules():
-    """Removes all VHOST related kernel modules
-    """
-    _remove_module_group('VHOST_MODULE')
-
 #
 # basic compatibility test
 #
 
-
 def _is_linux():
     """Check if running on Linux.
 
@@ -101,97 +82,10 @@ def _is_linux():
     """
     return _platform.startswith('linux') and os.path.isdir('/proc')
 
-#
-# hugepage management
-#
-
-
-def _is_hugepage_available():
-    """Check if hugepages are available on the system.
-    """
-    hugepage_re = re.compile(r'^HugePages_Free:\s+(?P<num_hp>\d+)$')
-
-    # read in meminfo
-    with open('/proc/meminfo') as mem_file:
-        mem_info = mem_file.readlines()
-
-    # first check if module is loaded
-    for line in mem_info:
-        result = hugepage_re.match(line)
-        if not result:
-            continue
-
-        num_huge = result.group('num_hp')
-        if not num_huge:
-            _LOGGER.info('No free hugepages.')
-        else:
-            _LOGGER.info('Found \'%s\' free hugepage(s).', num_huge)
-        return True
-
-    return False
-
-
-def _is_hugepage_mounted():
-    """Check if hugepages are mounted.
-    """
-    output = subprocess.check_output(['mount'], shell=True)
-    my_encoding = locale.getdefaultlocale()[1]
-    for line in output.decode(my_encoding).split('\n'):
-        if 'hugetlbfs' in line:
-            return True
-
-    return False
-
-
-def _mount_hugepages():
-    """Ensure hugepages are mounted.
-    """
-    if not _is_hugepage_available():
-        return
-
-    if _is_hugepage_mounted():
-        return
-
-    if not os.path.exists(settings.getValue('HUGEPAGE_DIR')):
-        os.makedirs(settings.getValue('HUGEPAGE_DIR'))
-    try:
-        tasks.run_task(['sudo', 'mount', '-t', 'hugetlbfs', 'nodev',
-                        settings.getValue('HUGEPAGE_DIR')],
-                       _LOGGER, 'Mounting hugepages...', True)
-    except subprocess.CalledProcessError:
-        _LOGGER.error('Unable to mount hugepages.')
-
-
-def _umount_hugepages():
-    """Ensure hugepages are unmounted.
-    """
-    if not _is_hugepage_mounted():
-        return
-
-    try:
-        tasks.run_task(['sudo', 'umount', settings.getValue('HUGEPAGE_DIR')],
-                       _LOGGER, 'Unmounting hugepages...', True)
-    except subprocess.CalledProcessError:
-        _LOGGER.error('Unable to umount hugepages.')
-
 #
 # module management
 #
 
-
-def _is_module_inserted(module):
-    """Check if a module is inserted on system.
-    """
-    with open('/proc/modules') as mod_file:
-        loaded_mods = mod_file.readlines()
-
-    # first check if module is loaded
-    for line in loaded_mods:
-        if line.startswith(module):
-            return True
-    return False
-
-
 def _insert_modules():
     """Ensure required modules are inserted on system.
     """
@@ -199,74 +93,49 @@ def _insert_modules():
     _DPDK_MODULE_MANAGER.insert_modules(settings.getValue('SYS_MODULES'))
 
     mod_path_prefix = settings.getValue('OVS_DIR')
-    _insert_module_group('OVS_MODULES', mod_path_prefix)
-    mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
-                                   settings.getValue('RTE_TARGET'))
-    _insert_module_group('DPDK_MODULES', mod_path_prefix)
-
-
-def _insert_module_group(module_group, group_path_prefix):
-    """Ensure all modules in a group are inserted into the system.
-
-    :param module_group: A name of configuration item containing a list
-    of module names
-    """
-    for module in settings.getValue(module_group):
-        # first check if module is loaded
-        if _is_module_inserted(module[1]):
-            continue
-
-        try:
-            mod_path = os.path.join(group_path_prefix, module[0],
-                                    '%s.ko' % module[1])
-            tasks.run_task(['sudo', 'insmod', mod_path], _LOGGER,
-                           'Inserting module \'%s\'...' % module[1], True)
-        except subprocess.CalledProcessError:
-            _LOGGER.error('Unable to insert module \'%s\'.', module[1])
-            raise  # fail catastrophically
-
+    _DPDK_MODULE_MANAGER.insert_module_group(settings.getValue('OVS_MODULES'),
+                                             mod_path_prefix)
+    if 'vfio-pci' not in settings.getValue('DPDK_MODULES'):
+        mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
+                                       settings.getValue('RTE_TARGET'))
+        _DPDK_MODULE_MANAGER.insert_module_group(settings.getValue('DPDK_MODULES'),
+                                                 mod_path_prefix)
+    else:
+        _DPDK_MODULE_MANAGER.insert_modules(settings.getValue('DPDK_MODULES'))
 
 def _remove_modules():
     """Ensure required modules are removed from system.
     """
-    _remove_module_group('OVS_MODULES')
-    _remove_module_group('DPDK_MODULES')
-
     _DPDK_MODULE_MANAGER.remove_modules()
 
-def _remove_module_group(module_group):
-    """Ensure all modules in a group are removed from the system.
+#
+# vhost specific modules management
+#
 
-    :param module_group: A name of configuration item containing a list
-    of module names
+def insert_vhost_modules():
+    """Inserts VHOST related kernel modules
     """
-    for module in settings.getValue(module_group):
-        # first check if module is loaded
-        if not _is_module_inserted(module[1]):
-            continue
+    mod_path_prefix = os.path.join(settings.getValue('RTE_SDK'),
+                                   'lib',
+                                   'librte_vhost')
+    _DPDK_MODULE_MANAGER.insert_module_group(settings.getValue('VHOST_MODULE'), mod_path_prefix)
 
-        try:
-            tasks.run_task(['sudo', 'rmmod', module[1]], _LOGGER,
-                           'Removing module \'%s\'...' % module[1], True)
-        except subprocess.CalledProcessError:
-            _LOGGER.error('Unable to remove module \'%s\'.', module[1])
-            continue
+
+def remove_vhost_modules():
+    """Removes all VHOST related kernel modules
+    """
+    # all modules are removed automatically by _remove_modules() method
+    pass
 
 
 #
-# 'vhost-net' module management
+# 'vhost-net' module cleanup
 #
 
 def _remove_vhost_net():
     """Remove vhost-net driver and file.
     """
-    if _is_module_inserted('vhost_net'):
-        try:
-            tasks.run_task(['sudo', 'rmmod', 'vhost_net'], _LOGGER,
-                           'Removing \'/dev/vhost-net\' directory...', True)
-        except subprocess.CalledProcessError:
-            _LOGGER.error('Unable to remove module \'vhost_net\'.')
-
+    _DPDK_MODULE_MANAGER.remove_module('vhost-net')
     try:
         tasks.run_task(['sudo', 'rm', '-f', '/dev/vhost-net'], _LOGGER,
                        'Removing \'/dev/vhost-net\' directory...', True)
@@ -274,6 +143,26 @@ def _remove_vhost_net():
         _LOGGER.error('Unable to remove directory \'/dev/vhost-net\'.')
 
 #
+# Vhost-user cleanup
+#
+
+def _vhost_user_cleanup():
+    """Remove files created by vhost-user tests.
+    """
+    for sock in settings.getValue('VHOST_USER_SOCKS'):
+        if os.path.exists(sock):
+            try:
+                tasks.run_task(['sudo', 'rm', sock],
+                               _LOGGER,
+                               'Deleting vhost-user socket \'%s\'...' %
+                               sock,
+                               True)
+
+            except subprocess.CalledProcessError:
+                _LOGGER.error('Unable to delete vhost-user socket \'%s\'.',
+                              sock)
+                continue
+#
 # NIC management
 #
 
@@ -282,79 +171,46 @@ def _bind_nics():
     """Bind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
     """
     try:
-        tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind', 'igb_uio'] +
-                       settings.getValue('WHITELIST_NICS'), _LOGGER,
-                       'Binding NICs %s...' %
-                       settings.getValue('WHITELIST_NICS'),
+        _driver = 'igb_uio'
+        if 'vfio-pci' in settings.getValue('DPDK_MODULES'):
+            _driver = 'vfio-pci'
+            tasks.run_task(['sudo', 'chmod', 'a+x', '/dev/vfio'],
+                           _LOGGER, 'Setting VFIO permissions .. a+x',
+                           True)
+            tasks.run_task(['sudo', 'chmod', '-R', '666', '/dev/vfio/'],
+                           _LOGGER, 'Setting VFIO permissions .. 0666',
+                           True)
+
+        tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind=' + _driver] +
+                       _NICS_PCI, _LOGGER,
+                       'Binding NICs %s...' % _NICS_PCI,
                        True)
     except subprocess.CalledProcessError:
-        _LOGGER.error('Unable to bind NICs %s',
-                      str(settings.getValue('WHITELIST_NICS')))
-
-def _unbind_nics_get_driver():
-    """Check what driver the NICs should be bound to
-       after unbinding them from DPDK.
-    """
-    _driver_list = []
-    _output = subprocess.check_output([os.path.expanduser(RTE_PCI_TOOL), '--status'])
-    _my_encoding = locale.getdefaultlocale()[1]
-    for line in _output.decode(_my_encoding).split('\n'):
-        for nic in settings.getValue('WHITELIST_NICS'):
-            if nic in line:
-                _driver_list.append((line.split("unused=", 1)[1]))
-    return _driver_list
+        _LOGGER.error('Unable to bind NICs %s', str(_NICS_PCI))
 
 def _unbind_nics():
     """Unbind NICs using the Intel DPDK ``dpdk_nic_bind.py`` tool.
     """
-    nic_drivers = _unbind_nics_get_driver()
     try:
         tasks.run_task(['sudo', RTE_PCI_TOOL, '--unbind'] +
-                       settings.getValue('WHITELIST_NICS'), _LOGGER,
-                       'Unbinding NICs %s...' %
-                       str(settings.getValue('WHITELIST_NICS')),
+                       _NICS_PCI, _LOGGER,
+                       'Unbinding NICs %s...' % str(_NICS_PCI),
                        True)
     except subprocess.CalledProcessError:
-        _LOGGER.error('Unable to unbind NICs %s',
-                      str(settings.getValue('WHITELIST_NICS')))
+        _LOGGER.error('Unable to unbind NICs %s', str(_NICS_PCI))
     # Rebind NICs to their original drivers
     # using the Intel DPDK ``dpdk_nic_bind.py`` tool.
-    for i, nic in enumerate(settings.getValue('WHITELIST_NICS')):
+    for nic in _NICS:
         try:
-            if nic_drivers[i] != '':
+            if nic['driver']:
                 tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind',
-                                nic_drivers[i], nic],
-                               _LOGGER, 'Binding NIC %s...' %
-                               nic,
+                                nic['driver'], nic['pci']],
+                               _LOGGER, 'Binding NIC %s to %s...' %
+                               (nic['pci'], nic['driver']),
                                True)
         except subprocess.CalledProcessError:
-            _LOGGER.error('Unable to bind NICs %s to drivers %s',
-                          str(settings.getValue('WHITELIST_NICS')),
-                          nic_drivers)
-
-
-
-#
-# Vhost-user cleanup
-#
-
-def _vhost_user_cleanup():
-    """Remove files created by vhost-user tests.
-    """
-    for sock in settings.getValue('VHOST_USER_SOCKS'):
-        if os.path.exists(sock):
-            try:
-                tasks.run_task(['sudo', 'rm', sock],
-                               _LOGGER,
-                               'Deleting vhost-user socket \'%s\'...' %
-                               sock,
-                               True)
-
-            except subprocess.CalledProcessError:
-                _LOGGER.error('Unable to delete vhost-user socket \'%s\'.',
-                              sock)
-                continue
-
+            _LOGGER.error('Unable to bind NIC %s to driver %s',
+                          nic['pci'], nic['driver'])
 
 class Dpdk(object):
     """A context manager for the system init/cleanup.