connections: Introduction of generic API 93/57893/5
authorMartin Klozik <martin.klozik@tieto.com>
Tue, 15 May 2018 08:42:35 +0000 (01:42 -0700)
committerMartin Klozik <martin.klozik@tieto.com>
Mon, 28 May 2018 12:48:23 +0000 (05:48 -0700)
Redesign of vSwitch and vSwitch controller classes, to use generic
connection methods for configuration of vSwitch. This API
is more generic and vSwitch agnostic, thus deployment scenarios like
P2P, PVP, PVVP (i.e. PVVPx) can be used for all (currently)
supported vSwitches. Usage of new API will simplify an introduction
of new vSwitches in the future.

This patchset introduces following changes:
* OVS: implementation of add_, del_, dump_ connection(s) and their
  validation methods
* VPP: bidir parameter removed - it is up to the deployment scenario
  implementation to take care about bidirectional connections
* P2P and PXP controllers were updated to use connection methods
  instead of flow related methods. Thus standard TCs will support
  both OVS and VPP. NOTE, PVPV is not supported for VPP (yet?).
* refactoring of vSwitch interfaces and inherited classes
* VPP step driven TCs were replaced by standard TCs with appropriate
  deployment scenarios. This is for backward compatibility with
  TC reporting. Once reporting of VPP TC results into results DB will be
  modified, this TCs can be removed.
* OVS routing tables support was generalized to support P2P and
  PXP deployments and step driven TCs. Usage of OVS routing tables
  is now configurable (turned off by default) for better comparison of
  results among various vSwitches.
* Multistream pre_installed_flows feature was generalized to
  support P2P and PXP deployments and step driven TCs.
* IxNet: TRAFFIC['l4']['dstport'] will be used as a start value for port
  iteration if L4 multistream feature is enabled.
* OVS: default flow template is now configurable via OVS_FLOW_TEMPLATE
* OVS: support of TRAFFIC['flow_type']='ip' was generalized to work
  with connection methods (i.e. with P2P and PXP deployments and
  step driven TCs)
* integration TCs: modification of integration TCs and their macros to
  utilize new generic connection based API
* CI: list of TCs for VERIFY & MERGE jobs was changed to run
  the same generic tests for both OVS & VPP
* documentation update
* small fixes and improvements

JIRA: VSPERF-579

Change-Id: If4e6e6037929eab9f16c2bbcb8a0fb30e5d6f9b0
Signed-off-by: Martin Klozik <martin.klozik@tieto.com>
Reviewed-by: Richard Elias <richard.elias@tieto.com>
Reviewed-by: Al Morton <acmorton@att.com>
Reviewed-by: Christian Trautman <ctrautma@redhat.com>
Reviewed-by: Sridhar Rao <sridhar.rao@spirent.com>
26 files changed:
3rd_party/ixia/ixnetrfc2544.tcl
3rd_party/ixia/ixnetrfc2544_bad_l2_crc.tcl
3rd_party/ixia/ixnetrfc2544v2.tcl
3rd_party/ixia/ixnetrfc2544v2_random_ip_crc.tcl
3rd_party/ixia/ixnetrfc2544v2_random_udp_crc.tcl
ci/build-vsperf.sh
conf/01_testcases.conf
conf/02_vswitch.conf
conf/03_traffic.conf
conf/integration/01_testcases.conf
conf/integration/01c_trex_vm_tests.conf
core/component_factory.py
core/pktfwd_controller.py
core/vswitch_controller.py
core/vswitch_controller_clean.py
core/vswitch_controller_op2p.py
core/vswitch_controller_p2p.py
core/vswitch_controller_ptunp.py
core/vswitch_controller_pxp.py
docs/testing/developer/devguide/design/vswitchperf_design.rst
testcases/testcase.py
vswitches/ovs.py
vswitches/ovs_dpdk_vhost.py
vswitches/ovs_vanilla.py
vswitches/vpp_dpdk_vhost.py
vswitches/vswitch.py

index c47e8fc..435f335 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env tclsh
 
 # Copyright (c) 2014, Ixia
-# Copyright (c) 2015-2017, Intel Corporation
+# Copyright (c) 2015-2018, Intel Corporation, Tieto
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -2971,7 +2971,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
          -trackingEnabled False \
          -valueType $L4ValueType \
          -activeFieldChoice False \
-         -startValue {0} \
+         -startValue $dstPort \
          -countValue $L4CountValue
         sg_commit
         set sg_field [lindex [ixNet remapIds $sg_field] 0]
index 31031ec..5c42ea5 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env tclsh
 
 # Copyright (c) 2014, Ixia
-# Copyright (c) 2015-2018, Intel Corporation
+# Copyright (c) 2015-2018, Intel Corporation, Tieto
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -2971,7 +2971,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
          -trackingEnabled False \
          -valueType $L4ValueType \
          -activeFieldChoice False \
-         -startValue {0} \
+         -startValue $dstPort \
          -countValue $L4CountValue
         sg_commit
         set sg_field [lindex [ixNet remapIds $sg_field] 0]
index b5c0fe2..01e7b48 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env tclsh
 
 # Copyright (c) 2014, Ixia
-# Copyright (c) 2015-2017, Intel Corporation
+# Copyright (c) 2015-2018, Intel Corporation, Tieto
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -1667,7 +1667,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
          -trackingEnabled False \
          -valueType $L4ValueType \
          -activeFieldChoice False \
-         -startValue {0} \
+         -startValue $dstPort \
          -countValue $L4CountValue
 
         #
index 7955fd2..29cb6e8 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env tclsh
 
 # Copyright (c) 2014, Ixia
-# Copyright (c) 2015-2017, Intel Corporation
+# Copyright (c) 2015-2018, Intel Corporation, Tieto
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -1667,7 +1667,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
          -trackingEnabled False \
          -valueType $L4ValueType \
          -activeFieldChoice False \
-         -startValue {0} \
+         -startValue $dstPort \
          -countValue $L4CountValue
 
         #
index dc35f78..7af4b9f 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env tclsh
 
 # Copyright (c) 2014, Ixia
-# Copyright (c) 2015-2017, Intel Corporation
+# Copyright (c) 2015-2018, Intel Corporation, Tieto
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -1667,7 +1667,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
          -trackingEnabled False \
          -valueType $L4ValueType \
          -activeFieldChoice False \
-         -startValue {0} \
+         -startValue $dstPort \
          -countValue $L4CountValue
 
         #
index 265a203..a5ee850 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -44,9 +44,9 @@ RESULTS_ARCHIVE="$HOME/ci_results_archive"
 
 # CI job specific configuration
 # VERIFY - run basic set of TCs with default settings
-TESTCASES_VERIFY="vswitch_add_del_bridge vswitch_add_del_bridges vswitch_add_del_vport vswitch_add_del_vports vswitch_vports_add_del_flow"
+TESTCASES_VERIFY="vswitch_add_del_bridge vswitch_add_del_bridges vswitch_add_del_vport vswitch_add_del_vports vswitch_vports_add_del_connection"
 TESTPARAM_VERIFY="--integration"
-TESTCASES_VERIFY_VPP="vswitch_add_del_bridge vswitch_add_del_bridges vswitch_add_del_vport vswitch_add_del_vports vswitch_vports_add_del_connection_vpp"
+TESTCASES_VERIFY_VPP=$TESTCASES_VERIFY
 TESTPARAM_VERIFY_VPP=$TESTPARAM_VERIFY
 # MERGE - run selected TCs with default settings
 TESTCASES_MERGE=$TESTCASES_VERIFY
index 4a68ab3..d766df6 100755 (executable)
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # "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
 #
@@ -397,9 +321,14 @@ PERFORMANCE_TESTS = [
             },
         },
     },
+    #
+    # Backward compatible definition of VPP TCs.
+    # It will be removed after CI reporting will be fixed to use
+    # default TCs for VPP reporting.
+    #
     {
         "Name": "phy2phy_tput_vpp",
-        "Deployment": "clean",
+        "Deployment": "p2p",
         "Description": "VPP: LTD.Throughput.RFC2544.PacketLossRatio",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -407,11 +336,10 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_throughput",
             },
         },
-        "TestSteps": VPP_P2P,
     },
     {
         "Name": "phy2phy_cont_vpp",
-        "Deployment": "clean",
+        "Deployment": "p2p",
         "Description": "VPP: Phy2Phy Continuous Stream",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -420,11 +348,10 @@ PERFORMANCE_TESTS = [
                 "frame_rate" : 100,
             },
         },
-        "TestSteps": VPP_P2P,
     },
     {
         "Name": "phy2phy_back2back_vpp",
-        "Deployment": "clean",
+        "Deployment": "p2p",
         "Description": "VPP: LTD.Throughput.RFC2544.BackToBackFrames",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -432,11 +359,10 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_back2back",
             },
         },
-        "TestSteps": VPP_P2P,
     },
     {
         "Name": "pvp_tput_vpp",
-        "Deployment": "clean",
+        "Deployment": "pvp",
         "Description": "VPP: LTD.Throughput.RFC2544.PacketLossRatio",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -444,11 +370,10 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_throughput",
             },
         },
-        "TestSteps": VPP_PVP,
     },
     {
         "Name": "pvp_cont_vpp",
-        "Deployment": "clean",
+        "Deployment": "pvp",
         "Description": "VPP: PVP Continuous Stream",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -456,11 +381,10 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_continuous",
             },
         },
-        "TestSteps": VPP_PVP,
     },
     {
         "Name": "pvp_back2back_vpp",
-        "Deployment": "clean",
+        "Deployment": "pvp",
         "Description": "VPP: LTD.Throughput.RFC2544.BackToBackFrames",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -468,11 +392,10 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_back2back",
             },
         },
-        "TestSteps": VPP_PVP,
     },
     {
         "Name": "pvvp_tput_vpp",
-        "Deployment": "clean",
+        "Deployment": "pvvp",
         "Description": "VPP: LTD.Throughput.RFC2544.PacketLossRatio",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -480,11 +403,10 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_throughput",
             },
         },
-        "TestSteps": VPP_PVVP,
     },
     {
         "Name": "pvvp_cont_vpp",
-        "Deployment": "clean",
+        "Deployment": "pvvp",
         "Description": "VPP: PVP Continuous Stream",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -492,11 +414,10 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_continuous",
             },
         },
-        "TestSteps": VPP_PVVP,
     },
     {
         "Name": "pvvp_back2back_vpp",
-        "Deployment": "clean",
+        "Deployment": "pvvp",
         "Description": "VPP: LTD.Throughput.RFC2544.BackToBackFrames",
         "vSwitch" : "VppDpdkVhost",
         "Parameters" : {
@@ -504,6 +425,5 @@ PERFORMANCE_TESTS = [
                 "traffic_type" : "rfc2544_back2back",
             },
         },
-        "TestSteps": VPP_PVVP,
     },
 ]
