summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Klozik <martinx.klozik@intel.com>2016-08-26 15:39:29 +0100
committerMartin Klozik <martinx.klozik@intel.com>2016-09-15 14:37:44 +0100
commit9b1af783ec53050129239102355e1a5c3ceb1d97 (patch)
tree4a994af7b986af3c72c21c0ac87f398b42a44b74
parentacdb444a54124834acdde45107062eaf1452c119 (diff)
paths: Support binary packages
Currently VSPERF supports OVS, DPDK and QEMU built from the source code only. In some cases it is required to support installation of these tools from binary packages available for given linux distribution. Thus VSPERF configuration and code was modified to suport both source and binary versions of tools. This can be configured perf tool, so various combinations of source and binary version are supported. Together with new configuration also a handling of kernel modules was modified to automatically detect and load module dependencies. JIRA: VSPERF-340 JIRA: VSPERF-339 Change-Id: I855cb438cbd8998bdc499613ea5e7de2526299d7 Signed-off-by: Martin Klozik <martinx.klozik@intel.com> Reviewed-by: Maryam Tahhan <maryam.tahhan@intel.com> Reviewed-by: Al Morton <acmorton@att.com> Reviewed-by: Christian Trautman <ctrautma@redhat.com> Reviewed-by: Bill Michalowski <bmichalo@redhat.com> Reviewed-by: Otto Sabart <osabart@redhat.com>
-rw-r--r--conf/00_common.conf54
-rw-r--r--conf/02_vswitch.conf113
-rw-r--r--conf/04_vnf.conf14
-rwxr-xr-xdocs/design/vswitchperf_design.rst158
-rwxr-xr-xdocs/userguide/integration.rst44
-rwxr-xr-xdocs/userguide/testusage.rst13
-rw-r--r--src/dpdk/dpdk.py51
-rw-r--r--src/dpdk/testpmd_proc.py6
-rw-r--r--src/ovs/dpctl.py5
-rw-r--r--src/ovs/ofctl.py17
-rw-r--r--testcases/testcase.py20
-rw-r--r--tools/functions.py124
-rw-r--r--tools/module_manager.py50
-rw-r--r--tools/networkcard.py2
-rw-r--r--tools/report/report.py5
-rw-r--r--tools/systeminfo.py104
-rw-r--r--vnfs/qemu/qemu.py2
-rw-r--r--vnfs/qemu/qemu_dpdk_vhost_user.py2
-rw-r--r--vnfs/qemu/qemu_pci_passthrough.py6
-rw-r--r--vswitches/ovs.py81
-rw-r--r--vswitches/ovs_dpdk_vhost.py3
-rw-r--r--vswitches/ovs_vanilla.py9
22 files changed, 635 insertions, 248 deletions
diff --git a/conf/00_common.conf b/conf/00_common.conf
index fe4e1f5d..7f30deb2 100644
--- a/conf/00_common.conf
+++ b/conf/00_common.conf
@@ -17,6 +17,7 @@
# ###########################
import os
+import copy
# default language and encoding, which will be set in case
# that locale is not set properly
@@ -36,14 +37,51 @@ ROOT_DIR = os.path.normpath(os.path.join(
TRAFFICGEN_DIR = os.path.join(ROOT_DIR, 'tools/pkt_gen')
SYSMETRICS_DIR = os.path.join(ROOT_DIR, 'tools/collectors')
-# deployment specific paths to OVS and DPDK
-OVS_DIR_VANILLA = os.path.join(ROOT_DIR, 'src_vanilla/ovs/ovs/')
-
-RTE_SDK_USER = os.path.join(ROOT_DIR, 'src/dpdk/dpdk/')
-OVS_DIR_USER = os.path.join(ROOT_DIR, 'src/ovs/ovs/')
-
-# the same qemu version is used for vanilla and vHost User
-QEMU_DIR = os.path.join(ROOT_DIR, 'src/qemu/qemu/')
+# Dictionary PATHS is used for configuration of vswitches, dpdk and qemu.
+# It contains paths to various utilities, temporary directories and kernel
+# modules used by VSPERF. Particular sections of PATHS dictionary are spread
+# among several configuration files, i.e.:
+# conf/02_vswtich.conf - configuration of vswitches (i.e. PATHS['vswitch'])
+# and dpdk (i.e. PATHS['dpdk']) can be found there
+# conf/04_vnf.conf - configuration of qemu (i.e. PATHS['qemu']) can
+# be found there
+#
+# VSPERF will process PATHS dictionary before execution of every testcase
+# and it will create a testcase specific dictionary TOOLS with paths to the
+# utilities used by the test. During PATHS processing, following rules
+# will apply for every item of PATHS dictionary:
+# item 'type' - string, which defines the type of paths ('src' or 'bin') to be selected
+# for a given section:
+# 'src' means, that VSPERF will use OVS, DPDK or QEMU built from sources
+# e.g. by execution of systems/build_base_machine.sh script during VSPERF
+# installation
+# 'bin' means, that VSPERF will use OVS, DPDK or QEMU binaries installed
+# in the OS, e.g. via OS specific packaging system
+# item 'path' - string with valid path; Its content is checked for existence, prefixed
+# with section name and stored into TOOLS for later use
+# e.g. TOOLS['dpdk_src'] or TOOLS['vswitch_src']
+# item 'modules' - list of strings; Every value from given list is checked for '.ko'
+# suffix. In case it matches and it is not an absolute path to the module, then
+# module name is prefixed with 'path' defined for the same section
+# e.g. TOOLS['vswitch_modules'] = [
+# '/tmp/vsperf/src_vanilla/ovs/ovs/datapath/linux/openvswitch.ko']
+# all other items - string - if given string is a relative path and item 'path'
+# is defined for a given section, then item content will be prefixed with
+# content of the 'path'. Otherwise tool name will be searched within
+# standard system directories. Also any OS filename wildcards will be
+# expanded to the real path. At the end of processing, every absolute
+# path is checked for its existence. In case that temporary path (i.e. path
+# with '_tmp' suffix) doesn't exist, then log will be written and vsperf will
+# continue. If any other path will not exist, then vsperf execution will
+# be terminated with runtime error.
+#
+# Note: In case that 'bin' type is set for DPDK, then TOOLS['dpdk_src'] will be set to
+# the value of PATHS['dpdk']['src']['path']. The reason is, that VSPERF uses downloaded
+# DPDK sources to copy DPDK and testpmd into the GUEST, where testpmd is built. In case,
+# that DPDK sources are not available, then vsperf will continue with test execution,
+# but testpmd can't be used as a guest loopback. This is useful in case, that other guest
+# loopback applications (e.g. buildin) are used by CI jobs, etc.
+PATHS = {}
# ############################
# Process configuration
diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf
index abca63bb..e504d3ad 100644
--- a/conf/02_vswitch.conf
+++ b/conf/02_vswitch.conf
@@ -13,18 +13,6 @@
# limitations under the License.
# ############################
-# Directories
-# ############################
-# use DPDK VHOST USER by default
-RTE_SDK = RTE_SDK_USER
-OVS_DIR = OVS_DIR_USER
-
-OVS_VAR_DIR = '/usr/local/var/run/openvswitch/'
-OVS_ETC_DIR = '/usr/local/etc/openvswitch/'
-
-VSWITCH_DIR = os.path.join(ROOT_DIR, 'vswitches')
-
-# ############################
# DPDK configuration
# ############################
@@ -38,29 +26,83 @@ RTE_TARGET = 'x86_64-native-linuxapp-gcc'
# will be used for testing
WHITELIST_NICS = ['0000:05:00.0', '0000:05:00.1']
-# for DPDK_MODULES the path is in reference to the build directory
-# To use vfio set
-# DPDK_MODULES = [
-# ('vfio-pci'),
-# ]
-DPDK_MODULES = [
- ('kmod', 'igb_uio'),
-]
+# vhost character device file used by dpdkvhostport QemuWrap cases
+VHOST_DEV_FILE = 'ovs-vhost-net'
-VHOST_MODULE = [
- ('eventfd_link', 'eventfd_link')
-]
+# location of vhost-user sockets relative to 'ovs_var_tmp'
+VHOST_USER_SOCKS = 'dpdkvhostuser*'
+
+# please see conf/00_common.conf for description of PATHS dictionary
+PATHS['dpdk'] = {
+ 'type' : 'src',
+ 'src': {
+ 'path': os.path.join(ROOT_DIR, 'src/dpdk/dpdk/'),
+ # To use vfio set:
+ # 'modules' : ['uio', 'vfio-pci'],
+ 'modules' : ['uio', os.path.join(RTE_TARGET, 'kmod/igb_uio.ko')],
+ 'bind-tool': 'tools/dpdk*bind.py',
+ 'testpmd': os.path.join(RTE_TARGET, 'app', 'testpmd'),
+ },
+ 'bin': {
+ 'bind-tool': '/usr/share/dpdk/tools/dpdk*bind.py',
+ 'modules' : ['uio', 'igb_uio'],
+ 'testpmd' : 'testpmd'
+ }
+ }
-# list of modules that will be inserted using 'modprobe' on system init
-# To use vfio set
-# SYS_MODULES = ['cuse']
-SYS_MODULES = ['uio', 'cuse']
+# ############################
+# Directories
+# ############################
+VSWITCH_DIR = os.path.join(ROOT_DIR, 'vswitches')
-# vhost character device file used by dpdkvhostport QemuWrap cases
-VHOST_DEV_FILE = 'ovs-vhost-net'
+# please see conf/00_common.conf for description of PATHS dictionary
+# Every vswitch type supported by VSPERF must have its configuration
+# stored inside PATHS['vswitch']. List of all supported vswitches
+# can be obtained by call of ./vsperf --list-vswitches
+#
+# Directories defined by "ovs_var_tmp" and "ovs_etc_tmp" will be used
+# by OVS to temporarily store its configuration, pid and socket files.
+# In case, that these directories exist already, then their original
+# content will be restored after the testcase execution.
+
+PATHS['vswitch'] = {
+ 'none' : { # used by SRIOV tests
+ 'type' : 'src',
+ 'src' : {},
+ },
+ 'OvsDpdkVhost': {
+ 'type' : 'src',
+ 'src': {
+ 'path': os.path.join(ROOT_DIR, 'src/ovs/ovs/'),
+ 'ovs-vswitchd': 'vswitchd/ovs-vswitchd',
+ 'ovsdb-server': 'ovsdb/ovsdb-server',
+ 'ovsdb-tool': 'ovsdb/ovsdb-tool',
+ 'ovsschema': 'vswitchd/vswitch.ovsschema',
+ 'ovs-vsctl': 'utilities/ovs-vsctl',
+ 'ovs-ofctl': 'utilities/ovs-ofctl',
+ 'ovs-dpctl': 'utilities/ovs-dpctl',
+ 'ovs-appctl': 'utilities/ovs-appctl',
+ },
+ 'bin': {
+ 'ovs-vswitchd': 'ovs-vswitchd',
+ 'ovsdb-server': 'ovsdb-server',
+ 'ovsdb-tool': 'ovsdb-tool',
+ 'ovsschema': '/usr/share/openvswitch/vswitch.ovsschema',
+ 'ovs-vsctl': 'ovs-vsctl',
+ 'ovs-ofctl': 'ovs-ofctl',
+ 'ovs-dpctl': 'ovs-dpctl',
+ 'ovs-appctl': 'ovs-appctl',
+ }
+ },
+ 'ovs_var_tmp': '/usr/local/var/run/openvswitch/',
+ 'ovs_etc_tmp': '/usr/local/etc/openvswitch/',
+}
-# location of vhost-user sockets
-VHOST_USER_SOCKS = os.path.join(OVS_VAR_DIR, 'dpdkvhostuser*')
+# default OvsVanilla configuration is similar to OvsDpdkVhost except 'path' and 'modules'
+PATHS['vswitch'].update({'OvsVanilla' : copy.deepcopy(PATHS['vswitch']['OvsDpdkVhost'])})
+PATHS['vswitch']['OvsVanilla']['src']['path'] = os.path.join(ROOT_DIR, 'src_vanilla/ovs/ovs/')
+PATHS['vswitch']['OvsVanilla']['src']['modules'] = ['datapath/linux/openvswitch.ko']
+PATHS['vswitch']['OvsVanilla']['bin']['modules'] = ['openvswitch']
# ############################
# vswitch configuration
@@ -93,9 +135,6 @@ OVS_OLD_STYLE_MQ = False
# parameters passed to ovs-vswitchd in case that OvsVanilla is selected
VSWITCHD_VANILLA_ARGS = []
-# use full module path to load module matching OVS version built from the source
-VSWITCH_VANILLA_KERNEL_MODULES = ['libcrc32c', 'ip_tunnel', 'vxlan', 'gre', 'nf_conntrack', 'nf_defrag_ipv4', 'nf_defrag_ipv6', os.path.join(OVS_DIR_VANILLA, 'datapath/linux/openvswitch.ko')]
-
# Bridge name to be used by VSWTICH
VSWITCH_BRIDGE_NAME = 'br0'
@@ -114,12 +153,6 @@ VSWITCH_AFFINITIZATION_ON = 1
VSWITCH_FLOW_TIMEOUT = '30000'
-# list of tuples of format (path, module_name), which will be inserted
-# using 'insmod' on system init
-
-# for OVS modules the path is in reference to the OVS directory.
-OVS_MODULES = []
-
# log file for ovs-vswitchd
LOG_FILE_VSWITCHD = 'vswitchd.log'
diff --git a/conf/04_vnf.conf b/conf/04_vnf.conf
index 2e86b358..dcdf3316 100644
--- a/conf/04_vnf.conf
+++ b/conf/04_vnf.conf
@@ -20,10 +20,20 @@ VNF = 'QemuDpdkVhostUser'
VNF_AFFINITIZATION_ON = True
# ############################
-# Executables and log files
+# Directories, executables and log files
# ############################
-QEMU_BIN = os.path.join(QEMU_DIR, 'x86_64-softmmu/qemu-system-x86_64')
+# please see conf/00_common.conf for description of PATHS dictionary
+PATHS['qemu'] = {
+ 'type' : 'src',
+ 'src': {
+ 'path': os.path.join(ROOT_DIR, 'src/qemu/qemu/'),
+ 'qemu-system': 'x86_64-softmmu/qemu-system-x86_64'
+ },
+ 'bin': {
+ 'qemu-system': 'qemu-system-x86_64'
+ }
+}
# log file for qemu
LOG_FILE_QEMU = 'qemu.log'
diff --git a/docs/design/vswitchperf_design.rst b/docs/design/vswitchperf_design.rst
index cdf9f318..375fa12e 100755
--- a/docs/design/vswitchperf_design.rst
+++ b/docs/design/vswitchperf_design.rst
@@ -100,6 +100,164 @@ The values in the file specified by ``--conf-file`` takes precedence over all
the other configuration files and does not have to follow the naming
convention.
+Configuration of PATHS dictionary
+---------------------------------
+
+VSPERF uses external tools like Open vSwitch and Qemu for execution of testcases. These
+tools may be downloaded and built automatically by `VSPERF installation scripts`_
+or installed manually by user from binary packages. It is also possible to use a combination
+of both approaches, but it is essential to correctly set paths to all required tools.
+These paths are stored within a PATHS dictionary, which is evaluated before execution
+of each testcase, in order to setup testcase specific environment. Values selected for testcase
+execution are internally stored inside TOOLS dictionary, which is used by VSPERF to execute
+external tools, load kernel modules, etc.
+
+The default configuration of PATHS dictionary is spread among three different configuration files
+to follow logical grouping of configuration options. Basic description of PATHS dictionary
+is placed inside ``conf/00_common.conf``. The configuration specific to DPDK and vswitches
+is located at ``conf/02_vswitch.conf``. The last part related to the Qemu is defined inside
+``conf/04_vnf.conf``. Default configuration values can be used in case, that all required
+tools were downloaded and built automatically by vsperf itself. In case, that some of
+tools were installed manually from binary packages, then it will be necessary to modify
+the content of PATHS dictionary accordingly.
+
+Dictionary has a specific section of configuration options for every tool type, it means:
+
+ * ``PATHS['vswitch']`` - contains a separete dictionary for each of vswitches supported by VSPEF
+
+ Example:
+
+ .. code-block:: python
+
+ PATHS['vswitch'] = {
+ 'OvsDpdkVhost': { ... },
+ 'OvsVanilla' : { ... },
+ ...
+ }
+
+ * ``PATHS['dpdk']`` - contains paths to the dpdk sources, kernel modules and tools (e.g. testpmd)
+
+ Example:
+
+ .. code-block:: python
+
+ PATHS['dpdk'] = {
+ 'type' : 'src',
+ 'src': {
+ 'path': os.path.join(ROOT_DIR, 'src/dpdk/dpdk/'),
+ 'modules' : ['uio', os.path.join(RTE_TARGET, 'kmod/igb_uio.ko')],
+ 'bind-tool': 'tools/dpdk*bind.py',
+ 'testpmd': os.path.join(RTE_TARGET, 'app', 'testpmd'),
+ },
+ ...
+ }
+
+ * ``PATHS['qemu']`` - contains paths to the qemu sources and executable file
+
+ Example:
+
+ .. code-block:: python
+
+ PATHS['qemu'] = {
+ 'type' : 'bin',
+ 'bin': {
+ 'qemu-system': 'qemu-system-x86_64'
+ },
+ ...
+ }
+
+Every section specific to the particular vswitch, dpdk or qemu may contain following types
+of configuration options:
+
+ * option ``type`` - is a string, which defines the type of configured paths ('src' or 'bin')
+ to be selected for a given section:
+
+ * value ``src`` means, that VSPERF will use vswitch, DPDK or QEMU built from sources
+ e.g. by execution of ``systems/build_base_machine.sh`` script during VSPERF
+ installation
+
+ * value ``bin`` means, that VSPERF will use vswitch, DPDK or QEMU binaries installed
+ directly in the operating system, e.g. via OS specific packaging system
+
+ * option ``path`` - is a string with a valid system path; Its content is checked for
+ existence, prefixed with section name and stored into TOOLS for later use
+ e.g. ``TOOLS['dpdk_src']`` or ``TOOLS['vswitch_src']``
+
+ * option ``modules`` - is list of strings with names of kernel modules; Every module name
+ from given list is checked for a '.ko' suffix. In case that it matches and if it is not
+ an absolute path to the module, then module name is prefixed with value of ``path``
+ option defined for the same section
+
+ Example:
+
+ .. code-block:: python
+
+ """
+ snippet of PATHS definition from the configuration file:
+ """
+ PATHS['vswitch'] = {
+ 'OvsVanilla' = {
+ 'type' : 'src',
+ 'src': {
+ 'path': '/tmp/vsperf/src_vanilla/ovs/ovs/',
+ 'modules' : ['datapath/linux/openvswitch.ko'],
+ ...
+ },
+ ...
+ }
+ ...
+ }
+
+ """
+ Final content of TOOLS dictionary used during runtime:
+ """
+ TOOLS['vswitch_modules'] = ['/tmp/vsperf/src_vanilla/ovs/ovs/datapath/linux/openvswitch.ko']
+
+ * all other options are strings with names and paths to specific tools; If a given string
+ contains a relative path and option ``path`` is defined for a given section, then string
+ content will be prefixed with content of the ``path``. Otherwise the name of the tool will be
+ searched within standard system directories. In case that filename contains OS specific
+ wildcards, then they will be expanded to the real path. At the end of the processing, every
+ absolute path will be checked for its existence. In case that temporary path (i.e. path with
+ a ``_tmp`` suffix) does not exist, then log will be written and vsperf will continue. If any
+ other path will not exist, then vsperf execution will be terminated with a runtime error.
+
+ Example:
+
+ .. code-block:: python
+
+ """
+ snippet of PATHS definition from the configuration file:
+ """
+ PATHS['vswitch'] = {
+ 'OvsDpdkVhost': {
+ 'type' : 'src',
+ 'src': {
+ 'path': '/tmp/vsperf/src_vanilla/ovs/ovs/',
+ 'ovs-vswitchd': 'vswitchd/ovs-vswitchd',
+ 'ovsdb-server': 'ovsdb/ovsdb-server',
+ ...
+ }
+ ...
+ }
+ ...
+ }
+
+ """
+ Final content of TOOLS dictionary used during runtime:
+ """
+ TOOLS['ovs-vswitchd'] = '/tmp/vsperf/src_vanilla/ovs/ovs/vswitchd/ovs-vswitchd'
+ TOOLS['ovsdb-server'] = '/tmp/vsperf/src_vanilla/ovs/ovs/ovsdb/ovsdb-server'
+
+Note: In case that ``bin`` type is set for DPDK, then ``TOOLS['dpdk_src']`` will be set to
+the value of ``PATHS['dpdk']['src']['path']``. The reason is, that VSPERF uses downloaded
+DPDK sources to copy DPDK and testpmd into the GUEST, where testpmd is built. In case,
+that DPDK sources are not available, then vsperf will continue with test execution,
+but testpmd can't be used as a guest loopback. This is useful in case, that other guest
+loopback applications (e.g. buildin or l2fwd) are used.
+
+.. _VSPERF installation scripts: http://artifacts.opnfv.org/vswitchperf/docs/configguide/installation.html#other-requirements
+
Configuration of GUEST options
------------------------------
diff --git a/docs/userguide/integration.rst b/docs/userguide/integration.rst
index 51c2f241..b0926d89 100755
--- a/docs/userguide/integration.rst
+++ b/docs/userguide/integration.rst
@@ -509,11 +509,15 @@ To run OVS NATIVE tunnel tests (VXLAN/GRE/GENEVE):
VSWITCH = 'OvsVanilla'
# Specify vport_* kernel module to test.
- VSWITCH_VANILLA_KERNEL_MODULES = ['vport_vxlan',
- 'vport_gre',
- 'vport_geneve',
- os.path.join(OVS_DIR_VANILLA,
- 'datapath/linux/openvswitch.ko')]
+ PATHS['vswitch']['OvsVanilla']['src']['modules'] = [
+ 'vport_vxlan',
+ 'vport_gre',
+ 'vport_geneve',
+ 'datapath/linux/openvswitch.ko',
+ ]
+
+ **NOTE:** In case, that Vanilla OVS is installed from binary package, then
+ please set ``PATHS['vswitch']['OvsVanilla']['bin']['modules']`` instead.
3. Run tests:
@@ -674,9 +678,10 @@ To run VXLAN decapsulation tests:
.. code-block:: python
- VSWITCH_VANILLA_KERNEL_MODULES = ['vport_vxlan',
- os.path.join(OVS_DIR_VANILLA,
- 'datapath/linux/openvswitch.ko')]
+ PATHS['vswitch']['OvsVanilla']['src']['modules'] = [
+ 'vport_vxlan',
+ 'datapath/linux/openvswitch.ko',
+ ]
DUT_NIC1_MAC = '<DUT NIC1 MAC ADDRESS>'
@@ -714,6 +719,9 @@ To run VXLAN decapsulation tests:
'inner_dstport': 3001,
}
+ **NOTE:** In case, that Vanilla OVS is installed from binary package, then
+ please set ``PATHS['vswitch']['OvsVanilla']['bin']['modules']`` instead.
+
2. Run test:
.. code-block:: console
@@ -730,9 +738,10 @@ To run GRE decapsulation tests:
.. code-block:: python
- VSWITCH_VANILLA_KERNEL_MODULES = ['vport_gre',
- os.path.join(OVS_DIR_VANILLA,
- 'datapath/linux/openvswitch.ko')]
+ PATHS['vswitch']['OvsVanilla']['src']['modules'] = [
+ 'vport_gre',
+ 'datapath/linux/openvswitch.ko',
+ ]
DUT_NIC1_MAC = '<DUT NIC1 MAC ADDRESS>'
@@ -769,6 +778,9 @@ To run GRE decapsulation tests:
'inner_dstport': 3001,
}
+ **NOTE:** In case, that Vanilla OVS is installed from binary package, then
+ please set ``PATHS['vswitch']['OvsVanilla']['bin']['modules']`` instead.
+
2. Run test:
.. code-block:: console
@@ -785,9 +797,10 @@ To run GENEVE decapsulation tests:
.. code-block:: python
- VSWITCH_VANILLA_KERNEL_MODULES = ['vport_geneve',
- os.path.join(OVS_DIR_VANILLA,
- 'datapath/linux/openvswitch.ko')]
+ PATHS['vswitch']['OvsVanilla']['src']['modules'] = [
+ 'vport_geneve',
+ 'datapath/linux/openvswitch.ko',
+ ]
DUT_NIC1_MAC = '<DUT NIC1 MAC ADDRESS>'
@@ -824,6 +837,9 @@ To run GENEVE decapsulation tests:
'inner_dstport': 3001,
}
+ **NOTE:** In case, that Vanilla OVS is installed from binary package, then
+ please set ``PATHS['vswitch']['OvsVanilla']['bin']['modules']`` instead.
+
2. Run test:
.. code-block:: console
diff --git a/docs/userguide/testusage.rst b/docs/userguide/testusage.rst
index ce647c6b..3c5cc4d4 100755
--- a/docs/userguide/testusage.rst
+++ b/docs/userguide/testusage.rst
@@ -306,15 +306,16 @@ To run tests using Vanilla OVS:
Using vfio_pci with DPDK
^^^^^^^^^^^^^^^^^^^^^^^^^
-To use vfio with DPDK instead of igb_uio edit 'conf/02_vswitch.conf'
-with the following parameters:
+To use vfio with DPDK instead of igb_uio add into your custom configuration
+file the following parameter:
.. code-block:: console
- DPDK_MODULES = [
- ('vfio-pci'),
- ]
- SYS_MODULES = ['cuse']
+ PATHS['dpdk']['src']['modules'] = ['uio', 'vfio-pci']
+
+
+**NOTE:** In case, that DPDK is installed from binary package, then please
+set ``PATHS['dpdk']['bin']['modules']`` instead.
**NOTE:** Please ensure that Intel VT-d is enabled in BIOS.
diff --git a/src/dpdk/dpdk.py b/src/dpdk/dpdk.py
index bd9bb9cf..16223915 100644
--- a/src/dpdk/dpdk.py
+++ b/src/dpdk/dpdk.py
@@ -25,13 +25,11 @@ import subprocess
import logging
import glob
-from conf import settings
+from conf import settings as S
from tools import tasks
from tools.module_manager import ModuleManager
_LOGGER = logging.getLogger(__name__)
-RTE_PCI_TOOL = glob.glob(os.path.join(
- settings.getValue('RTE_SDK_USER'), 'tools', 'dpdk*bind.py'))[0]
_DPDK_MODULE_MANAGER = ModuleManager()
@@ -48,7 +46,7 @@ def init():
"""
global _NICS
global _NICS_PCI
- _NICS = settings.getValue('NICS')
+ _NICS = S.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...')
@@ -91,18 +89,7 @@ def _insert_modules():
"""Ensure required modules are inserted on system.
"""
- _DPDK_MODULE_MANAGER.insert_modules(settings.getValue('SYS_MODULES'))
-
- mod_path_prefix = settings.getValue('OVS_DIR')
- _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'))
+ _DPDK_MODULE_MANAGER.insert_modules(S.getValue('TOOLS')['dpdk_modules'])
def _remove_modules():
"""Ensure required modules are removed from system.
@@ -110,26 +97,6 @@ def _remove_modules():
_DPDK_MODULE_MANAGER.remove_modules()
#
-# 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')
- _DPDK_MODULE_MANAGER.insert_module_group(settings.getValue('VHOST_MODULE'), mod_path_prefix)
-
-
-def remove_vhost_modules():
- """Removes all VHOST related kernel modules
- """
- # all modules are removed automatically by _remove_modules() method
- pass
-
-
-#
# 'vhost-net' module cleanup
#
@@ -150,7 +117,8 @@ def _remove_vhost_net():
def _vhost_user_cleanup():
"""Remove files created by vhost-user tests.
"""
- for sock in glob.glob(settings.getValue('VHOST_USER_SOCKS')):
+ for sock in glob.glob(os.path.join(S.getValue('TOOLS')['ovs_var_tmp'],
+ S.getValue('VHOST_USER_SOCKS'))):
if os.path.exists(sock):
try:
tasks.run_task(['sudo', 'rm', sock],
@@ -173,7 +141,7 @@ def _bind_nics():
"""
try:
_driver = 'igb_uio'
- if 'vfio-pci' in settings.getValue('DPDK_MODULES'):
+ if 'vfio-pci' in S.getValue('TOOLS')['dpdk_modules']:
_driver = 'vfio-pci'
tasks.run_task(['sudo', 'chmod', 'a+x', '/dev/vfio'],
_LOGGER, 'Setting VFIO permissions .. a+x',
@@ -182,7 +150,8 @@ def _bind_nics():
_LOGGER, 'Setting VFIO permissions .. 0666',
True)
- tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind=' + _driver] +
+ tasks.run_task(['sudo', S.getValue('TOOLS')['bind-tool'],
+ '--bind=' + _driver] +
_NICS_PCI, _LOGGER,
'Binding NICs %s...' % _NICS_PCI,
True)
@@ -193,7 +162,7 @@ def _unbind_nics():
"""Unbind NICs using the Intel DPDK ``dpdk*bind.py`` tool.
"""
try:
- tasks.run_task(['sudo', RTE_PCI_TOOL, '--unbind'] +
+ tasks.run_task(['sudo', S.getValue('TOOLS')['bind-tool'], '--unbind'] +
_NICS_PCI, _LOGGER,
'Unbinding NICs %s...' % str(_NICS_PCI),
True)
@@ -204,7 +173,7 @@ def _unbind_nics():
for nic in _NICS:
try:
if nic['driver']:
- tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind',
+ tasks.run_task(['sudo', S.getValue('TOOLS')['bind-tool'], '--bind',
nic['driver'], nic['pci']],
_LOGGER, 'Binding NIC %s to %s...' %
(nic['pci'], nic['driver']),
diff --git a/src/dpdk/testpmd_proc.py b/src/dpdk/testpmd_proc.py
index 990ef8da..a8fa8eee 100644
--- a/src/dpdk/testpmd_proc.py
+++ b/src/dpdk/testpmd_proc.py
@@ -27,10 +27,6 @@ from tools import tasks
_TESTPMD_PROMPT = 'Done'
-_TESTPMD_BIN = os.path.join(
- settings.getValue('RTE_SDK'), settings.getValue('RTE_TARGET'),
- 'app', 'testpmd')
-
_LOG_FILE_VSWITCHD = os.path.join(
settings.getValue('LOG_DIR'), settings.getValue('LOG_FILE_VSWITCHD'))
@@ -57,7 +53,7 @@ class TestPMDProcess(tasks.Process):
if not self._expect:
self._expect = _TESTPMD_PROMPT
testpmd_args = testpmd_args or []
- self._cmd = ['sudo', '-E', _TESTPMD_BIN] + testpmd_args
+ self._cmd = ['sudo', '-E', settings.getValue('TOOLS')['testpmd']] + testpmd_args
# startup/shutdown
diff --git a/src/ovs/dpctl.py b/src/ovs/dpctl.py
index 8ecac6dc..44a4ec9b 100644
--- a/src/ovs/dpctl.py
+++ b/src/ovs/dpctl.py
@@ -23,9 +23,6 @@ import string
from tools import tasks
from conf import settings
-_OVS_DPCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities',
- 'ovs-dpctl')
-
_OVS_LOCAL_DATAPATH = 'ovs-system'
class DPCtl(object):
@@ -51,7 +48,7 @@ class DPCtl(object):
:return: None
"""
- cmd = ['sudo', _OVS_DPCTL_BIN,
+ cmd = ['sudo', settings.getValue('TOOLS')['ovs-dpctl'],
'--timeout',
str(self.timeout)] + args
return tasks.run_task(
diff --git a/src/ovs/ofctl.py b/src/ovs/ofctl.py
index a75d0be2..27349a92 100644
--- a/src/ovs/ofctl.py
+++ b/src/ovs/ofctl.py
@@ -28,13 +28,6 @@ import re
from tools import tasks
from conf import settings
-_OVS_VSCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities',
- 'ovs-vsctl')
-_OVS_OFCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities',
- 'ovs-ofctl')
-_OVS_APPCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities',
- 'ovs-appctl')
-
_OVS_BRIDGE_NAME = settings.getValue('VSWITCH_BRIDGE_NAME')
_CACHE_FILE_NAME = '/tmp/vsperf_flows_cache'
@@ -66,9 +59,9 @@ class OFBase(object):
:return: None
"""
if self.timeout == -1:
- cmd = ['sudo', _OVS_VSCTL_BIN, '--no-wait'] + args
+ cmd = ['sudo', settings.getValue('TOOLS')['ovs-vsctl'], '--no-wait'] + args
else:
- cmd = ['sudo', _OVS_VSCTL_BIN, '--timeout', str(self.timeout)] + args
+ cmd = ['sudo', settings.getValue('TOOLS')['ovs-vsctl'], '--timeout', str(self.timeout)] + args
return tasks.run_task(
cmd, self.logger, 'Running ovs-vsctl...', check_error)
@@ -81,7 +74,7 @@ class OFBase(object):
:return: None
"""
- cmd = ['sudo', _OVS_APPCTL_BIN,
+ cmd = ['sudo', settings.getValue('TOOLS')['ovs-appctl'],
'--timeout',
str(self.timeout)] + args
return tasks.run_task(
@@ -184,8 +177,8 @@ class OFBridge(OFBase):
:return: None
"""
tmp_timeout = self.timeout if timeout == None else timeout
- cmd = ['sudo', _OVS_OFCTL_BIN, '-O', 'OpenFlow13', '--timeout',
- str(tmp_timeout)] + args
+ cmd = ['sudo', settings.getValue('TOOLS')['ovs-ofctl'], '-O',
+ 'OpenFlow13', '--timeout', str(tmp_timeout)] + args
return tasks.run_task(
cmd, self.logger, 'Running ovs-ofctl...', check_error)
diff --git a/testcases/testcase.py b/testcases/testcase.py
index 6e215b46..06e9cd24 100644
--- a/testcases/testcase.py
+++ b/testcases/testcase.py
@@ -67,18 +67,12 @@ class TestCase(object):
self._update_settings('TEST_PARAMS', cfg.get('Parameters', S.getValue('TEST_PARAMS')))
# update global settings
+ functions.settings_update_paths()
guest_loopback = get_test_param('guest_loopback', None)
if guest_loopback:
# we can put just one item, it'll be expanded automatically for all VMs
self._update_settings('GUEST_LOOPBACK', [guest_loopback])
- if 'VSWITCH' in self._settings_original or 'VNF' in self._settings_original:
- self._settings_original.update({
- 'RTE_SDK' : S.getValue('RTE_SDK'),
- 'OVS_DIR' : S.getValue('OVS_DIR'),
- })
- functions.settings_update_paths()
-
# set test parameters; CLI options take precedence to testcase settings
self._logger = logging.getLogger(__name__)
self.name = cfg['Name']
@@ -384,14 +378,19 @@ class TestCase(object):
# copy sources into shared dir only if neccessary
guest_loopback = set(S.getValue('GUEST_LOOPBACK'))
- if 'testpmd' in guest_loopback or 'l2fwd' in guest_loopback:
+ if 'testpmd' in guest_loopback:
try:
tasks.run_task(['rsync', '-a', '-r', '-l', r'--exclude="\.git"',
- os.path.join(S.getValue('RTE_SDK_USER'), ''),
+ os.path.join(S.getValue('TOOLS')['dpdk_src'], ''),
os.path.join(guest_dir, 'DPDK')],
self._logger,
'Copying DPDK to shared directory...',
True)
+ except subprocess.CalledProcessError:
+ self._logger.error('Unable to copy DPDK to shared directory')
+ raise
+ if 'l2fwd' in guest_loopback:
+ try:
tasks.run_task(['rsync', '-a', '-r', '-l',
os.path.join(S.getValue('ROOT_DIR'), 'src/l2fwd/'),
os.path.join(guest_dir, 'l2fwd')],
@@ -399,7 +398,8 @@ class TestCase(object):
'Copying l2fwd to shared directory...',
True)
except subprocess.CalledProcessError:
- self._logger.error('Unable to copy DPDK and l2fwd to shared directory')
+ self._logger.error('Unable to copy l2fwd to shared directory')
+ raise
def _mount_hugepages(self):
"""Mount hugepages if usage of DPDK or Qemu is detected
diff --git a/tools/functions.py b/tools/functions.py
index 60ed0802..3bd8cc4d 100644
--- a/tools/functions.py
+++ b/tools/functions.py
@@ -15,20 +15,126 @@
"""Various helper functions
"""
-from conf import settings
+import os
+import logging
+import glob
+import shutil
+from conf import settings as S
#
# Support functions
#
def settings_update_paths():
- """ Configure paths to OVS and DPDK based on VSWITCH and VNF values
+ """ Configure paths to OVS, DPDK and QEMU sources and binaries based on
+ selected vswitch type and src/binary switch. Data are taken from
+ PATHS dictionary and after their processing they are stored inside TOOLS.
+ PATHS dictionary has specific section for 'vswitch', 'qemu' and 'dpdk'
+ Following processing is done for every item:
+ item 'type' - string, which defines the type of paths ('src' or 'bin') to be selected
+ for a given section:
+ 'src' means, that VSPERF will use OVS, DPDK or QEMU built from sources
+ e.g. by execution of systems/build_base_machine.sh script during VSPERF
+ installation
+ 'bin' means, that VSPERF will use OVS, DPDK or QEMU binaries installed
+ in the OS, e.g. via OS specific packaging system
+ item 'path' - string with valid path; Its content is checked for existence, prefixed
+ with section name and stored into TOOLS for later use
+ e.g. TOOLS['dpdk_src'] or TOOLS['vswitch_src']
+ item 'modules' - list of strings; Every value from given list is checked for '.ko'
+ suffix. In case it matches and it is not an absolute path to the module, then
+ module name is prefixed with 'path' defined for the same section
+ e.g. TOOLS['vswitch_modules'] = [
+ '/tmp/vsperf/src_vanilla/ovs/ovs/datapath/linux/openvswitch.ko']
+ all other items - string - if given string is a relative path and item 'path'
+ is defined for a given section, then item content will be prefixed with
+ content of the 'path'. Otherwise tool name will be searched within
+ standard system directories. Also any OS filename wildcards will be
+ expanded to the real path. At the end of processing, every absolute
+ path is checked for its existence. In case that temporary path (i.e. path
+ with '_tmp' suffix) doesn't exist, then log will be written and vsperf will
+ continue. If any other path will not exist, then vsperf execution will
+ be terminated with runtime error.
+
+ Note: In case that 'bin' type is set for DPDK, then TOOLS['dpdk_src'] will be set to
+ the value of PATHS['dpdk']['src']['path']. The reason is, that VSPERF uses downloaded
+ DPDK sources to copy DPDK and testpmd into the GUEST, where testpmd is built. In case,
+ that DPDK sources are not available, then vsperf will continue with test execution,
+ but testpmd can't be used as a guest loopback. This is useful in case, that other guest
+ loopback applications (e.g. buildin) are used by CI jobs, etc.
"""
# set dpdk and ovs paths accorfing to VNF and VSWITCH
- if settings.getValue('VSWITCH').endswith('Vanilla'):
- # settings paths for Vanilla
- settings.setValue('OVS_DIR', (settings.getValue('OVS_DIR_VANILLA')))
- else:
- # default - set to VHOST USER but can be changed during enhancement
- settings.setValue('RTE_SDK', (settings.getValue('RTE_SDK_USER')))
- settings.setValue('OVS_DIR', (settings.getValue('OVS_DIR_USER')))
+ paths = {}
+ vswitch_type = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')]['type']
+ paths['vswitch'] = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')][vswitch_type]
+ paths['dpdk'] = S.getValue('PATHS')['dpdk'][S.getValue('PATHS')['dpdk']['type']]
+ paths['qemu'] = S.getValue('PATHS')['qemu'][S.getValue('PATHS')['qemu']['type']]
+ paths['paths'] = {}
+ paths['paths']['ovs_var_tmp'] = S.getValue('PATHS')['vswitch']['ovs_var_tmp']
+ paths['paths']['ovs_etc_tmp'] = S.getValue('PATHS')['vswitch']['ovs_etc_tmp']
+
+ tools = {}
+ for path_class in paths:
+ for tool in paths[path_class]:
+ tmp_tool = paths[path_class][tool]
+
+ # store valid path of given class into tools dict
+ if tool == 'path':
+ if os.path.isdir(tmp_tool):
+ tools['{}_src'.format(path_class)] = tmp_tool
+ continue
+ else:
+ raise RuntimeError('Path {} does not exist.'.format(tmp_tool))
+
+ # store list of modules of given class into tools dict
+ if tool == 'modules':
+ tmp_modules = []
+ for module in tmp_tool:
+ # add path to the .ko modules and check it for existence
+ if module.endswith('.ko') and not os.path.isabs(module):
+ module = os.path.join(paths[path_class]['path'], module)
+ if not os.path.exists(module):
+ raise RuntimeError('Cannot locate modlue {}'.format(module))
+
+ tmp_modules.append(module)
+
+ tools['{}_modules'.format(path_class)] = tmp_modules
+ continue
+
+ # if path to the tool is relative, then 'path' will be prefixed
+ # in case that 'path' is not defined, then tool will be searched
+ # within standard system paths
+ if not os.path.isabs(tmp_tool):
+ if 'path' in paths[path_class]:
+ tmp_tool = os.path.join(paths[path_class]['path'], tmp_tool)
+ elif shutil.which(tmp_tool):
+ tmp_tool = shutil.which(tmp_tool)
+ else:
+ raise RuntimeError('Cannot locate tool {}'.format(tmp_tool))
+
+ # expand OS wildcards in paths if needed
+ if glob.has_magic(tmp_tool):
+ tmp_glob = glob.glob(tmp_tool)
+ if len(tmp_glob) == 0:
+ raise RuntimeError('Path to the {} is not valid: {}.'.format(tool, tmp_tool))
+ elif len(tmp_glob) > 1:
+ raise RuntimeError('Path to the {} is ambiguous {}'.format(tool, tmp_glob))
+ elif len(tmp_glob) == 1:
+ tmp_tool = tmp_glob[0]
+ elif not os.path.exists(tmp_tool):
+ if tool.endswith('_tmp'):
+ logging.getLogger().debug('Temporary path to the {} does not '
+ 'exist: {}.'.format(tool, tmp_tool))
+ else:
+ raise RuntimeError('Path to the {} is not valid: {}'.format(tool, tmp_tool))
+
+ tools[tool] = tmp_tool
+
+ # ensure, that dpkg_src for bin will be set to downloaded DPDK sources, so it can
+ # be copied to the guest share dir and used by GUEST to build and run testpmd
+ # Validity of the path is not checked by purpose, so user can use VSPERF without
+ # downloading DPDK sources. In that case guest loopback can't be set to 'testpmd'
+ if S.getValue('PATHS')['dpdk']['type'] == 'bin':
+ tools['dpdk_src'] = S.getValue('PATHS')['dpdk']['src']['path']
+
+ S.setValue('TOOLS', tools)
diff --git a/tools/module_manager.py b/tools/module_manager.py
index 2eb4c63d..911f7252 100644
--- a/tools/module_manager.py
+++ b/tools/module_manager.py
@@ -31,30 +31,40 @@ class ModuleManager(object):
"""
self._modules = []
- def insert_module(self, module):
+ def insert_module(self, module, auto_remove=True):
"""Method inserts given module.
In case that module name ends with .ko suffix then insmod will
be used for its insertion. Otherwise modprobe will be called.
:param module: a name of kernel module
+ :param auto_remove: if True (by default), then module will be
+ automatically removed by remove_modules() method
"""
module_base_name = os.path.basename(os.path.splitext(module)[0])
if self.is_module_inserted(module):
self._logger.info('Module already loaded \'%s\'.', module_base_name)
# add it to internal list, so we can try to remove it at the end
- self._modules.append(module)
+ if auto_remove:
+ self._modules.append(module)
return
try:
if module.endswith('.ko'):
+ # load module dependecies first, but suppress automatic
+ # module removal at the end; Just for case, that module
+ # depends on generic module
+ for depmod in self.get_module_dependecies(module):
+ self.insert_module(depmod, auto_remove=False)
+
tasks.run_task(['sudo', 'insmod', module], self._logger,
'Insmod module \'%s\'...' % module_base_name, True)
else:
tasks.run_task(['sudo', 'modprobe', module], self._logger,
'Modprobe module \'%s\'...' % module_base_name, True)
- self._modules.append(module)
+ if auto_remove:
+ self._modules.append(module)
except subprocess.CalledProcessError:
# in case of error, show full module name
self._logger.error('Unable to insert module \'%s\'.', module)
@@ -68,17 +78,6 @@ class ModuleManager(object):
for module in modules:
self.insert_module(module)
- def insert_module_group(self, module_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
- :param path_prefix: A name of directory which contains given
- group of modules
- """
- for (path_suffix, module) in module_group:
- self.insert_module(os.path.join(path_prefix, path_suffix, '%s.ko' % module))
-
def remove_module(self, module):
"""Removes a single module.
@@ -143,3 +142,26 @@ class ModuleManager(object):
return line
return None
+
+ @staticmethod
+ def get_module_dependecies(module):
+ """Return list of modules, which must be loaded before module itself
+
+ :param module: a name of kernel module
+ :returns: In case that module has any dependencies, then list of module
+ names will be returned. Otherwise it returns empty list, i.e. [].
+ """
+ deps = ''
+ try:
+ # get list of module dependecies from kernel
+ deps = subprocess.check_output('modinfo -F depends {}'.format(module),
+ shell=True).decode().rstrip('\n')
+ except subprocess.CalledProcessError:
+ # in case of error, show full module name...
+ self._logger.info('Unable to get list of dependecies for module \'%s\'.', module)
+ # ...and try to continue, just for case that dependecies are already loaded
+
+ if len(deps):
+ return deps.split(',')
+ else:
+ return []
diff --git a/tools/networkcard.py b/tools/networkcard.py
index 8d704fd5..945534be 100644
--- a/tools/networkcard.py
+++ b/tools/networkcard.py
@@ -249,7 +249,7 @@ def reinit_vfs(pf_pci_handle):
:param pf_pci_handle: PCI slot identifier of PF with domain part.
"""
- rte_pci_tool = glob.glob(os.path.join(settings.getValue('RTE_SDK'), 'tools', 'dpdk*bind.py'))[0]
+ rte_pci_tool = settings.getValue('TOOLS')['bind-tool']
for vf_nic in get_sriov_vfs_list(pf_pci_handle):
nic_driver = get_driver(vf_nic)
diff --git a/tools/report/report.py b/tools/report/report.py
index 7d991011..1115f052 100644
--- a/tools/report/report.py
+++ b/tools/report/report.py
@@ -20,8 +20,8 @@ Generate reports in format defined by X.
import sys
import os
-import jinja2
import logging
+import jinja2
from core.results.results_constants import ResultsConstants
from conf import settings as S
@@ -64,7 +64,8 @@ def _get_env(result):
if result[ResultsConstants.DEPLOYMENT].count('v'):
env.update({'vnf': systeminfo.get_version(S.getValue('VNF')),
'guest_image': S.getValue('GUEST_IMAGE'),
- 'loopback_app': list(map(systeminfo.get_version, S.getValue('GUEST_LOOPBACK'))),
+ 'loopback_app': list(map(systeminfo.get_loopback_version,
+ S.getValue('GUEST_LOOPBACK'))),
})
return env
diff --git a/tools/systeminfo.py b/tools/systeminfo.py
index 50dc17e0..fb1616d4 100644
--- a/tools/systeminfo.py
+++ b/tools/systeminfo.py
@@ -19,6 +19,7 @@ import os
import platform
import subprocess
import locale
+import re
from conf import settings as S
@@ -176,6 +177,40 @@ def pid_isalive(pid):
"""
return os.path.isdir('/proc/' + str(pid))
+def get_bin_version(binary, regex):
+ """ get version of given binary selected by given regex
+
+ :returns: version string or None
+ """
+ try:
+ output = subprocess.check_output(binary, shell=True).decode().rstrip('\n')
+ except subprocess.CalledProcessError:
+ return None
+
+ versions = re.findall(regex, output)
+ if len(versions):
+ return versions[0]
+ else:
+ return None
+
+def get_git_tag(path):
+ """ get tag of recent commit from repository located at 'path'
+
+ :returns: git tag in form of string with commit hash or None if there
+ isn't any git repository at given path
+ """
+ try:
+ if os.path.isdir(path):
+ return subprocess.check_output('cd {}; git rev-parse HEAD'.format(path), shell=True,
+ stderr=subprocess.DEVNULL).decode().rstrip('\n')
+ elif os.path.isfile(path):
+ return subprocess.check_output('cd $(dirname {}); git log -1 --pretty="%H" {}'.format(path, path),
+ shell=True, stderr=subprocess.DEVNULL).decode().rstrip('\n')
+ else:
+ return None
+ except subprocess.CalledProcessError:
+ return None
+
# This function uses long switch per purpose, so let us suppress pylint warning too-many-branches
# pylint: disable=R0912
def get_version(app_name):
@@ -186,45 +221,38 @@ def get_version(app_name):
"""
app_version_file = {
- 'ovs' : os.path.join(S.getValue('OVS_DIR'), 'include/openvswitch/version.h'),
- 'dpdk' : os.path.join(S.getValue('RTE_SDK'), 'lib/librte_eal/common/include/rte_version.h'),
- 'qemu' : os.path.join(S.getValue('QEMU_DIR'), 'VERSION'),
- 'l2fwd' : os.path.join(S.getValue('ROOT_DIR'), 'src/l2fwd/l2fwd.c'),
+ 'ovs' : r'Open vSwitch\) ([0-9.]+)',
+ 'testpmd' : r'RTE Version: \'\S+ ([0-9.]+)',
+ 'qemu' : r'QEMU emulator version ([0-9.]+)',
+ 'loopback_l2fwd' : os.path.join(S.getValue('ROOT_DIR'), 'src/l2fwd/l2fwd.c'),
+ 'loopback_testpmd' : os.path.join(S.getValue('TOOLS')['dpdk_src'],
+ 'lib/librte_eal/common/include/rte_version.h'),
'ixnet' : os.path.join(S.getValue('TRAFFICGEN_IXNET_LIB_PATH'), 'pkgIndex.tcl'),
}
- def get_git_tag(path):
- """ get tag of recent commit from repository located at 'path'
-
- :returns: git tag in form of string with commit hash or None if there
- isn't any git repository at given path
- """
- try:
- if os.path.isdir(path):
- return subprocess.check_output('cd {}; git rev-parse HEAD'.format(path), shell=True,
- stderr=subprocess.DEVNULL).decode().rstrip('\n')
- elif os.path.isfile(path):
- return subprocess.check_output('cd $(dirname {}); git log -1 --pretty="%H" {}'.format(path, path),
- shell=True, stderr=subprocess.DEVNULL).decode().rstrip('\n')
- else:
- return None
- except subprocess.CalledProcessError:
- return None
-
app_version = None
app_git_tag = None
if app_name.lower().startswith('ovs'):
- app_version = match_line(app_version_file['ovs'], '#define OVS_PACKAGE_VERSION')
- if app_version:
- app_version = app_version.split('"')[1]
- app_git_tag = get_git_tag(S.getValue('OVS_DIR'))
+ app_version = get_bin_version('{} --version'.format(S.getValue('TOOLS')['ovs-vswitchd']),
+ app_version_file['ovs'])
+ if 'vswitch_src' in S.getValue('TOOLS'):
+ app_git_tag = get_git_tag(S.getValue('TOOLS')['vswitch_src'])
elif app_name.lower() in ['dpdk', 'testpmd']:
+ app_version = get_bin_version('{} -v -h'.format(S.getValue('TOOLS')['testpmd']),
+ app_version_file['testpmd'])
+ # we have to consult PATHS settings to be sure, that dpdk/testpmd
+ # were build from the sources
+ if S.getValue('PATHS')[app_name.lower()]['type'] == 'src':
+ app_git_tag = get_git_tag(S.getValue('TOOLS')['dpdk_src'])
+ elif app_name.lower() == 'loopback_testpmd':
+ # testpmd inside the guest is compiled from downloaded sources
+ # stored at TOOS['dpdk_src'] directory
tmp_ver = ['', '', '']
dpdk_16 = False
- with open(app_version_file['dpdk']) as file_:
+ with open(app_version_file['loopback_testpmd']) as file_:
for line in file_:
if not line.strip():
continue
@@ -263,10 +291,12 @@ def get_version(app_name):
if len(tmp_ver[0]):
app_version = '.'.join(tmp_ver)
- app_git_tag = get_git_tag(S.getValue('RTE_SDK'))
+ app_git_tag = get_git_tag(S.getValue('TOOLS')['dpdk_src'])
elif app_name.lower().startswith('qemu'):
- app_version = match_line(app_version_file['qemu'], '')
- app_git_tag = get_git_tag(S.getValue('QEMU_DIR'))
+ app_version = get_bin_version('{} --version'.format(S.getValue('TOOLS')['qemu-system']),
+ app_version_file['qemu'])
+ if 'qemu_src' in S.getValue('TOOLS'):
+ app_git_tag = get_git_tag(S.getValue('TOOLS')['qemu_src'])
elif app_name.lower() == 'ixnet':
app_version = match_line(app_version_file['ixnet'], 'package provide IxTclNetwork')
if app_version:
@@ -283,13 +313,23 @@ def get_version(app_name):
elif app_name.lower() == 'vswitchperf':
app_git_tag = get_git_tag(S.getValue('ROOT_DIR'))
elif app_name.lower() == 'l2fwd':
- app_version = match_line(app_version_file[app_name], 'MODULE_VERSION')
+ app_version = match_line(app_version_file['loopback_l2fwd'], 'MODULE_VERSION')
if app_version:
app_version = app_version.split('"')[1]
- app_git_tag = get_git_tag(app_version_file[app_name])
+ app_git_tag = get_git_tag(app_version_file['loopback_l2fwd'])
elif app_name.lower() in ['linux_bridge', 'buildin']:
# without login into running VM, it is not possible to check bridge_utils version
app_version = 'NA'
app_git_tag = 'NA'
return {'name' : app_name, 'version' : app_version, 'git_tag' : app_git_tag}
+
+def get_loopback_version(loopback_app_name):
+ """ Get version of given guest loopback application and its git tag
+
+ :returns: dictionary {'name' : app_name, 'version' : app_version, 'git_tag' : app_git_tag) in case that
+ version or git tag are not known or not applicaple, than None is returned for any unknown value
+ """
+ version = get_version("loopback_{}".format(loopback_app_name))
+ version['name'] = loopback_app_name
+ return version
diff --git a/vnfs/qemu/qemu.py b/vnfs/qemu/qemu.py
index c9569ae6..01c16a0f 100644
--- a/vnfs/qemu/qemu.py
+++ b/vnfs/qemu/qemu.py
@@ -85,7 +85,7 @@ class IVnfQemu(IVnf):
vnc = ':%d' % self._number
# don't use taskset to affinize main qemu process; It causes hangup
# of 2nd VM in case of DPDK. It also slows down VM responsivnes.
- self._cmd = ['sudo', '-E', S.getValue('QEMU_BIN'),
+ self._cmd = ['sudo', '-E', S.getValue('TOOLS')['qemu-system'],
'-m', S.getValue('GUEST_MEMORY')[self._number],
'-smp', str(S.getValue('GUEST_SMP')[self._number]),
'-cpu', 'host,migratable=off',
diff --git a/vnfs/qemu/qemu_dpdk_vhost_user.py b/vnfs/qemu/qemu_dpdk_vhost_user.py
index fc46aba1..7e418e18 100644
--- a/vnfs/qemu/qemu_dpdk_vhost_user.py
+++ b/vnfs/qemu/qemu_dpdk_vhost_user.py
@@ -52,7 +52,7 @@ class QemuDpdkVhostUser(IVnfQemu):
self._cmd += ['-chardev',
'socket,id=char' + ifi +
- ',path=' + S.getValue('OVS_VAR_DIR') +
+ ',path=' + S.getValue('TOOLS')['ovs_var_tmp'] +
'dpdkvhostuser' + ifi,
'-netdev',
'type=vhost-user,id=' + net +
diff --git a/vnfs/qemu/qemu_pci_passthrough.py b/vnfs/qemu/qemu_pci_passthrough.py
index ba1f1010..f32f33d3 100644
--- a/vnfs/qemu/qemu_pci_passthrough.py
+++ b/vnfs/qemu/qemu_pci_passthrough.py
@@ -19,7 +19,6 @@
import logging
import subprocess
import os
-import glob
from conf import settings as S
from vnfs.qemu.qemu import IVnfQemu
@@ -27,7 +26,6 @@ from tools import tasks
from tools.module_manager import ModuleManager
_MODULE_MANAGER = ModuleManager()
-_RTE_PCI_TOOL = glob.glob(os.path.join(S.getValue('RTE_SDK'), 'tools', 'dpdk*bind.py'))[0]
class QemuPciPassthrough(IVnfQemu):
"""
@@ -60,7 +58,7 @@ class QemuPciPassthrough(IVnfQemu):
# bind every interface to vfio-pci driver
try:
nics_list = list(tmp_nic['pci'] for tmp_nic in self._host_nics)
- tasks.run_task(['sudo', _RTE_PCI_TOOL, '--bind=vfio-pci'] + nics_list,
+ tasks.run_task(['sudo', S.getValue('TOOLS')['bind-tool'], '--bind=vfio-pci'] + nics_list,
self._logger, 'Binding NICs %s...' % nics_list, True)
except subprocess.CalledProcessError:
@@ -78,7 +76,7 @@ class QemuPciPassthrough(IVnfQemu):
for nic in self._host_nics:
if nic['driver']:
try:
- tasks.run_task(['sudo', _RTE_PCI_TOOL, '--bind=' + nic['driver'], nic['pci']],
+ tasks.run_task(['sudo', S.getValue('TOOLS')['bind-tool'], '--bind=' + nic['driver'], nic['pci']],
self._logger, 'Binding NIC %s...' % nic['pci'], True)
except subprocess.CalledProcessError:
diff --git a/vswitches/ovs.py b/vswitches/ovs.py
index d2814b6a..886a98e0 100644
--- a/vswitches/ovs.py
+++ b/vswitches/ovs.py
@@ -17,19 +17,17 @@
import logging
import os
-import pexpect
import re
import time
+import datetime
+import random
+import pexpect
from conf import settings
from src.ovs import OFBridge, flow_key, flow_match
from tools import tasks
from vswitches.vswitch import IVSwitch
-_OVS_VAR_DIR = settings.getValue('OVS_VAR_DIR')
-_OVS_ETC_DIR = settings.getValue('OVS_ETC_DIR')
-
-
class IVSwitchOvs(IVSwitch, tasks.Process):
"""Open vSwitch base class implementation
@@ -37,23 +35,26 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
implementation. For generic information of the nature of the methods,
see the interface.
"""
- _logfile = os.path.join(settings.getValue('LOG_DIR'), settings.getValue('LOG_FILE_VSWITCHD'))
- _ovsdb_pidfile_path = os.path.join(_OVS_VAR_DIR, "ovsdb-server.pid")
- _vswitchd_pidfile_path = os.path.join(_OVS_VAR_DIR, "ovs-vswitchd.pid")
_proc_name = 'ovs-vswitchd'
def __init__(self):
"""See IVswitch for general description
"""
+ self._logfile = os.path.join(settings.getValue('LOG_DIR'),
+ settings.getValue('LOG_FILE_VSWITCHD'))
+ self._ovsdb_pidfile_path = os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'],
+ "ovsdb-server.pid")
+ self._vswitchd_pidfile_path = os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'],
+ "{}.pid".format(self._proc_name))
self._logger = logging.getLogger(__name__)
- self._expect = r'bridge|INFO|ovs-vswitchd'
+ self._expect = r'bridge|INFO|{}'.format(self._proc_name)
self._timeout = 30
self._bridges = {}
self._vswitchd_args = ['--pidfile=' + self._vswitchd_pidfile_path,
'--overwrite-pidfile', '--log-file=' + self._logfile]
self._cmd = []
- self._cmd_template = ['sudo', '-E', os.path.join(settings.getValue('OVS_DIR'),
- 'vswitchd', 'ovs-vswitchd')]
+ self._cmd_template = ['sudo', '-E', settings.getValue('TOOLS')['ovs-vswitchd']]
+ self._stamp = None
def start(self):
""" Start ``ovsdb-server`` and ``ovs-vswitchd`` instance.
@@ -62,6 +63,10 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
"""
self._logger.info("Starting vswitchd...")
+ # insert kernel modules if required
+ if 'vswitch_modules' in settings.getValue('TOOLS'):
+ self._module_manager.insert_modules(settings.getValue('TOOLS')['vswitch_modules'])
+
self._cmd = self._cmd_template + self._vswitchd_args
# DB must be started before vswitchd
@@ -123,7 +128,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
raise NotImplementedError
def add_veth_pair_port(self, switch_name=None, remote_switch_name=None,
- local_opts=None, remote_opts=None):
+ local_opts=None, remote_opts=None):
"""Creates veth-pair port between 'switch_name' and 'remote_switch_name'
"""
@@ -140,8 +145,8 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
'type=patch',
'options:peer=' + remote_port_name]
remote_params = ['--', 'set', 'Interface', remote_port_name,
- 'type=patch',
- 'options:peer=' + local_port_name]
+ 'type=patch',
+ 'options:peer=' + local_port_name]
if local_opts is not None:
local_params = local_params + local_opts
@@ -296,14 +301,20 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
"""
self._logger.info('Resetting system after last run...')
- tasks.run_task(['sudo', 'rm', '-rf', _OVS_VAR_DIR], self._logger)
- tasks.run_task(['sudo', 'mkdir', '-p', _OVS_VAR_DIR], self._logger)
- tasks.run_task(['sudo', 'rm', '-rf', _OVS_ETC_DIR], self._logger)
- tasks.run_task(['sudo', 'mkdir', '-p', _OVS_ETC_DIR], self._logger)
-
- tasks.run_task(['sudo', 'rm', '-f',
- os.path.join(_OVS_ETC_DIR, 'conf.db')],
- self._logger)
+ # create a backup of ovs_var_tmp and ovs_etc_tmp; It is
+ # essential for OVS installed from binary packages.
+ self._stamp = '{:%Y%m%d_%H%M%S}_{}'.format(datetime.datetime.now(),
+ random.randrange(1000, 9999))
+ for tmp_dir in ['ovs_var_tmp', 'ovs_etc_tmp']:
+ if os.path.exists(settings.getValue('TOOLS')[tmp_dir]):
+ orig_dir = os.path.normpath(settings.getValue('TOOLS')[tmp_dir])
+ self._logger.info('Creating backup of %s directory...', tmp_dir)
+ tasks.run_task(['sudo', 'mv', orig_dir, '{}.{}'.format(orig_dir, self._stamp)],
+ self._logger)
+
+ # create fresh tmp dirs
+ tasks.run_task(['sudo', 'mkdir', '-p', settings.getValue('TOOLS')['ovs_var_tmp']], self._logger)
+ tasks.run_task(['sudo', 'mkdir', '-p', settings.getValue('TOOLS')['ovs_etc_tmp']], self._logger)
self._logger.info('System reset after last run.')
@@ -312,21 +323,18 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
:returns: None
"""
- ovsdb_tool_bin = os.path.join(
- settings.getValue('OVS_DIR'), 'ovsdb', 'ovsdb-tool')
+ ovsdb_tool_bin = settings.getValue('TOOLS')['ovsdb-tool']
tasks.run_task(['sudo', ovsdb_tool_bin, 'create',
- os.path.join(_OVS_ETC_DIR, 'conf.db'),
- os.path.join(settings.getValue('OVS_DIR'), 'vswitchd',
- 'vswitch.ovsschema')],
+ os.path.join(settings.getValue('TOOLS')['ovs_etc_tmp'], 'conf.db'),
+ settings.getValue('TOOLS')['ovsschema']],
self._logger,
'Creating ovsdb configuration database...')
- ovsdb_server_bin = os.path.join(
- settings.getValue('OVS_DIR'), 'ovsdb', 'ovsdb-server')
+ ovsdb_server_bin = settings.getValue('TOOLS')['ovsdb-server']
tasks.run_background_task(
['sudo', ovsdb_server_bin,
- '--remote=punix:%s' % os.path.join(_OVS_VAR_DIR, 'db.sock'),
+ '--remote=punix:%s' % os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'], 'db.sock'),
'--remote=db:Open_vSwitch,Open_vSwitch,manager_options',
'--pidfile=' + self._ovsdb_pidfile_path, '--overwrite-pidfile'],
self._logger,
@@ -346,13 +354,24 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
if ovsdb_pid:
tasks.terminate_task(ovsdb_pid, logger=self._logger)
+ # restore original content of ovs_var_tmp and ovs_etc_tmp; It is
+ # essential for OVS installed from binary packages.
+ if self._stamp:
+ for tmp_dir in ['ovs_var_tmp', 'ovs_etc_tmp']:
+ orig_dir = os.path.normpath(settings.getValue('TOOLS')[tmp_dir])
+ if os.path.exists('{}.{}'.format(orig_dir, self._stamp)):
+ self._logger.info('Restoring backup of %s directory...', tmp_dir)
+ tasks.run_task(['sudo', 'rm', '-rf', orig_dir], self._logger)
+ tasks.run_task(['sudo', 'mv', '{}.{}'.format(orig_dir, self._stamp), orig_dir],
+ self._logger)
+
@staticmethod
def get_db_sock_path():
"""Method returns location of db.sock file
:returns: path to db.sock file.
"""
- return os.path.join(_OVS_VAR_DIR, 'db.sock')
+ return os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'], 'db.sock')
#
# validate methods required for integration testcases
diff --git a/vswitches/ovs_dpdk_vhost.py b/vswitches/ovs_dpdk_vhost.py
index c0764c87..327a697d 100644
--- a/vswitches/ovs_dpdk_vhost.py
+++ b/vswitches/ovs_dpdk_vhost.py
@@ -84,7 +84,6 @@ class OvsDpdkVhost(IVSwitchOvs):
super(OvsDpdkVhost, self).stop()
dpdk.cleanup()
- dpdk.remove_vhost_modules()
def add_switch(self, switch_name, params=None):
"""See IVswitch for general description
@@ -147,7 +146,7 @@ class OvsDpdkVhost(IVSwitchOvs):
:returns: True if legacy --dpdk option is supported, otherwise it returns False
"""
- ovs_vswitchd_bin = os.path.join(settings.getValue('OVS_DIR'), 'vswitchd', 'ovs-vswitchd')
+ ovs_vswitchd_bin = settings.getValue('TOOLS')['ovs-vswitchd']
try:
subprocess.check_output(ovs_vswitchd_bin + r' --help | grep "\-\-dpdk"', shell=True)
return True
diff --git a/vswitches/ovs_vanilla.py b/vswitches/ovs_vanilla.py
index 40ca970e..12a460af 100644
--- a/vswitches/ovs_vanilla.py
+++ b/vswitches/ovs_vanilla.py
@@ -43,15 +43,6 @@ class OvsVanilla(IVSwitchOvs):
self._vswitchd_args += settings.getValue('VSWITCHD_VANILLA_ARGS')
self._module_manager = ModuleManager()
- def start(self):
- """See IVswitch for general description
-
- Activates kernel modules, ovsdb and vswitchd.
- """
- self._module_manager.insert_modules(
- settings.getValue('VSWITCH_VANILLA_KERNEL_MODULES'))
- super(OvsVanilla, self).start()
-
def stop(self):
"""See IVswitch for general description