# 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.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file introduces a set of regression tests, which verify several DPDK features
# used internally by Open vSwitch. Tests can be used for verification of performance
# and correct functionality of upcoming DPDK and OVS releases and release candidates.

############################################################
#
#  Generic configuration used by OVSDPDK testcases
#
############################################################

# required to import path to the log file
from conf import settings

_OVSDPDK_1st_PMD_CORE = 4
_OVSDPDK_2nd_PMD_CORE = 5
# calculate PMD mask from core IDs configured above
_OVSDPDK_PMD_MASK_1_CORE = str(hex(1<<_OVSDPDK_1st_PMD_CORE))[2:]
_OVSDPDK_PMD_MASK_2_CORE = str(hex((1<<_OVSDPDK_1st_PMD_CORE) + (1<<_OVSDPDK_2nd_PMD_CORE))[2:])

_OVSDPDK_GUEST_5_CORES = [('7', '8', '9', '10', '11')]

# number of queues configured in OVS and GUEST
_OVSDPDK_MQ = '2'

# path to the log file
_RESULTS_PATH = settings.getValue('RESULTS_PATH')
name, ext = os.path.splitext(settings.getValue('LOG_FILE_VSWITCHD'))
log_file = "{name}_{uid}{ex}".format(name=name,uid=settings.getValue('LOG_TIMESTAMP'),ex=ext)
_OVSDPDK_VSWITCH_LOG = os.path.join(_RESULTS_PATH, log_file)

_OVSDPDK_HEADER_LEN = 18                # length of frame headers in bytes, it's used for calculation
                                        # of payload size, i.e. payload = frame_size - header_len

_OVSDPDK_PKT_SIZES = (64,128,256,512,1024,1500)

INTEGRATION_TESTS = INTEGRATION_TESTS + [
    ############################################################
    #
    #  DPDK NIC Support
    #
    ############################################################
    {
        "Name": "ovsdpdk_nic_p2p_single_pmd_unidir_cont",
        "Deployment": "p2p",
        "Description": "P2P with single PMD in OVS and unidirectional traffic.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
            },
            "TRAFFICGEN_PKT_SIZES" : _OVSDPDK_PKT_SIZES,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_1_CORE,
        },
    },
    {
        "Name": "ovsdpdk_nic_p2p_single_pmd_bidir_cont",
        "Deployment": "p2p",
        "Description": "P2P with single PMD in OVS and bidirectional traffic.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "TRAFFICGEN_PKT_SIZES" : _OVSDPDK_PKT_SIZES,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_1_CORE,
        },
    },
    {
        "Name": "ovsdpdk_nic_p2p_two_pmd_bidir_cont",
        "Deployment": "p2p",
        "Description": "P2P with two PMDs in OVS and bidirectional traffic.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "TRAFFICGEN_PKT_SIZES" : _OVSDPDK_PKT_SIZES,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_2_CORE,
        },
    },
    {
        "Name": "ovsdpdk_nic_p2p_single_pmd_unidir_tput",
        "Deployment": "p2p",
        "Description": "P2P with single PMD in OVS and unidirectional traffic.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_throughput",
                'bidir' : 'False',
            },
            "TRAFFICGEN_PKT_SIZES" : _OVSDPDK_PKT_SIZES,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_1_CORE,
        },
    },
    {
        "Name": "ovsdpdk_nic_p2p_single_pmd_bidir_tput",
        "Deployment": "p2p",
        "Description": "P2P with single PMD in OVS and bidirectional traffic.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_throughput",
                'bidir' : 'True',
            },
            "TRAFFICGEN_PKT_SIZES" : _OVSDPDK_PKT_SIZES,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_1_CORE,
        },
    },
    {
        "Name": "ovsdpdk_nic_p2p_two_pmd_bidir_tput",
        "Deployment": "p2p",
        "Description": "P2P with two PMDs in OVS and bidirectional traffic.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_throughput",
                'bidir' : 'True',
            },
            "TRAFFICGEN_PKT_SIZES" : _OVSDPDK_PKT_SIZES,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_2_CORE,
        },
    },
    ############################################################
    #
    #  DPDK Hotplug Support
    #
    ############################################################
    {
        "Name": "ovsdpdk_hotplug_attach",
        "Deployment": "clean",
        "Description": "Ensure successful port-add after binding a device to igb_uio after ovs-vswitchd is launched.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            # suppress DPDK configuration, so physical interfaces are not bound to DPDK driver
            'WHITELIST_NICS' : [],
            'NICS' : [],
        },
        "TestSteps": [
                        # restore original NICS configuration, so we can use add/del_phy_port
                        ['settings', 'setValue', 'TEST_PARAMS', ''],
                        # add DPDK port, but it should fail
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['#port', 'vswitch', 'add_phy_port', 'int_br0'],
                        # check, that DPDK port is not available and remove it
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show',
                                                '|Error attaching device.*$NICS[0]["pci"]'],
                        # NOTE: it fails in case that NIC was already bound to DPDK driver
                        ['tools', 'assert', 'len(#STEP[-1])'],
                        ['vswitch', 'del_port', 'int_br0', '#STEP[port][0]'],
                        # find out which DPDK driver is being used; it should be the last configured
                        # DPDK module; optional path and .ko suffix must be removed
                        ['tools', 'eval', '\'$TOOLS["dpdk_modules"][-1]\'.split("/")[-1].split(".")[0]'],
                        # bind NIC to DPDK driver
                        ['tools', 'exec_shell', 'sudo $TOOLS["bind-tool"] --bind #STEP[-1] $NICS[0]["pci"]'],
                        # and check that DPDK port can be created without errors
                        ['#port2', 'vswitch', 'add_phy_port', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show',
                                                '|Error attaching device.*$NICS[0]["pci"]'],
                        ['tools', 'assert', 'not len(#STEP[-1])'],
                     ]
    },
]

############################################################
#
#  RX Checksum Support
#
############################################################
# TCL script used for simulation of traffic with wrong CRC
_OVSDPDK_CRC_CRC_TCL = ''
_OVSDPDK_CRC_FRAME_LOSS = ''

_OVSDPDK_CRC_VERIFY_CRC = [
    # use TCL script with tunneling protocols encap/decap support;
    # it must be configured dynamically, otherwise it won't
    # be possible to change it again below.
    ['settings', 'setValue', 'TRAFFICGEN_IXNET_TCL_SCRIPT',
     'ixnetrfc2544v2.tcl'],
    # send traffic before IP or UDP header checksum is randomized
    ['trafficgen', 'send_traffic', {}],
    ['trafficgen', 'get_results'],
    # packets should flow through OVS without frameloss (frame_rate is low)
    ['tools', 'assert', 'float(#STEP[-1][0]["frame_loss_percent"]) == 0'],
    # for 2nd run use TCL file with randomized checksum values
    ['settings', 'setValue', 'TRAFFICGEN_IXNET_TCL_SCRIPT',
     '$_OVSDPDK_CRC_CRC_TCL'],
    ['trafficgen', 'send_traffic', {}],
    ['trafficgen', 'get_results'],
    # and verify that majority of frames but not all of them were lost
    ['tools', 'assert', 'round(float(#STEP[-1][0]["frame_loss_percent"]),3) == $_OVSDPDK_CRC_FRAME_LOSS'],
]