index c9ffa0b..873b5bc 100644 (file)
@@ -210,6 +210,15 @@ OVS_VSCTL_ARGS = []
 OVS_OFCTL_ARGS = ['-O', 'OpenFlow13']   # backward compatible default value
 OVS_APPCTL_ARGS = []
 
+# default flow template to be used by OVS classes
+OVS_FLOW_TEMPLATE = {
+    'idle_timeout': '0'
+}
+
+# enable or disable configuration of routing tables; See vswitchperf_design.rst
+# for details.
+OVS_ROUTING_TABLES = False
+
 #########################
 ## VPP
 #########################
index f043b4c..597f2ce 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -64,7 +64,6 @@ LOG_FILE_TRAFFIC_GEN = 'traffic-gen.log'
 #                      feature. If enabled, it will implicitly insert a flow
 #                      for each stream. If multistream is disabled, then
 #                      pre-installed flows will be ignored.
-#                      Note: It is supported only for p2p deployment scenario.
 #                      Data type: str
 #                      Supported values:
 #                         "Yes" - flows will be inserted into OVS
index 142ec81..4e3c192 100644 (file)
@@ -35,7 +35,9 @@
 # Common TestSteps parts ("macros")
 #
 
+#
 # P2P macros
+#
 STEP_VSWITCH_P2P_INIT = [
     ['vswitch', 'add_switch', 'int_br0'],           # STEP 0
     ['vswitch', 'add_phy_port', 'int_br0'],         # STEP 1
@@ -48,6 +50,18 @@ STEP_VSWITCH_P2P_FINIT = [
     ['vswitch', 'del_switch', 'int_br0'],
 ]
 
+STEP_VSWITCH_P2P_CONNECTIONS_INIT = STEP_VSWITCH_P2P_INIT + [
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[2][0]', '#STEP[1][0]'],
+]
+
+STEP_VSWITCH_P2P_CONNECTIONS_FINIT = [
+    ['vswitch', 'dump_connections', 'int_br0'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[2][0]', '#STEP[1][0]'],
+] + STEP_VSWITCH_P2P_FINIT
+
+# P2P OVS specific macros
 STEP_VSWITCH_P2P_FLOWS_INIT = STEP_VSWITCH_P2P_INIT + [
     ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
     ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[2][1]', 'actions': ['output:#STEP[1][1]'], 'idle_timeout': '0'}],
@@ -59,7 +73,9 @@ STEP_VSWITCH_P2P_FLOWS_FINIT = [
     ['vswitch', 'del_flow', 'int_br0', {'in_port': '#STEP[2][1]'}],
 ] + STEP_VSWITCH_P2P_FINIT
 
-# PVP and PVVP macros
+#
+# PVP macros
+#
 STEP_VSWITCH_PVP_INIT = STEP_VSWITCH_P2P_INIT + [
     ['vswitch', 'add_vport', 'int_br0'],            # STEP 3    vm1 ports
     ['vswitch', 'add_vport', 'int_br0'],            # STEP 4
@@ -70,6 +86,22 @@ STEP_VSWITCH_PVP_FINIT = [
     ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
 ] + STEP_VSWITCH_P2P_FINIT
 
+STEP_VSWITCH_PVP_CONNECTIONS_INIT = STEP_VSWITCH_PVP_INIT + [
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[4][0]', '#STEP[2][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[2][0]', '#STEP[4][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]'],
+]
+
+STEP_VSWITCH_PVP_CONNECTIONS_FINIT = [
+    ['vswitch', 'dump_connections', 'int_br0'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[4][0]', '#STEP[2][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[2][0]', '#STEP[4][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]'],
+] + STEP_VSWITCH_PVP_FINIT
+
+# PVP OVS specific macros
 STEP_VSWITCH_PVP_FLOWS_INIT = STEP_VSWITCH_PVP_INIT + [
     ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
     ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
@@ -85,6 +117,9 @@ STEP_VSWITCH_PVP_FLOWS_FINIT = [
     ['vswitch', 'del_flow', 'int_br0', {'in_port': '#STEP[3][1]'}],
 ] + STEP_VSWITCH_PVP_FINIT
 
+#
+# PVVP macros
+#
 STEP_VSWITCH_PVVP_INIT = STEP_VSWITCH_PVP_INIT + [
     ['vswitch', 'add_vport', 'int_br0'],            # STEP 5    vm2 ports
     ['vswitch', 'add_vport', 'int_br0'],            # STEP 6
@@ -95,6 +130,26 @@ STEP_VSWITCH_PVVP_FINIT = [
     ['vswitch', 'del_port', 'int_br0', '#STEP[6][0]'],
 ] + STEP_VSWITCH_PVP_FINIT
 
+STEP_VSWITCH_PVVP_CONNECTIONS_INIT = STEP_VSWITCH_PVVP_INIT + [
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[4][0]', '#STEP[5][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[6][0]', '#STEP[2][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[2][0]', '#STEP[6][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[5][0]', '#STEP[4][0]'],
+    ['vswitch', 'add_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]'],
+]
+
+STEP_VSWITCH_PVVP_CONNECTIONS_FINIT = [
+    ['vswitch', 'dump_connections', 'int_br0'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[3][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[4][0]', '#STEP[5][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[6][0]', '#STEP[2][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[2][0]', '#STEP[6][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[5][0]', '#STEP[4][0]'],
+    ['vswitch', 'del_connection', 'int_br0', '#STEP[3][0]', '#STEP[1][0]'],
+] + STEP_VSWITCH_PVVP_FINIT
+
+# PVVP OVS specific macros
 STEP_VSWITCH_PVVP_FLOWS_INIT = STEP_VSWITCH_PVVP_INIT + [
     ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
     ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}],
@@ -440,10 +495,50 @@ INTEGRATION_TESTS = [
                         ['vswitch', 'del_switch', 'int_br0'],
                      ]
     },
+    {
+        "Name": "vswitch_add_del_connection",
+        "Deployment": "clean",
+        "Description": "vSwitch - add and delete connection",
+        "TestSteps": [
+                        ['vswitch', 'add_switch', 'int_br0'],
+                        ['vswitch', 'add_phy_port', 'int_br0'],
+                        ['vswitch', 'add_phy_port', 'int_br0'],
+                        ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]'],
+                        ['vswitch', 'dump_connections', 'int_br0'],
+                        ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]'],
+                        ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+                        ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+                        ['vswitch', 'del_switch', 'int_br0'],
+                     ]
+    },
+    {
+        "Name": "vswitch_vports_add_del_connection",
+        "Deployment": "clean",
+        "Description": "vSwitch - add and delete connection",
+        "Description": "vSwitch - configure switch with vports, add and delete connection",
+        "TestSteps": [
+                        ['vswitch', 'add_switch', 'int_br0'],
+                        ['vswitch', 'add_vport', 'int_br0'],
+                        ['vswitch', 'add_vport', 'int_br0'],
+                        ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]'],
+                        ['vswitch', 'dump_connections', 'int_br0'],
+                        ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]'],
+                        ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+                        ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+                        ['vswitch', 'del_switch', 'int_br0'],
+                     ]
+    },
+    {
+        "Name": "vswitch_add_del_connections",
+        "Deployment": "clean",
+        "Description": "vSwitch - add and delete connections",
+        "TestSteps": STEP_VSWITCH_P2P_CONNECTIONS_INIT +
+                     STEP_VSWITCH_P2P_CONNECTIONS_FINIT
+    },
     {
         "Name": "vswitch_add_del_flow",
         "Deployment": "clean",
-        "Description": "vSwitch - add and delete flow",
+        "Description": "OVS: vSwitch - add and delete flow",
         "TestSteps": [
                         ['vswitch', 'add_switch', 'int_br0'],
                         ['vswitch', 'add_phy_port', 'int_br0'],
@@ -458,7 +553,7 @@ INTEGRATION_TESTS = [
     {
         "Name": "vswitch_vports_add_del_flow",
         "Deployment": "clean",
-        "Description": "vSwitch - configure switch with vports, add and delete flow",
+        "Description": "OVS: vSwitch - configure switch with vports, add and delete flow",
         "TestSteps": [
                         ['vswitch', 'add_switch', 'int_br0'],
                         ['vswitch', 'add_vport', 'int_br0'],
@@ -473,7 +568,7 @@ INTEGRATION_TESTS = [
     {
         "Name": "vswitch_add_del_flows",
         "Deployment": "clean",
-        "Description": "vSwitch - add and delete flows",
+        "Description": "OVS: vSwitch - add and delete flows",
         "TestSteps": STEP_VSWITCH_P2P_FLOWS_INIT +
                      STEP_VSWITCH_P2P_FLOWS_FINIT
     },
@@ -481,31 +576,31 @@ INTEGRATION_TESTS = [
         "Name": "vswitch_p2p_tput",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch and execute RFC2544 throughput test",
-        "TestSteps": STEP_VSWITCH_P2P_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_P2P_CONNECTIONS_INIT +
                      [
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_throughput', 'bidir' : 'True'}],
                      ] +
-                     STEP_VSWITCH_P2P_FLOWS_FINIT
+                     STEP_VSWITCH_P2P_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_p2p_back2back",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch and execute RFC2544 back2back test",
-        "TestSteps": STEP_VSWITCH_P2P_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_P2P_CONNECTIONS_INIT +
                      [
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_back2back', 'bidir' : 'True'}],
                      ] +
-                     STEP_VSWITCH_P2P_FLOWS_FINIT
+                     STEP_VSWITCH_P2P_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_p2p_cont",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch and execute RFC2544 continuous stream test",
-        "TestSteps": STEP_VSWITCH_P2P_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_P2P_CONNECTIONS_INIT +
                      [
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_continuous', 'bidir' : 'True'}],
                      ] +
-                     STEP_VSWITCH_P2P_FLOWS_FINIT
+                     STEP_VSWITCH_P2P_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvp",
@@ -537,43 +632,43 @@ INTEGRATION_TESTS = [
         "Name": "vswitch_pvp_tput",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, vnf and execute RFC2544 throughput test",
-        "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVP_CONNECTIONS_INIT +
                      [
                         ['vnf', 'start'],
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_throughput', 'bidir' : 'True'}],
                         ['vnf', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvp_back2back",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, vnf and execute RFC2544 back2back test",
-        "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVP_CONNECTIONS_INIT +
                      [
                         ['vnf', 'start'],
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_back2back', 'bidir' : 'True'}],
                         ['vnf', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvp_cont",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, vnf and execute RFC2544 continuous stream test",
-        "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVP_CONNECTIONS_INIT +
                      [
                         ['vnf', 'start'],
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_continuous', 'bidir' : 'True'}],
                         ['vnf', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvp_all",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, vnf and execute all test types",
-        "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVP_CONNECTIONS_INIT +
                      [
                         ['vnf', 'start'],
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_throughput', 'bidir' : 'True'}],
@@ -581,7 +676,7 @@ INTEGRATION_TESTS = [
                         ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_continuous', 'bidir' : 'True'}],
                         ['vnf', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvvp",
@@ -600,7 +695,7 @@ INTEGRATION_TESTS = [
         "Name": "vswitch_pvvp_tput",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, two chained vnfs and execute RFC2544 throughput test",
-        "TestSteps": STEP_VSWITCH_PVVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVVP_CONNECTIONS_INIT +
                      [
                         ['vnf1', 'start'],
                         ['vnf2', 'start'],
@@ -608,13 +703,13 @@ INTEGRATION_TESTS = [
                         ['vnf1', 'stop'],
                         ['vnf2', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvvp_back2back",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, two chained vnfs and execute RFC2544 back2back test",
-        "TestSteps": STEP_VSWITCH_PVVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVVP_CONNECTIONS_INIT +
                      [
                         ['vnf1', 'start'],
                         ['vnf2', 'start'],
@@ -622,13 +717,13 @@ INTEGRATION_TESTS = [
                         ['vnf1', 'stop'],
                         ['vnf2', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvvp_cont",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, two chained vnfs and execute RFC2544 continuous stream test",
-        "TestSteps": STEP_VSWITCH_PVVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVVP_CONNECTIONS_INIT +
                      [
                         ['vnf1', 'start'],
                         ['vnf2', 'start'],
@@ -636,13 +731,13 @@ INTEGRATION_TESTS = [
                         ['vnf1', 'stop'],
                         ['vnf2', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_pvvp_all",
         "Deployment": "clean",
         "Description": "vSwitch - configure switch, two chained vnfs and execute all test types",
-        "TestSteps": STEP_VSWITCH_PVVP_FLOWS_INIT +
+        "TestSteps": STEP_VSWITCH_PVVP_CONNECTIONS_INIT +
                      [
                         ['vnf1', 'start'],
                         ['vnf2', 'start'],
@@ -652,7 +747,7 @@ INTEGRATION_TESTS = [
                         ['vnf1', 'stop'],
                         ['vnf2', 'stop'],
                      ] +
-                     STEP_VSWITCH_PVVP_FLOWS_FINIT
+                     STEP_VSWITCH_PVVP_CONNECTIONS_FINIT
     },
     {
         "Name": "vswitch_p4vp",
@@ -971,23 +1066,6 @@ INTEGRATION_TESTS = [
                         ['tools', 'assert', 'len(#STEP[-1][0])'],
                      ]
     },
-    {
-        "Name": "vswitch_vports_add_del_connection_vpp",
-        "Deployment": "clean",
-        "Description": "VPP: vSwitch - configure switch with vports, add and delete connection",
-        "vSwitch" : "VppDpdkVhost",
-        "TestSteps": [
-                        ['vswitch', 'add_switch', 'int_br0'],
-                        ['vswitch', 'add_vport', 'int_br0'],
-                        ['vswitch', 'add_vport', 'int_br0'],
-                        ['vswitch', 'add_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]', True],
-                        ['vswitch', 'dump_connections', 'int_br0'],
-                        ['vswitch', 'del_connection', 'int_br0', '#STEP[1][0]', '#STEP[2][0]', True],
-                        ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
-                        ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
-                        ['vswitch', 'del_switch', 'int_br0'],
-                     ]
-    },
     #
     # END of VPP tests used by VERIFY and MERGE jobs by OPNFV Jenkins
     #
@@ -1163,11 +1241,11 @@ INTEGRATION_TESTS += [
 #        "VNF" : "QemuVirtioNet",
 #        "Trafficgen": "IxNet",
 #        "Parameters": {"GUEST_LOOPBACK" : ["linux_bridge"],},
-#        "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT +
+#        "TestSteps": STEP_VSWITCH_PVP_CONNECTIONS_INIT +
 #                     [
 #                        ['vnf', 'start'],
 #                        ['trafficgen', 'send_traffic', {'traffic_type' : 'rfc2544_continuous', 'bidir' : 'True'}],
 #                        ['vnf', 'stop'],
 #                     ] +
-#                     STEP_VSWITCH_PVP_FLOWS_FINIT
+#                     STEP_VSWITCH_PVP_CONNECTIONS_FINIT
 #    },
index 50982be..1bec4ef 100644 (file)
@@ -30,6 +30,7 @@ TREX_VM_INIT = [
     ['#trex_p2', 'vswitch', 'add_vport', 'int_br0'],
     # configure IP access to T-Rex VM
     ['vswitch', 'add_switch', 'trex_br'],
+    ['vswitch', 'add_flow', 'trex_br', {'actions': ['NORMAL']}], # turn on MAC learning mode
     ['#trex_admin', 'vswitch', 'add_vport', 'trex_br'],
     ['#trex_spare', 'vswitch', 'add_vport', 'trex_br'],    # spare to have even number of NICs
     ['tools', 'exec_shell', 'sudo ip addr flush dev trex_br'],
index b6bd267..2c51a06 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -66,23 +66,23 @@ def create_vswitch(deployment_scenario, vswitch_class, traffic,
     :return: IVSwitchController for the deployment_scenario
     """
     # pylint: disable=too-many-return-statements
-    deployment_scenario = deployment_scenario.lower()
-    if deployment_scenario.startswith("p2p"):
-        return VswitchControllerP2P(vswitch_class, traffic)
-    elif deployment_scenario.startswith("pvp"):
-        return VswitchControllerPXP(deployment_scenario, vswitch_class, traffic)
-    elif deployment_scenario.startswith("pvvp"):
-        return VswitchControllerPXP(deployment_scenario, vswitch_class, traffic)
-    elif deployment_scenario.startswith("pvpv"):
-        return VswitchControllerPXP(deployment_scenario, vswitch_class, traffic)
-    elif deployment_scenario.startswith("op2p"):
-        return VswitchControllerOP2P(vswitch_class, traffic, tunnel_operation)
-    elif deployment_scenario.startswith("ptunp"):
-        return VswitchControllerPtunP(vswitch_class, traffic)
-    elif deployment_scenario.startswith("clean"):
-        return VswitchControllerClean(vswitch_class, traffic)
+    deployment = deployment_scenario.lower()
+    if deployment.startswith("p2p"):
+        return VswitchControllerP2P(deployment, vswitch_class, traffic)
+    elif deployment.startswith("pvp"):
+        return VswitchControllerPXP(deployment, vswitch_class, traffic)
+    elif deployment.startswith("pvvp"):
+        return VswitchControllerPXP(deployment, vswitch_class, traffic)
+    elif deployment.startswith("pvpv"):
+        return VswitchControllerPXP(deployment, vswitch_class, traffic)
+    elif deployment.startswith("op2p"):
+        return VswitchControllerOP2P(deployment, vswitch_class, traffic, tunnel_operation)
+    elif deployment.startswith("ptunp"):
+        return VswitchControllerPtunP(deployment, vswitch_class, traffic)
+    elif deployment.startswith("clean"):
+        return VswitchControllerClean(deployment, vswitch_class, traffic)
     else:
-        raise RuntimeError("Unknown deployment scenario '{}'.".format(deployment_scenario))
+        raise RuntimeError("Unknown deployment scenario '{}'.".format(deployment))
 
 
 def create_vnf(deployment_scenario, vnf_class, extra_vnfs):
index bdc9182..363302c 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2016 Intel Corporation.
+# Copyright 2016-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -89,9 +89,9 @@ class PktFwdController(object):
         """
         return self._pktfwd
 
-    def dump_vswitch_flows(self):
-        """ Dumps flows from vswitch
+    def dump_vswitch_connections(self):
+        """ Dumps connections from vswitch
         """
         raise NotImplementedError(
             "The PktFwdController does not implement the "
-            "\"dump_vswitch_flows\" function.")
+            "\"dump_vswitch_connections\" function.")
index 855de8b..889f14b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # limitations under the License.
 """Interface for deployment specific vSwitch controllers
 """
+import logging
 
 class IVswitchController(object):
-    """Abstract class which defines a vSwitch controller object
+    """Interface class for a vSwitch controller object
 
     This interface is used to setup and control a vSwitch provider for a
     particular deployment scenario.
     """
-    def __enter__(self):
+    def __init__(self, deployment, vswitch_class, traffic):
+        """Initializes up the generic prerequisites for deployment scenario.
+
+        :deployment: the deployment scenario to configure
+        :vswitch_class: the vSwitch class to be used.
+        :traffic: dictionary with detailed traffic definition
+        """
+        self._logger = logging.getLogger(__name__)
+        self._vswitch_class = vswitch_class
+        self._vswitch = vswitch_class()
+        self._deployment_scenario = deployment
+        self._logger.debug('Creation using %s', str(self._vswitch_class))
+        self._traffic = traffic.copy()
+        self._bridge = None
+
+    def setup(self):
         """Sets up the switch for the particular deployment scenario
         """
         raise NotImplementedError(
             "The VswitchController does not implement the \"setup\" function.")
 
-    def __exit__(self, type_, value, traceback):
+    def stop(self):
         """Tears down the switch created in setup()
         """
         raise NotImplementedError(
             "The VswitchController does not implement the \"stop\" function.")
 
+    def __enter__(self):
+        """Sets up the switch for the particular deployment scenario
+        """
+        self.setup()
+
+    def __exit__(self, type_, value, traceback):
+        """Tears down the switch created in setup()
+        """
+        self.stop()
+
     def get_vswitch(self):
         """Get the controlled vSwitch
 
         :return: The controlled IVswitch
         """
-        raise NotImplementedError(
-            "The VswitchController does not implement the \"get_vswitch\" "
-            "function.")
+        return self._vswitch
 
     def get_ports_info(self):
         """Returns a dictionary describing all ports on the vSwitch.
@@ -50,9 +74,9 @@ class IVswitchController(object):
             "The VswitchController does not implement the \"get_ports_info\" "
             "function.")
 
-    def dump_vswitch_flows(self):
-        """ Dumps flows from vswitch
+    def dump_vswitch_connections(self):
+        """ Dumps connections from vswitch
         """
         raise NotImplementedError(
             "The VswitchController does not implement the "
-            "\"dump_vswitch_flows\" function.")
+            "\"dump_vswitch_connections\" function.")
index 432406a..7a77122 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2016 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -14,9 +14,6 @@
 
 """VSwitch controller for basic initialization of vswitch
 """
-
-import logging
-
 from core.vswitch_controller import IVswitchController
 
 class VswitchControllerClean(IVswitchController):
@@ -28,18 +25,6 @@ class VswitchControllerClean(IVswitchController):
         _deployment_scenario: A string describing the scenario to set-up in the
             constructor.
     """
-    def __init__(self, vswitch_class, traffic):
-        """Initializes up the prerequisites for the Clean deployment scenario.
-
-        :vswitch_class: the vSwitch class to be used.
-        """
-        self._logger = logging.getLogger(__name__)
-        self._vswitch_class = vswitch_class
-        self._vswitch = vswitch_class()
-        self._deployment_scenario = "Clean"
-        self._logger.debug('Creation using %s', str(self._vswitch_class))
-        self._traffic = traffic.copy()
-
     def setup(self):
         """Sets up the switch for Clean.
         """
@@ -57,23 +42,12 @@ class VswitchControllerClean(IVswitchController):
         self._logger.debug('Stop using %s', str(self._vswitch_class))
         self._vswitch.stop()
 
-    def __enter__(self):
-        self.setup()
-
-    def __exit__(self, type_, value, traceback):
-        self.stop()
-
-    def get_vswitch(self):
-        """See IVswitchController for description
-        """
-        return self._vswitch
-
     def get_ports_info(self):
         """See IVswitchController for description
         """
         pass
 
-    def dump_vswitch_flows(self):
+    def dump_vswitch_connections(self):
         """See IVswitchController for description
         """
         pass
index 3f879f9..072a690 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 
 """VSwitch controller for Physical to Tunnel Endpoint to Physical deployment
 """
-
-import logging
-
 from core.vswitch_controller import IVswitchController
 from vswitches.utils import add_ports_to_flow
 from conf import settings as S
 from tools import tasks
 
-_FLOW_TEMPLATE = {
-    'idle_timeout': '0'
-}
-
 class VswitchControllerOP2P(IVswitchController):
     """VSwitch controller for OP2P deployment scenario.
-
-    Attributes:
-        _vswitch_class: The vSwitch class to be used.
-        _vswitch: The vSwitch object controlled by this controller
-        _deployment_scenario: A string describing the scenario to set-up in the
-            constructor.
     """
-    def __init__(self, vswitch_class, traffic, tunnel_operation=None):
-        """Initializes up the prerequisites for the OP2P deployment scenario.
-
-        :vswitch_class: the vSwitch class to be used.
+    def __init__(self, deployment, vswitch_class, traffic, tunnel_operation=None):
+        """See IVswitchController for general description
         """
-        self._logger = logging.getLogger(__name__)
-        self._vswitch_class = vswitch_class
-        self._vswitch = vswitch_class()
-        self._deployment_scenario = "OP2P"
-        self._traffic = traffic.copy()
+        super().__init__(deployment, vswitch_class, traffic)
         self._tunnel_operation = tunnel_operation
-        self._logger.debug('Creation using %s', str(self._vswitch_class))
 
     def setup(self):
         """ Sets up the switch for overlay P2P (tunnel encap or decap)
@@ -118,10 +98,13 @@ class VswitchControllerOP2P(IVswitchController):
 
             # Test is unidirectional for now
             self._vswitch.del_flow(bridge)
-            flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy1_number,
+            flow1 = add_ports_to_flow(S.getValue('OVS_FLOW_TEMPLATE'), phy1_number,
                                       phy2_number)
             self._vswitch.add_flow(bridge, flow1)
-
+            # enable MAC learning mode at external bridge
+            flow_ext = S.getValue('OVS_FLOW_TEMPLATE').copy()
+            flow_ext.update({'actions': ['NORMAL']})
+            self._vswitch.add_flow(bridge_ext, flow_ext)
         except:
             self._vswitch.stop()
             raise
@@ -178,7 +161,7 @@ class VswitchControllerOP2P(IVswitchController):
                                          bridge)
             # Test is unidirectional for now
             self._vswitch.del_flow(bridge_ext)
-            flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy3_number,
+            flow1 = add_ports_to_flow(S.getValue('OVS_FLOW_TEMPLATE'), phy3_number,
                                       phy2_number)
             self._vswitch.add_flow(bridge_ext, flow1)
 
@@ -251,7 +234,7 @@ class VswitchControllerOP2P(IVswitchController):
             # Test is unidirectional for now
             self._vswitch.del_flow(bridge_ext)
 
-            flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy2_number, 'LOCAL')
+            flow1 = add_ports_to_flow(S.getValue('OVS_FLOW_TEMPLATE'), phy2_number, 'LOCAL')
             self._vswitch.add_flow(bridge_ext, flow1)
 
         except:
@@ -264,17 +247,6 @@ class VswitchControllerOP2P(IVswitchController):
         self._logger.debug('Stop using %s', str(self._vswitch_class))
         self._vswitch.stop()
 
-    def __enter__(self):
-        self.setup()
-
-    def __exit__(self, type_, value, traceback):
-        self.stop()
-
-    def get_vswitch(self):
-        """See IVswitchController for description
-        """
-        return self._vswitch
-
     def get_ports_info(self):
         """See IVswitchController for description
         """
@@ -286,8 +258,8 @@ class VswitchControllerOP2P(IVswitchController):
                 self._vswitch.get_ports(
                     S.getValue('TUNNEL_EXTERNAL_BRIDGE'))
 
-    def dump_vswitch_flows(self):
+    def dump_vswitch_connections(self):
         """See IVswitchController for description
         """
-        self._vswitch.dump_flows(S.getValue('TUNNEL_INTEGRATION_BRIDGE'))
-        self._vswitch.dump_flows(S.getValue('TUNNEL_EXTERNAL_BRIDGE'))
+        self._vswitch.dump_connections(S.getValue('TUNNEL_INTEGRATION_BRIDGE'))
+        self._vswitch.dump_connections(S.getValue('TUNNEL_EXTERNAL_BRIDGE'))
index eb1f57f..d8f22e4 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 
 """VSwitch controller for Physical to Physical deployment
 """
-
-import logging
-import netaddr
-
 from core.vswitch_controller import IVswitchController
 from conf import settings
 
-_FLOW_TEMPLATE = {
-    'idle_timeout': '0'
-}
-
-_PROTO_TCP = 6
-_PROTO_UDP = 17
-
 class VswitchControllerP2P(IVswitchController):
     """VSwitch controller for P2P deployment scenario.
 
@@ -37,17 +26,11 @@ class VswitchControllerP2P(IVswitchController):
         _deployment_scenario: A string describing the scenario to set-up in the
             constructor.
     """
-    def __init__(self, vswitch_class, traffic):
-        """Initializes up the prerequisites for the P2P deployment scenario.
-
-        :vswitch_class: the vSwitch class to be used.
+    def __init__(self, deployment, vswitch_class, traffic):
+        """See IVswitchController for general description
         """
-        self._logger = logging.getLogger(__name__)
-        self._vswitch_class = vswitch_class
-        self._vswitch = vswitch_class()
-        self._deployment_scenario = "P2P"
-        self._logger.debug('Creation using %s', str(self._vswitch_class))
-        self._traffic = traffic.copy()
+        super().__init__(deployment, vswitch_class, traffic)
+        self._bridge = settings.getValue('VSWITCH_BRIDGE_NAME')
 
     def setup(self):
         """Sets up the switch for p2p.
@@ -57,51 +40,14 @@ class VswitchControllerP2P(IVswitchController):
         try:
             self._vswitch.start()
 
-            bridge = settings.getValue('VSWITCH_BRIDGE_NAME')
-            self._vswitch.add_switch(bridge)
-
-            (_, _) = self._vswitch.add_phy_port(bridge)
-            (_, _) = self._vswitch.add_phy_port(bridge)
-
-            self._vswitch.del_flow(bridge)
-
-            # table#0 - flows designed to force 5 & 13 tuple matches go here
-            flow = {'table':'0', 'priority':'1', 'actions': ['goto_table:1']}
-            self._vswitch.add_flow(bridge, flow)
-
-            # table#1 - flows to route packets between ports goes here. The
-            # chosen port is communicated to subsequent tables by setting the
-            # metadata value to the egress port number
+            self._vswitch.add_switch(self._bridge)
 
-            # configure flows according to the TC definition
-            flow_template = _FLOW_TEMPLATE.copy()
-            if self._traffic['flow_type'] == 'IP':
-                flow_template.update({'dl_type':'0x0800', 'nw_src':self._traffic['l3']['srcip'],
-                                      'nw_dst':self._traffic['l3']['dstip']})
+            (port1, _) = self._vswitch.add_phy_port(self._bridge)
+            (port2, _) = self._vswitch.add_phy_port(self._bridge)
 
-            flow = flow_template.copy()
-            flow.update({'table':'1', 'priority':'1', 'in_port':'1',
-                         'actions': ['write_actions(output:2)', 'write_metadata:0x2',
-                                     'goto_table:2']})
-            self.process_flow_template(bridge, flow)
-            flow = flow_template.copy()
-            flow.update({'table':'1', 'priority':'1', 'in_port':'2',
-                         'actions': ['write_actions(output:1)', 'write_metadata:0x1',
-                                     'goto_table:2']})
-            self.process_flow_template(bridge, flow)
+            self._vswitch.add_connection(self._bridge, port1, port2, self._traffic)
+            self._vswitch.add_connection(self._bridge, port2, port1, self._traffic)
 
-            # Frame modification table. Frame modification flow rules are
-            # isolated in this table so that they can be turned on or off
-            # without affecting the routing or tuple-matching flow rules.
-            flow = {'table':'2', 'priority':'1', 'actions': ['goto_table:3']}
-            self._vswitch.add_flow(bridge, flow)
-
-            # Egress table
-            # (TODO) Billy O'Mahony - the drop action here actually required in
-            # order to egress the packet. This is the subject of a thread on
-            # ovs-discuss 2015-06-30.
-            flow = {'table':'3', 'priority':'1', 'actions': ['drop']}
-            self._vswitch.add_flow(bridge, flow)
         except:
             self._vswitch.stop()
             raise
@@ -112,65 +58,13 @@ class VswitchControllerP2P(IVswitchController):
         self._logger.debug('Stop using %s', str(self._vswitch_class))
         self._vswitch.stop()
 
-    def __enter__(self):
-        self.setup()
-
-    def __exit__(self, type_, value, traceback):
-        self.stop()
-
-    def get_vswitch(self):
-        """See IVswitchController for description
-        """
-        return self._vswitch
-
     def get_ports_info(self):
         """See IVswitchController for description
         """
         self._logger.debug('get_ports_info  using %s', str(self._vswitch_class))
-        return self._vswitch.get_ports(settings.getValue('VSWITCH_BRIDGE_NAME'))
+        return self._vswitch.get_ports(self._bridge)
 
-    def dump_vswitch_flows(self):
+    def dump_vswitch_connections(self):
         """See IVswitchController for description
         """
-        self._vswitch.dump_flows(settings.getValue('VSWITCH_BRIDGE_NAME'))
-
-    def process_flow_template(self, bridge, flow_template):
-        """Method adds flows into the vswitch based on given flow template
-           and configuration of multistream feature.
-        """
-        if ('pre_installed_flows' in self._traffic and
-                self._traffic['pre_installed_flows'].lower() == 'yes' and
-                'multistream' in self._traffic and self._traffic['multistream'] > 0 and
-                'stream_type' in self._traffic):
-            # multistream feature is enabled and flows should be inserted into OVS
-            # so generate flows based on template and multistream configuration
-            if self._traffic['stream_type'] == 'L2':
-                # iterate through destimation MAC address
-                dst_mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value
-                for i in range(self._traffic['multistream']):
-                    tmp_mac = netaddr.EUI(dst_mac_value + i)
-                    tmp_mac.dialect = netaddr.mac_unix_expanded
-                    flow_template.update({'dl_dst':tmp_mac})
-                    # optimize flow insertion by usage of cache
-                    self._vswitch.add_flow(bridge, flow_template, cache='on')
-            elif self._traffic['stream_type'] == 'L3':
-                # iterate through destimation IP address
-                dst_ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value
-                for i in range(self._traffic['multistream']):
-                    tmp_ip = netaddr.IPAddress(dst_ip_value + i)
-                    flow_template.update({'dl_type':'0x0800', 'nw_dst':tmp_ip})
-                    # optimize flow insertion by usage of cache
-                    self._vswitch.add_flow(bridge, flow_template, cache='on')
-            elif self._traffic['stream_type'] == 'L4':
-                # read transport protocol from configuration and iterate through its destination port
-                proto = _PROTO_TCP if self._traffic['l3']['proto'].lower() == 'tcp' else _PROTO_UDP
-                for i in range(self._traffic['multistream']):
-                    flow_template.update({'dl_type':'0x0800', 'nw_proto':proto, 'tp_dst':i})
-                    # optimize flow insertion by usage of cache
-                    self._vswitch.add_flow(bridge, flow_template, cache='on')
-            else:
-                self._logger.error('Stream type is set to uknown value %s', self._traffic['stream_type'])
-            # insert cached flows into the OVS
-            self._vswitch.add_flow(bridge, [], cache='flush')
-        else:
-            self._vswitch.add_flow(bridge, flow_template)
+        self._vswitch.dump_connections(self._bridge)
index 853c7d5..b10da2a 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2016 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,8 +15,6 @@
 """VSwitch controller for Physical to VxLAN Tunnel Endpoint to Physical
    deployment with mod operation.
 """
-
-import logging
 from netaddr import EUI, IPNetwork, mac_unix
 
 from core.vswitch_controller import IVswitchController
@@ -24,10 +22,6 @@ from vswitches.utils import add_ports_to_flow
 from conf import settings
 from tools import tasks
 
-_FLOW_TEMPLATE = {
-    'idle_timeout': '0'
-}
-
 class VswitchControllerPtunP(IVswitchController):
     """VSwitch controller for VxLAN ptunp deployment scenario.
     The deployment scenario is to test VxLAN tunneling feature without using an
@@ -40,16 +34,10 @@ class VswitchControllerPtunP(IVswitchController):
         _deployment_scenario: A string describing the scenario to set-up in the
             constructor.
     """
-    def __init__(self, vswitch_class, traffic):
-        """Initializes up the prerequisites for the ptunp deployment scenario.
-
-        :vswitch_class: the vSwitch class to be used.
+    def __init__(self, deployment, vswitch_class, traffic):
+        """See IVswitchController for general description
         """
-        self._logger = logging.getLogger(__name__)
-        self._vswitch_class = vswitch_class
-        self._vswitch = vswitch_class()
-        self._deployment_scenario = "ptunp"
-        self._traffic = traffic.copy()
+        super().__init__(deployment, vswitch_class, traffic)
         self.bridge_phy1 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE1')
         self.bridge_phy2 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE2')
         self.bridge_mod1 = settings.getValue('TUNNEL_MODIFY_BRIDGE1')
@@ -59,7 +47,6 @@ class VswitchControllerPtunP(IVswitchController):
         self.br_mod_ip1 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP1')
         self.br_mod_ip2 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP2')
         self.tunnel_type = settings.getValue('TUNNEL_TYPE')
-        self._logger.debug('Creation using %s', str(self._vswitch_class))
 
     def setup(self):
         """ Sets up the switch for VxLAN overlay PTUNP (tunnel encap or decap)
@@ -156,23 +143,23 @@ class VswitchControllerPtunP(IVswitchController):
             self._vswitch.del_flow(self.bridge_phy2)
             self._vswitch.del_flow(self.bridge_mod1)
             self._vswitch.del_flow(self.bridge_mod2)
-            flow = add_ports_to_flow(_FLOW_TEMPLATE, phy1_number,
+            flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy1_number,
                                      phy3_number)
             self._vswitch.add_flow(self.bridge_phy1, flow)
-            flow = add_ports_to_flow(_FLOW_TEMPLATE, phy3_number,
+            flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy3_number,
                                      phy1_number)
             self._vswitch.add_flow(self.bridge_phy1, flow)
 
-            flow = add_ports_to_flow(_FLOW_TEMPLATE, phy2_number,
+            flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy2_number,
                                      phy4_number)
             self._vswitch.add_flow(self.bridge_phy2, flow)
-            flow = add_ports_to_flow(_FLOW_TEMPLATE, phy4_number,
+            flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy4_number,
                                      phy2_number)
             self._vswitch.add_flow(self.bridge_phy2, flow)
-            flow = add_ports_to_flow(_FLOW_TEMPLATE, phy5_number,
+            flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy5_number,
                                      'LOCAL')
             self._vswitch.add_flow(self.bridge_mod1, flow)
-            mod_flow_template = _FLOW_TEMPLATE.copy()
+            mod_flow_template = settings.getValue('OVS_FLOW_TEMPLATE').copy()
             mod_flow_template.update({'ip':'',
                                       'actions':
                                       ['mod_dl_src:' + str(vxlan_rem_mac2),
@@ -183,10 +170,10 @@ class VswitchControllerPtunP(IVswitchController):
                                      })
             flow = add_ports_to_flow(mod_flow_template, 'LOCAL', phy5_number)
             self._vswitch.add_flow(self.bridge_mod1, flow)
-            flow = add_ports_to_flow(_FLOW_TEMPLATE, phy6_number,
+            flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy6_number,
                                      'LOCAL')
             self._vswitch.add_flow(self.bridge_mod2, flow)
-            mod_flow_template = _FLOW_TEMPLATE.copy()
+            mod_flow_template = settings.getValue('OVS_FLOW_TEMPLATE').copy()
             mod_flow_template.update({'ip':'',
                                       'actions':
                                       ['mod_dl_src:' + str(vxlan_rem_mac1),
@@ -207,17 +194,6 @@ class VswitchControllerPtunP(IVswitchController):
         self._logger.debug('Stop using %s', str(self._vswitch_class))
         self._vswitch.stop()
 
-    def __enter__(self):
-        self.setup()
-
-    def __exit__(self, type_, value, traceback):
-        self.stop()
-
-    def get_vswitch(self):
-        """See IVswitchController for description
-        """
-        return self._vswitch
-
     def get_ports_info(self):
         """See IVswitchController for description
         """
@@ -228,11 +204,11 @@ class VswitchControllerPtunP(IVswitchController):
                 self._vswitch.get_ports(self.bridge_mod2)
         return ports
 
-    def dump_vswitch_flows(self):
+    def dump_vswitch_connections(self):
         """See IVswitchController for description
         """
-        self._logger.debug('dump_flows using %s', str(self._vswitch_class))
-        self._vswitch.dump_flows(self.bridge_phy1)
-        self._vswitch.dump_flows(self.bridge_mod1)
-        self._vswitch.dump_flows(self.bridge_phy2)
-        self._vswitch.dump_flows(self.bridge_mod2)
+        self._logger.debug('dump_connections using %s', str(self._vswitch_class))
+        self._vswitch.dump_connections(self.bridge_phy1)
+        self._vswitch.dump_connections(self.bridge_mod1)
+        self._vswitch.dump_connections(self.bridge_phy2)
+        self._vswitch.dump_connections(self.bridge_mod2)
index e3c208a..d36ecdb 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2016 Intel Corporation.
+# Copyright 2016-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 
 """VSwitch controller for multi VM scenarios with serial or parallel connection
 """
-
-import logging
 import netaddr
 
 from core.vswitch_controller import IVswitchController
-from vswitches.utils import add_ports_to_flow
 from conf import settings
 
-_FLOW_TEMPLATE = {
-    'idle_timeout': '0'
-}
-
-_PROTO_TCP = 6
-_PROTO_UDP = 17
-
 class VswitchControllerPXP(IVswitchController):
     """VSwitch controller for PXP deployment scenario.
     """
     def __init__(self, deployment, vswitch_class, traffic):
-        """Initializes up the prerequisites for the PXP deployment scenario.
-
-        :vswitch_class: the vSwitch class to be used.
-        :deployment: the deployment scenario to configure
-        :traffic: dictionary with detailed traffic definition
+        """See IVswitchController for general description
         """
-        self._logger = logging.getLogger(__name__)
-        self._vswitch_class = vswitch_class
-        self._vswitch = vswitch_class()
+        super().__init__(deployment, vswitch_class, traffic)
         self._pxp_topology = 'parallel' if deployment.startswith('pvpv') else 'serial'
         if deployment == 'pvp':
             self._pxp_vm_count = 1
@@ -55,9 +39,7 @@ class VswitchControllerPXP(IVswitchController):
 
         self._deployment_scenario = deployment
 
-        self._traffic = traffic.copy()
         self._bidir = True if self._traffic['bidir'] == 'True' else False
-        self._logger.debug('Creation using %s', str(self._vswitch_class))
         self._bridge = settings.getValue('VSWITCH_BRIDGE_NAME')
 
     def setup(self):
@@ -71,8 +53,8 @@ class VswitchControllerPXP(IVswitchController):
             self._vswitch.add_switch(self._bridge)
 
             # create physical ports
-            (_, phy1_number) = self._vswitch.add_phy_port(self._bridge)
-            (_, phy2_number) = self._vswitch.add_phy_port(self._bridge)
+            (phy1, _) = self._vswitch.add_phy_port(self._bridge)
+            (phy2, _) = self._vswitch.add_phy_port(self._bridge)
 
             # create VM ports
             # initialize vport array to requested number of VMs
@@ -86,54 +68,42 @@ class VswitchControllerPXP(IVswitchController):
                 self._logger.debug('Create %s vports for %s. VM with index %s',
                                    nics_nr, vmindex + 1, vmindex)
                 for _ in range(nics_nr):
-                    (_, vport) = self._vswitch.add_vport(self._bridge)
+                    (vport, _) = self._vswitch.add_vport(self._bridge)
                     vm_ports[vmindex].append(vport)
 
-            self._vswitch.del_flow(self._bridge)
-
-            # configure flows according to the TC definition
+            # configure connections according to the TC definition
             if self._pxp_topology == 'serial':
-                flow = _FLOW_TEMPLATE.copy()
-                if self._traffic['flow_type'] == 'IP':
-                    flow.update({'dl_type':'0x0800',
-                                 'nw_src':self._traffic['l3']['srcip'],
-                                 'nw_dst':self._traffic['l3']['dstip']})
+                # NOTE: all traffic from VMs is sent to other ports directly
+                # without applying traffic options to avoid issues with MAC swapping
+                # and upper layer mods performed inside guests
 
-                # insert flows for phy ports first
+                # insert connections for phy ports first
                 # from 1st PHY to 1st vport of 1st VM
-                self._add_flow(flow,
-                               phy1_number,
-                               vm_ports[0][0],
-                               self._bidir)
+                self._vswitch.add_connection(self._bridge, phy1, vm_ports[0][0], self._traffic)
+                self._vswitch.add_connection(self._bridge, vm_ports[0][0], phy1)
                 # from last vport of last VM to 2nd phy
-                self._add_flow(flow,
-                               vm_ports[self._pxp_vm_count-1][-1],
-                               phy2_number,
-                               self._bidir)
+                self._vswitch.add_connection(self._bridge, vm_ports[self._pxp_vm_count-1][-1], phy2)
+                self._vswitch.add_connection(self._bridge, phy2, vm_ports[self._pxp_vm_count-1][-1], self._traffic)
 
                 # add serial connections among VMs and VM NICs pairs if needed
                 # in case of multiple NICs pairs per VM, the pairs are chained
-                # first, before flow to the next VM is created
+                # first, before connection to the next VM is created
                 for vmindex in range(self._pxp_vm_count):
                     # connect VMs NICs pairs in case of 4 and more NICs per VM
                     connections = [(vm_ports[vmindex][2*(x+1)-1],
                                     vm_ports[vmindex][2*(x+1)])
                                    for x in range(int(len(vm_ports[vmindex])/2)-1)]
                     for connection in connections:
-                        self._add_flow(flow,
-                                       connection[0],
-                                       connection[1],
-                                       self._bidir)
+                        self._vswitch.add_connection(self._bridge, connection[0], connection[1])
+                        self._vswitch.add_connection(self._bridge, connection[1], connection[0])
                     # connect last NICs to the next VM if there is any
                     if self._pxp_vm_count > vmindex + 1:
-                        self._add_flow(flow,
-                                       vm_ports[vmindex][-1],
-                                       vm_ports[vmindex+1][0],
-                                       self._bidir)
+                        self._vswitch.add_connection(self._bridge, vm_ports[vmindex][-1], vm_ports[vmindex+1][0])
+                        self._vswitch.add_connection(self._bridge, vm_ports[vmindex+1][0], vm_ports[vmindex][-1])
             else:
-                proto = _PROTO_TCP if self._traffic['l3']['proto'].lower() == 'tcp' else _PROTO_UDP
-                dst_mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value
-                dst_ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value
+                mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value
+                ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value
+                port_value = self._traffic['l4']['dstport']
                 # initialize stream index; every NIC pair of every VM uses unique stream
                 stream = 0
                 for vmindex in range(self._pxp_vm_count):
@@ -146,31 +116,33 @@ class VswitchControllerPXP(IVswitchController):
                         port_pairs = [(vm_ports[vmindex][0], vm_ports[vmindex][0])]
 
                     for port_pair in port_pairs:
-                        flow_p = _FLOW_TEMPLATE.copy()
-                        flow_v = _FLOW_TEMPLATE.copy()
-
-                        # update flow based on trafficgen settings
+                        # override traffic options to ensure, that traffic is
+                        # dispatched among VMs connected in parallel
+                        options = {'multistream':1,
+                                   'stream_type':self._traffic['stream_type'],
+                                   'pre_installed_flows':'Yes'}
+                        # update connection based on trafficgen settings
                         if self._traffic['stream_type'] == 'L2':
-                            tmp_mac = netaddr.EUI(dst_mac_value + stream)
+                            tmp_mac = netaddr.EUI(mac_value + stream)
                             tmp_mac.dialect = netaddr.mac_unix_expanded
-                            flow_p.update({'dl_dst':tmp_mac})
+                            options.update({'l2':{'dstmac':tmp_mac}})
                         elif self._traffic['stream_type'] == 'L3':
-                            tmp_ip = netaddr.IPAddress(dst_ip_value + stream)
-                            flow_p.update({'dl_type':'0x0800', 'nw_dst':tmp_ip})
+                            tmp_ip = netaddr.IPAddress(ip_value + stream)
+                            options.update({'l3':{'dstip':tmp_ip}})
                         elif self._traffic['stream_type'] == 'L4':
-                            flow_p.update({'dl_type':'0x0800', 'nw_proto':proto, 'tp_dst':stream})
+                            options.update({'l3':{'proto':self._traffic['l3']['proto']}})
+                            options.update({'l4':{'dstport':(port_value + stream) % 65536}})
                         else:
                             raise RuntimeError('Unknown stream_type {}'.format(self._traffic['stream_type']))
 
-                        # insert flow to dispatch traffic from physical ports
+                        # insert connection to dispatch traffic from physical ports
                         # to VMs based on stream type; all traffic from VMs is
                         # sent to physical ports to avoid issues with MAC swapping
                         # and upper layer mods performed inside guests
-                        self._add_flow(flow_p, phy1_number, port_pair[0])
-                        self._add_flow(flow_v, port_pair[1], phy2_number)
-                        if self._bidir:
-                            self._add_flow(flow_p, phy2_number, port_pair[1])
-                            self._add_flow(flow_v, port_pair[0], phy1_number)
+                        self._vswitch.add_connection(self._bridge, phy1, port_pair[0], options)
+                        self._vswitch.add_connection(self._bridge, port_pair[1], phy2)
+                        self._vswitch.add_connection(self._bridge, phy2, port_pair[1], options)
+                        self._vswitch.add_connection(self._bridge, port_pair[0], phy1)
 
                         # every NIC pair needs its own unique traffic stream
                         stream += 1
@@ -185,37 +157,13 @@ class VswitchControllerPXP(IVswitchController):
         self._logger.debug('Stop using %s', str(self._vswitch_class))
         self._vswitch.stop()
 
-    def _add_flow(self, flow, port1, port2, reverse_flow=False):
-        """ Helper method to insert flow into the vSwitch
-        """
-        self._vswitch.add_flow(self._bridge,
-                               add_ports_to_flow(flow,
-                                                 port1,
-                                                 port2))
-        if reverse_flow:
-            self._vswitch.add_flow(self._bridge,
-                                   add_ports_to_flow(flow,
-                                                     port2,
-                                                     port1))
-
-    def __enter__(self):
-        self.setup()
-
-    def __exit__(self, type_, value, traceback):
-        self.stop()
-
-    def get_vswitch(self):
-        """See IVswitchController for description
-        """
-        return self._vswitch
-
     def get_ports_info(self):
         """See IVswitchController for description
         """
         self._logger.debug('get_ports_info  using %s', str(self._vswitch_class))
         return self._vswitch.get_ports(self._bridge)
 
-    def dump_vswitch_flows(self):
+    def dump_vswitch_connections(self):
         """See IVswitchController for description
         """
-        self._vswitch.dump_flows(self._bridge)
+        self._vswitch.dump_connections(self._bridge)
index 7fbde88..b8a3ba1 100644 (file)
@@ -1,6 +1,6 @@
 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
 .. http://creativecommons.org/licenses/by/4.0
-.. (c) OPNFV, Intel Corporation, AT&T and others.
+.. (c) OPNFV, Intel Corporation, AT&T, Tieto and others.
 
 .. _vsperf-design:
 
@@ -332,7 +332,6 @@ Detailed description of ``TRAFFIC`` dictionary items follows:
                       feature. If enabled, it will implicitly insert a flow
                       for each stream. If multistream is disabled, then
                       pre-installed flows will be ignored.
-                      Note: It is supported only for p2p deployment scenario.
                       Data type: str
                       Supported values:
                          "Yes" - flows will be inserted into OVS
@@ -777,6 +776,13 @@ As it is able to forward traffic between multiple VM NIC pairs.
 Note: In case of ``linux_bridge``, all NICs are connected to the same
 bridge inside the VM.
 
+Note: In case that multistream feature is configured and ``pre_installed_flows``
+is set to ``Yes``, then stream specific flows will be inserted only for connections
+originating at physical ports. The rest of the flows will be based on port
+numbers only. The same logic applies in case that ``flow_type`` TRAFFIC option
+is set to ``ip``. This configuration will avoid a testcase malfunction if frame headers
+are modified inside VM (e.g. MAC swap or IP change).
+
 VM, vSwitch, Traffic Generator Independence
 ===========================================
 
@@ -912,6 +918,10 @@ Vsperf uses a standard set of routing tables in order to allow tests to easily
 mix and match Deployment Scenarios (PVP, P2P topology), Tuple Matching and
 Frame Modification requirements.
 
+The usage of routing tables is driven by configuration parameter ``OVS_ROUTING_TABLES``.
+Routing tables are disabled by default (i.e. parameter is set to ``False``) for better
+comparison of results among supported vSwitches (e.g. OVS vs. VPP).
+
 .. code-block:: console
 
       +--------------+
index 809e3b3..a30558f 100644 (file)
@@ -373,7 +373,7 @@ class TestCase(object):
 
                         # dump vswitch flows before they are affected by VNF termination
                         if not self._vswitch_none:
-                            self._vswitch_ctl.dump_vswitch_flows()
+                            self._vswitch_ctl.dump_vswitch_connections()
 
                     # garbage collection for case that TestSteps modify existing deployment
                     self.step_stop_vnfs()
index be7b77d..6dbf0cf 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2018 Intel Corporation, Tieto and Others.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 """VSPERF Open vSwitch base class
 """
 
-import logging
 import os
 import re
 import time
 import datetime
 import random
+import socket
+import netaddr
 import pexpect
 
 from conf import settings
@@ -28,6 +29,10 @@ from src.ovs import OFBridge, flow_key, flow_match
 from vswitches.vswitch import IVSwitch
 from tools import tasks
 from tools.module_manager import ModuleManager
+
+# enable caching of flows if their number exceeds given limit
+_CACHE_FLOWS_LIMIT = 10
+
 # pylint: disable=too-many-public-methods
 class IVSwitchOvs(IVSwitch, tasks.Process):
     """Open vSwitch base class implementation
@@ -41,23 +46,31 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def __init__(self):
         """See IVswitch for general description
         """
+        super().__init__()
         self._logfile = os.path.join(settings.getValue('LOG_DIR'),
                                      settings.getValue('LOG_FILE_VSWITCHD'))
         self._ovsdb_pidfile_path = os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'],
                                                 "ovsdb-server.pid")
         self._vswitchd_pidfile_path = os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'],
                                                    "{}.pid".format(self._proc_name))
-        self._logger = logging.getLogger(__name__)
         # sign '|' must be escaped or avoided, otherwise it is handled as 'or' by regex
         self._expect = r'bridge.INFO.{}'.format(self._proc_name)
-        self._timeout = 30
-        self._bridges = {}
         self._vswitchd_args = ['--pidfile=' + self._vswitchd_pidfile_path,
                                '--overwrite-pidfile', '--log-file=' + self._logfile]
-        self._cmd = []
         self._cmd_template = ['sudo', '-E', settings.getValue('TOOLS')['ovs-vswitchd']]
-        self._stamp = None
         self._module_manager = ModuleManager()
+        self._flow_template = settings.getValue('OVS_FLOW_TEMPLATE').copy()
+        self._flow_actions = ['output:{}']
+
+        # if routing tables are enabled, then flows should go into table 1
+        # see design document for details about Routing Tables feature
+        if settings.getValue('OVS_ROUTING_TABLES'):
+            # flows should be added into table 1
+            self._flow_template.update({'table':'1', 'priority':'1'})
+            # and chosen port will be propagated via metadata
+            self._flow_actions = ['write_actions(output:{})',
+                                  'write_metadata:{}',
+                                  'goto_table:2']
 
     def start(self):
         """ Start ``ovsdb-server`` and ``ovs-vswitchd`` instance.
@@ -85,7 +98,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
             tasks.Process.start(self)
             self.relinquish()
         except (pexpect.EOF, pexpect.TIMEOUT) as exc:
-            logging.error("Exception during VSwitch start.")
+            self._logger.error("Exception during VSwitch start.")
             self._kill_ovsdb()
             raise exc
 
@@ -107,7 +120,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
             tasks.Process.start(self)
             self.relinquish()
         except (pexpect.EOF, pexpect.TIMEOUT) as exc:
-            logging.error("Exception during VSwitch start.")
+            self._logger.error("Exception during VSwitch start.")
             self._kill_ovsdb()
             raise exc
         self._logger.info("Vswitchd...Started.")
@@ -128,31 +141,57 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def stop(self):
         """See IVswitch for general description
         """
-        for switch_name in list(self._bridges):
+        for switch_name in list(self._switches):
             self.del_switch(switch_name)
         self._logger.info("Terminating vswitchd...")
         self.kill()
-        self._bridges = {}
+        self._switches = {}
         self._logger.info("Vswitchd...Terminated.")
 
     def add_switch(self, switch_name, params=None):
         """See IVswitch for general description
         """
+        # create and configure new ovs bridge and delete all default flows
         bridge = OFBridge(switch_name)
         bridge.create(params)
+        bridge.del_flow({})
         bridge.set_db_attribute('Open_vSwitch', '.',
                                 'other_config:max-idle',
                                 settings.getValue('VSWITCH_FLOW_TIMEOUT'))
-        self._bridges[switch_name] = bridge
+        self._switches[switch_name] = bridge
+        if settings.getValue('OVS_ROUTING_TABLES'):
+            # table#0 - flows designed to force 5 & 13 tuple matches go here
+            flow = {'table':'0', 'priority':'1', 'actions': ['goto_table:1']}
+            bridge.add_flow(flow)
+
+            # table#1 - flows to route packets between ports goes here. The
+            # chosen port is communicated to subsequent tables by setting the
+            # metadata value to the egress port number
+            #
+            # A placeholder - flows are added into this table by deployments
+            #                 or by TestSteps via add_connection() method
+
+            # table#2 - frame modification table. Frame modification flow rules are
+            # isolated in this table so that they can be turned on or off
+            # without affecting the routing or tuple-matching flow rules.
+            flow = {'table':'2', 'priority':'1', 'actions': ['goto_table:3']}
+            bridge.add_flow(flow)
+
+            # table#3 - egress table
+            # (NOTE) Billy O'Mahony - the drop action here actually required in
+            # order to egress the packet. This is the subject of a thread on
+            # ovs-discuss 2015-06-30.
+            flow = {'table':'3', 'priority':'1', 'actions': ['drop']}
+            bridge.add_flow(flow)
 
     def del_switch(self, switch_name):
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.del_flow({})
         for port in list(bridge.get_ports()):
             bridge.del_port(port)
-        self._bridges.pop(switch_name)
+        self._switches.pop(switch_name)
         bridge.destroy()
 
     def add_phy_port(self, switch_name):
@@ -173,8 +212,8 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
         if switch_name is None or remote_switch_name is None:
             return None
 
-        bridge = self._bridges[switch_name]
-        remote_bridge = self._bridges[remote_switch_name]
+        bridge = self._switches[switch_name]
+        remote_bridge = self._switches[remote_switch_name]
         pcount = str(self._get_port_count('type=patch'))
         # NOTE ::: What if interface name longer than allowed width??
         local_port_name = switch_name + '-' + remote_switch_name + '-' + pcount
@@ -200,7 +239,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan', params=None):
         """Creates tunneling port
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         pcount = str(self._get_port_count('type=' + tunnel_type))
         port_name = tunnel_type + pcount
         local_params = ['--', 'set', 'Interface', port_name,
@@ -216,53 +255,123 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def get_ports(self, switch_name):
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         ports = list(bridge.get_ports().items())
         return [(name, of_port) for (name, (of_port, _)) in ports]
 
     def del_port(self, switch_name, port_name):
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.del_port(port_name)
 
     def add_flow(self, switch_name, flow, cache='off'):
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.add_flow(flow, cache=cache)
 
     def del_flow(self, switch_name, flow=None):
         """See IVswitch for general description
         """
         flow = flow or {}
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.del_flow(flow)
 
     def dump_flows(self, switch_name):
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.dump_flows()
 
+    def _prepare_flows(self, operation, switch_name, port1, port2, traffic=None):
+        """Prepare flows for add_connection, del_connection and validate methods
+           It returns a list of flows based on given parameters.
+        """
+        flows = []
+        if operation == 'add':
+            bridge = self._switches[switch_name]
+            flow = self._flow_template.copy()
+            actions = [action.format(bridge.get_ports()[port2][0]) for action in self._flow_actions]
+            flow.update({'in_port': bridge.get_ports()[port1][0], 'actions': actions})
+            # check if stream specific connection(s) should be crated for multistream feature
+            if traffic and traffic['pre_installed_flows'].lower() == 'yes':
+                for stream in range(traffic['multistream']):
+                    tmp_flow = flow.copy()
+                    # update flow based on trafficgen settings
+                    if traffic['stream_type'] == 'L2':
+                        dst_mac_value = netaddr.EUI(traffic['l2']['dstmac']).value
+                        tmp_mac = netaddr.EUI(dst_mac_value + stream)
+                        tmp_mac.dialect = netaddr.mac_unix_expanded
+                        tmp_flow.update({'dl_dst':tmp_mac})
+                    elif traffic['stream_type'] == 'L3':
+                        dst_ip_value = netaddr.IPAddress(traffic['l3']['dstip']).value
+                        tmp_ip = netaddr.IPAddress(dst_ip_value + stream)
+                        tmp_flow.update({'dl_type':'0x0800', 'nw_dst':tmp_ip})
+                    elif traffic['stream_type'] == 'L4':
+                        tmp_flow.update({'dl_type':'0x0800',
+                                         'nw_proto':socket.getprotobyname(traffic['l3']['proto'].lower()),
+                                         'tp_dst':(traffic['l4']['dstport'] + stream) % 65536})
+                    flows.append(tmp_flow)
+            elif traffic and traffic['flow_type'].lower() == 'ip':
+                flow.update({'dl_type':'0x0800', 'nw_src':traffic['l3']['srcip'],
+                             'nw_dst':traffic['l3']['dstip']})
+                flows.append(flow)
+            else:
+                flows.append(flow)
+        elif operation == 'del' and port1:
+            bridge = self._switches[switch_name]
+            flows.append({'in_port': bridge.get_ports()[port1][0]})
+        else:
+            flows.append({})
+
+        return flows
+
+    def add_connection(self, switch_name, port1, port2, traffic=None):
+        """See IVswitch for general description
+        """
+        flows = self._prepare_flows('add', switch_name, port1, port2, traffic)
+
+        # enable flows caching for large number of flows
+        cache = 'on' if len(flows) > _CACHE_FLOWS_LIMIT else 'off'
+
+        for flow in flows:
+            self.add_flow(switch_name, flow, cache)
+
+        if cache == 'on':
+            self.add_flow(switch_name, [], cache='flush')
+
+    def del_connection(self, switch_name, port1=None, port2=None):
+        """See IVswitch for general description
+        """
+        flows = self._prepare_flows('del', switch_name, port1, port2)
+
+        for flow in flows:
+            self.del_flow(switch_name, flow)
+
+    def dump_connections(self, switch_name):
+        """See IVswitch for general description
+        """
+        self.dump_flows(switch_name)
+
     def add_route(self, switch_name, network, destination):
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.add_route(network, destination)
 
     def set_tunnel_arp(self, ip_addr, mac_addr, switch_name):
         """See IVswitch for general description
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.set_tunnel_arp(ip_addr, mac_addr, switch_name)
 
     def _get_port_count(self, param):
         """Returns the number of ports having a certain parameter
         """
         cnt = 0
-        for k in self._bridges:
-            pparams = [c for (_, (_, c)) in list(self._bridges[k].get_ports().items())]
+        for k in self._switches:
+            pparams = [c for (_, (_, c)) in list(self._switches[k].get_ports().items())]
             phits = [i for i in pparams if param in i]
             cnt += len(phits)
 
@@ -276,7 +385,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
         :param switch_name: bridge to disable stp
         :return: None
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.set_stp(False)
         self._logger.info('Sleeping for 50 secs to allow stp to stop.')
         time.sleep(50)  # needs time to disable
@@ -287,7 +396,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
         :param switch_name: bridge to enable stp
         :return: None
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.set_stp(True)
         self._logger.info('Sleeping for 50 secs to allow stp to start.')
         time.sleep(50)  # needs time to enable
@@ -298,7 +407,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
         :param switch_name: bridge to disable rstp
         :return: None
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.set_rstp(False)
         self._logger.info('Sleeping for 15 secs to allow rstp to stop.')
         time.sleep(15)  # needs time to disable
@@ -309,7 +418,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
         :param switch_name: bridge to enable rstp
         :return: None
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         bridge.set_rstp(True)
         self._logger.info('Sleeping for 15 secs to allow rstp to start.')
         time.sleep(15)  # needs time to enable
@@ -417,7 +526,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def validate_add_switch(self, _dummy_result, switch_name, _dummy_params=None):
         """Validate - Create a new logical switch with no ports
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         output = bridge.run_vsctl(['show'], check_error=True)
         assert not output[1]  # there shouldn't be any stderr, but in case
         assert re.search('Bridge ["\']?%s["\']?' % switch_name, output[0]) is not None
@@ -437,7 +546,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def validate_add_phy_port(self, result, switch_name):
         """ Validate that physical port was added to bridge.
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         output = bridge.run_vsctl(['show'], check_error=True)
         assert not output[1]  # there shouldn't be any stderr, but in case
         assert re.search('Port ["\']?%s["\']?' % result[0], output[0]) is not None
@@ -452,12 +561,35 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def validate_del_port(self, _dummy_result, switch_name, port_name):
         """ Validate that port_name was removed from bridge.
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         output = bridge.run_vsctl(['show'], check_error=True)
         assert not output[1]  # there shouldn't be any stderr, but in case
         assert 'Port "%s"' % port_name not in output[0]
         return True
 
+    def validate_add_connection(self, result, switch_name, port1, port2, traffic=None):
+        """ Validate that connection was added
+        """
+        for flow in self._prepare_flows('add', switch_name, port1, port2, traffic):
+            if not self.validate_add_flow(result, switch_name, flow):
+                return False
+
+        return True
+
+    def validate_del_connection(self, result, switch_name, port1, port2):
+        """ Validate that connection was deleted
+        """
+        for flow in self._prepare_flows('del', switch_name, port1, port2):
+            if not self.validate_del_flow(result, switch_name, flow):
+                return False
+
+        return True
+
+    def validate_dump_connections(self, _dummy_result, _dummy_switch_name):
+        """ Validate dump connections call
+        """
+        return True
+
     def validate_add_flow(self, _dummy_result, switch_name, flow, _dummy_cache='off'):
         """ Validate insertion of the flow into the switch
         """
@@ -471,7 +603,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
 
         # get dump of flows and compare them one by one
         flow_src = flow_key(flow)
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         output = bridge.run_ofctl(['dump-flows', switch_name], check_error=True)
         for flow_dump in output[0].split('\n'):
             if flow_match(flow_dump, flow_src):
@@ -495,25 +627,25 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
     def validate_disable_rstp(self, _dummy_result, switch_name):
         """ Validate rstp disable
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         return 'rstp_enable         : false' in ''.join(bridge.bridge_info())
 
     def validate_enable_rstp(self, _dummy_result, switch_name):
         """ Validate rstp enable
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         return 'rstp_enable         : true' in ''.join(bridge.bridge_info())
 
     def validate_disable_stp(self, _dummy_result, switch_name):
         """ Validate stp disable
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         return 'stp_enable          : false' in ''.join(bridge.bridge_info())
 
     def validate_enable_stp(self, _dummy_result, switch_name):
         """ Validate stp enable
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         return 'stp_enable          : true' in ''.join(bridge.bridge_info())
 
     def validate_restart(self, _dummy_result):
index 6deb0c2..8da043c 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
 """VSPERF VSwitch implementation using DPDK and vhost ports
 """
 
-import logging
 import subprocess
 
 from src.ovs import OFBridge
@@ -36,9 +35,7 @@ class OvsDpdkVhost(IVSwitchOvs):
     """
 
     def __init__(self):
-        super(OvsDpdkVhost, self).__init__()
-        self._logger = logging.getLogger(__name__)
-
+        super().__init__()
         vswitchd_args = []
 
         # legacy DPDK configuration through --dpdk option of vswitchd
@@ -104,9 +101,9 @@ class OvsDpdkVhost(IVSwitchOvs):
         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',
-                                                        S.getValue('VSWITCH_PMD_CPU_MASK'))
+            self._switches[switch_name].set_db_attribute('Open_vSwitch', '.',
+                                                         'other_config:pmd-cpu-mask',
+                                                         S.getValue('VSWITCH_PMD_CPU_MASK'))
 
     def add_phy_port(self, switch_name):
         """See IVswitch for general description
@@ -115,7 +112,7 @@ class OvsDpdkVhost(IVSwitchOvs):
         The new port is named dpdk<n> where n is an integer starting from 0.
         """
         _nics = S.getValue('NICS')
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
         dpdk_count = self._get_port_count('type=dpdk')
         if dpdk_count == len(_nics):
             raise RuntimeError("Can't add phy port! There are only {} ports defined "
@@ -144,7 +141,7 @@ class OvsDpdkVhost(IVSwitchOvs):
         The new port is named dpdkvhost<n> where n is an integer starting
         from 0
         """
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[switch_name]
 
         if S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
             nic_type = 'dpdkvhostuser'
@@ -177,18 +174,3 @@ class OvsDpdkVhost(IVSwitchOvs):
             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()
index 83c5205..d23a0c6 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
 """VSPERF Vanilla OVS implementation
 """
 
-import logging
 import time
 from conf import settings
 from vswitches.ovs import IVSwitchOvs
@@ -36,9 +35,8 @@ class OvsVanilla(IVSwitchOvs):
     _vport_id = 0
 
     def __init__(self):
-        super(OvsVanilla, self).__init__()
+        super().__init__()
         self._ports = list(nic['device'] for nic in settings.getValue('NICS'))
-        self._logger = logging.getLogger(__name__)
         self._vswitchd_args += ["unix:%s" % self.get_db_sock_path()]
         self._vswitchd_args += settings.getValue('VSWITCHD_VANILLA_ARGS')
 
@@ -81,7 +79,7 @@ class OvsVanilla(IVSwitchOvs):
             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]
+        bridge = self._switches[switch_name]
         port_name = self._ports[self._current_id]
         params = []
 
@@ -129,21 +127,6 @@ class OvsVanilla(IVSwitchOvs):
         tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', tap_name, 'up'],
                        self._logger, 'Bring up ' + tap_name, False)
 
-        bridge = self._bridges[switch_name]
+        bridge = self._switches[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()
index 15e32f3..5d676a0 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2017 Intel Corporation.
+# Copyright 2017-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
 """VSPERF VPP implementation using DPDK and vhostuser vports
 """
 
-import logging
 import os
 import copy
 import re
@@ -37,19 +36,13 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
     def __init__(self):
         """See IVswitch for general description
         """
+        super().__init__()
         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 = {}
         self._vpp_ctl = ['sudo', S.getValue('TOOLS')['vppctl']]
 
         # configure DPDK NICs
@@ -151,7 +144,7 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
             tasks.Process.start(self)
             self.relinquish()
         except (pexpect.EOF, pexpect.TIMEOUT) as exc:
-            logging.error("Exception during VPP start.")
+            self._logger.error("Exception during VPP start.")
             raise exc
 
         self._logger.info("VPP...Started.")
@@ -269,21 +262,17 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
         else:
             self._logger.warning("Port %s is not configured.", port_name)
 
-    def add_l2patch(self, port1, port2, bidir=False):
+    def add_l2patch(self, port1, port2):
         """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):
+    def add_xconnect(self, port1, port2):
         """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):
+    def add_bridge(self, switch_name, port1, port2):
         """Add given ports to bridge ``switch_name``
         """
         self.run_vppctl(['set', 'interface', 'l2', 'bridge', port1,
@@ -291,33 +280,33 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
         self.run_vppctl(['set', 'interface', 'l2', 'bridge', port2,
                          str(self._switches[switch_name])])
 
-    def add_connection(self, switch_name, port1, port2, bidir=False):
+    def add_connection(self, switch_name, port1, port2, traffic=None):
         """See IVswitch for general description
 
         :raises: RuntimeError
         """
+        if traffic:
+            self._logger.warning("VPP add_connection() does not support 'traffic' options.")
+
         mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
         if mode == 'l2patch':
-            self.add_l2patch(port1, port2, bidir)
+            self.add_l2patch(port1, port2)
         elif mode == 'xconnect':
-            self.add_xconnect(port1, port2, bidir)
+            self.add_xconnect(port1, port2)
         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):
+    def del_l2patch(self, port1, port2):
         """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, port1, port2, _dummy_bidir=False):
+    def del_xconnect(self, port1, port2):
         """Remove xconnect connection between given ports
         """
         self.run_vppctl(['set', 'interface', 'l3', port1])
@@ -329,20 +318,21 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
         self.run_vppctl(['set', 'interface', 'l3', port1])
         self.run_vppctl(['set', 'interface', 'l3', port2])
 
-    def del_connection(self, switch_name, port1, port2, bidir=False):
+    def del_connection(self, switch_name, port1=None, port2=None):
         """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)
+        if port1 and port2:
+            mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
+            if mode == 'l2patch':
+                self.del_l2patch(port1, port2)
+            elif mode == 'xconnect':
+                self.del_xconnect(port1, port2)
+            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
@@ -417,13 +407,13 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
 
     # pylint: disable=no-self-use
     def validate_add_connection(self, _dummy_result, _dummy_switch_name, _dummy_port1,
-                                _dummy_port2, _dummy_bidir=False):
+                                _dummy_port2, _dummy_traffic=None):
         """ Validate that connection was added
         """
         return True
 
     def validate_del_connection(self, _dummy_result, _dummy_switch_name, _dummy_port1,
-                                _dummy_port2, _dummy_bidir=False):
+                                _dummy_port2):
         """ Validate that connection was deleted
         """
         return True
@@ -442,21 +432,6 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
     #
     # 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
         """
index efa3a34..a3d4e97 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2015-2016 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 
 """Generic interface VSPERF uses for controlling a vSwitch
 """
+import logging
 
 class IVSwitch(object):
     """Interface class that is implemented by vSwitch-specific classes
 
     Other methods are called only between start() and stop()
     """
+    def __init__(self):
+        """Initialization of vswitch class
+        """
+        self._timeout = 30
+        self._switches = {}
+        self._logger = logging.getLogger(__name__)
+        self._cmd = []
+        self._vswitch_args = []
+        self._stamp = None
+
     def get_version(self):
         """Return version of vSwitch and DPDK (if used by vSwitch)
            This method should be implemented in case, that version
@@ -112,58 +123,23 @@ class IVSwitch(object):
         """
         raise NotImplementedError()
 
-    def add_flow(self, switch_name, flow, cache='off'):
-        """Add a flow rule to the logical switch
-
-        :param switch_name: The switch on which to operate
-        :param flow: Flow description as a dictionary
-        :param cache: Optional. Specifies if flow should be inserted
-            to the switch or cached to increase performance during manipulation
-            with large number of flows.
-            Values:
-                'off'   - cache is off and flow is inserted directly to the switch
-                'on'    - cache is on and flow is inserted into the cache
-                'flush' - cache content will be inserted into the switch
-
-        Example flow dictionary:
-            flow = {
-                'in_port': '1',
-                'idle_timeout': '0',
-                'actions': ['output:3']
-            }
-        """
-        raise NotImplementedError()
-
-    def del_flow(self, switch_name, flow=None):
-        """Delete the flow rule from the logical switch
-
-        :param switch_name: The switch on which to operate
-        :param flow: Flow description as a dictionary
-
-        For flow dictionary description, see add_flow
-        For flow==None, all flows are deleted
-        """
-        raise NotImplementedError()
-
-    def add_connection(self, switch_name, port1, port2, bidir=False):
+    def add_connection(self, switch_name, port1, port2, traffic=None):
         """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):
+    def del_connection(self, switch_name, port1=None, port2=None):
         """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
         """
@@ -178,13 +154,6 @@ class IVSwitch(object):
         """
         raise NotImplementedError()
 
-    def dump_flows(self, switch_name):
-        """Dump flows from the logical switch
-
-        :param switch_name: The switch on which to operate
-        """
-        raise NotImplementedError()
-
     def add_route(self, switch_name, network, destination):
         """Add a route for tunneling routing table