summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Klozik <martinx.klozik@intel.com>2017-02-27 09:00:50 +0000
committerMartin Klozik <martinx.klozik@intel.com>2017-03-15 16:11:45 +0000
commitd1145851ad5cb9b5abe963ee97491aa694d389dc (patch)
tree83898844525496cedbea0b4ed82130008fe87d0d
parent7c4a2cdcdd99f309dccfe0a24e829bbf3afa95f9 (diff)
vpp: Initial support of VPP vSwitch
Support of VPP was implemented into VSPERF. Initial implementation uses step driven testcases to configure P2P, PVP and PVVP network scenarios. These testcases were prepared for three RFC2544 traffic types, i.e. throughput, continuous stream and back to back. VPP configuration is driven by new configuration option VSWITCH_VPP_ARGS. It is possible to use three types of l2 port connection supported by VPP, i.e. l2 xconnect (default), l2patch and l2 bridge features. Configuration is driven by parameter VSWITCH_VPP_L2_CONNECT_MODE. JIRA: VSPERF-495 Change-Id: Idebef9b10fb0d70796adb3405fec77302de00a7e Signed-off-by: Martin Klozik <martinx.klozik@intel.com> Reviewed-by: Al Morton <acmorton@att.com> Reviewed-by: Christian Trautman <ctrautma@redhat.com> Reviewed-by: Sridhar Rao <sridhar.rao@spirent.com> Reviewed-by: Trevor Cooper <trevor.cooper@intel.com>
-rwxr-xr-xconf/01_testcases.conf188
-rw-r--r--conf/02_vswitch.conf52
-rw-r--r--conf/05_collector.conf2
-rw-r--r--conf/06_pktfwd.conf2
-rw-r--r--core/loader/loader_servant.py3
-rw-r--r--docs/configguide/installation.rst32
-rw-r--r--docs/configguide/trafficgen.rst1
-rw-r--r--docs/design/vswitchperf_design.rst2
-rw-r--r--docs/userguide/teststeps.rst2
-rw-r--r--docs/userguide/testusage.rst49
-rw-r--r--testcases/testcase.py29
-rw-r--r--tools/pkt_fwd/testpmd.py8
-rwxr-xr-xvsperf31
-rw-r--r--vswitches/ovs_dpdk_vhost.py50
-rw-r--r--vswitches/ovs_vanilla.py15
-rw-r--r--vswitches/vpp_dpdk_vhost.py403
-rw-r--r--vswitches/vswitch.py33
17 files changed, 837 insertions, 65 deletions
diff --git a/conf/01_testcases.conf b/conf/01_testcases.conf
index b30afc8f..4851b043 100755
--- a/conf/01_testcases.conf
+++ b/conf/01_testcases.conf
@@ -78,6 +78,85 @@
# "Test Modifier": [FrameMod|Other],
# "Dependency": [Test_Case_Name |None],
+#
+# VPP specific macros used in TC defintions
+#
+VPP_P2P = [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[2][0]', '#STEP[1][0]', True],
+ ['trafficgen', 'send_traffic', {}],
+ ['vswitch', 'dump_connections', 'int_br0'],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[2][0]', '#STEP[1][0]', True],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+VPP_PVP = [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 3
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 4
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[4][0]', '#STEP[2][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[2][0]', '#STEP[4][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]', True],
+ ['vnf', 'start'],
+ ['trafficgen', 'send_traffic', {}],
+ ['vnf', 'stop'],
+ ['vswitch', 'dump_connections', 'int_br0'],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[4][0]', '#STEP[2][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[2][0]', '#STEP[4][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]', True],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+VPP_PVVP = [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 3
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 4
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 5
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 6
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[4][0]', '#STEP[5][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[6][0]', '#STEP[2][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[2][0]', '#STEP[6][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[5][0]', '#STEP[4][0]', True],
+ ['vswitch', 'add_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]', True],
+ ['vnf1', 'start'],
+ ['vnf2', 'start'],
+ ['trafficgen', 'send_traffic', {}],
+ ['vnf2', 'stop'],
+ ['vnf1', 'stop'],
+ ['vswitch', 'dump_connections', 'int_br0'],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[4][0]', '#STEP[5][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[6][0]', '#STEP[2][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[2][0]', '#STEP[6][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[5][0]', '#STEP[4][0]', True],
+ ['vswitch', 'del_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]', True],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[5][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[6][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+
+#
+# Generic performance TC definitions
+#
PERFORMANCE_TESTS = [
{
"Name": "phy2phy_tput",
@@ -269,4 +348,113 @@ PERFORMANCE_TESTS = [
},
},
},
+ {
+ "Name": "phy2phy_tput_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: LTD.Throughput.RFC2544.PacketLossRatio",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_throughput",
+ },
+ },
+ "TestSteps": VPP_P2P,
+ },
+ {
+ "Name": "phy2phy_cont_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: Phy2Phy Continuous Stream",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_continuous",
+ "frame_rate" : 100,
+ },
+ },
+ "TestSteps": VPP_P2P,
+ },
+ {
+ "Name": "phy2phy_back2back_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: LTD.Throughput.RFC2544.BackToBackFrames",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_back2back",
+ },
+ },
+ "TestSteps": VPP_P2P,
+ },
+ {
+ "Name": "pvp_tput_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: LTD.Throughput.RFC2544.PacketLossRatio",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_throughput",
+ },
+ },
+ "TestSteps": VPP_PVP,
+ },
+ {
+ "Name": "pvp_cont_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: PVP Continuous Stream",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_continuous",
+ },
+ },
+ "TestSteps": VPP_PVP,
+ },
+ {
+ "Name": "pvp_back2back_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: LTD.Throughput.RFC2544.BackToBackFrames",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_back2back",
+ },
+ },
+ "TestSteps": VPP_PVP,
+ },
+ {
+ "Name": "pvvp_tput_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: LTD.Throughput.RFC2544.PacketLossRatio",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_throughput",
+ },
+ },
+ "TestSteps": VPP_PVVP,
+ },
+ {
+ "Name": "pvvp_cont_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: PVP Continuous Stream",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_continuous",
+ },
+ },
+ "TestSteps": VPP_PVVP,
+ },
+ {
+ "Name": "pvvp_back2back_vpp",
+ "Deployment": "clean",
+ "Description": "VPP: LTD.Throughput.RFC2544.BackToBackFrames",
+ "vSwitch" : "VppDpdkVhost",
+ "Parameters" : {
+ "TRAFFIC" : {
+ "traffic_type" : "rfc2544_back2back",
+ },
+ },
+ "TestSteps": VPP_PVVP,
+ },
]
diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf
index 2ca7591c..2bac1732 100644
--- a/conf/02_vswitch.conf
+++ b/conf/02_vswitch.conf
@@ -33,6 +33,12 @@ RTE_TARGET = 'x86_64-native-linuxapp-gcc'
# will be used for testing
WHITELIST_NICS = []
+# List defines an amount of memory to be allocated by DPDK at NUMA nodes. This
+# option is shared by all vSwitches with DPDK support. In case, that there is
+# a socket-mem configuration specified in vSwitch specific configuration option,
+# then it will be overridden by DPDK_SOCKET_MEM value.
+DPDK_SOCKET_MEM = ['1024', '0']
+
# vhost character device file used by dpdkvhostport QemuWrap cases
VHOST_DEV_FILE = 'ovs-vhost-net'
@@ -103,6 +109,18 @@ PATHS['vswitch'] = {
},
'ovs_var_tmp': '/usr/local/var/run/openvswitch/',
'ovs_etc_tmp': '/usr/local/etc/openvswitch/',
+ 'VppDpdkVhost': {
+ 'type' : 'bin',
+ 'src': {
+ 'path': os.path.join(ROOT_DIR, 'src/vpp/vpp/build-root/build-vpp-native'),
+ 'vpp': 'vpp',
+ 'vppctl': 'vppctl',
+ },
+ 'bin': {
+ 'vpp': 'vpp',
+ 'vppctl': 'vppctl',
+ }
+ },
}
# default OvsVanilla configuration is similar to OvsDpdkVhost except 'path' and 'modules'
@@ -116,18 +134,19 @@ PATHS['vswitch']['OvsVanilla']['bin']['modules'] = ['openvswitch']
# ############################
# These are DPDK EAL parameters and they may need to be changed depending on
# hardware configuration, like cpu numbering and NUMA.
-#
+
# parameters used for legacy DPDK configuration through '--dpdk' option of ovs-vswitchd
# e.g. ovs-vswitchd --dpdk --socket-mem 1024,0
# This config line is also used for pkt_fwd option (TestPMD phy2phy and pvp tests)
-VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4', '--socket-mem 1024,0']
+# NOTE: DPDK socket mem allocation is driven by parameter DPDK_SOCKET_MEM
+VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4']
# options used for new type of OVS configuration via calls to ovs-vsctl
# e.g. ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024,0"
+# NOTE: DPDK socket mem allocation is driven by parameter DPDK_SOCKET_MEM
VSWITCHD_DPDK_CONFIG = {
'dpdk-init' : 'true',
'dpdk-lcore-mask' : '0x4',
- 'dpdk-socket-mem' : '1024,0',
}
# Note: VSPERF will automatically detect, which type of DPDK configuration should
# be used.
@@ -169,3 +188,30 @@ LOG_FILE_OVS = 'ovs.log'
# default vswitch implementation
VSWITCH = "OvsDpdkVhost"
+
+#########################
+## VPP
+#########################
+# Set of arguments used for startup of VPP
+# NOTE: DPDK socket mem allocation is driven by parameter DPDK_SOCKET_MEM
+VSWITCH_VPP_ARGS = {
+ 'unix' : [
+ 'interactive', # required by VSPERF to detect successful VPP startup
+ 'log /tmp/vpp.log',
+ 'full-coredump',
+ ],
+ 'cpu' : [
+ 'main-core 3',
+ 'corelist-workers 4,5',
+ ],
+}
+
+# log file for VPP
+LOG_FILE_VPP = 'vsperf-vpp.log'
+
+# Select l2 connection method used by VPP.
+# Supported values are: 'xconnect', 'l2patch' and 'bridge'
+VSWITCH_VPP_L2_CONNECT_MODE = 'xconnect'
+
+# Options used during creation of dpdkvhostuser interface
+VSWITCH_VPP_VHOSTUSER_ARGS = ['feature-mask', '0xFF']
diff --git a/conf/05_collector.conf b/conf/05_collector.conf
index bda0ac8d..9fd2558c 100644
--- a/conf/05_collector.conf
+++ b/conf/05_collector.conf
@@ -20,7 +20,7 @@ COLLECTOR = 'Pidstat'
COLLECTOR_DIR = os.path.join(ROOT_DIR, 'tools/collectors')
# processes to be monitored by pidstat
-PIDSTAT_MONITOR = ['ovs-vswitchd', 'ovsdb-server', 'qemu-system-x86_64']
+PIDSTAT_MONITOR = ['ovs-vswitchd', 'ovsdb-server', 'qemu-system-x86_64', 'vpp']
# options which will be passed to pidstat
PIDSTAT_OPTIONS = '-dur'
diff --git a/conf/06_pktfwd.conf b/conf/06_pktfwd.conf
index 6175aa6a..bb4c1d79 100644
--- a/conf/06_pktfwd.conf
+++ b/conf/06_pktfwd.conf
@@ -36,4 +36,4 @@ TESTPMD_CSUM_CALC = 'sw'
# recognize tunnel headers: on|off
TESTPMD_CSUM_PARSE_TUNNEL = 'off'
-PIDSTAT_MONITOR = ['ovs-vswitchd', 'ovsdb-server', 'qemu-system-x86_64', 'testpmd']
+PIDSTAT_MONITOR = ['ovs-vswitchd', 'ovsdb-server', 'qemu-system-x86_64', 'vpp', 'testpmd']
diff --git a/core/loader/loader_servant.py b/core/loader/loader_servant.py
index bbb4ea9d..8bad9ab9 100644
--- a/core/loader/loader_servant.py
+++ b/core/loader/loader_servant.py
@@ -86,7 +86,8 @@ class LoaderServant(object):
interface=self._interface)
results = []
- for (name, mod) in list(out.items()):
+ # sort modules to produce the same output everytime
+ for (name, mod) in sorted(out.items()):
desc = (mod.__doc__ or 'No description').strip().split('\n')[0]
results.append((name, desc))
diff --git a/docs/configguide/installation.rst b/docs/configguide/installation.rst
index bda5a0bc..1965a8f5 100644
--- a/docs/configguide/installation.rst
+++ b/docs/configguide/installation.rst
@@ -165,6 +165,22 @@ built from upstream source due to kernel incompatibilities. Please see the
instructions in the vswitchperf_design document for details on configuring
OVS Vanilla for binary package usage.
+.. _vpp-installation:
+
+VPP installation
+================
+
+Currently vswitchperf installation scripts do not support automatic build
+of VPP. In order to execute tests with VPP, it is required to install it
+manually. Please refer to the official documentation of `fd.io`_ project to
+install VPP from `packages`_ or from the `sources`_.
+
+See details about :ref:`vpp-test`.
+
+.. _fd.io: https://fd.io/
+.. _packages: https://wiki.fd.io/view/VPP/Installing_VPP_binaries_from_packages
+.. _sources: https://wiki.fd.io/view/VPP/Build,_install,_and_test_images
+
Using vswitchperf
-----------------
@@ -260,20 +276,10 @@ your configuration in the ``02_vswitch.conf`` file.
.. code:: bash
- VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4', '--socket-mem 1024,1024']
- VSWITCHD_DPDK_CONFIG = {
- 'dpdk-init' : 'true',
- 'dpdk-lcore-mask' : '0x4',
- 'dpdk-socket-mem' : '1024,1024',
- }
-
-**NOTE:** Option ``VSWITCHD_DPDK_ARGS`` is used for vswitchd, which supports ``--dpdk``
-parameter. In recent vswitchd versions, option ``VSWITCHD_DPDK_CONFIG`` is
-used to configure vswitchd via ``ovs-vsctl`` calls.
+ DPDK_SOCKET_MEM = ['1024', '0']
-With the ``--socket-mem`` argument set to use 1 hugepage on the specified sockets as
-seen above, the configuration will need 10 hugepages total to run all tests
-within vsperf if the pagesize is set correctly to 1GB.
+**NOTE:** Option ``DPDK_SOCKET_MEM`` is used by all vSwitches with DPDK support.
+It means Open vSwitch, VPP and TestPMD.
VSPerf will verify hugepage amounts are free before executing test
environments. In case of hugepage amounts not being free, test initialization
diff --git a/docs/configguide/trafficgen.rst b/docs/configguide/trafficgen.rst
index 3c33d4ef..4e42b2be 100644
--- a/docs/configguide/trafficgen.rst
+++ b/docs/configguide/trafficgen.rst
@@ -469,6 +469,7 @@ For RFC2889 tests, specifying the locations for the monitoring ports is mandator
Necessary parameters are:
.. code-block:: console
+
TRAFFICGEN_STC_RFC2889_TEST_FILE_NAME
TRAFFICGEN_STC_EAST_CHASSIS_ADDR = " "
TRAFFICGEN_STC_EAST_SLOT_NUM = " "
diff --git a/docs/design/vswitchperf_design.rst b/docs/design/vswitchperf_design.rst
index 9e74e599..da7ec6fd 100644
--- a/docs/design/vswitchperf_design.rst
+++ b/docs/design/vswitchperf_design.rst
@@ -498,6 +498,8 @@ Other Configuration
``conf.settings`` also loads configuration from the command line and from the environment.
+.. _pxp-deployment:
+
PXP Deployment
==============
diff --git a/docs/userguide/teststeps.rst b/docs/userguide/teststeps.rst
index 4e6c0808..870c3d80 100644
--- a/docs/userguide/teststeps.rst
+++ b/docs/userguide/teststeps.rst
@@ -2,6 +2,8 @@
.. http://creativecommons.org/licenses/by/4.0
.. (c) OPNFV, Intel Corporation, AT&T and others.
+.. _step-driven-tests:
+
Step driven tests
=================
diff --git a/docs/userguide/testusage.rst b/docs/userguide/testusage.rst
index 0055164e..c6037aaf 100644
--- a/docs/userguide/testusage.rst
+++ b/docs/userguide/testusage.rst
@@ -335,6 +335,43 @@ To run tests using Vanilla OVS:
$ ./vsperf --conf-file<path_to_custom_conf>/10_custom.conf
+.. _vpp-test:
+
+Executing VPP tests
+^^^^^^^^^^^^^^^^^^^
+
+Currently it is not possible to use standard scenario deployments for execution of
+tests with VPP. It means, that deployments ``p2p``, ``pvp``, ``pvvp`` and in general any
+:ref:`pxp-deployment` won't work with VPP. However it is possible to use VPP in
+:ref:`step-driven-tests`. A basic set of VPP testcases covering ``phy2phy``, ``pvp``
+and ``pvvp`` tests are already prepared.
+
+List of performance tests with VPP support follows:
+
+* phy2phy_tput_vpp: VPP: LTD.Throughput.RFC2544.PacketLossRatio
+* phy2phy_cont_vpp: VPP: Phy2Phy Continuous Stream
+* phy2phy_back2back_vpp: VPP: LTD.Throughput.RFC2544.BackToBackFrames
+* pvp_tput_vpp: VPP: LTD.Throughput.RFC2544.PacketLossRatio
+* pvp_cont_vpp: VPP: PVP Continuous Stream
+* pvp_back2back_vpp: VPP: LTD.Throughput.RFC2544.BackToBackFrames
+* pvvp_tput_vpp: VPP: LTD.Throughput.RFC2544.PacketLossRatio
+* pvvp_cont_vpp: VPP: PVP Continuous Stream
+* pvvp_back2back_vpp: VPP: LTD.Throughput.RFC2544.BackToBackFrames
+
+In order to execute testcases with VPP it is required to:
+
+* install VPP manually, see :ref:`vpp-installation`
+* configure ``WHITELIST_NICS``, with two physical NICs connected to the traffic generator
+* configure traffic generator, see :ref:`trafficgen-installation`
+
+After that it is possible to execute VPP testcases listed above.
+
+For example:
+
+.. code-block:: console
+
+ $ ./vsperf --conf-file=<path_to_custom_conf> phy2phy_tput_vpp
+
.. _vfio-pci:
Using vfio_pci with DPDK
@@ -689,7 +726,8 @@ application to use the correct number of nb-cores.
.. code-block:: python
- VSWITCHD_DPDK_ARGS = ['-l', '46,44,42,40,38', '-n', '4', '--socket-mem 1024,0']
+ DPDK_SOCKET_MEM = ['1024', '0']
+ VSWITCHD_DPDK_ARGS = ['-l', '46,44,42,40,38', '-n', '4']
TESTPMD_ARGS = ['--nb-cores=4', '--txq=1', '--rxq=1']
For guest TestPMD 3 VCpus should be assigned with the following TestPMD params.
@@ -790,16 +828,17 @@ an appropriate amount of memory:
.. code-block:: python
- VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4', '--socket-mem 1024,0']
+ DPDK_SOCKET_MEM = ['1024', '0']
+ VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4']
VSWITCHD_DPDK_CONFIG = {
'dpdk-init' : 'true',
'dpdk-lcore-mask' : '0x4',
'dpdk-socket-mem' : '1024,0',
}
-Note: Option VSWITCHD_DPDK_ARGS is used for vswitchd, which supports --dpdk
-parameter. In recent vswitchd versions, option VSWITCHD_DPDK_CONFIG will be
-used to configure vswitchd via ovs-vsctl calls.
+Note: Option ``VSWITCHD_DPDK_ARGS`` is used for vswitchd, which supports ``--dpdk``
+parameter. In recent vswitchd versions, option ``VSWITCHD_DPDK_CONFIG`` will be
+used to configure vswitchd via ``ovs-vsctl`` calls.
More information
diff --git a/testcases/testcase.py b/testcases/testcase.py
index d74f34ad..4fbf9c04 100644
--- a/testcases/testcase.py
+++ b/testcases/testcase.py
@@ -257,9 +257,6 @@ class TestCase(object):
# umount hugepages if mounted
self._umount_hugepages()
- # restore original settings
- S.load_from_dict(self._settings_original)
-
# cleanup any namespaces created
if os.path.isdir('/tmp/namespaces'):
namespace_list = os.listdir('/tmp/namespaces')
@@ -333,6 +330,9 @@ class TestCase(object):
# report test results
self.run_report()
+ # restore original settings
+ S.load_from_dict(self._settings_original)
+
def _update_settings(self, param, value):
""" Check value of given configuration parameter
In case that new value is different, then testcase
@@ -460,26 +460,11 @@ class TestCase(object):
# get hugepage amounts for each socket on dpdk
sock0_mem, sock1_mem = 0, 0
+
if S.getValue('VSWITCH').lower().count('dpdk'):
- # the import below needs to remain here and not put into the module
- # imports because of an exception due to settings not yet loaded
- from vswitches import ovs_dpdk_vhost
- if ovs_dpdk_vhost.OvsDpdkVhost.old_dpdk_config():
- match = re.search(
- r'-socket-mem\s+(\d+),(\d+)',
- ''.join(S.getValue('VSWITCHD_DPDK_ARGS')))
- if match:
- sock0_mem, sock1_mem = (int(match.group(1)) * 1024 / hugepage_size,
- int(match.group(2)) * 1024 / hugepage_size)
- else:
- logging.info(
- 'Could not parse socket memory config in dpdk params.')
- else:
- sock0_mem, sock1_mem = (
- S.getValue(
- 'VSWITCHD_DPDK_CONFIG')['dpdk-socket-mem'].split(','))
- sock0_mem, sock1_mem = (int(sock0_mem) * 1024 / hugepage_size,
- int(sock1_mem) * 1024 / hugepage_size)
+ sock_mem = S.getValue('DPDK_SOCKET_MEM')
+ sock0_mem, sock1_mem = (int(sock_mem[0]) * 1024 / hugepage_size,
+ int(sock_mem[1]) * 1024 / hugepage_size)
# If hugepages needed, verify the amounts are free
if any([hugepages_needed, sock0_mem, sock1_mem]):
diff --git a/tools/pkt_fwd/testpmd.py b/tools/pkt_fwd/testpmd.py
index 8255f1d8..970259dc 100644
--- a/tools/pkt_fwd/testpmd.py
+++ b/tools/pkt_fwd/testpmd.py
@@ -41,6 +41,14 @@ class TestPMD(IPktFwd):
def __init__(self, guest=False):
vswitchd_args = settings.getValue('VSWITCHD_DPDK_ARGS')
+
+ # override socket-mem settings
+ for tmp_arg in vswitchd_args:
+ if tmp_arg.startswith('--socket-mem'):
+ vswitchd_args.remove(tmp_arg)
+ vswitchd_args += ['--socket-mem ' +
+ ','.join(settings.getValue('DPDK_SOCKET_MEM'))]
+
if guest:
vswitchd_args += _TESTPMD_PVP_CONST_ARGS
vswitchd_args += _VSWITCHD_CONST_ARGS
diff --git a/vsperf b/vsperf
index 44887fcf..fea7997b 100755
--- a/vsperf
+++ b/vsperf
@@ -285,6 +285,28 @@ def check_and_set_locale():
_LOGGER.warning("Locale was not properly configured. Default values were set. Old locale: %s, New locale: %s",
system_locale, locale.getdefaultlocale())
+def get_vswitch_names(rst_files):
+ """ Function will return a list of vSwitches detected in given ``rst_files``.
+ """
+ vswitch_names = set()
+ if len(rst_files):
+ try:
+ output = subprocess.check_output(['grep', '-h', '^* vSwitch'] + rst_files).decode().splitlines()
+ for line in output:
+ match = re.search(r'^\* vSwitch: ([^,]+)', str(line))
+ if match:
+ vswitch_names.add(match.group(1))
+
+ if len(vswitch_names):
+ return list(vswitch_names)
+
+ except subprocess.CalledProcessError:
+ _LOGGER.warning('Cannot detect vSwitches used during testing.')
+
+ # fallback to the default value
+ return ['vSwitch']
+
+
def generate_final_report():
""" Function will check if partial test results are available
@@ -294,18 +316,15 @@ def generate_final_report():
path = settings.getValue('RESULTS_PATH')
# check if there are any results in rst format
rst_results = glob.glob(os.path.join(path, 'result*rst'))
+ pkt_processors = get_vswitch_names(rst_results)
if len(rst_results):
try:
- test_report = os.path.join(path, '{}_{}'.format(settings.getValue('VSWITCH'), _TEMPLATE_RST['final']))
+ test_report = os.path.join(path, '{}_{}'.format('_'.join(pkt_processors), _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',
- pkt_processor,
+ ', '.join(pkt_processors),
'============================================================')
with open(_TEMPLATE_RST['tmp'], 'w') as file_:
diff --git a/vswitches/ovs_dpdk_vhost.py b/vswitches/ovs_dpdk_vhost.py
index a49c8dd7..3387fda7 100644
--- a/vswitches/ovs_dpdk_vhost.py
+++ b/vswitches/ovs_dpdk_vhost.py
@@ -20,7 +20,7 @@ import subprocess
from src.ovs import OFBridge
from src.dpdk import dpdk
-from conf import settings
+from conf import settings as S
from vswitches.ovs import IVSwitchOvs
class OvsDpdkVhost(IVSwitchOvs):
@@ -43,7 +43,14 @@ class OvsDpdkVhost(IVSwitchOvs):
# legacy DPDK configuration through --dpdk option of vswitchd
if self.old_dpdk_config():
- vswitchd_args = ['--dpdk'] + settings.getValue('VSWITCHD_DPDK_ARGS')
+ # override socket-mem settings
+ tmp_dpdk_args = S.getValue('VSWITCHD_DPDK_ARGS')
+ for tmp_arg in tmp_dpdk_args:
+ if tmp_arg.startswith('--socket-mem'):
+ tmp_dpdk_args.remove(tmp_arg)
+ tmp_dpdk_args += ['--socket-mem ' + ','.join(S.getValue('DPDK_SOCKET_MEM'))]
+ vswitchd_args = ['--dpdk'] + tmp_dpdk_args
+ # add dpdk args to generic ovs-vswitchd settings
if self._vswitchd_args:
self._vswitchd_args = vswitchd_args + ['--'] + self._vswitchd_args
else:
@@ -52,8 +59,10 @@ class OvsDpdkVhost(IVSwitchOvs):
def configure(self):
""" Configure vswitchd DPDK options through ovsdb if needed
"""
- dpdk_config = settings.getValue('VSWITCHD_DPDK_CONFIG')
+ dpdk_config = S.getValue('VSWITCHD_DPDK_CONFIG')
if dpdk_config and not self.old_dpdk_config():
+ # override socket-mem settings
+ dpdk_config['dpdk-socket-mem'] = ','.join(S.getValue('DPDK_SOCKET_MEM'))
# enforce calls to ovs-vsctl with --no-wait
tmp_br = OFBridge(timeout=-1)
for option in dpdk_config:
@@ -68,12 +77,12 @@ class OvsDpdkVhost(IVSwitchOvs):
dpdk.init()
super(OvsDpdkVhost, self).start()
# old style OVS <= 2.5.0 multi-queue enable
- if settings.getValue('OVS_OLD_STYLE_MQ') and \
- int(settings.getValue('VSWITCH_DPDK_MULTI_QUEUES')):
+ if S.getValue('OVS_OLD_STYLE_MQ') and \
+ int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')):
tmp_br = OFBridge(timeout=-1)
tmp_br.set_db_attribute(
'Open_vSwitch', '.', 'other_config:' +
- 'n-dpdk-rxqs', settings.getValue('VSWITCH_DPDK_MULTI_QUEUES'))
+ 'n-dpdk-rxqs', S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))
def stop(self):
"""See IVswitch for general description
@@ -92,12 +101,12 @@ class OvsDpdkVhost(IVSwitchOvs):
switch_params = switch_params + params
super(OvsDpdkVhost, self).add_switch(switch_name, switch_params)
- if settings.getValue('VSWITCH_AFFINITIZATION_ON') == 1:
+ if S.getValue('VSWITCH_AFFINITIZATION_ON') == 1:
# Sets the PMD core mask to VSWITCH_PMD_CPU_MASK
# for CPU core affinitization
self._bridges[switch_name].set_db_attribute('Open_vSwitch', '.',
'other_config:pmd-cpu-mask',
- settings.getValue('VSWITCH_PMD_CPU_MASK'))
+ S.getValue('VSWITCH_PMD_CPU_MASK'))
def add_phy_port(self, switch_name):
"""See IVswitch for general description
@@ -110,15 +119,15 @@ class OvsDpdkVhost(IVSwitchOvs):
port_name = 'dpdk' + str(dpdk_count)
# PCI info. Please note there must be no blank space, eg must be
# like 'options:dpdk-devargs=0000:06:00.0'
- _nics = settings.getValue('NICS')
+ _nics = S.getValue('NICS')
nic_pci = 'options:dpdk-devargs=' + _nics[dpdk_count]['pci']
params = ['--', 'set', 'Interface', port_name, 'type=dpdk', nic_pci]
# multi-queue enable
- if int(settings.getValue('VSWITCH_DPDK_MULTI_QUEUES')) and \
- not settings.getValue('OVS_OLD_STYLE_MQ'):
+ if int(S.getValue('VSWITCH_DPDK_MULTI_QUEUES')) and \
+ not S.getValue('OVS_OLD_STYLE_MQ'):
params += ['options:n_rxq={}'.format(
- settings.getValue('VSWITCH_DPDK_MULTI_QUEUES'))]
+ S.getValue('VSWITCH_DPDK_MULTI_QUEUES'))]
of_port = bridge.add_port(port_name, params)
return (port_name, of_port)
@@ -144,9 +153,24 @@ class OvsDpdkVhost(IVSwitchOvs):
:returns: True if legacy --dpdk option is supported, otherwise it returns False
"""
- ovs_vswitchd_bin = settings.getValue('TOOLS')['ovs-vswitchd']
+ ovs_vswitchd_bin = S.getValue('TOOLS')['ovs-vswitchd']
try:
subprocess.check_output(ovs_vswitchd_bin + r' --help | grep "\-\-dpdk"', shell=True)
return True
except subprocess.CalledProcessError:
return False
+
+ def add_connection(self, switch_name, port1, port2, bidir=False):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def del_connection(self, switch_name, port1, port2, bidir=False):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def dump_connections(self, switch_name):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
diff --git a/vswitches/ovs_vanilla.py b/vswitches/ovs_vanilla.py
index 649a5ab9..75870ab7 100644
--- a/vswitches/ovs_vanilla.py
+++ b/vswitches/ovs_vanilla.py
@@ -125,3 +125,18 @@ class OvsVanilla(IVSwitchOvs):
bridge = self._bridges[switch_name]
of_port = bridge.add_port(tap_name, [])
return (tap_name, of_port)
+
+ def add_connection(self, switch_name, port1, port2, bidir=False):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def del_connection(self, switch_name, port1, port2, bidir=False):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def dump_connections(self, switch_name):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
diff --git a/vswitches/vpp_dpdk_vhost.py b/vswitches/vpp_dpdk_vhost.py
new file mode 100644
index 00000000..d0d9e2ac
--- /dev/null
+++ b/vswitches/vpp_dpdk_vhost.py
@@ -0,0 +1,403 @@
+# Copyright 2017 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.
+
+"""VSPERF VPP implementation using DPDK and vhostuser vports
+"""
+
+import logging
+import os
+import copy
+import re
+import pexpect
+
+from src.dpdk import dpdk
+from conf import settings as S
+from vswitches.vswitch import IVSwitch
+from tools import tasks
+
+# pylint: disable=too-many-public-methods
+class VppDpdkVhost(IVSwitch, tasks.Process):
+ """ VPP with DPDK support
+ """
+ _proc_name = 'vpp'
+ _bridge_idx_counter = 100
+
+ def __init__(self):
+ """See IVswitch for general description
+ """
+ self._logfile = os.path.join(S.getValue('LOG_DIR'),
+ S.getValue('LOG_FILE_VPP'))
+ self._logger = logging.getLogger(__name__)
+ self._expect = r'vpp#'
+ self._timeout = 30
+ self._vswitch_args = []
+ self._cmd = []
+ self._cmd_template = ['sudo', '-E', S.getValue('TOOLS')['vpp']]
+ self._stamp = None
+ self._logger = logging.getLogger(__name__)
+ self._phy_ports = []
+ self._virt_ports = []
+ self._switches = {}
+
+ # configure DPDK NICs
+ tmp_args = copy.deepcopy(S.getValue('VSWITCH_VPP_ARGS'))
+ if 'dpdk' not in tmp_args:
+ tmp_args['dpdk'] = []
+
+ # override socket-mem settings
+ for tmp_arg in tmp_args['dpdk']:
+ if tmp_arg.startswith('socket-mem'):
+ tmp_args['dpdk'].remove(tmp_arg)
+ tmp_args['dpdk'].append('socket-mem ' +
+ ','.join(S.getValue('DPDK_SOCKET_MEM')))
+
+ for nic in S.getValue('NICS'):
+ tmp_args['dpdk'].append("dev {}".format(nic['pci']))
+ self._vswitch_args = self._process_vpp_args(tmp_args)
+
+ def _get_nic_info(self, key='Name'):
+ """Read NIC info from VPP and return NIC details in a dictionary
+ indexed by given ``key``
+
+ :param key: Name of the key to be used for indexing result dictionary
+
+ :returns: Dictionary with NIC infos including their PCI addresses
+ """
+ result = {}
+ output = self.run_vppctl(['show', 'hardware', 'brief'])
+ # parse output and store basic info about NICS
+ ifaces = output[0].split('\n')
+ keys = ifaces[0].split()
+ keys.append('Pci')
+ keyidx = keys.index(key)
+ for iface in ifaces[1:]:
+ tmpif = iface.split()
+ # get PCI address of given interface
+ output = self.run_vppctl(['show', 'hardware', tmpif[1], 'detail'])
+ match = re.search(r'pci address:\s*([\d:\.]+)', output[0])
+ if match:
+ # normalize PCI address, e.g. 0000:05:10.01 => 0000:05:10.1
+ tmp_pci = match.group(1).split('.')
+ tmp_pci[1] = str(int(tmp_pci[1]))
+ tmpif.append('.'.join(tmp_pci))
+ else:
+ tmpif.append(None)
+ # store only NICs with reasonable index
+ if tmpif[keyidx] is not None:
+ result[tmpif[keyidx]] = dict(zip(keys, tmpif))
+
+ return result
+
+ def _process_vpp_args(self, args):
+ """Produce VPP CLI args from input dictionary ``args``
+ """
+ cli_args = []
+ for cfg_key in args:
+ cli_args.append(cfg_key)
+ cli_args.append("{{ {} }}".format(' '.join(args[cfg_key])))
+
+ self._logger.debug("VPP CLI args: %s", cli_args)
+ return cli_args
+
+
+ def start(self):
+ """Activates DPDK kernel modules and starts VPP
+
+ :raises: pexpect.EOF, pexpect.TIMEOUT
+ """
+ dpdk.init()
+ self._logger.info("Starting VPP...")
+
+ self._cmd = self._cmd_template + self._vswitch_args
+
+ try:
+ tasks.Process.start(self)
+ self.relinquish()
+ except (pexpect.EOF, pexpect.TIMEOUT) as exc:
+ logging.error("Exception during VPP start.")
+ raise exc
+
+ self._logger.info("VPP...Started.")
+
+ def stop(self):
+ """See IVswitch for general description
+
+ Kills VPP and removes DPDK kernel modules.
+ """
+ self._logger.info("Terminating VPP...")
+ self.kill()
+ self._logger.info("VPP...Terminated.")
+ dpdk.cleanup()
+
+ def kill(self, signal='-15', sleep=10):
+ """See IVswitch for general description
+
+ Kills ``vpp``
+ """
+ # try to get VPP pid
+ output = self.run_vppctl(['show', 'version', 'verbose'])
+ match = re.search(r'Current PID:\s*([0-9]+)', output[0])
+ if match:
+ vpp_pid = match.group(1)
+ tasks.terminate_task(vpp_pid, logger=self._logger)
+
+ # in case, that pid was not detected or sudo envelope
+ # has not been terminated yet
+ tasks.Process.kill(self, signal, sleep)
+
+ def add_switch(self, switch_name, dummy_params=None):
+ """See IVswitch for general description
+ """
+ if switch_name in self._switches:
+ self._logger.warning("switch %s already exists...", switch_name)
+ else:
+ self._switches[switch_name] = self._bridge_idx_counter
+ self._bridge_idx_counter += 1
+
+ def del_switch(self, switch_name):
+ """See IVswitch for general description
+ """
+ if switch_name in self._switches:
+ del self._switches[switch_name]
+
+ def add_phy_port(self, dummy_switch_name):
+ """See IVswitch for general description
+ :raises: RuntimeError
+ """
+ # get list of physical interfaces with PCI addresses
+ vpp_nics = self._get_nic_info(key='Pci')
+ # check if there are any NICs left
+ if len(self._phy_ports) >= len(S.getValue('NICS')):
+ raise RuntimeError('All available NICs are already configured!')
+
+ nic = S.getValue('NICS')[len(self._phy_ports)]
+ if not nic['pci'] in vpp_nics:
+ raise RuntimeError('VPP cannot access nic with PCI address: {}'.format(nic['pci']))
+ nic_name = vpp_nics[nic['pci']]['Name']
+ self._phy_ports.append(nic_name)
+ self.run_vppctl(['set', 'int', 'state', nic_name, 'up'])
+ return (nic_name, vpp_nics[nic['pci']]['Idx'])
+
+ def add_vport(self, dummy_switch_name):
+ """See IVswitch for general description
+ """
+ socket_name = S.getValue('TOOLS')['ovs_var_tmp'] + 'dpdkvhostuser' + str(len(self._virt_ports))
+ output = self.run_vppctl(['create', 'vhost-user', 'socket', socket_name, 'server'] +
+ S.getValue('VSWITCH_VPP_VHOSTUSER_ARGS'))
+ nic_name = output[0]
+ self._virt_ports.append(nic_name)
+ self.run_vppctl(['set', 'int', 'state', nic_name, 'up'])
+ return (nic_name, None)
+
+ def del_port(self, switch_name, port_name):
+ """See IVswitch for general description
+ """
+ if port_name in self._phy_ports:
+ self.run_vppctl(['set', 'int', 'state', port_name, 'down'])
+ self._phy_ports.remove(port_name)
+ elif port_name in self._virt_ports:
+ self.run_vppctl(['set', 'int', 'state', port_name, 'down'])
+ self.run_vppctl(['delete', 'vhost-user', port_name])
+ self._virt_ports.remove(port_name)
+ else:
+ self._logger.warning("Port %s is not configured.", port_name)
+
+ def add_l2patch(self, port1, port2, bidir=False):
+ """Create l2patch connection between given ports
+ """
+ self.run_vppctl(['test', 'l2patch', 'rx', port1, 'tx', port2])
+ if bidir:
+ self.run_vppctl(['test', 'l2patch', 'rx', port2, 'tx', port1])
+
+ def add_xconnect(self, port1, port2, bidir=False):
+ """Create l2patch connection between given ports
+ """
+ self.run_vppctl(['set', 'interface', 'l2', 'xconnect', port1, port2])
+ if bidir:
+ self.run_vppctl(['set', 'interface', 'l2', 'xconnect', port2, port1])
+
+ def add_bridge(self, switch_name, port1, port2, dummy_bidir=False):
+ """Add given ports to bridge ``switch_name``
+ """
+ self.run_vppctl(['set', 'interface', 'l2', 'bridge', port1,
+ str(self._switches[switch_name])])
+ self.run_vppctl(['set', 'interface', 'l2', 'bridge', port2,
+ str(self._switches[switch_name])])
+
+ def add_connection(self, switch_name, port1, port2, bidir=False):
+ """See IVswitch for general description
+
+ :raises: RuntimeError
+ """
+ mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
+ if mode == 'l2patch':
+ self.add_l2patch(port1, port2, bidir)
+ elif mode == 'xconnect':
+ self.add_xconnect(port1, port2, bidir)
+ elif mode == 'bridge':
+ self.add_bridge(switch_name, port1, port2)
+ else:
+ raise RuntimeError('VPP: Unsupported l2 connection mode detected %s', mode)
+
+ def del_l2patch(self, port1, port2, bidir=False):
+ """Remove l2patch connection between given ports
+
+ :param port1: port to be used in connection
+ :param port2: port to be used in connection
+ :param bidir: switch between uni and bidirectional traffic
+ """
+ self.run_vppctl(['test', 'l2patch', 'rx', port1, 'tx', port2, 'del'])
+ if bidir:
+ self.run_vppctl(['test', 'l2patch', 'rx', port2, 'tx', port1, 'del'])
+
+ def del_xconnect(self, dummy_port1, dummy_port2, dummy_bidir=False):
+ """Remove xconnect connection between given ports
+ """
+ self._logger.warning('VPP: Removal of l2 xconnect is not implemented.')
+
+ def del_bridge(self, dummy_switch_name, dummy_port1, dummy_port2):
+ """Remove given ports from the bridge
+ """
+ self._logger.warning('VPP: Removal of interfaces from bridge is not implemented.')
+
+ def del_connection(self, switch_name, port1, port2, bidir=False):
+ """See IVswitch for general description
+
+ :raises: RuntimeError
+ """
+ mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
+ if mode == 'l2patch':
+ self.del_l2patch(port1, port2, bidir)
+ elif mode == 'xconnect':
+ self.del_xconnect(port1, port2, bidir)
+ elif mode == 'bridge':
+ self.del_bridge(switch_name, port1, port2)
+ else:
+ raise RuntimeError('VPP: Unsupported l2 connection mode detected %s', mode)
+
+ def dump_l2patch(self):
+ """Dump l2patch connections
+ """
+ self.run_vppctl(['show', 'l2patch'])
+
+ def dump_xconnect(self):
+ """Dump l2 xconnect connections
+ """
+ self._logger.warning("VPP: Dump of l2 xconnections is not supported.")
+
+ def dump_bridge(self, switch_name):
+ """Show bridge details
+
+ :param switch_name: switch on which to operate
+ """
+ self.run_vppctl(['show', 'bridge-domain', str(self._switches[switch_name]), 'int'])
+
+ def dump_connections(self, switch_name):
+ """See IVswitch for general description
+
+ :raises: RuntimeError
+ """
+ mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
+ if mode == 'l2patch':
+ self.dump_l2patch()
+ elif mode == 'xconnect':
+ self.dump_xconnect()
+ elif mode == 'bridge':
+ self.dump_bridge(switch_name)
+ else:
+ raise RuntimeError('VPP: Unsupported l2 connection mode detected %s', mode)
+
+ def run_vppctl(self, args, check_error=False):
+ """Run ``vppctl`` with supplied arguments.
+
+ :param args: Arguments to pass to ``vppctl``
+ :param check_error: Throw exception on error
+
+ :return: None
+ """
+ cmd = ['sudo', S.getValue('TOOLS')['vppctl']] + args
+ return tasks.run_task(cmd, self._logger, 'Running vppctl...', check_error)
+
+ #
+ # Validate methods
+ #
+ def validate_add_switch(self, dummy_result, switch_name, dummy_params=None):
+ """Validate - Create a new logical switch with no ports
+ """
+ return switch_name in self._switches
+
+ def validate_del_switch(self, dummy_result, switch_name):
+ """Validate removal of switch
+ """
+ return not self.validate_add_switch(dummy_result, switch_name)
+
+ def validate_add_phy_port(self, result, dummy_switch_name):
+ """ Validate that physical port was added to bridge.
+ """
+ return result[0] in self._phy_ports
+
+ def validate_add_vport(self, result, dummy_switch_name):
+ """ Validate that virtual port was added to bridge.
+ """
+ return result[0] in self._virt_ports
+
+ def validate_del_port(self, dummy_result, dummy_switch_name, port_name):
+ """ Validate that port_name was removed from bridge.
+ """
+ return not (port_name in self._phy_ports or port_name in self._virt_ports)
+
+ # pylint: disable=no-self-use
+ def validate_run_vppctl(self, result, dummy_args, dummy_check_error=False):
+ """validate execution of ``vppctl`` with supplied arguments.
+ """
+ # there shouldn't be any stderr
+ return not result[1]
+
+ #
+ # Non implemented methods
+ #
+ def add_flow(self, switch_name, flow, cache='off'):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def del_flow(self, switch_name, flow=None):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def dump_flows(self, switch_name):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def add_route(self, switch_name, network, destination):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def set_tunnel_arp(self, ip_addr, mac_addr, switch_name):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan', params=None):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
+
+ def get_ports(self, switch_name):
+ """See IVswitch for general description
+ """
+ raise NotImplementedError()
diff --git a/vswitches/vswitch.py b/vswitches/vswitch.py
index 73e0a0c3..893bd1ff 100644
--- a/vswitches/vswitch.py
+++ b/vswitches/vswitch.py
@@ -130,6 +130,39 @@ class IVSwitch(object):
"""
raise NotImplementedError()
+ def add_connection(self, switch_name, port1, port2, bidir=False):
+ """Creates connection between given ports.
+
+ :param switch_name: switch on which to operate
+ :param port1: port to be used in connection
+ :param port2: port to be used in connection
+ :param bidir: switch between uni and bidirectional traffic
+
+ :raises: RuntimeError
+ """
+ raise NotImplementedError()
+
+ def del_connection(self, switch_name, port1, port2, bidir=False):
+ """Remove connection between two interfaces.
+
+ :param switch_name: switch on which to operate
+ :param port1: port to be used in connection
+ :param port2: port to be used in connection
+ :param bidir: switch between uni and bidirectional traffic
+
+ :raises: RuntimeError
+ """
+ raise NotImplementedError()
+
+ def dump_connections(self, switch_name):
+ """Dump connections between interfaces.
+
+ :param switch_name: switch on which to operate
+
+ :raises: RuntimeError
+ """
+ raise NotImplementedError()
+
def dump_flows(self, switch_name):
"""Dump flows from the logical switch