INTEGRATION_TESTS = INTEGRATION_TESTS + [
    {
        "Name": "ovsdpdk_checksum_l3",
        "Deployment": "op2p",
        "Description": "Test verifies RX IP header checksum (offloading) validation for tunneling protocols.",
        "Tunnel Type": "vxlan",
        "Tunnel Operation": "decapsulation",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFICGEN" : "IxNet",
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 20,
                'bidir' : 'False',
            },
            "TRAFFICGEN_DURATION" : 10,
            "TRAFFICGEN_PKT_SIZES" : (64,)
        },
        "TestSteps": [
                        # TCL file with randomized IP header checksum values
                        ['settings', 'setValue', '_OVSDPDK_CRC_CRC_TCL',
                         'ixnetrfc2544v2_random_ip_crc.tcl'],
                        # IP checksum is a value between 0 and 65536, so only 1 of 65536
                        # frames has correct CRC and all other frames will be dropped
                        ['settings', 'setValue', '_OVSDPDK_CRC_FRAME_LOSS',
                         round(100 - 1 / 65536 * 100, 3)],
                    ] + _OVSDPDK_CRC_VERIFY_CRC
    },
    {
        "Name": "ovsdpdk_checksum_l4",
        "Deployment": "op2p",
        "Description": "Test verifies RX UDP header checksum (offloading) validation for tunneling protocols.",
        "Tunnel Type": "vxlan",
        "Tunnel Operation": "decapsulation",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFICGEN" : "IxNet",
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 20,
                'bidir' : 'False',
            },
            "TRAFFICGEN_DURATION" : 10,
            "TRAFFICGEN_PKT_SIZES" : (64,)
        },
        "TestSteps": [
                        # TCL file with randomized UDP header checksum values
                        ['settings', 'setValue', '_OVSDPDK_CRC_CRC_TCL',
                         'ixnetrfc2544v2_random_udp_crc.tcl'],
                        # UDP checksum can be disabled by value 0; so valid checksum
                        # values are from 1 to 65535; It means that only one of 65535 frames
                        # has correct checksum and all other frames will be dropped
                        ['settings', 'setValue', '_OVSDPDK_CRC_FRAME_LOSS',
                         round(100 - 1 / 65535 * 100, 3)],
                    ] + _OVSDPDK_CRC_VERIFY_CRC
    },
    ############################################################
    #
    #  Flow Control Support
    #
    ############################################################
    {
        "Name": "ovsdpdk_flow_ctrl_rx",
        "Deployment": "p2p",
        "Description": "Test the rx flow control functionality of DPDK PHY ports.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFICGEN" : "IxNet",
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                "flow_control" : True,
                'bidir' : 'True',
            },
            "TRAFFICGEN_DURATION" : 10,
            "TRAFFICGEN_PKT_SIZES" : (64,)
        },
        "TestSteps": [
                        # send traffic before flow control is applied
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show'],
                        ['trafficgen', 'send_traffic', {}],
                        ['trafficgen', 'get_results'],
                        # frame loss with small packets should be detected
                        ['tools', 'assert', '#STEP[-1][0]["frame_loss_percent"] > 10'],
                        # delete phy ports so they can be created with flow control
                        ['vswitch', 'del_flow', '$VSWITCH_BRIDGE_NAME', {}],
                        ['vswitch', 'del_port', '$VSWITCH_BRIDGE_NAME', 'dpdk0'],
                        ['vswitch', 'del_port', '$VSWITCH_BRIDGE_NAME', 'dpdk1'],
                        # turn on flow control
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] add-port $VSWITCH_BRIDGE_NAME dpdk0 -- set Interface dpdk0 type=dpdk options:dpdk-devargs=$NICS[0]["pci"] options:rx-flow-ctrl=true'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] add-port $VSWITCH_BRIDGE_NAME dpdk1 -- set Interface dpdk1 type=dpdk options:dpdk-devargs=$NICS[1]["pci"] options:rx-flow-ctrl=true'],
                        ['vswitch', 'add_flow', '$VSWITCH_BRIDGE_NAME', {'in_port': '3', 'actions': ['output:4'], 'idle_timeout': '0'}],
                        ['vswitch', 'add_flow', '$VSWITCH_BRIDGE_NAME', {'in_port': '4', 'actions': ['output:3'], 'idle_timeout': '0'}],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show'],
                        ['trafficgen', 'send_traffic', {}],
                        ['trafficgen', 'get_results'],
                        # frame loss with flow control enabled should converge to 0%
                        ['tools', 'assert', 'float(#STEP[-1][0]["frame_loss_percent"]) == 0'],
                    ]
    },
    {
        "Name": "ovsdpdk_flow_ctrl_rx_dynamic",
        "Deployment": "p2p",
        "Description": "Change the rx flow control support at run time and ensure the system honored the changes.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFICGEN" : "IxNet",
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                "flow_control" : True,
                'bidir' : 'True',
            },
            "TRAFFICGEN_DURATION" : 10,
            "TRAFFICGEN_PKT_SIZES" : (64,)
        },
        "TestSteps": [
                        # send traffic before flow control is applied
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show'],
                        ['trafficgen', 'send_traffic', {}],
                        ['trafficgen', 'get_results'],
                        # frame loss with small packets should be detected
                        ['tools', 'assert', '#STEP[-1][0]["frame_loss_percent"] > 10'],
                        # turn on flow control
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 type=dpdk options:rx-flow-ctrl=true'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk1 type=dpdk options:rx-flow-ctrl=true'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show'],
                        ['trafficgen', 'send_traffic', {}],
                        ['trafficgen', 'get_results'],
                        # frame loss with flow control enabled should converge to 0%
                        ['tools', 'assert', 'float(#STEP[-1][0]["frame_loss_percent"]) == 0'],
                    ]
    },
    ############################################################
    #
    #  Multiqueue Support
    #
    ############################################################
    {
        "Name": "ovsdpdk_mq_p2p_rxqs",
        "Deployment": "p2p",
        "Description": "Setup rxqs on NIC port.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "TRAFFICGEN_DURATION" : 1,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_2_CORE,
            "VSWITCH_DPDK_MULTI_QUEUES" : _OVSDPDK_MQ,
        },
        "TestSteps": [
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpif-netdev/pmd-rxq-show','|dpdk[01]\s+queue-id:\s+\d+'],
                        # check that requested nr of queues was created on both NICs
                        ['tools', 'assert', 'len(#STEP[-1])=={}'.format(int(_OVSDPDK_MQ)*2)],
                    ]
    },
    {
        "Name": "ovsdpdk_mq_p2p_rxqs_same_core_affinity",
        "Deployment": "p2p",
        "Description": "Affinitize rxqs to the same core.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "TRAFFICGEN_DURATION" : 1,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_2_CORE,
            "VSWITCH_DPDK_MULTI_QUEUES" : _OVSDPDK_MQ,
        },
        "TestSteps": [
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"]  -- set Interface dpdk0 other_config:pmd-rxq-affinity="0:{},1:{}"'.format(_OVSDPDK_1st_PMD_CORE, _OVSDPDK_1st_PMD_CORE)],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpif-netdev/pmd-rxq-show','|dpdk0\s+queue-id:\s+0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpif-netdev/pmd-rxq-show','|dpdk0\s+queue-id:\s+1'],
                        ['tools', 'assert', 'len(#STEP[-2])==1'],
                        ['tools', 'assert', 'len(#STEP[-2])==1'],
                    ]
    },
    {
        "Name": "ovsdpdk_mq_p2p_rxqs_multi_core_affinity",
        "Deployment": "p2p",
        "Description": "Affinitize rxqs to separate cores.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "TRAFFICGEN_DURATION" : 1,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_2_CORE,
            "VSWITCH_DPDK_MULTI_QUEUES" : _OVSDPDK_MQ,
        },
        "TestSteps": [
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"]  -- set Interface dpdk0 other_config:pmd-rxq-affinity="0:{},1:{}"'.format(_OVSDPDK_1st_PMD_CORE, _OVSDPDK_2nd_PMD_CORE)],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpif-netdev/pmd-rxq-show','|dpdk0\s+queue-id:\s+0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpif-netdev/pmd-rxq-show','|dpdk0\s+queue-id:\s+1'],
                        ['tools', 'assert', 'len(#STEP[-2])==1'],
                        ['tools', 'assert', 'len(#STEP[-2])==1'],
                    ]
    },
    {
        "Name" : "ovsdpdk_mq_pvp_rxqs",
        "Deployment" : "clean",
        "Description" : "Setup rxqs on vhost user port.",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "VSWITCH_DPDK_MULTI_QUEUES" : _OVSDPDK_MQ,
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_1_CORE,
            "GUEST_NIC_QUEUES" : [_OVSDPDK_MQ],
            "GUEST_LOOPBACK" : ['clean'],
        },
        "TestSteps": STEP_VSWITCH_PVP_INIT +
                     [
                        ['tools', 'exec_shell', "sudo $TOOLS['ovs-appctl'] dpif-netdev/pmd-rxq-show",
                         '|dpdkvhostuserclient0\s+queue-id:\s+\d'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                        ['vnf', 'start'],
                        ['tools', 'exec_shell', "sudo $TOOLS['ovs-appctl'] dpif-netdev/pmd-rxq-show",
                         '|dpdkvhostuserclient0\s+queue-id:\s+0'],
                        ['tools', 'exec_shell', "sudo $TOOLS['ovs-appctl'] dpif-netdev/pmd-rxq-show",
                         '|dpdkvhostuserclient0\s+queue-id:\s+1'],
                        ['tools', 'assert', 'len(#STEP[-2])==1'],
                        ['tools', 'assert', 'len(#STEP[-2])==1'],
                        ['vnf', 'stop'],
                     ] +
                     STEP_VSWITCH_PVP_FINIT
    },
    {
        "Name" : "ovsdpdk_mq_pvp_rxqs_linux_bridge",
        "Deployment" : "clean",
        "Description" : "Confirm traffic received over vhost RXQs with Linux virtio device in guest.",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            # configure 2 queues at both OVS and QEMU
            "VSWITCH_DPDK_MULTI_QUEUES" : _OVSDPDK_MQ,
            "GUEST_NIC_QUEUES" : [_OVSDPDK_MQ],
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_2_CORE,
            "GUEST_LOOPBACK" : ['clean'],
            "TRAFFICGEN_DURATION" : 5,
            "TRAFFICGEN" : "IxNet",
            "TRAFFIC" : {
                "bidir" : "False",
                "traffic_type" : "rfc2544_continuous",
                "multistream" : 6,
                "stream_type" : "L3",
                "frame_rate" : 1,
                "learning_frames" : False,
                'l2': {
                    'srcmac': "00:00:07:00:0E:00",
                    'dstmac': "00:00:00:00:00:01"
                },
                'l3': {
                    'enabled': True,
                    'proto': 'udp',
                    'srcip': '6.6.6.6',
                    'dstip': '1.1.1.1',
                }
            }
        },
        "TestSteps": STEP_VSWITCH_PVP_INIT + [
                        # one flow will sent data to the VM
                        ['vswitch', 'add_flow', 'int_br0',
                         {'in_port': '#STEP[1][1]', 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
                        # second flow just forwards traffic to the traffic generator,
                        # so send_traffic() will end with success
                        ['vswitch', 'add_flow', 'int_br0',
                         {'in_port': '#STEP[2][1]', 'actions': ['output:#STEP[1][1]'], 'idle_timeout': '0'}],
                        ['vswitch', 'add_flow', 'int_br0', {'priority' : '0', 'actions' : ['NORMAL']}],
                        ['vnf', 'start'],
                        # configure two channels, so multiple cores could be used
                        ['vnf', 'execute_and_wait', 'ethtool -L eth0 combined 2'],
                        ['vnf', 'execute_and_wait', 'ethtool -l eth0', '|Combined:\s+2'],
                        ['tools', 'assert', 'len(#STEP[-1])==2'],
                        # traffic will be sent to several DST IPs so it can be
                        # dispatched between channels; We have to insert routes
                        # and ARPs, otherwise traffic will be dropped
                        ['vnf', 'execute_and_wait', 'ifconfig eth0 5.5.5.1/24 up'],
                        ['vnf', 'execute_and_wait', 'sysctl -w net.ipv4.ip_forward=1'],
                        ['vnf', 'execute_and_wait', 'sysctl -w net.ipv4.conf.all.rp_filter=0'],
                        ['vnf', 'execute_and_wait', 'ip route add 6.6.6.0/24 dev eth0'],
                        ['vnf', 'execute_and_wait', 'route add default gw 6.6.6.6 eth0'],
                        ['vnf', 'execute_and_wait', 'arp -s 6.6.6.6 00:00:07:00:0E:00'],
                        ['vnf', 'execute_and_wait', 'ip route add 1.1.1.0/31 dev eth0'],
                        ['vnf', 'execute_and_wait', 'route add default gw 1.1.1.1 eth0'],
                        ['vnf', 'execute_and_wait', 'arp -s 1.1.1.1 DE:AD:BE:EF:CA:FA'],
                        ['vnf', 'execute_and_wait', 'ip route add 1.1.1.2/31 dev eth0'],
                        ['vnf', 'execute_and_wait', 'route add default gw 1.1.1.3 eth0'],
                        ['vnf', 'execute_and_wait', 'arp -s 1.1.1.3 DE:AD:BE:EF:CA:FB'],
                        ['vnf', 'execute_and_wait', 'ip route add 1.1.1.4/31 dev eth0'],
                        ['vnf', 'execute_and_wait', 'route add default gw 1.1.1.5 eth0'],
                        ['vnf', 'execute_and_wait', 'arp -s 1.1.1.5 DE:AD:BE:EF:CA:FC'],
                        ['vnf', 'execute_and_wait', 'ip a'],
                        ['trafficgen', 'send_traffic',{}],
                        # check interrupts to verify that traffic was corectly dispatched...
                        ['#result', 'vnf', 'execute_and_wait', 'cat /proc/interrupts',
                         '|^\s*\d+:\s+(\d+)\s+(\d+).+virtio0-input'],
                        # ...it means that two channels were created...
                        ['tools', 'assert', 'len(#STEP[result])==2'],
                        # ...and both channels processed data; Check that interrupt count is "much"
                        # higher than 0 to eliminate impact of rogue interrupts.
                        ['tools', 'assert', 'int(#STEP[result][0][0]) + int(#STEP[result][0][1]) > 1000'],
                        ['tools', 'assert', 'int(#STEP[result][1][0]) + int(#STEP[result][1][1]) > 1000'],
                        ['vnf', 'stop'],
                     ]
    },
    {
        "Name" : "ovsdpdk_mq_pvp_rxqs_testpmd",
        "Deployment" : "clean",
        "Description" : "Confirm traffic received over vhost RXQs with DPDK device in guest.",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "TRAFFICGEN" : "IxNet",
            # configure 2 queues at both OVS and QEMU
            "VSWITCH_DPDK_MULTI_QUEUES" : _OVSDPDK_MQ,
            "GUEST_NIC_QUEUES" : [_OVSDPDK_MQ],
            "VSWITCH_PMD_CPU_MASK" : _OVSDPDK_PMD_MASK_2_CORE,
            "GUEST_CORE_BINDING" : _OVSDPDK_GUEST_5_CORES,
            "GUEST_LOOPBACK" : ['testpmd'],
            # there must be separate CPU for each of RX/TX queues
            "GUEST_SMP" : ['5'],
            "GUEST_TESTPMD_PARAMS" : ['-c 0x1F -n 4 --socket-mem 512 -- '
                                      '--burst=64 -i --nb-cores=4 '
                                      '--rxq=2 --txq=2'],
            "TRAFFICGEN_DURATION" : 5,
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "multistream" : 3,
                "stream_type" : "L3",
                "frame_rate" : 1,
                "learning_frames" : False,
                'l3': {
                    'enabled': True,
                    'proto': 'udp',
                    'srcip': '6.6.6.6',
                    'dstip': '1.1.1.1',
                },
            },
            "GUEST_QUEUE_STATS_MAPPING" : ["rx 0 0 0",
                                           "rx 0 1 1",
                                           "rx 1 0 2",
                                           "rx 1 1 3",
                                           "tx 0 0 4",
                                           "tx 0 1 5",
                                           "tx 1 0 6",
                                           "tx 1 1 7"
                                          ]
        },
        "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT +
                     [
                        ['vnf', 'start'],
                        ['tools', 'exec_shell', "sudo $TOOLS['ovs-appctl'] dpif-netdev/pmd-rxq-show",
                         '|dpdk\w+\s+queue-id:\s+\d'],
                        # there must be two standalone queue records for every interface (2x4)
                        ['tools', 'assert', 'len(#STEP[-1])==8'],
                        ['trafficgen', 'send_traffic', {}],

                        # check that packets were received by both queues at both ports
                        ['vnf', 'execute_and_wait', 'show port stats 0', 60, 'testpmd>',
                         '|Stats reg  [01] RX-packets:\s+(\d+)'],
                        ['tools', 'assert', '"0" not in #STEP[-1]'],
                        # rx queue of 2nd port should be mapped to reg 2 and 3, but mapping might not work
                        # so let us check that exactly two RX regs have non zero values
                        ['vnf', 'execute_and_wait', 'show port stats 1', 60, 'testpmd>',
                         '|Stats reg\s+\d+ RX-packets:\s+\d\d+'],
                        ['tools', 'assert', 'len(#STEP[-1])==2'],
                        # clean up
                        ['vnf', 'stop'],
                     ]
    },
    ############################################################
    #
    #  Vhost User
    #
    ############################################################
    {
        "Name": "ovsdpdk_vhostuser_client",
        "Deployment": "pvp",
        "Description": "Test vhost-user client mode",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "TRAFFICGEN_DURATION" : 1,
        },
        "TestSteps": [
                        # check that client ports are really used
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show',
                                                '|type.*dpdkvhostuserclient'],
                        ['tools', 'assert', 'len(#STEP[-1])==2'],
                        # send traffic manually, so TC will fail in case
                        # that packets won't make it through
                        ['trafficgen', 'send_traffic', {}],
                     ],
    },
    {
        "Name": "ovsdpdk_vhostuser_client_reconnect",
        "Deployment": "pvp",
        "Description": "Test vhost-user client mode reconnect feature",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "TRAFFICGEN_DURATION" : 1,
        },
        "TestSteps": [
                        # send traffic to verify correct PVP configuration
                        ['trafficgen', 'send_traffic', {}],
                        ['vswitch', 'dump_flows', '$VSWITCH_BRIDGE_NAME'],
                        # restart vswitchd, ovsdb is kept untouched, so ovs configuration
                        # (except flows) will be restored
                        ['vswitch', 'restart'],
                        ['vswitch', 'del_flow', '$VSWITCH_BRIDGE_NAME', {}],
                        ['vswitch', 'dump_flows', '$VSWITCH_BRIDGE_NAME'],
                        ['vswitch', 'add_flow', '$VSWITCH_BRIDGE_NAME', {'in_port': '1', 'actions': ['output:3'], 'idle_timeout': '0'}],
                        ['vswitch', 'add_flow', '$VSWITCH_BRIDGE_NAME', {'in_port': '3', 'actions': ['output:1'], 'idle_timeout': '0'}],
                        ['vswitch', 'add_flow', '$VSWITCH_BRIDGE_NAME', {'in_port': '2', 'actions': ['output:4'], 'idle_timeout': '0'}],
                        ['vswitch', 'add_flow', '$VSWITCH_BRIDGE_NAME', {'in_port': '4', 'actions': ['output:2'], 'idle_timeout': '0'}],
                        ['vswitch', 'dump_flows', '$VSWITCH_BRIDGE_NAME'],
                        # send traffic to verify that OVS works correctly after restart
                        ['trafficgen', 'send_traffic', {}],
                     ],
    },
    {
        "Name": "ovsdpdk_vhostuser_server",
        "Deployment": "pvp",
        "Description": "Test vhost-user server mode",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'True',
            },
            "VSWITCH_VHOSTUSER_SERVER_MODE" : True,
            "TRAFFICGEN_DURATION" : 1,
        },
        "TestSteps": [
                        # check that server ports are really used
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show',
                                                '|type.*dpdkvhostuser$'],
                        ['tools', 'assert', 'len(#STEP[-1])==2'],
                        # send traffic manually, so TC will fail in case
                        # that packets won't make it through
                        ['trafficgen', 'send_traffic', {}],
                     ],
    },
    {
        "Name": "ovsdpdk_vhostuser_sock_dir",
        "Deployment": "clean",
        "Description": "Verify functionality of vhost-sock-dir flag",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : True,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', '$VSWITCH_BRIDGE_NAME'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Open_vSwitch . '
                         'other_config:vhost-sock-dir=test_dir'],
                        # enforce vswitchd to read new configuration
                        ['vswitch', 'restart'],
                        ['tools', 'exec_shell', 'sudo mkdir $TOOLS["ovs_var_tmp"]/test_dir'],
                        ['vswitch', 'add_vport', '$VSWITCH_BRIDGE_NAME'],
                        ['tools', 'exec_shell', 'ls -1 $TOOLS["ovs_var_tmp"]/test_dir',
                         '|dpdkvhostuser0'],
                        ['tools', 'assert', 'len(#STEP[-1])'],
                     ],
    },
]
############################################################
#
#  Virtual Devices Support
#
############################################################
_OVSDPDK_VDEV_ADD_NULL = [
    ['vswitch', 'add_switch', 'int_br0'],
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"]  add-port int_br0 null0 -- '
     'set Interface null0 type=dpdk options:dpdk-devargs=eth_null0'],
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show', '|dpdk-devargs=eth_null0'],
    ['tools', 'assert', 'len(#STEP[-1])==1'],
]

