summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--conf/02_vswitch.conf15
-rw-r--r--conf/04_vnf.conf3
-rw-r--r--core/component_factory.py5
-rw-r--r--core/loader/loader_servant.py4
-rw-r--r--core/pktfwd_controller.py9
-rwxr-xr-xdocs/userguide/integration.rst1
-rwxr-xr-xdocs/userguide/testusage.rst62
-rw-r--r--src/dpdk/dpdk.py56
-rw-r--r--testcases/integration.py4
-rw-r--r--testcases/performance.py4
-rw-r--r--testcases/testcase.py13
-rw-r--r--tools/networkcard.py266
-rw-r--r--tools/pkt_fwd/testpmd.py2
-rw-r--r--tools/systeminfo.py5
-rw-r--r--vnfs/qemu/qemu.py22
-rw-r--r--vnfs/qemu/qemu_pci_passthrough.py87
-rwxr-xr-xvsperf273
-rw-r--r--vswitches/ovs_vanilla.py9
18 files changed, 701 insertions, 139 deletions
diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf
index f0475313..d36d1786 100644
--- a/conf/02_vswitch.conf
+++ b/conf/02_vswitch.conf
@@ -31,14 +31,12 @@ VSWITCH_DIR = os.path.join(ROOT_DIR, 'vswitches')
# DPDK target used when builing DPDK
RTE_TARGET = 'x86_64-native-linuxapp-gcc'
-# list of NIC HWIDs which will be bound to the 'igb_uio' driver on
-# system init
-WHITELIST_NICS = ['05:00.0', '05:00.1']
-
-# list of NIC HWIDs which will be ignored by the 'igb_uio' driver on
-# system init
-BLACKLIST_NICS = ['0000:09:00.0', '0000:09:00.1', '0000:09:00.2',
- '0000:09:00.3']
+# list of NIC HWIDs to which traffic generator is connected
+# In case of NIC with SRIOV suport, it is possible to define,
+# which virtual function should be used
+# e.g. value '0000:05:00.0|vf1' will configure two VFs and second VF
+# 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
@@ -74,7 +72,6 @@ VHOST_USER_SOCKS = ['/tmp/dpdkvhostuser0', '/tmp/dpdkvhostuser1',
VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4', '--socket-mem 1024,0']
VSWITCHD_VANILLA_ARGS = ['--pidfile']
-VSWITCH_VANILLA_PHY_PORT_NAMES = ['', '']
# 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')]
diff --git a/conf/04_vnf.conf b/conf/04_vnf.conf
index a78564c3..926ea50a 100644
--- a/conf/04_vnf.conf
+++ b/conf/04_vnf.conf
@@ -35,6 +35,9 @@ GUEST_IMAGE = ['', '']
# For 2 VNFs you may use [180, 180]
GUEST_TIMEOUT = [180, 180]
+# packet forwarding mode: io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho
+GUEST_TESTPMD_FWD_MODE = 'csum'
+
# guest loopback application method; supported options are:
# 'testpmd' - testpmd from dpdk will be built and used
# 'l2fwd' - l2fwd module provided by Huawei will be built and used
diff --git a/core/component_factory.py b/core/component_factory.py
index 9c58fc5c..a91872e2 100644
--- a/core/component_factory.py
+++ b/core/component_factory.py
@@ -118,13 +118,14 @@ def create_loadgen(loadgen_type, loadgen_cfg):
elif loadgen_type.find("stress") >= 0:
return Stress(loadgen_cfg)
-def create_pktfwd(pktfwd_class):
+def create_pktfwd(deployment, pktfwd_class):
"""Return a new packet forwarder controller
The returned controller is configured with the given
packet forwarder class.
:param pktfwd_class: Reference to packet forwarder class to be used.
+ :param deployment: The deployment scenario name
:return: packet forwarder controller
"""
- return PktFwdController(pktfwd_class)
+ return PktFwdController(deployment, pktfwd_class)
diff --git a/core/loader/loader_servant.py b/core/loader/loader_servant.py
index dc6353ff..226b0931 100644
--- a/core/loader/loader_servant.py
+++ b/core/loader/loader_servant.py
@@ -90,8 +90,8 @@ class LoaderServant(object):
desc = (mod.__doc__ or 'No description').strip().split('\n')[0]
results.append((name, desc))
- output = [
- 'Classes derived from: ' + self._interface.__name__ + '\n======\n']
+ header = 'Classes derived from: ' + self._interface.__name__
+ output = [header + '\n' + '=' * len(header) + '\n']
for (name, desc) in results:
output.append('* %-18s%s' % ('%s:' % name, desc))
diff --git a/core/pktfwd_controller.py b/core/pktfwd_controller.py
index 40565504..b1e37f2e 100644
--- a/core/pktfwd_controller.py
+++ b/core/pktfwd_controller.py
@@ -24,11 +24,12 @@ class PktFwdController(object):
_pktfwd_class: The packet forwarder class to be used.
_pktfwd: The packet forwarder object controlled by this controller
"""
- def __init__(self, pktfwd_class):
+ def __init__(self, deployment, pktfwd_class):
"""Initializes up the prerequisites for the P2P deployment scenario.
:vswitch_class: the vSwitch class to be used.
"""
+ self._deployment = deployment
self._logger = logging.getLogger(__name__)
self._pktfwd_class = pktfwd_class
self._pktfwd = pktfwd_class()
@@ -52,10 +53,12 @@ class PktFwdController(object):
self._pktfwd.stop()
def __enter__(self):
- self.setup()
+ if self._deployment.find("p2p") == 0:
+ self.setup()
def __exit__(self, type_, value, traceback):
- self.stop()
+ if self._deployment.find("p2p") == 0:
+ self.stop()
def get_pktfwd(self):
"""Get the controlled packet forwarder
diff --git a/docs/userguide/integration.rst b/docs/userguide/integration.rst
index 27bf2cd0..db9fdd0b 100755
--- a/docs/userguide/integration.rst
+++ b/docs/userguide/integration.rst
@@ -90,7 +90,6 @@ To run OVS NATIVE tunnel tests (VXLAN/GRE/GENEVE):
.. code-block:: python
VSWITCH = 'OvsVanilla'
- VSWITCH_VANILLA_PHY_PORT_NAMES = ['nic1name', 'nic2name']
# Specify vport_* kernel module to test.
VSWITCH_VANILLA_KERNEL_MODULES = ['vport_vxlan',
'vport_gre',
diff --git a/docs/userguide/testusage.rst b/docs/userguide/testusage.rst
index ac46ba3f..233f7015 100755
--- a/docs/userguide/testusage.rst
+++ b/docs/userguide/testusage.rst
@@ -199,7 +199,6 @@ for Vanilla OVS:
.. code-block:: console
VSWITCH = 'OvsVanilla'
- VSWITCH_VANILLA_PHY_PORT_NAMES = ['$PORT1', '$PORT2']
Where $PORT1 and $PORT2 are the Linux interfaces you'd like to bind
to the vswitch.
@@ -309,6 +308,8 @@ To run tests using Vanilla OVS:
$ ./vsperf --conf-file<path_to_custom_conf>/10_custom.conf
+.. _vfio-pci:
+
Using vfio_pci with DPDK
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -346,6 +347,65 @@ To check that IOMMU is enabled on your platform:
[ 3.335746] IOMMU: dmar1 using Queued invalidation
....
+.. _SRIOV-support:
+
+Using SRIOV support
+^^^^^^^^^^^^^^^^^^^
+
+To use virtual functions of NIC with SRIOV support, use extended form
+of NIC PCI slot definition:
+
+.. code-block:: python
+
+ WHITELIST_NICS = ['0000:05:00.0|vf0', '0000:05:00.1|vf3']
+
+Where 'vf' is an indication of virtual function usage and following
+number defines a VF to be used. In case that VF usage is detected,
+then vswitchperf will enable SRIOV support for given card and it will
+detect PCI slot numbers of selected VFs.
+
+So in example above, one VF will be configured for NIC '0000:05:00.0'
+and four VFs will be configured for NIC '0000:05:00.1'. Vswitchperf
+will detect PCI addresses of selected VFs and it will use them during
+test execution.
+
+At the end of vswitchperf execution, SRIOV support will be disabled.
+
+SRIOV support is generic and it can be used in different testing scenarios.
+For example:
+
+* vSwitch tests with DPDK or without DPDK support to verify impact
+ of VF usage on vSwitch performance
+* tests without vSwitch, where traffic is forwared directly
+ between VF interfaces by packet forwarder (e.g. testpmd application)
+* tests without vSwitch, where VM accesses VF interfaces directly
+ by PCI-passthrough_ to measure raw VM throughput performance.
+
+.. _PCI-passthrough:
+
+Using QEMU with PCI passthrough support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Raw virtual machine throughput performance can be measured by execution of PVP
+test with direct access to NICs by PCI passthrough. To execute VM with direct
+access to PCI devices, enable vfio-pci_. In order to use virtual functions,
+SRIOV-support_ must be enabled.
+
+Execution of test with PCI passthrough with vswitch disabled:
+
+.. code-block:: console
+
+ $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf
+ --vswtich none --vnf QemuPciPassthrough pvp_tput
+
+Any of supported guest-loopback-application_ can be used inside VM with
+PCI passthrough support.
+
+Note: Qemu with PCI passthrough support can be used only with PVP test
+deployment.
+
+.. _guest-loopback-application:
+
Selection of loopback application for PVP and PVVP tests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/dpdk/dpdk.py b/src/dpdk/dpdk.py
index f8cbbd81..36f1d055 100644
--- a/src/dpdk/dpdk.py
+++ b/src/dpdk/dpdk.py
@@ -23,7 +23,6 @@ from sys import platform as _platform
import os
import subprocess
import logging
-import locale
from tools import tasks
from conf import settings
@@ -34,14 +33,22 @@ RTE_PCI_TOOL = os.path.join(
settings.getValue('RTE_SDK'), '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
@@ -175,54 +182,35 @@ def _bind_nics():
True)
tasks.run_task(['sudo', RTE_PCI_TOOL, '--bind=' + _driver] +
- settings.getValue('WHITELIST_NICS'), _LOGGER,
- 'Binding NICs %s...' %
- settings.getValue('WHITELIST_NICS'),
+ _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)
+ _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.
diff --git a/testcases/integration.py b/testcases/integration.py
index ecaed14f..53ba17f4 100644
--- a/testcases/integration.py
+++ b/testcases/integration.py
@@ -28,11 +28,11 @@ class IntegrationTestCase(TestCase):
"""IntegrationTestCase class
"""
- def __init__(self, cfg, results_dir):
+ def __init__(self, cfg):
""" Testcase initialization
"""
self._type = 'integration'
- super(IntegrationTestCase, self).__init__(cfg, results_dir)
+ super(IntegrationTestCase, self).__init__(cfg)
self._logger = logging.getLogger(__name__)
self._inttest = None
diff --git a/testcases/performance.py b/testcases/performance.py
index 0ae3ea77..a4769a28 100644
--- a/testcases/performance.py
+++ b/testcases/performance.py
@@ -25,11 +25,11 @@ class PerformanceTestCase(TestCase):
In this basic form runs RFC2544 throughput test
"""
- def __init__(self, cfg, results_dir):
+ def __init__(self, cfg):
""" Testcase initialization
"""
self._type = 'performance'
- super(PerformanceTestCase, self).__init__(cfg, results_dir)
+ super(PerformanceTestCase, self).__init__(cfg)
self._logger = logging.getLogger(__name__)
def run_report(self):
diff --git a/testcases/testcase.py b/testcases/testcase.py
index 0effce75..ff1247fc 100644
--- a/testcases/testcase.py
+++ b/testcases/testcase.py
@@ -36,7 +36,7 @@ class TestCase(object):
In this basic form runs RFC2544 throughput test
"""
- def __init__(self, cfg, results_dir):
+ def __init__(self, cfg):
"""Pull out fields from test config
:param cfg: A dictionary of string-value pairs describing the test
@@ -114,7 +114,7 @@ class TestCase(object):
if self._frame_mod:
self._frame_mod = self._frame_mod.lower()
- self._results_dir = results_dir
+ self._results_dir = S.getValue('RESULTS_PATH')
# set traffic details, so they can be passed to vswitch and traffic ctls
self._traffic = copy.deepcopy(TRAFFIC_DEFAULTS)
@@ -163,6 +163,14 @@ class TestCase(object):
self._traffic['l2'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L2')
self._traffic['l3'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L3')
self._traffic['l4'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L4')
+ elif S.getValue('NICS')[0]['type'] == 'vf' or S.getValue('NICS')[1]['type'] == 'vf':
+ mac1 = S.getValue('NICS')[0]['mac']
+ mac2 = S.getValue('NICS')[1]['mac']
+ if mac1 and mac2:
+ self._traffic['l2'].update({'srcmac': mac2, 'dstmac': mac1})
+ else:
+ self._logger.debug("MAC addresses can not be read")
+
self._logger.debug("Controllers:")
@@ -177,6 +185,7 @@ class TestCase(object):
if self._vswitch_none:
self._vswitch_ctl = component_factory.create_pktfwd(
+ self.deployment,
loader.get_pktfwd_class())
else:
self._vswitch_ctl = component_factory.create_vswitch(
diff --git a/tools/networkcard.py b/tools/networkcard.py
new file mode 100644
index 00000000..c31be691
--- /dev/null
+++ b/tools/networkcard.py
@@ -0,0 +1,266 @@
+# Copyright 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.
+# 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.
+
+"""Tools for network card manipulation
+"""
+
+import os
+import subprocess
+import logging
+import glob
+from conf import settings
+
+_LOGGER = logging.getLogger('tools.networkcard')
+
+_PCI_DIR = '/sys/bus/pci/devices/{}/'
+_SRIOV_NUMVFS = os.path.join(_PCI_DIR, 'sriov_numvfs')
+_SRIOV_TOTALVFS = os.path.join(_PCI_DIR, 'sriov_totalvfs')
+_SRIOV_VF_PREFIX = 'virtfn'
+_SRIOV_PF = 'physfn'
+_PCI_NET = 'net'
+_PCI_DRIVER = 'driver'
+
+
+def check_pci(pci_handle):
+ """ Checks if given extended PCI handle has correct length and fixes
+ it if possible.
+
+ :param pci_handle: PCI slot identifier. It can contain vsperf specific
+ suffix after '|' with VF indication. e.g. '0000:05:00.0|vf1'
+
+ :returns: PCI handle
+ """
+ pci = pci_handle.split('|')
+ pci_len = len(pci[0])
+ if pci_len == 12:
+ return pci_handle
+ elif pci_len == 7:
+ pci[0] = '0000:' + pci[0][-7:]
+ _LOGGER.debug('Adding domain part to PCI slot %s', pci[0])
+ return '|'.join(pci)
+ elif pci_len > 12:
+ pci[0] = pci[0][-12:]
+ _LOGGER.warning('PCI slot is too long, it will be shortened to %s', pci[0])
+ return '|'.join(pci)
+ else:
+ # pci_handle has a strange length, but let us try to use it
+ _LOGGER.error('Unknown format of PCI slot %s', pci_handle)
+ return pci_handle
+
+def is_sriov_supported(pci_handle):
+ """ Checks if sriov is supported by given NIC
+
+ :param pci_handle: PCI slot identifier with domain part.
+
+ :returns: True on success, False otherwise
+ """
+ return os.path.isfile(_SRIOV_TOTALVFS.format(pci_handle))
+
+def is_sriov_nic(pci_handle):
+ """ Checks if given extended PCI ID refers to the VF
+
+ :param pci_handle: PCI slot identifier with domain part. It can contain
+ vsperf specific suffix after '|' with VF indication.
+ e.g. '0000:05:00.0|vf1'
+
+ :returns: True on success, False otherwise
+ """
+ for item in pci_handle.split('|'):
+ if item.lower().startswith('vf'):
+ return True
+ return False
+
+def set_sriov_numvfs(pci_handle, numvfs):
+ """ Checks if sriov is supported and configures given number of VFs
+
+ :param pci_handle: PCI slot identifier with domain part.
+ :param numvfs: Number of VFs to be configured at given NIC.
+
+ :returns: True on success, False otherwise
+ """
+ if not is_sriov_supported(pci_handle):
+ return False
+
+ if get_sriov_numvfs(pci_handle) == numvfs:
+ return True
+
+ if numvfs and get_sriov_numvfs(pci_handle) != 0:
+ if not set_sriov_numvfs(pci_handle, 0):
+ return False
+
+ try:
+ subprocess.call('sudo bash -c "echo {} > {}"'.format(numvfs, _SRIOV_NUMVFS.format(pci_handle)), shell=True)
+ return get_sriov_numvfs(pci_handle) == numvfs
+ except OSError:
+ _LOGGER.debug('Number of VFs cant be changed to %s for PF %s', numvfs, pci_handle)
+ return False
+
+def get_sriov_numvfs(pci_handle):
+ """ Returns the number of configured VFs
+
+ :param pci_handle: PCI slot identifier with domain part
+ :returns: the number of configured VFs
+ """
+ if is_sriov_supported(pci_handle):
+ with open(_SRIOV_NUMVFS.format(pci_handle), 'r') as numvfs:
+ return int(numvfs.readline().rstrip('\n'))
+
+ return None
+
+def get_sriov_totalvfs(pci_handle):
+ """ Checks if sriov is supported and returns max number of supported VFs
+
+ :param pci_handle: PCI slot identifier with domain part
+ :returns: the max number of supported VFs by given NIC
+ """
+ if is_sriov_supported(pci_handle):
+ with open(_SRIOV_TOTALVFS.format(pci_handle), 'r') as total:
+ return int(total.readline().rstrip('\n'))
+
+ return None
+
+def get_sriov_vfs_list(pf_pci_handle):
+ """ Returns list of PCI handles of VFs configured at given NIC/PF
+
+ :param pf_pci_handle: PCI slot identifier of PF with domain part.
+ :returns: list
+ """
+ vfs = []
+ if is_sriov_supported(pf_pci_handle):
+ for vf_name in glob.glob(os.path.join(_PCI_DIR, _SRIOV_VF_PREFIX + '*').format(pf_pci_handle)):
+ vfs.append(os.path.basename(os.path.realpath(vf_name)))
+
+ return vfs
+
+def get_sriov_pf(vf_pci_handle):
+ """ Get PCI handle of PF which belongs to given VF
+
+ :param vf_pci_handle: PCI slot identifier of VF with domain part.
+ :returns: PCI handle of parent PF
+ """
+ pf_path = os.path.join(_PCI_DIR, _SRIOV_PF).format(vf_pci_handle)
+ if os.path.isdir(pf_path):
+ return os.path.basename(os.path.realpath(pf_path))
+
+ return None
+
+def get_driver(pci_handle):
+ """ Returns name of kernel driver assigned to given NIC
+
+ :param pci_handle: PCI slot identifier with domain part.
+ :returns: string with assigned kernel driver, None otherwise
+ """
+ driver_path = os.path.join(_PCI_DIR, _PCI_DRIVER).format(pci_handle)
+ if os.path.isdir(driver_path):
+ return os.path.basename(os.path.realpath(driver_path))
+
+ return None
+
+def get_device_name(pci_handle):
+ """ Returns name of network card device name
+
+ :param pci_handle: PCI slot identifier with domain part.
+ :returns: string with assigned NIC device name, None otherwise
+ """
+ net_path = os.path.join(_PCI_DIR, _PCI_NET).format(pci_handle)
+ try:
+ return os.listdir(net_path)[0]
+ except FileNotFoundError:
+ return None
+ except IndexError:
+ return None
+
+ return None
+
+def get_mac(pci_handle):
+ """ Returns MAC address of given NIC
+
+ :param pci_handle: PCI slot identifier with domain part.
+ :returns: string with assigned MAC address, None otherwise
+ """
+ mac_path = glob.glob(os.path.join(_PCI_DIR, _PCI_NET, '*', 'address').format(pci_handle))
+ # kernel driver is loaded and MAC can be read
+ if len(mac_path) and os.path.isfile(mac_path[0]):
+ with open(mac_path[0], 'r') as _file:
+ return _file.readline().rstrip('\n')
+
+ # MAC address is unknown, e.g. NIC is assigned to DPDK
+ return None
+
+def get_nic_info(full_pci_handle):
+ """ Parse given pci handle with additional info and returns
+ requested NIC info.
+
+ :param full_pci_handle: A string with extended network card PCI ID.
+ extended PCI ID syntax: PCI_ID[|vfx][|(mac|dev)]
+ examples:
+ 0000:06:00.0 - returns the same value
+ 0000:06:00.0|vf0 - returns PCI ID of 1st virtual function of given NIC
+ 0000:06:00.0|mac - returns MAC address of given NIC
+ 0000:06:00.0|vf0|mac - returns MAC address of 1st virtual function of given NIC
+
+ :returns: A string with requested NIC data or None if data cannot be read.
+ """
+ parsed_handle = full_pci_handle.split('|')
+ if len(parsed_handle) not in (1, 2, 3):
+ _LOGGER.error("Invalid PCI device name: '%s'", full_pci_handle)
+ return None
+
+ pci_handle = parsed_handle[0]
+
+ for action in parsed_handle[1:]:
+ # in case of SRIOV get PCI handle of given virtual function
+ if action.lower().startswith('vf'):
+ try:
+ vf_num = int(action[2:])
+ pci_handle = get_sriov_vfs_list(pci_handle)[vf_num]
+ except ValueError:
+ _LOGGER.error("Pci device '%s', does not have VF with index '%s'", pci_handle, action[2:])
+ return None
+ except IndexError:
+ _LOGGER.error("Pci device '%s', does not have VF with index '%s'", pci_handle, vf_num)
+ return None
+ continue
+
+ # return requested info for given PCI handle
+ if action.lower() == 'mac':
+ return get_mac(pci_handle)
+ elif action.lower() == 'dev':
+ return get_device_name(pci_handle)
+ else:
+ _LOGGER.error("Invalid item '%s' in PCI handle '%s'", action, full_pci_handle)
+ return None
+
+ return pci_handle
+
+def reinit_vfs(pf_pci_handle):
+ """ Reinitializates all VFs, which belong to given PF
+
+ :param pf_pci_handle: PCI slot identifier of PF with domain part.
+ """
+ rte_pci_tool = os.path.join(settings.getValue('RTE_SDK'), 'tools', 'dpdk_nic_bind.py')
+
+ for vf_nic in get_sriov_vfs_list(pf_pci_handle):
+ nic_driver = get_driver(vf_nic)
+ if nic_driver:
+ try:
+ subprocess.call(['sudo', rte_pci_tool, '--unbind', vf_nic],
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ subprocess.call(['sudo', rte_pci_tool, '--bind=' + nic_driver, vf_nic],
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ except subprocess.CalledProcessError:
+ _LOGGER.warning('Error during reinitialization of VF %s', vf_nic)
+ else:
+ _LOGGER.warning("Can't detect driver for VF %s", vf_nic)
+
diff --git a/tools/pkt_fwd/testpmd.py b/tools/pkt_fwd/testpmd.py
index d8ed8905..e1b987bc 100644
--- a/tools/pkt_fwd/testpmd.py
+++ b/tools/pkt_fwd/testpmd.py
@@ -42,7 +42,7 @@ class TestPMD(IPktFwd):
vswitchd_args += _VSWITCHD_CONST_ARGS
vswitchd_args += settings.getValue('TESTPMD_ARGS')
- self._nports = len(settings.getValue('WHITELIST_NICS'))
+ self._nports = len(settings.getValue('NICS'))
self._fwdmode = settings.getValue('TESTPMD_FWD_MODE')
self._csum_layer = settings.getValue('TESTPMD_CSUM_LAYER')
self._csum_calc = settings.getValue('TESTPMD_CSUM_CALC')
diff --git a/tools/systeminfo.py b/tools/systeminfo.py
index 62db852b..531f1c92 100644
--- a/tools/systeminfo.py
+++ b/tools/systeminfo.py
@@ -71,8 +71,9 @@ def get_nic():
output = subprocess.check_output('lspci', shell=True)
output = output.decode(locale.getdefaultlocale()[1])
for line in output.split('\n'):
- for nic_pciid in S.getValue('WHITELIST_NICS'):
- if line.startswith(nic_pciid):
+ for nic in S.getValue('NICS'):
+ # lspci shows PCI addresses without domain part, i.e. last 7 chars
+ if line.startswith(nic['pci'][-7:]):
nics.append(''.join(line.split(':')[2:]).strip())
return nics
diff --git a/vnfs/qemu/qemu.py b/vnfs/qemu/qemu.py
index ec728c5c..9cb23ac6 100644
--- a/vnfs/qemu/qemu.py
+++ b/vnfs/qemu/qemu.py
@@ -66,6 +66,14 @@ class IVnfQemu(IVnf):
# cli option take precedence to config file values
self._guest_loopback = S.getValue('GUEST_LOOPBACK')[self._number]
+ self._testpmd_fwd_mode = S.getValue('GUEST_TESTPMD_FWD_MODE')
+ # in case of SRIOV we must ensure, that MAC addresses are not swapped
+ if S.getValue('SRIOV_ENABLED') and self._testpmd_fwd_mode.startswith('mac') and \
+ not S.getValue('VNF').endswith('PciPassthrough'):
+
+ self._logger.info("SRIOV detected, forwarding mode of testpmd was changed from '%s' to '%s'",
+ self._testpmd_fwd_mode, 'io')
+ self._testpmd_fwd_mode = 'io'
name = 'Client%d' % self._number
vnc = ':%d' % self._number
@@ -306,6 +314,11 @@ class IVnfQemu(IVnf):
# modify makefile if needed
self._modify_dpdk_makefile()
+ # disable network interfaces, so DPDK can take care of them
+ self.execute_and_wait('ifdown ' + self._net1)
+ self.execute_and_wait('ifdown ' + self._net2)
+
+ # build and insert igb_uio and rebind interfaces to it
self.execute_and_wait('make RTE_OUTPUT=$RTE_SDK/$RTE_TARGET -C '
'$RTE_SDK/lib/librte_eal/linuxapp/igb_uio')
self.execute_and_wait('modprobe uio')
@@ -313,9 +326,14 @@ class IVnfQemu(IVnf):
S.getValue('RTE_TARGET'))
self.execute_and_wait('./tools/dpdk_nic_bind.py --status')
self.execute_and_wait(
+ './tools/dpdk_nic_bind.py -u' ' ' +
+ S.getValue('GUEST_NET1_PCI_ADDRESS')[self._number] + ' ' +
+ S.getValue('GUEST_NET2_PCI_ADDRESS')[self._number])
+ self.execute_and_wait(
'./tools/dpdk_nic_bind.py -b igb_uio' ' ' +
S.getValue('GUEST_NET1_PCI_ADDRESS')[self._number] + ' ' +
S.getValue('GUEST_NET2_PCI_ADDRESS')[self._number])
+ self.execute_and_wait('./tools/dpdk_nic_bind.py --status')
# build and run 'test-pmd'
self.execute_and_wait('cd ' + S.getValue('GUEST_OVS_DPDK_DIR') +
@@ -325,9 +343,9 @@ class IVnfQemu(IVnf):
self.execute_and_wait('./testpmd -c 0x3 -n 4 --socket-mem 512 --'
' --burst=64 -i --txqflags=0xf00 ' +
'--disable-hw-vlan', 60, "Done")
- self.execute('set fwd mac_retry', 1)
+ self.execute('set fwd ' + self._testpmd_fwd_mode, 1)
self.execute_and_wait('start', 20,
- 'TX RS bit threshold=0 - TXQ flags=0xf00')
+ 'TX RS bit threshold=.+ - TXQ flags=0xf00')
def _configure_l2fwd(self):
"""
diff --git a/vnfs/qemu/qemu_pci_passthrough.py b/vnfs/qemu/qemu_pci_passthrough.py
new file mode 100644
index 00000000..1b55fdf2
--- /dev/null
+++ b/vnfs/qemu/qemu_pci_passthrough.py
@@ -0,0 +1,87 @@
+# 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 QEMU hypervisor with direct access to host NICs via
+ PCI passthrough.
+"""
+
+import logging
+import subprocess
+import os
+
+from conf import settings as S
+from vnfs.qemu.qemu import IVnfQemu
+from tools import tasks
+from tools.module_manager import ModuleManager
+
+_MODULE_MANAGER = ModuleManager()
+_RTE_PCI_TOOL = os.path.join(S.getValue('RTE_SDK'), 'tools', 'dpdk_nic_bind.py')
+
+class QemuPciPassthrough(IVnfQemu):
+ """
+ Control an instance of QEMU with direct access to the host network devices
+ """
+ def __init__(self):
+ """
+ Initialization function.
+ """
+ super(QemuPciPassthrough, self).__init__()
+ self._logger = logging.getLogger(__name__)
+ self._nics = S.getValue('NICS')
+
+ # in case of SRIOV and PCI passthrough we must ensure, that MAC addresses are swapped
+ if S.getValue('SRIOV_ENABLED') and not self._testpmd_fwd_mode.startswith('mac'):
+ self._logger.info("SRIOV detected, forwarding mode of testpmd was changed from '%s' to '%s'",
+ self._testpmd_fwd_mode, 'mac_retry')
+ self._testpmd_fwd_mode = 'mac_retry'
+
+ for nic in self._nics:
+ self._cmd += ['-device', 'vfio-pci,host=' + nic['pci']]
+
+ def start(self):
+ """
+ Start QEMU instance, bind host NICs to vfio-pci driver
+ """
+ # load vfio-pci
+ _MODULE_MANAGER.insert_modules(['vfio-pci'])
+
+ # bind every interface to vfio-pci driver
+ try:
+ nics_list = list(tmp_nic['pci'] for tmp_nic in self._nics)
+ tasks.run_task(['sudo', _RTE_PCI_TOOL, '--bind=vfio-pci'] + nics_list,
+ self._logger, 'Binding NICs %s...' % nics_list, True)
+
+ except subprocess.CalledProcessError:
+ self._logger.error('Unable to bind NICs %s', self._nics)
+
+ super(QemuPciPassthrough, self).start()
+
+ def stop(self):
+ """
+ Stop QEMU instance, bind host NICs to the original driver
+ """
+ super(QemuPciPassthrough, self).stop()
+
+ # bind original driver to every interface
+ for nic in self._nics:
+ if nic['driver']:
+ try:
+ tasks.run_task(['sudo', _RTE_PCI_TOOL, '--bind=' + nic['driver'], nic['pci']],
+ self._logger, 'Binding NIC %s...' % nic['pci'], True)
+
+ except subprocess.CalledProcessError:
+ self._logger.error('Unable to bind NIC %s to driver %s', nic['pci'], nic['driver'])
+
+ # unload vfio-pci driver
+ _MODULE_MANAGER.remove_modules()
diff --git a/vsperf b/vsperf
index 35283185..57d68990 100755
--- a/vsperf
+++ b/vsperf
@@ -39,6 +39,7 @@ from core.loader import Loader
from testcases import PerformanceTestCase
from testcases import IntegrationTestCase
from tools import tasks
+from tools import networkcard
from tools.pkt_gen import trafficgen
from tools.opnfvdashboard import opnfvdashboard
from tools.pkt_gen.trafficgen.trafficgenhelper import TRAFFIC_DEFAULTS
@@ -58,6 +59,8 @@ _TEMPLATE_RST = {'head' : 'tools/report/report_head.rst',
'tmp' : 'tools/report/report_tmp_caption.rst'
}
+_LOGGER = logging.getLogger()
+
def parse_arguments():
"""
Parse command line arguments.
@@ -194,18 +197,17 @@ def configure_logging(level):
settings.getValue('LOG_DIR'),
settings.getValue('LOG_FILE_TRAFFIC_GEN'))
- logger = logging.getLogger()
- logger.setLevel(logging.DEBUG)
+ _LOGGER.setLevel(logging.DEBUG)
stream_logger = logging.StreamHandler(sys.stdout)
stream_logger.setLevel(VERBOSITY_LEVELS[level])
stream_logger.setFormatter(logging.Formatter(
- '[%(levelname)s] %(asctime)s : (%(name)s) - %(message)s'))
- logger.addHandler(stream_logger)
+ '[%(levelname)-5s] %(asctime)s : (%(name)s) - %(message)s'))
+ _LOGGER.addHandler(stream_logger)
file_logger = logging.FileHandler(filename=log_file_default)
file_logger.setLevel(logging.DEBUG)
- logger.addHandler(file_logger)
+ _LOGGER.addHandler(file_logger)
class CommandFilter(logging.Filter):
"""Filter out strings beginning with 'cmd :'"""
@@ -220,12 +222,12 @@ def configure_logging(level):
cmd_logger = logging.FileHandler(filename=log_file_host_cmds)
cmd_logger.setLevel(logging.DEBUG)
cmd_logger.addFilter(CommandFilter())
- logger.addHandler(cmd_logger)
+ _LOGGER.addHandler(cmd_logger)
gen_logger = logging.FileHandler(filename=log_file_traffic_gen)
gen_logger.setLevel(logging.DEBUG)
gen_logger.addFilter(TrafficGenCommandFilter())
- logger.addHandler(gen_logger)
+ _LOGGER.addHandler(gen_logger)
def apply_filter(tests, tc_filter):
@@ -267,26 +269,30 @@ def check_and_set_locale():
system_locale = locale.getdefaultlocale()
if None in system_locale:
os.environ['LC_ALL'] = settings.getValue('DEFAULT_LOCALE')
- logging.warning("Locale was not properly configured. Default values were set. Old locale: %s, New locale: %s",
+ _LOGGER.warning("Locale was not properly configured. Default values were set. Old locale: %s, New locale: %s",
system_locale, locale.getdefaultlocale())
-def generate_final_report(path):
+def generate_final_report():
""" Function will check if partial test results are available
and generates final report in rst format.
"""
+ path = settings.getValue('RESULTS_PATH')
# check if there are any results in rst format
rst_results = glob.glob(os.path.join(path, 'result*rst'))
if len(rst_results):
try:
test_report = os.path.join(path, '{}_{}'.format(settings.getValue('VSWITCH'), _TEMPLATE_RST['final']))
# create report caption directly - it is not worth to execute jinja machinery
+ if settings.getValue('VSWITCH').lower() != 'none':
+ pkt_processor = Loader().get_vswitches()[settings.getValue('VSWITCH')].__doc__.strip().split('\n')[0]
+ else:
+ pkt_processor = Loader().get_pktfwds()[settings.getValue('PKTFWD')].__doc__.strip().split('\n')[0]
report_caption = '{}\n{} {}\n{}\n\n'.format(
'============================================================',
'Performance report for',
- Loader().get_vswitches()[settings.getValue('VSWITCH')].__doc__.strip().split('\n')[0],
-
+ pkt_processor,
'============================================================')
with open(_TEMPLATE_RST['tmp'], 'w') as file_:
@@ -296,15 +302,143 @@ def generate_final_report(path):
' '.join(rst_results), _TEMPLATE_RST['foot'],
test_report), shell=True)
if retval == 0 and os.path.isfile(test_report):
- logging.info('Overall test report written to "%s"', test_report)
+ _LOGGER.info('Overall test report written to "%s"', test_report)
else:
- logging.error('Generatrion of overall test report has failed.')
+ _LOGGER.error('Generatrion of overall test report has failed.')
# remove temporary file
os.remove(_TEMPLATE_RST['tmp'])
except subprocess.CalledProcessError:
- logging.error('Generatrion of overall test report has failed.')
+ _LOGGER.error('Generatrion of overall test report has failed.')
+
+
+def enable_sriov(nic_list):
+ """ Enable SRIOV for given enhanced PCI IDs
+
+ :param nic_list: A list of enhanced PCI IDs
+ """
+ # detect if sriov is required
+ sriov_nic = {}
+ for nic in nic_list:
+ if networkcard.is_sriov_nic(nic):
+ tmp_nic = nic.split('|')
+ if tmp_nic[0] in sriov_nic:
+ if int(tmp_nic[1][2:]) > sriov_nic[tmp_nic[0]]:
+ sriov_nic[tmp_nic[0]] = int(tmp_nic[1][2:])
+ else:
+ sriov_nic.update({tmp_nic[0] : int(tmp_nic[1][2:])})
+
+ # sriov is required for some NICs
+ if len(sriov_nic):
+ for nic in sriov_nic:
+ # check if SRIOV is supported and enough virt interfaces are available
+ if not networkcard.is_sriov_supported(nic) \
+ or networkcard.get_sriov_numvfs(nic) <= sriov_nic[nic]:
+ # if not, enable and set appropriate number of VFs
+ if not networkcard.set_sriov_numvfs(nic, sriov_nic[nic] + 1):
+ _LOGGER.error("SRIOV cannot be enabled for NIC %s", nic)
+ raise
+ else:
+ _LOGGER.debug("SRIOV enabled for NIC %s", nic)
+
+ # WORKAROUND: it has been observed with IXGBE(VF) driver,
+ # that NIC doesn't correclty dispatch traffic to VFs based
+ # on their MAC address. Unbind and bind to the same driver
+ # solves this issue.
+ networkcard.reinit_vfs(nic)
+
+ # After SRIOV is enabled it takes some time until network drivers
+ # properly initialize all cards.
+ # Wait also in case, that SRIOV was already configured as it can be
+ # configured automatically just before vsperf execution.
+ time.sleep(2)
+
+ return True
+
+ return False
+
+
+def disable_sriov(nic_list):
+ """ Disable SRIOV for given PCI IDs
+
+ :param nic_list: A list of enhanced PCI IDs
+ """
+ for nic in nic_list:
+ if networkcard.is_sriov_nic(nic):
+ if not networkcard.set_sriov_numvfs(nic.split('|')[0], 0):
+ _LOGGER.error("SRIOV cannot be disabled for NIC %s", nic)
+ raise
+ else:
+ _LOGGER.debug("SRIOV disabled for NIC %s", nic.split('|')[0])
+
+
+def handle_list_options(args):
+ """ Process --list cli arguments if needed
+
+ :param args: A dictionary with all CLI arguments
+ """
+ if args['list_trafficgens']:
+ print(Loader().get_trafficgens_printable())
+ sys.exit(0)
+
+ if args['list_collectors']:
+ print(Loader().get_collectors_printable())
+ sys.exit(0)
+
+ if args['list_vswitches']:
+ print(Loader().get_vswitches_printable())
+ sys.exit(0)
+
+ if args['list_vnfs']:
+ print(Loader().get_vnfs_printable())
+ sys.exit(0)
+
+ if args['list_fwdapps']:
+ print(Loader().get_pktfwds_printable())
+ sys.exit(0)
+
+ if args['list_settings']:
+ print(str(settings))
+ sys.exit(0)
+
+ if args['list']:
+ # configure tests
+ if args['integration']:
+ testcases = settings.getValue('INTEGRATION_TESTS')
+ else:
+ testcases = settings.getValue('PERFORMANCE_TESTS')
+
+ print("Available Tests:")
+ print("================")
+
+ for test in testcases:
+ print('* %-30s %s' % ('%s:' % test['Name'], test['Description']))
+ sys.exit(0)
+
+
+def vsperf_finalize():
+ """ Clean up before exit
+ """
+ # remove directory if no result files were created
+ try:
+ results_path = settings.getValue('RESULTS_PATH')
+ if os.path.exists(results_path):
+ files_list = os.listdir(results_path)
+ if files_list == []:
+ _LOGGER.info("Removing empty result directory: " + results_path)
+ shutil.rmtree(results_path)
+ except AttributeError:
+ # skip it if parameter doesn't exist
+ pass
+
+ # disable SRIOV if needed
+ try:
+ if settings.getValue('SRIOV_ENABLED'):
+ disable_sriov(settings.getValue('WHITELIST_NICS_ORIG'))
+ except AttributeError:
+ # skip it if parameter doesn't exist
+ pass
class MockTestCase(unittest.TestCase):
@@ -383,8 +517,10 @@ def main():
if 'none' == settings.getValue('VSWITCH').strip().lower():
vswitch_none = True
+ # if required, handle list-* operations
+ handle_list_options(args)
+
configure_logging(settings.getValue('VERBOSITY'))
- logger = logging.getLogger()
# check and fix locale
check_and_set_locale()
@@ -393,12 +529,12 @@ def main():
if args['trafficgen']:
trafficgens = Loader().get_trafficgens()
if args['trafficgen'] not in trafficgens:
- logging.error('There are no trafficgens matching \'%s\' found in'
+ _LOGGER.error('There are no trafficgens matching \'%s\' found in'
' \'%s\'. Exiting...', args['trafficgen'],
settings.getValue('TRAFFICGEN_DIR'))
sys.exit(1)
- # configure vswitch
+ # configuration validity checks
if args['vswitch']:
vswitch_none = 'none' == args['vswitch'].strip().lower()
if vswitch_none:
@@ -406,7 +542,7 @@ def main():
else:
vswitches = Loader().get_vswitches()
if args['vswitch'] not in vswitches:
- logging.error('There are no vswitches matching \'%s\' found in'
+ _LOGGER.error('There are no vswitches matching \'%s\' found in'
' \'%s\'. Exiting...', args['vswitch'],
settings.getValue('VSWITCH_DIR'))
sys.exit(1)
@@ -415,7 +551,7 @@ def main():
settings.setValue('PKTFWD', args['fwdapp'])
fwdapps = Loader().get_pktfwds()
if args['fwdapp'] not in fwdapps:
- logging.error('There are no forwarding application'
+ _LOGGER.error('There are no forwarding application'
' matching \'%s\' found in'
' \'%s\'. Exiting...', args['fwdapp'],
settings.getValue('PKTFWD_DIR'))
@@ -424,16 +560,45 @@ def main():
if args['vnf']:
vnfs = Loader().get_vnfs()
if args['vnf'] not in vnfs:
- logging.error('there are no vnfs matching \'%s\' found in'
+ _LOGGER.error('there are no vnfs matching \'%s\' found in'
' \'%s\'. exiting...', args['vnf'],
settings.getValue('vnf_dir'))
sys.exit(1)
+ if args['exact_test_name'] and args['tests']:
+ _LOGGER.error("Cannot specify tests with both positional args and --test.")
+ sys.exit(1)
+
+ # sriov handling
+ settings.setValue('SRIOV_ENABLED', enable_sriov(settings.getValue('WHITELIST_NICS')))
+
+ # modify NIC configuration to decode enhanced PCI IDs
+ wl_nics_orig = list(networkcard.check_pci(pci) for pci in settings.getValue('WHITELIST_NICS'))
+ settings.setValue('WHITELIST_NICS_ORIG', wl_nics_orig)
+
+ nic_list = []
+ for nic in wl_nics_orig:
+ tmp_nic = networkcard.get_nic_info(nic)
+ if tmp_nic:
+ nic_list.append({'pci' : tmp_nic,
+ 'type' : 'vf' if networkcard.get_sriov_pf(tmp_nic) else 'pf',
+ 'mac' : networkcard.get_mac(tmp_nic),
+ 'driver' : networkcard.get_driver(tmp_nic),
+ 'device' : networkcard.get_device_name(tmp_nic)})
+ else:
+ _LOGGER.error("Invalid network card PCI ID: '%s'", nic)
+ vsperf_finalize()
+ raise
+
+ settings.setValue('NICS', nic_list)
+ # for backward compatibility
+ settings.setValue('WHITELIST_NICS', list(nic['pci'] for nic in nic_list))
+
# update global settings
guest_loopback = get_test_param('guest_loopback', None)
if guest_loopback:
tmp_gl = []
- for i in range(len(settings.getValue('GUEST_LOOPBACK'))):
+ for dummy_i in range(len(settings.getValue('GUEST_LOOPBACK'))):
tmp_gl.append(guest_loopback)
settings.setValue('GUEST_LOOPBACK', tmp_gl)
@@ -443,15 +608,16 @@ def main():
date = datetime.datetime.fromtimestamp(time.time())
results_dir = "results_" + date.strftime('%Y-%m-%d_%H-%M-%S')
results_path = os.path.join(settings.getValue('LOG_DIR'), results_dir)
+ settings.setValue('RESULTS_PATH', results_path)
# create results directory
if not os.path.exists(results_path):
- logger.info("Creating result directory: " + results_path)
+ _LOGGER.info("Creating result directory: " + results_path)
os.makedirs(results_path)
if settings.getValue('mode') == 'trafficgen':
# execute only traffic generator
- logging.debug("Executing traffic generator:")
+ _LOGGER.debug("Executing traffic generator:")
loader = Loader()
# set traffic details, so they can be passed to traffic ctl
traffic = copy.deepcopy(TRAFFIC_DEFAULTS)
@@ -466,7 +632,7 @@ def main():
loader.get_trafficgen_class())
with traffic_ctl:
traffic_ctl.send_traffic(traffic)
- logging.debug("Traffic Results:")
+ _LOGGER.debug("Traffic Results:")
traffic_ctl.print_results()
else:
# configure tests
@@ -479,48 +645,16 @@ def main():
for cfg in testcases:
try:
if args['integration']:
- all_tests.append(IntegrationTestCase(cfg, results_path))
+ all_tests.append(IntegrationTestCase(cfg))
else:
- all_tests.append(PerformanceTestCase(cfg, results_path))
+ all_tests.append(PerformanceTestCase(cfg))
except (Exception) as _:
- logger.exception("Failed to create test: %s",
- cfg.get('Name', '<Name not set>'))
+ _LOGGER.exception("Failed to create test: %s",
+ cfg.get('Name', '<Name not set>'))
+ vsperf_finalize()
raise
- # if required, handle list-* operations
-
- if args['list']:
- print("Available Tests:")
- print("================")
- for test in all_tests:
- print('* %-30s %s' % ('%s:' % test.name, test.desc))
- exit()
-
- if args['list_trafficgens']:
- print(Loader().get_trafficgens_printable())
- exit()
-
- if args['list_collectors']:
- print(Loader().get_collectors_printable())
- exit()
-
- if args['list_vswitches']:
- print(Loader().get_vswitches_printable())
- exit()
-
- if args['list_vnfs']:
- print(Loader().get_vnfs_printable())
- exit()
-
- if args['list_settings']:
- print(str(settings))
- exit()
-
# select requested tests
- if args['exact_test_name'] and args['tests']:
- logger.error("Cannot specify tests with both positional args and --test.")
- sys.exit(1)
-
if args['exact_test_name']:
exact_names = args['exact_test_name']
# positional args => exact matches only
@@ -533,7 +667,8 @@ def main():
selected_tests = all_tests
if not selected_tests:
- logger.error("No tests matched --test option or positional args. Done.")
+ _LOGGER.error("No tests matched --test option or positional args. Done.")
+ vsperf_finalize()
sys.exit(1)
# run tests
@@ -544,12 +679,12 @@ def main():
suite.addTest(MockTestCase('', True, test.name))
#pylint: disable=broad-except
except (Exception) as ex:
- logger.exception("Failed to run test: %s", test.name)
+ _LOGGER.exception("Failed to run test: %s", test.name)
suite.addTest(MockTestCase(str(ex), False, test.name))
- logger.info("Continuing with next test...")
+ _LOGGER.info("Continuing with next test...")
# generate final rst report with results of all executed TCs
- generate_final_report(results_path)
+ generate_final_report()
if settings.getValue('XUNIT'):
xmlrunner.XMLTestRunner(
@@ -574,13 +709,9 @@ def main():
int_data['cuse'] = True
opnfvdashboard.results2opnfv_dashboard(results_path, int_data)
- #remove directory if no result files were created.
- if os.path.exists(results_path):
- files_list = os.listdir(results_path)
- if files_list == []:
- shutil.rmtree(results_path)
+ # cleanup before exit
+ vsperf_finalize()
if __name__ == "__main__":
main()
-
diff --git a/vswitches/ovs_vanilla.py b/vswitches/ovs_vanilla.py
index 6a380b1b..f5fecc2a 100644
--- a/vswitches/ovs_vanilla.py
+++ b/vswitches/ovs_vanilla.py
@@ -32,12 +32,12 @@ class OvsVanilla(IVSwitchOvs):
see the interface definition.
"""
- _ports = settings.getValue('VSWITCH_VANILLA_PHY_PORT_NAMES')
_current_id = 0
_vport_id = 0
def __init__(self):
super(OvsVanilla, self).__init__()
+ self._ports = list(nic['device'] for nic in settings.getValue('NICS'))
self._logger = logging.getLogger(__name__)
self._vswitchd_args = ["unix:%s" % VSwitchd.get_db_sock_path()]
self._vswitchd_args += settings.getValue('VSWITCHD_VANILLA_ARGS')
@@ -77,8 +77,7 @@ class OvsVanilla(IVSwitchOvs):
def add_phy_port(self, switch_name):
"""
- Method adds port based on configured VSWITCH_VANILLA_PHY_PORT_NAMES
- stored in config file.
+ Method adds port based on detected device names.
See IVswitch for general description
"""
@@ -89,8 +88,8 @@ class OvsVanilla(IVSwitchOvs):
raise
if not self._ports[self._current_id]:
- self._logger.error("VSWITCH_VANILLA_PHY_PORT_NAMES not set")
- raise ValueError("Invalid VSWITCH_VANILLA_PHY_PORT_NAMES")
+ self._logger.error("Can't detect device name for NIC %s", self._current_id)
+ raise ValueError("Invalid device name for %s" % self._current_id)
bridge = self._bridges[switch_name]
port_name = self._ports[self._current_id]