summaryrefslogtreecommitdiffstats
path: root/src/dpdk
diff options
context:
space:
mode:
authorBilly O'Mahony <billy.o.mahony@intel.com>2015-05-29 15:24:03 +0100
committerBilly O'Mahony <billy.o.mahony@intel.com>2015-06-08 13:55:35 +0000
commit8d6777df09c3dc441013a31f21cc50ab3b0f42a3 (patch)
treed00f189e00631c33385122012727dd3c6438f406 /src/dpdk
parentacd2499310f81565c6b1eb11d18528f7372894f5 (diff)
framework: Add reworked framework to repo
This commit adds the vSwitch Integration Test Framework whose design, based off TOIT, is outlined in the HLD previously made availiable to the community for review. The design of this framework allows developers to add different implementations of components, specifically vSwitches, Traffic Generators, Metrics Collectors and VNFs, easily. The goal of this design is that all testcases should run regardless of what is "under the hood". This commit adds support for running the framework for a phy to phy RFC2544 testcase only. More testcases will be added by the community. vSwitches supported at this time: * Intel DPDK (r) accelerated OpenvSwitch Traffic Generators supported at this time: * IxNet - IxNetwork Implementation * Ixia - IxExplorer Implementation * Dummy - Manual Implementation Metrics Collectors supported at this time: * Linux Metrics No VNFs are supported at this time but the framework outlines how they should be integrated and provides APIs for them to adhere to. JIRA: VSPERF-27 Change-Id: I312e1a1199487ffee8f824be06cd97d4f793eee0 Signed-off-by: Stephen Finucane <Stephen.Finucane@intel.com> Signed-off-by: Meghan Halton <Meghan.Halton@intel.com> Signed-off-by: Christopher Nolan <Christopher.Nolan@intel.com> Signed-off-by: Maryam Tahhan <Maryam.Tahhan@intel.com> Signed-off-by: Ciara Loftus <Ciara.Loftus@intel.com> Signed-off-by: Mark Kavanagh <Mark.B.Kavanagh@intel.com> Signed-off-by: Cian Ferriter <Cian.Ferriter@intel.com> Signed-off-by: Timo Puha <TimoX.Puha@intel.com> Signed-off-by: Billy O'Mahony <billy.o.mahony@intel.com> Signed-off-by: Michal Weglicki <MichalX.Weglicki@intel.com> Signed-off-by: Rory Sexton <Rory.Sexton@intel.com> Signed-off-by: Ian Stokes <Ian.Stokes@intel.com> Signed-off-by: Kevin Traynor <Kevin.Traynor@intel.com> Signed-off-by: Dino Simeon Madarang <dino.simeonx.madarang@intel.com> Reviewed-by: Eugene Snider <Eugene.Snider@huawei.com> Reviewed-by: Aihua Li <aihua.li@huawei.com>
Diffstat (limited to 'src/dpdk')
-rw-r--r--src/dpdk/__init__.py21
-rw-r--r--src/dpdk/dpdk.py377
2 files changed, 398 insertions, 0 deletions
diff --git a/src/dpdk/__init__.py b/src/dpdk/__init__.py
new file mode 100644
index 00000000..4be1e215
--- /dev/null
+++ b/src/dpdk/__init__.py
@@ -0,0 +1,21 @@
+# Copyright 2015 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""A collection of functions for automating the DPDK setup and teardown.
+
+These automation tasks include mounting/unmounting hugepages, inserting
+and removing drivers and binding/unbinding NICs.
+"""
+
+from src.dpdk.dpdk import *
diff --git a/src/dpdk/dpdk.py b/src/dpdk/dpdk.py
new file mode 100644
index 00000000..9b3d1385
--- /dev/null
+++ b/src/dpdk/dpdk.py
@@ -0,0 +1,377 @@
+# Copyright 2015 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Automation of system configuration for DPDK use.
+
+Parts of this based on ``tools/pci_unbind.py`` script from Intel(R) 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
+
+_LOGGER = logging.getLogger(__name__)
+RTE_PCI_TOOL = os.path.join(
+ settings.getValue('RTE_SDK'), 'tools', 'dpdk_nic_bind.py')
+
+#
+# system management
+#
+
+
+def init():
+ """Setup system for DPDK.
+ """
+ if not _is_linux():
+ _LOGGER.error('Not running on a compatible Linux version. Exiting...')
+ return
+
+ _mount_hugepages()
+ _insert_modules()
+ _remove_vhost_net()
+ _bind_nics()
+ _copy_dpdk_for_guest()
+
+
+def cleanup():
+ """Setup system for DPDK.
+ """
+ if not _is_linux():
+ _LOGGER.error('Not running on a compatible Linux version. Exiting...')
+ return
+
+ _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.
+
+ Many of the functions in this file rely on features commonly found
+ only on Linux (i.e. ``/proc`` is not present on FreeBSD). Hence, this
+ check is important to ensure someone doesn't run this on an incompatible
+ OS or distro.
+ """
+ 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.
+ """
+ for module in settings.getValue('SYS_MODULES'):
+ if _is_module_inserted(module):
+ continue
+
+ try:
+ tasks.run_task(['sudo', 'modprobe', module], _LOGGER,
+ 'Inserting module \'%s\'...' % module, True)
+ except subprocess.CalledProcessError:
+ _LOGGER.error('Unable to insert module \'%s\'.', module)
+ raise # fail catastrophically
+
+ 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
+
+
+def _remove_modules():
+ """Ensure required modules are removed from system.
+ """
+ _remove_module_group('OVS_MODULES')
+ _remove_module_group('DPDK_MODULES')
+
+ for module in settings.getValue('SYS_MODULES'):
+ # first check if module is loaded
+ if not _is_module_inserted(module):
+ continue
+
+ try:
+ tasks.run_task(['sudo', 'rmmod', module], _LOGGER,
+ 'Removing module \'%s\'...' % module, True)
+ except subprocess.CalledProcessError:
+ _LOGGER.error('Unable to remove module \'%s\'.', module)
+ continue
+
+
+def _remove_module_group(module_group):
+ """Ensure all modules in a group are removed from 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 not _is_module_inserted(module[1]):
+ continue
+
+ 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
+
+
+#
+# 'vhost-net' module management
+#
+
+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\'.')
+
+ try:
+ tasks.run_task(['sudo', 'rm', '-f', '/dev/vhost-net'], _LOGGER,
+ 'Removing \'/dev/vhost-net\' directory...', True)
+ except subprocess.CalledProcessError:
+ _LOGGER.error('Unable to remove directory \'/dev/vhost-net\'.')
+
+#
+# NIC management
+#
+
+
+def _bind_nics():
+ """Bind NICs using the Intel DPDK ``pci_unbind.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'),
+ True)
+ except subprocess.CalledProcessError:
+ _LOGGER.error('Unable to bind NICs %s',
+ str(settings.getValue('WHITELIST_NICS')))
+
+
+def _unbind_nics():
+ """Unbind NICs using the Intel DPDK ``pci_unbind.py`` tool.
+ """
+ try:
+ tasks.run_task(['sudo', RTE_PCI_TOOL, '--unbind'] +
+ settings.getValue('WHITELIST_NICS'), _LOGGER,
+ 'Unbinding NICs %s...' %
+ str(settings.getValue('WHITELIST_NICS')),
+ True)
+ except subprocess.CalledProcessError:
+ _LOGGER.error('Unable to unbind NICs %s',
+ str(settings.getValue('WHITELIST_NICS')))
+
+
+def _copy_dpdk_for_guest():
+ """Copy dpdk code to GUEST_SHARE_DIR for use by guests.
+ """
+ guest_share_dir = os.path.join(
+ settings.getValue('GUEST_SHARE_DIR'), 'DPDK')
+
+ if not os.path.exists(guest_share_dir):
+ os.makedirs(guest_share_dir)
+
+ try:
+ tasks.run_task(['rsync', '-a', '-r', '-l', r'--exclude="\.git"',
+ os.path.join(settings.getValue('RTE_SDK'), ''),
+ guest_share_dir],
+ _LOGGER,
+ 'Copying DPDK to shared directory...',
+ True)
+ except subprocess.CalledProcessError:
+ _LOGGER.error('Unable to copy DPDK to shared directory')
+
+
+#
+# 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
+
+
+class Dpdk(object):
+ """A context manager for the system init/cleanup.
+ """
+ def __enter__(self):
+ _LOGGER.info('Setting up DPDK')
+ init()
+ return self
+
+ def __exit__(self, type_, value, traceback):
+ _LOGGER.info('Cleaning up DPDK')
+ cleanup()