_OVSDPDK_VDEV_ADD_AF_PACKET = [
    # resore original NICS configuration, so we can use NICS dictionary
    ['settings', 'setValue', 'TEST_PARAMS', ''],
    # check if vsperf was able to read device name
    ['tools', 'assert', 'str(\"$NICS[0]["device"]\") != \"None\"'],
    ['tools', 'exec_shell', 'sudo ip link set dev $NICS[0]["device"] up'],
    ['vswitch', 'add_switch', 'int_br0'],
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"]  add-port int_br0 myeth0 -- '
     'set Interface myeth0 type=dpdk options:dpdk-devargs=eth_af_packet0,iface=$NICS[0]["device"]'],
    # check if device was created...
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show', '|dpdk-devargs=\S+eth_af_packet0'],
    ['tools', 'assert', 'len(#STEP[-1])==1'],
    # ...without errors
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show', '|Error attaching device'],
    ['tools', 'assert', 'not len(#STEP[-1])'],
]

INTEGRATION_TESTS = INTEGRATION_TESTS + [
    {
        "Name": "ovsdpdk_vdev_add_null_pmd",
        "Deployment": "clean",
        "Description": "Test addition of port using the null DPDK PMD driver.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": _OVSDPDK_VDEV_ADD_NULL
    },
    {
        "Name": "ovsdpdk_vdev_del_null_pmd",
        "Deployment": "clean",
        "Description": "Test deletion of port using the null DPDK PMD driver.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": _OVSDPDK_VDEV_ADD_NULL + [
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"]  del-port null0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show',
                         '|dpdk-devargs=eth_null0'],
                        ['tools', 'assert', 'not len(#STEP[-1])'],
                    ]
    },
    {
        "Name": "ovsdpdk_vdev_add_af_packet_pmd",
        "Deployment": "clean",
        "Description": "Test addition of port using the af_packet DPDK PMD driver.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            # suppress DPDK configuration, so physical interfaces are not bound to DPDK driver
            'WHITELIST_NICS' : [],
            'NICS' : [],
        },
        "TestSteps": _OVSDPDK_VDEV_ADD_AF_PACKET
    },
    {
        "Name": "ovsdpdk_vdev_del_af_packet_pmd",
        "Deployment": "clean",
        "Description": "Test deletion of port using the af_packet DPDK PMD driver.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            # suppress DPDK configuration, so physical interfaces are not bound to DPDK driver
            'WHITELIST_NICS' : [],
            'NICS' : [],
        },
        "TestSteps": _OVSDPDK_VDEV_ADD_AF_PACKET + [
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"]  del-port myeth0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] show',
                         '|dpdk-devargs=\S+eth_af_packet0'],
                        ['tools', 'assert', 'not len(#STEP[-1])'],
                    ]
    },
    ############################################################
    #
    #  NUMA Support
    #
    ############################################################
    {
        "Name": "ovsdpdk_numa",
        "Deployment": "clean",
        "Description": "Test vhost-user NUMA support. Vhostuser PMD threads should migrate "
                       "to the same numa slot, where QEMU is executed.",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            # ensure that memory and cpus are available at both numa slots
            "DPDK_SOCKET_MEM" : ['1024', '1024'],
            "VSWITCH_PMD_CPU_MASK" : 'FFFFFE',
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            # traffic won't be send, so speed up VNF deployment
            "GUEST_LOOPBACK" : ['clean']
        },
        "TestSteps": STEP_VSWITCH_PVP_INIT +
            [
                # check that at least 2 numa slots are available
                ['tools', 'exec_shell', 'numactl -H', '|available: ([0-9]+)'],
                ['tools', 'assert', '#STEP[-1][0]>1'],
                # check that PMD thread serving dpdkvhostuserclient0 runs at NUMA slot 0
                ['tools', 'exec_shell', "sudo $TOOLS['ovs-appctl'] "
                    "dpif-netdev/pmd-rxq-show | "
                    "sed -e '/dpdkvhostuserclient0/,$d' | tac",
                    '|pmd thread numa_id ([0-9])+'
                ],
                ['tools', 'assert', '#STEP[-1][0]==0'],
                # store last 2 cores from 2nd numa slot
                ['tools', 'exec_shell', 'numactl -H', '|node 1 cpus:.*\s+(\\d+) (\\d+)$'],
                # pin VNF to 2nd NUMA slot
                ['settings', 'setValue', 'GUEST_CORE_BINDING',
                    [("#STEP[-1][0][0]", "#STEP[-1][0][1]")]
                ],
                ['vnf', 'start'],
                # ...and check that PMD thread serving dpdkvhostuserclient0
                # has migrated to NUMA slot 1
                ['tools', 'exec_shell', "sudo $TOOLS['ovs-appctl'] "
                    "dpif-netdev/pmd-rxq-show | "
                    "sed -e '/dpdkvhostuserclient0/,$d' | tac",
                    '|pmd thread numa_id ([0-9])+'
                ],
                ['tools', 'assert', '#STEP[-1][0]==1'],
                ['vnf', 'stop'],
            ] +
            STEP_VSWITCH_PVP_FINIT
    },
    ############################################################
    #
    #  Jumbo Frame Support
    #
    ############################################################
    {
        "Name": "ovsdpdk_jumbo_increase_mtu_phy_port_ovsdb",
        "Deployment": "clean",
        "Description": "Ensure that the increased MTU for a DPDK physical port is updated in OVSDB.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==1500'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_increase_mtu_vport_ovsdb",
        "Deployment": "clean",
        "Description": "Ensure that the increased MTU for a DPDK vhost-user port is updated in OVSDB.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==1500'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_reduce_mtu_phy_port_ovsdb",
        "Deployment": "clean",
        "Description": "Ensure that the reduced MTU for a DPDK physical port is updated in OVSDB.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_JUMBO_FRAMES_ENABLED" : 'True',
            "VSWITCH_JUMBO_FRAMES_SIZE" : 9000,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=2000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==2000'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_reduce_mtu_vport_ovsdb",
        "Deployment": "clean",
        "Description": "Ensure that the reduced MTU for a DPDK vhost-user port is updated in OVSDB.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "VSWITCH_JUMBO_FRAMES_ENABLED" : 'True',
            "VSWITCH_JUMBO_FRAMES_SIZE" : 9000,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=2000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==2000'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_increase_mtu_phy_port_datapath",
        "Deployment": "clean",
        "Description": "Ensure that the MTU for a DPDK physical port is updated in the datapath itself when increased to a valid value.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=1500'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=9000'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_increase_mtu_vport_datapath",
        "Deployment": "clean",
        "Description": "Ensure that the MTU for a DPDK vhost-user port is updated in the datapath itself when increased to a valid value.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=1500'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=9000'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_reduce_mtu_phy_port_datapath",
        "Deployment": "clean",
        "Description": "Ensure that the MTU for a DPDK physical port is updated in the datapath itself when decreased to a valid value.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_JUMBO_FRAMES_ENABLED" : 'True',
            "VSWITCH_JUMBO_FRAMES_SIZE" : 9000,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=9000'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=2000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=2000'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_reduce_mtu_vport_datapath",
        "Deployment": "clean",
        "Description": "Ensure that the MTU for a DPDK vhost-user port is updated in the datapath itself when decreased to a valid value.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "VSWITCH_JUMBO_FRAMES_ENABLED" : 'True',
            "VSWITCH_JUMBO_FRAMES_SIZE" : 9000,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=9000'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=2000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] dpctl/show', '|mtu=2000'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_mtu_upper_bound_phy_port",
        "Deployment": "clean",
        "Description": "Verify that the upper bound limit is enforced for OvS DPDK Phy ports.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=9702'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9702'],
                        # get line number of next log file entry
                        ['tools', 'exec_shell', 'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=9711'],
                        # check vswitchd log file, that new MTU request was denied
                        ['tools', 'exec_shell', "sed -n '#STEP[-2][0],$ p' $_OVSDPDK_VSWITCH_LOG",
                         '|unsupported MTU 9711'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9702'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_mtu_upper_bound_vport",
        "Deployment": "clean",
        "Description": "Verify that the upper bound limit is enforced for OvS DPDK vhost-user ports.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=9702'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9702'],
                        # get line number of next log file entry
                        ['tools', 'exec_shell', 'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=9711'],
                        # check vswitchd log file, that new MTU request was denied
                        ['tools', 'exec_shell', "sed -n '#STEP[-2][0],$ p' $_OVSDPDK_VSWITCH_LOG",
                         '|unsupported MTU 9711'],
                        ['tools', 'assert', 'len(#STEP[-1])'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9702'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_mtu_lower_bound_phy_port",
        "Deployment": "clean",
        "Description": "Verify that the lower bound limit is enforced for OvS DPDK Phy ports.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=68'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==68'],
                        # get line number of next log file entry
                        ['tools', 'exec_shell', 'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdk0 mtu_request=67'],
                        # check vswitchd log file, that new MTU request was denied
                        ['tools', 'exec_shell', "sed -n '#STEP[-2][0],$ p' $_OVSDPDK_VSWITCH_LOG",
                         '|unsupported MTU 67'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==68'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_mtu_lower_bound_vport",
        "Deployment": "clean",
        "Description": "Verify that the lower bound limit is enforced for OvS DPDK vhost-user ports.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=68'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==68'],
                        # get line number of next log file entry
                        ['tools', 'exec_shell', 'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set Interface dpdkvhostuserclient0 mtu_request=67'],
                        # check vswitchd log file, that new MTU request was denied
                        ['tools', 'exec_shell', "sed -n '#STEP[-2][0],$ p' $_OVSDPDK_VSWITCH_LOG",
                         '|unsupported MTU 67'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==68'],
                    ]
    },
    {
        "Name": "ovsdpdk_jumbo_p2p",
        "Deployment": "p2p",
        "Description": "Ensure that jumbo frames are received, processed and forwarded correctly by DPDK physical ports.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
                'learning_frames' : False,
            },
            "TRAFFICGEN_PKT_SIZES" : (9018,),
            "VSWITCH_JUMBO_FRAMES_ENABLED" : 'True',
            "VSWITCH_JUMBO_FRAMES_SIZE" : 9000,
        },
        "TestSteps": [
                        # verify jumbo frame configuration
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk1 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['trafficgen', 'send_traffic', {}],
                        # check that jumbo frames were received by traffic generator
                        ['trafficgen', 'get_results'],
                        # i.e. (RX in Bytes/s) divide (RX frames/s) ~ 9018 Bytes
                        ['tools', 'assert', 'round(float(#STEP[-1][0]["throughput_rx_mbps"])*1000000/8 / '
                         'float(#STEP[-1][0]["throughput_rx_fps"]))==9018'],
                     ]
    },
{
        "Name": "ovsdpdk_jumbo_pvp",
        "Deployment": "clean",
        "Description": "Ensure that jumbo frames are received, processed and forwarded correctly by DPDK vhost-user ports.",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
                'learning_frames' : False,
            },
            "TRAFFICGEN_PKT_SIZES" : (9018,),
            "VSWITCH_JUMBO_FRAMES_ENABLED" : 'True',
            "VSWITCH_JUMBO_FRAMES_SIZE" : 9000,
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "GUEST_LOOPBACK" : ['linux_bridge'],
            "GUEST_NIC_MERGE_BUFFERS_DISABLE" : [False],
        },
        "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT + [
                        # verify jumbo frame configuration
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk1 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdkvhostuserclient1 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        # VNF startup, MTU configuration
                        ['vnf', 'start'],
                        ['vnf', 'execute_and_wait', 'ifconfig eth0 mtu 9000'],
                        ['vnf', 'execute_and_wait', 'ifconfig eth1 mtu 9000'],
                        ['trafficgen', 'send_traffic', {}],
                        # check that jumbo frames were received by traffic generator
                        ['trafficgen', 'get_results'],
                        # i.e. (RX in Bytes/s) divide (RX frames/s) ~ 9018 Bytes
                        ['tools', 'assert', 'round(float(#STEP[-1][0]["throughput_rx_mbps"])*1000000/8 / '
                         'float(#STEP[-1][0]["throughput_rx_fps"]))==9018'],
                        ['vnf', 'stop'],
                   ] + STEP_VSWITCH_PVP_FLOWS_FINIT
    },
    {
        "Name": "ovsdpdk_jumbo_p2p_upper_bound",
        "Deployment": "p2p",
        "Description": "Ensure that jumbo frames above the configured Rx port's MTU are not accepted",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 10,
                'bidir' : 'False',
                'learning_frames' : False,
            },
            "VSWITCH_JUMBO_FRAMES_ENABLED" : 'True',
            "VSWITCH_JUMBO_FRAMES_SIZE" : 9000,
        },
        "TestSteps": [
                        # set and verify jumbo frame support
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk0 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] get Interface dpdk1 mtu'],
                        ['tools', 'assert', 'int(#STEP[-1])==9000'],
                        # set packetsize to 9018 and send traffic
                        ['settings', 'setValue', 'TRAFFICGEN_PKT_SIZES', (9018,)],
                        ['trafficgen', 'send_traffic', {}],
                        ['trafficgen', 'get_results'],
                        # all traffic should pass through (i.e. 0% frame loss)
                        ['tools', 'assert', 'float(#STEP[-1][0]["frame_loss_percent"])==0'],
                        # set packetsize to 9702 and send traffic
                        ['settings', 'setValue', 'TRAFFICGEN_PKT_SIZES', (9702,)],
                        # disable verification of send_traffic "!" prefix, otherwise vsperf
                        # will fail when 100% packet loss is detected
                        ['!trafficgen', 'send_traffic', {}],
                        ['trafficgen', 'get_results'],
                        # all traffic should be dropped
                        ['tools', 'assert', 'float(#STEP[-1][0]["frame_loss_percent"])==100'],
                     ]
    },
]
############################################################
#
#  Rate Limiting
#
############################################################
# default settings of limiter used in macros and tests
_OVSDPDK_RATE_PORT = 'dpdk'
_OVSDPDK_RATE_NICID = '0'
_OVSDPDK_RATE_RATE = '10000'             # desired maximum rate of PAYLOAD carried by frames
_OVSDPDK_RATE_BURST = '8000'
_OVSDPDK_RATE_LIMITER_CREATED = 'True'   # set to False to verify that limiter was not created

