aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Klozik <martinx.klozik@intel.com>2017-03-16 15:11:32 +0000
committerGerrit Code Review <gerrit@opnfv.org>2017-03-16 15:11:32 +0000
commit8fb2907c4e169ac54acce7a869aeca435b85532e (patch)
tree29e436b19de8a9dfcde381845a4b73f8cb2660df
parent0e5346ac983841c2b082ca7d3934922dc70624f3 (diff)
parentd1145851ad5cb9b5abe963ee97491aa694d389dc (diff)
Merge "vpp: Initial support of VPP vSwitch"
-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