_OVSDPDK_RATE_DEVIATION = '5'            # acceptable deviation from configured frame rate in %
# Formula used for validation of rate settings.
# Note: OVS parameter "ingress_policing_rate" configures maximum rate of payload in Kbps,
# but traffic generator measures throughput in Mbps based on whole frames including headers.
# Thus measured RX throughput value reported by traffic generator must be deducted by bit
# rate consumed by frame header transmission.
_OVSDPDK_RATE_CHECK = ('abs(1-float(#STEP[{}][{}]["throughput_rx_mbps"])*1000*'
                       '(1-$_OVSDPDK_HEADER_LEN/float(#STEP[{}][{}]["packet_size"]))'
                       '/float($_OVSDPDK_RATE_RATE))*100 < $_OVSDPDK_RATE_DEVIATION')

# macro will setup rate limiter at interface defined by _DPDK_RATE_PORT and
# _DPDK_RATE_NICID; It will verify, that limiter was created by parsing
# vswitchd log file. It will also check that proper limiter values are
# set for given interface.
_OVSDPDK_RATE_set_rate_limiter = [
    # get line number of next log file entry
    ['tools', 'exec_shell', 'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] '
     'set Interface $_OVSDPDK_RATE_PORT$_OVSDPDK_RATE_NICID '
     'ingress_policing_burst=$_OVSDPDK_RATE_BURST '
     'ingress_policing_rate=$_OVSDPDK_RATE_RATE'],
    # verify that interface has correct rate limiter configuration
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] '
     'list interface $_OVSDPDK_RATE_PORT$_OVSDPDK_RATE_NICID',
     '(ingress_policing_\w+: \d+)'],
    ['tools', 'assert', '"ingress_policing_burst: $_OVSDPDK_RATE_BURST" in #STEP[-1]'],
    ['tools', 'assert', '"ingress_policing_rate: $_OVSDPDK_RATE_RATE" in #STEP[-2]'],
]

_OVSDPDK_RATE_set_rate_limiter_NIC0 = [
    ['settings', 'setValue', '_OVSDPDK_RATE_NICID', '0']
] + _OVSDPDK_RATE_set_rate_limiter

_OVSDPDK_RATE_set_rate_limiter_NIC1 = [
    ['settings', 'setValue', '_OVSDPDK_RATE_NICID', '1']
] + _OVSDPDK_RATE_set_rate_limiter

# macro will set different limiter values and sends traffic to verify proper
# limiter functionality
_OVSDPDK_RATE_confirm_multiple_rate_limit_setup = \
    _OVSDPDK_RATE_set_rate_limiter_NIC0 + _OVSDPDK_RATE_set_rate_limiter_NIC1 + [
        # by default rate limit is 10Mbits/s
        ['trafficgen', 'send_traffic', {}],
        ['trafficgen', 'get_results'],
        # check result and accept preconfigured deviation to the configured frame rate
        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("-1", "0", "-1", "0")],
        # set rate limit to 20Mbits/s
        ['settings', 'setValue', '_OVSDPDK_RATE_RATE', '20000']
     ] + _OVSDPDK_RATE_set_rate_limiter_NIC0 + _OVSDPDK_RATE_set_rate_limiter_NIC1 + [
        ['trafficgen', 'send_traffic', {}],
        ['trafficgen', 'get_results'],
        # check result and accept preconfigured deviation to the configured frame rate
        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("-1", "0", "-1", "0")],
        # set rate limit to 30Mbits/s
        ['settings', 'setValue', '_OVSDPDK_RATE_RATE', '30000']
     ] + _OVSDPDK_RATE_set_rate_limiter_NIC0 + _OVSDPDK_RATE_set_rate_limiter_NIC1 + [
        ['trafficgen', 'send_traffic', {}],
        ['trafficgen', 'get_results'],
        # check result and accept preconfigured deviation to the configured frame rate
        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("-1", "0", "-1", "0")],
        # disable rate limiter and verify unlimited speed
        ['settings', 'setValue', '_OVSDPDK_RATE_RATE', '0'],
        ['settings', 'setValue', '_OVSDPDK_RATE_BURST', '0'],
        ['settings', 'setValue', '_OVSDPDK_RATE_LIMITER_CREATED', 'False'],
     ] + _OVSDPDK_RATE_set_rate_limiter_NIC0 + _OVSDPDK_RATE_set_rate_limiter_NIC1 + [
        ['trafficgen', 'send_traffic', {}],
        # check that traffic rate is no longer limited
        ['trafficgen', 'get_results'],
        ['tools', 'assert', 'int(#STEP[-1][0]["throughput_rx_mbps"])>500'],
        ['vswitch', 'dump_flows', '$VSWITCH_BRIDGE_NAME'],
    ]

INTEGRATION_TESTS = INTEGRATION_TESTS + [
    {
        "Name": "ovsdpdk_rate_create_phy_port",
        "Deployment": "clean",
        "Description": "Ensure a rate limiting interface can be created on a physical DPDK port.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                    ] + _OVSDPDK_RATE_set_rate_limiter
    },
    {
        "Name": "ovsdpdk_rate_delete_phy_port",
        "Deployment": "clean",
        "Description": "Ensure a rate limiting interface can be destroyed on a physical DPDK port.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                    ] + _OVSDPDK_RATE_set_rate_limiter + [
                        ['settings', 'setValue', '_OVSDPDK_RATE_RATE', '0'],
                        ['settings', 'setValue', '_OVSDPDK_RATE_BURST', '0'],
                        ['settings', 'setValue', '_OVSDPDK_RATE_LIMITER_CREATED', 'False'],
                    ] + _OVSDPDK_RATE_set_rate_limiter
    },
    {
        "Name": "ovsdpdk_rate_create_vport",
        "Deployment": "clean",
        "Description": "Ensure a rate limiting interface can be created on a vhost-user port.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "_OVSDPDK_RATE_PORT" : 'dpdkvhostuserclient',
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                    ] + _OVSDPDK_RATE_set_rate_limiter
    },
    {
        "Name": "ovsdpdk_rate_delete_vport",
        "Deployment": "clean",
        "Description": "Ensure a rate limiting interface can be destroyed on a vhost-user port.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "_OVSDPDK_RATE_PORT" : 'dpdkvhostuserclient',
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                    ] + _OVSDPDK_RATE_set_rate_limiter + [
                        ['settings', 'setValue', '_OVSDPDK_RATE_RATE', '0'],
                        ['settings', 'setValue', '_OVSDPDK_RATE_BURST', '0'],
                        ['settings', 'setValue', '_OVSDPDK_RATE_LIMITER_CREATED', 'False'],
                    ] + _OVSDPDK_RATE_set_rate_limiter
    },
    {
        "Name": "ovsdpdk_rate_no_policing",
        "Deployment": "clean",
        "Description": "Ensure when a user attempts to create a rate limiting interface but is missing policing rate argument, no rate limitiner is created.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "_OVSDPDK_RATE_PORT" : 'dpdkvhostuserclient',
            "_OVSDPDK_RATE_RATE" : '0',
            "_OVSDPDK_RATE_BURST" : '1000',
            "_OVSDPDK_RATE_LIMITER_CREATED" : 'False',
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                    ] + _OVSDPDK_RATE_set_rate_limiter
    },
    {
        "Name": "ovsdpdk_rate_no_burst",
        "Deployment": "clean",
        "Description": "Ensure when a user attempts to create a rate limiting interface but is missing policing burst argument, rate limitiner is created.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "_OVSDPDK_RATE_PORT" : 'dpdkvhostuserclient',
            "_OVSDPDK_RATE_RATE" : '10000',
            "_OVSDPDK_RATE_BURST" : '0',
            "_OVSDPDK_RATE_LIMITER_CREATED" : 'True',
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                    ] + _OVSDPDK_RATE_set_rate_limiter
    },
    {
        "Name": "ovsdpdk_rate_p2p",
        "Deployment": "p2p",
        "Description": "Ensure when a user creates a rate limiting physical interface that the traffic is limited to the specified policer rate in a p2p setup.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "_OVSDPDK_RATE_PORT" : 'dpdk',
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
            },
        },
        "TestSteps": _OVSDPDK_RATE_confirm_multiple_rate_limit_setup
    },
    {
        "Name": "ovsdpdk_rate_pvp",
        "Deployment": "pvp",
        "Description": "Ensure when a user creates a rate limiting vHost User interface that the traffic is limited to the specified policer rate in a pvp setup.",
        "vSwitch" : "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "_OVSDPDK_RATE_PORT" : 'dpdkvhostuserclient',
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
            },
        },
        "TestSteps": _OVSDPDK_RATE_confirm_multiple_rate_limit_setup
    },
    {
        "Name": "ovsdpdk_rate_p2p_multi_pkt_sizes",
        "Deployment": "p2p",
        "Description": "Ensure that rate limiting works for various frame sizes.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "_OVSDPDK_RATE_PORT" : 'dpdk',
            "_OVSDPDK_RATE_RATE" : '10000',
            "TRAFFICGEN_PKT_SIZES" : _OVSDPDK_PKT_SIZES,
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
            },
        },
        "TestSteps": _OVSDPDK_RATE_set_rate_limiter_NIC0 + _OVSDPDK_RATE_set_rate_limiter_NIC1 + [
                        # dump rate limiter configuration of both NICs
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] '
                         'list interface dpdk0'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] '
                         'list interface dpdk1'],
                        ['trafficgen', 'send_traffic', {}],
                        ['#result', 'trafficgen', 'get_results'],
                        # check results and accept preconfigured deviation to the configured frame rates
                        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("result","0", "result","0")],
                        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("result","1", "result","1")],
                        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("result","2", "result","2")],
                        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("result","3", "result","3")],
                        ['tools', 'assert', _OVSDPDK_RATE_CHECK.format("result","4", "result","4")],
                    ],
    },
]
############################################################
#
#  Quality of Service
#
############################################################
# default settings of limiter used in macros and tests
_OVSDPDK_QOS_PORT = 'dpdk'
_OVSDPDK_QOS_NICID = '0'
_OVSDPDK_QOS_CIR = '1250000'  # desired maximum rate of PAYLOAD carried by frames in BYTEs
_OVSDPDK_QOS_CBS = '2048'

_OVSDPDK_QOS_DEVIATION = '5'            # acceptable deviation from configured frame rate in %
# Formula used for validation of rate settings.
# Note: OVS parameter "ingress_policing_rate" configures maximum rate of payload in Kbps,
# but traffic generator measures throughput in Mbps based on whole frames including headers.
# Thus measured RX throughput value reported by traffic generator must be deducted by bit
# rate consumed by frame header transmission.
_OVSDPDK_QOS_CHECK = ('abs(1-float(#STEP[{}][{}]["throughput_rx_mbps"])*1000000*'
                      '(1-$_OVSDPDK_HEADER_LEN/float(#STEP[{}][{}]["packet_size"]))'
                      '/float($_OVSDPDK_QOS_CIR*8))*100 < $_OVSDPDK_QOS_DEVIATION')


# macro will setup QoS at interface defined by _OVSDPDK_QOS_PORT and
# _OVSDPDK_QOS_NICID; It will verify, that QoS was created by parsing
# vswitchd log file. It will also check that proper QoS values are
# set for given interface.
_OVSDPDK_QOS_set_qos = [
    # get line number of next log file entry
    ['tools', 'exec_shell', 'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],

    # Crete QoS policy and check the returned policy ID
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] '
     'set port $_OVSDPDK_QOS_PORT$_OVSDPDK_QOS_NICID qos=@newqos -- '
     '--id=@newqos create qos type=egress-policer other-config:cir=$_OVSDPDK_QOS_CIR '
     'other-config:cbs=$_OVSDPDK_QOS_CBS','|\w{8}-\w{4}-\w{4}-\w{4}-\w{12}'],
    ['tools', 'assert', 'len(#STEP[-1])==1'],

    # Check the QoS policy and attributes
    ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] -t ovs-vswitchd qos/show '
     '$_OVSDPDK_QOS_PORT$_OVSDPDK_QOS_NICID', '.+'],
    ['tools', 'assert', "'QoS: $_OVSDPDK_QOS_PORT$_OVSDPDK_QOS_NICID egress-policer' in #STEP[-1]"],
    ['tools', 'assert', "'cbs: $_OVSDPDK_QOS_CBS' in #STEP[-2]"],
    ['tools', 'assert', "'cir: $_OVSDPDK_QOS_CIR' in #STEP[-3]"],
]

_OVSDPDK_QOS_set_qos_NIC0 = [
    ['settings', 'setValue', '_OVSDPDK_QOS_NICID', '0']
] + _OVSDPDK_QOS_set_qos

_OVSDPDK_QOS_set_qos_NIC1 = [
    ['settings', 'setValue', '_OVSDPDK_QOS_NICID', '1']
] + _OVSDPDK_QOS_set_qos

# macro will set different limiter values and sends traffic to verify proper
# QoS functionality
_OVSDPDK_QOS_confirm_multiple_qos_setup = [
        # Create QoS policy with payload rate of 23*10^6 Bytes/s
        ['settings', 'setValue', '_OVSDPDK_QOS_CIR', '23000000']
     ] + _OVSDPDK_QOS_set_qos_NIC0 + _OVSDPDK_QOS_set_qos_NIC1 + [
        ['trafficgen', 'send_traffic', {}],
        ['trafficgen', 'get_results'],
        ['tools', 'assert', _OVSDPDK_QOS_CHECK.format("-1", "0", "-1", "0")],
        # Create QoS policy with payload rate of 46*10^6 Bytes/s
        ['settings', 'setValue', '_OVSDPDK_QOS_CIR', '46000000']
     ] + _OVSDPDK_QOS_set_qos_NIC0 + _OVSDPDK_QOS_set_qos_NIC1 + [
        ['trafficgen', 'send_traffic', {}],
        ['trafficgen', 'get_results'],
        ['tools', 'assert', _OVSDPDK_QOS_CHECK.format("-1", "0", "-1", "0")],
        # Create QoS policy with payload rate of 92*10^6 Bytes/s
        ['settings', 'setValue', '_OVSDPDK_QOS_CIR', '92000000']
     ] + _OVSDPDK_QOS_set_qos_NIC0 + _OVSDPDK_QOS_set_qos_NIC1 + [
        ['trafficgen', 'send_traffic', {}],
        ['trafficgen', 'get_results'],
        ['tools', 'assert', _OVSDPDK_QOS_CHECK.format("-1", "0", "-1", "0")],
     ]

INTEGRATION_TESTS = INTEGRATION_TESTS + [
    {
        "Name": "ovsdpdk_qos_create_phy_port",
        "Deployment": "clean",
        "Description": "Ensure a QoS policy can be created on a physical DPDK port",
        "vSwitch": "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                    ] + _OVSDPDK_QOS_set_qos
    },
    {
        "Name": "ovsdpdk_qos_delete_phy_port",
        "Deployment": "clean",
        "Description": "Ensure an existing QoS policy can be destroyed on a physical DPDK port.",
        "vSwitch": "OvsDpdkVhost",
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_phy_port', 'int_br0'],
                     ] + _OVSDPDK_QOS_set_qos + [
                        # Destroy the QoS policy and check the attributes
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] -- destroy QoS #STEP[1][0] -- clear Port #STEP[1][0] qos'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] -t ovs-vswitchd qos/show #STEP[1][0]', 'QoS not configured on #STEP[1][0]'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                     ]
    },
    {
        "Name": "ovsdpdk_qos_create_vport",
        "Deployment": "clean",
        "Description": "Ensure a QoS policy can be created on a virtual vhost user port.",
        "vSwitch": "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "_OVSDPDK_QOS_PORT" : 'dpdkvhostuserclient',
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                    ] + _OVSDPDK_QOS_set_qos
    },
    {
        "Name": "ovsdpdk_qos_delete_vport",
        "Deployment": "clean",
        "Description": "Ensure an existing QoS policy can be destroyed on a vhost user port.",
        "vSwitch": "OvsDpdkVhost",
        "Parameters" : {
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "_OVSDPDK_QOS_PORT" : 'dpdkvhostuserclient',
        },
        "TestSteps": [
                        ['vswitch', 'add_switch', 'int_br0'],
                        ['vswitch', 'add_vport', 'int_br0'],
                     ] + _OVSDPDK_QOS_set_qos + [
                        # Destroy the QoS policy and check the attributes
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] -- destroy QoS #STEP[1][0] -- clear Port #STEP[1][0] qos'],
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] -t ovs-vswitchd qos/show #STEP[1][0]', 'QoS not configured on #STEP[1][0]'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                     ]
    },
    {
        "Name": "ovsdpdk_qos_create_no_cir",
        "Deployment": "clean",
        "Description": "Ensure that a QoS policy cannot be created if the egress policer cir argument is missing.",
        "vSwitch": "OvsDpdkVhost",
        "Parameters" : {},
        "TestSteps": [
                         # Setup switch,port and logs
                        ['vswitch', 'add_switch', '$VSWITCH_BRIDGE_NAME'],
                        ['vswitch', 'add_vport', '$VSWITCH_BRIDGE_NAME'],
                        ['#LOG_MARK', 'tools', 'exec_shell',
                         'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],

                        # Crete QoS policy and check the returned policy ID
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set port #STEP[1][0] qos=@newqos -- '
                         '--id=@newqos create qos type=egress-policer other-config:cbs=2048',
                         '\w{8}-\w{4}-\w{4}-\w{4}-\w{12}'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],

                        # Check the OVS logs
                        ['tools', 'exec_shell', "sed -n '#STEP[LOG_MARK][0],$ p' $_OVSDPDK_VSWITCH_LOG",
                         'Failed to set QoS type egress-policer on port #STEP[1][0]: Invalid argument'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],

                        # Check the attributes for vhost0
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] -t ovs-vswitchd qos/show #STEP[1][0]',
                         'QoS not configured on #STEP[1][0]'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                    ]
    },
    {
        "Name": "ovsdpdk_qos_create_no_cbs",
        "Deployment": "clean",
        "Description": "Ensure that a QoS policy cannot be created if the egress policer cbs argument is missing.",
        "vSwitch": "OvsDpdkVhost",
        "Parameters" : {},
        "TestSteps": [
                         # Setup switch,port and logs
                        ['vswitch', 'add_switch', '$VSWITCH_BRIDGE_NAME'],
                        ['vswitch', 'add_vport', '$VSWITCH_BRIDGE_NAME'],
                        ['#LOG_MARK', 'tools', 'exec_shell',
                         'echo $((1+`wc -l $_OVSDPDK_VSWITCH_LOG | cut -d" " -f1`))', '(\d+)'],

                        # Crete QoS policy and check the returned policy ID
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-vsctl"] set port #STEP[1][0] qos=@newqos -- '
                         '--id=@newqos create qos type=egress-policer other-config:cir=1250000',
                         '\w{8}-\w{4}-\w{4}-\w{4}-\w{12}'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],

                        # Check the OVS logs
                        ['tools', 'exec_shell', "sed -n '#STEP[LOG_MARK][0],$ p' $_OVSDPDK_VSWITCH_LOG",
                         'Failed to set QoS type egress-policer on port #STEP[1][0]: Invalid argument'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],

                        # Check the attributes for vhost0
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-appctl"] -t ovs-vswitchd qos/show #STEP[1][0]',
                         'QoS not configured on #STEP[1][0]'],
                        ['tools', 'assert', 'len(#STEP[-1])==1'],
                    ]
    },
    {
        "Name": "ovsdpdk_qos_p2p",
        "Deployment": "p2p",
        "Description": "In a p2p setup, ensure when a QoS egress policer is created that the traffic is limited to the specified rate.",
        "vSwitch": "OvsDpdkVhost",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
            },
        },
        "TestSteps": _OVSDPDK_QOS_confirm_multiple_qos_setup
    },
    {
        "Name": "ovsdpdk_qos_pvp",
        "Deployment": "pvp",
        "Description": "In a pvp setup, ensure when a QoS egress policer is created that the traffic is limited to the specified rate.",
        "vSwitch": "OvsDpdkVhost",
        "VNF" : "QemuDpdkVhostUser",
        "Parameters" : {
            "_OVSDPDK_QOS_PORT" : 'dpdkvhostuserclient',
            "VSWITCH_VHOSTUSER_SERVER_MODE" : False,
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 100,
                'bidir' : 'False',
            },
        },
        "TestSteps": _OVSDPDK_QOS_confirm_multiple_qos_setup
    },
    ############################################################
    #
    #  Custom statistics
    #
    ############################################################
    {
        "Name": "ovsdpdk_custstat_check",
        "Deployment": "clean",
        "Description": "Test if custom statistics are supported.",
        "vSwitch" : "OvsDpdkVhost",
        "TestSteps": [
                        # enable custom statistics
                        ['vswitch', 'add_switch', 'int_br0', [
                                                  'protocols=OpenFlow10,OpenFlow11,OpenFlow12,'
                                                  'OpenFlow13,OpenFlow14,OpenFlow15']],
                        ['#port', 'vswitch', 'add_phy_port', 'int_br0'],
                        # check that custom statistics are available for given interface
                        ['tools', 'exec_shell', 'sudo $TOOLS["ovs-ofctl"] -O OpenFlow14 '
                                                'dump-ports int_br0 #STEP[port][1]',
                                                '|CUSTOM Statistics'],
                        ['tools', 'assert', 'len(#STEP[-1])'],
                        ['vswitch', 'del_port', 'int_br0', '#STEP[port][0]'],
                        ['vswitch', 'del_switch', 'int_br0'],
                    ]
    },
    {
        "Name": "ovsdpdk_custstat_rx_error",
        "Deployment": "clean",
        "Description": "Test bad ethernet CRC counter 'rx_crc_errors' exposed by custom statistics.",
        "vSwitch" : "OvsDpdkVhost",
        "Parameters" : {
            "OVS_OFCTL_ARGS" : [],
            "TRAFFICGEN" : "IxNet",
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
                "frame_rate" : 10,
            },
            "TRAFFICGEN_DURATION" : 10,
            "TRAFFICGEN_IXNET_TCL_SCRIPT" : "ixnetrfc2544_bad_l2_crc.tcl",
        },
        "TestSteps": [
                        # enable custom statistics
                        ['vswitch', 'add_switch', 'int_br0', [
                                                  'protocols=OpenFlow10,OpenFlow11,OpenFlow12,'
                                                  'OpenFlow13,OpenFlow14,OpenFlow15']],
                        ['#port1', 'vswitch', 'add_phy_port', 'int_br0'],
                        ['#port2', 'vswitch', 'add_phy_port', 'int_br0'],
                        ['vswitch', 'add_flow', 'int_br0', {'in_port': '1', 'actions': ['output:2']}],
                        ['vswitch', 'add_flow', 'int_br0', {'in_port': '2', 'actions': ['output:1']}],
                        ['#crc_old', 'tools', 'exec_shell', 'sudo $TOOLS["ovs-ofctl"] -O OpenFlow14 '
                                              'dump-ports int_br0 #STEP[port1][1]',
                                              '|rx_crc_errors=(\d+)'],
                        # frames will be dropped by NIC, so we have to suppress send_traffic validation
                        # to avoid test failure
                        ['!trafficgen', 'send_traffic', {}],
                        # check that custom statistics are available for given interface
                        ['#crc_new', 'tools', 'exec_shell', 'sudo $TOOLS["ovs-ofctl"] -O OpenFlow14 '
                                              'dump-ports int_br0 #STEP[port1][1]',
                                              '|rx_crc_errors=(\d+)'],
                        ['tools', 'assert', '#STEP[crc_new] > #STEP[crc_old]'],
                        # tear down the environment
                        ['vswitch', 'dump_flows', 'int_br0'],
                        ['vswitch', 'del_flow', 'int_br0', {}],
                        ['vswitch', 'del_port', 'int_br0', '#STEP[port1][0]'],
                        ['vswitch', 'del_port', 'int_br0', '#STEP[port2][0]'],
                        ['vswitch', 'del_switch', 'int_br0'],
                    ]
    },
]