# Copyright 2018 Intel Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#
# Testcases in this files use T-Rex running in VM as a traffic generator.
#

# A set of options passed to the T-Rex stateless server
_TREX_OPTIONS="--no-scapy-server --no-watchdog --nc"
_TREX_SERVER_IP="192.168.35.2"
_TREX_BRIDGE_IP="192.168.35.1"
_TREX_IP_MASK="24"

# Macro for initialization of T-Rex VM and execution of T-Rex server
# NOTE: It is expected that T-Rex will run in the LAST VM!
TREX_VM_INIT = [
    # configure T-Rex ports, which will be used for traffic generation
    ['#trex_p1', 'vswitch', 'add_vport', 'int_br0'],
    ['#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'],
    ['tools', 'exec_shell', 'sudo ip addr add $_TREX_BRIDGE_IP/$_TREX_IP_MASK dev trex_br'],
    ['tools', 'exec_shell', 'sudo ip link set dev trex_br up'],
    ['vnf_trex', 'start'],
    ['vnf_trex', 'execute_and_wait', 'sudo ip addr flush dev eth2'],
    ['vnf_trex', 'execute_and_wait', 'sudo ip addr add $_TREX_SERVER_IP/$_TREX_IP_MASK dev eth2'],
    ['vnf_trex', 'execute_and_wait', 'sudo ip link set dev eth2 up'],
    # preapre system for T-Rex execution
    ['vnf_trex', 'execute_and_wait', 'sysctl vm.nr_hugepages=$GUEST_HUGEPAGES_NR[-1]'],
    ['vnf_trex', 'execute_and_wait', 'mkdir -p /dev/hugepages'],
    ['vnf_trex', 'execute_and_wait', 'mount -t hugetlbfs hugetlbfs /dev/hugepages'],
    ['vnf_trex', 'execute_and_wait', 'grep -i huge /proc/meminfo'],
    ['vnf_trex', 'execute_and_wait', 'iptables -F'],
    # configure passwordless ssh access to VM with T-Rex server
    ['tools', 'exec_shell', 'sshpass -p $GUEST_PASSWORD[-1] ssh-copy-id -o StrictHostKeyChecking=no $GUEST_USERNAME[-1]@$_TREX_SERVER_IP'],
    # prepare T-Rex configuration
    ['vnf_trex', 'execute_and_wait', 'echo \'- port_limit: 2\' > /etc/trex_cfg.yaml'],
    ['vnf_trex', 'execute_and_wait', 'echo \'  version: 2\' >> /etc/trex_cfg.yaml'],
    ['vnf_trex', 'execute_and_wait', "echo \"  interfaces: [ '$GUEST_NICS[-1][0]['pci']', '$GUEST_NICS[-1][1]['pci']' ]\" >> /etc/trex_cfg.yaml"],
    # execute T-Rex stateless server and wait until it is up and running
    ['vnf_trex', 'execute_and_wait', 'cd $TRAFFICGEN_TREX_BASE_DIR'],
    ['#trex_pid', 'vnf_trex', 'execute_and_wait', 'nohup sudo bash -c "./t-rex-64 -i $_TREX_OPTIONS" &', '|\[1\] (\d+)$'],
    ['vnf_trex', 'execute_and_wait', 'echo -ne "Starting T-Rex " ; while ! netstat -nl | grep 4501 &> /dev/null ; do echo -ne "."; sleep 1 ; done; echo', 300],
]

# T-Rex VM teardown macro
TREX_VM_FINIT = [
    ['vnf_trex', 'execute_and_wait', 'sudo kill #STEP[trex_pid][0]'],
    ['vnf_trex', 'execute_and_wait', 'sudo pkill t-rex-64'],
    ['vnf_trex', 'stop'],
    ['vswitch', 'del_port', 'trex_br', '#STEP[trex_admin][0]'],
    ['vswitch', 'del_port', 'trex_br', '#STEP[trex_spare][0]'],
    ['tools', 'exec_shell', 'sudo ip link set dev trex_br down'],
    ['tools', 'exec_shell', 'sudo ip addr flush dev trex_br'],
    ['vswitch', 'del_switch', 'trex_br'],
]

# Configure T-Rex loopback test, where traffic from T-Rex is forwarded back via OVS flows
TREX_VM_TEST = [
       ['vswitch', 'add_switch', 'int_br0'],
    ] + TREX_VM_INIT + [
       ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[trex_p1][1]', 'actions': ['output:#STEP[trex_p2][1]'], 'idle_timeout': '0'}],
       ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[trex_p2][1]', 'actions': ['output:#STEP[trex_p1][1]'], 'idle_timeout': '0'}],
       ['trafficgen', 'send_traffic', {}],
       ['trafficgen', 'get_results'],
       # cleanup
    ] + TREX_VM_FINIT

# Configure VM2VM test, where traffic from T-Rex VM is forwarded to 2nd VM with loopback app.
TREX_VM2VM_TEST = [
       ['vswitch', 'add_switch', 'int_br0'],
       ['#vm_p1', 'vswitch', 'add_vport', 'int_br0'],
       ['#vm_p2', 'vswitch', 'add_vport', 'int_br0'],
       ['vnf', 'start'],
    ] + TREX_VM_INIT + [
       ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[trex_p1][1]', 'actions': ['output:#STEP[vm_p1][1]'], 'idle_timeout': '0'}],
       ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[vm_p1][1]', 'actions': ['output:#STEP[trex_p1][1]'], 'idle_timeout': '0'}],
       ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[trex_p2][1]', 'actions': ['output:#STEP[vm_p2][1]'], 'idle_timeout': '0'}],
       ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[vm_p2][1]', 'actions': ['output:#STEP[trex_p2][1]'], 'idle_timeout': '0'}],
       ['trafficgen', 'send_traffic', {}],
       ['trafficgen', 'get_results'],
       ['vnf', 'stop'],
       ['vswitch', 'dump_flows', 'int_br0'],
       # cleanup
    ] + TREX_VM_FINIT

#
# A set of tests with T-Rex VM as a traffic generator.
#
INTEGRATION_TESTS = INTEGRATION_TESTS + [
    {
        "Name": "trex_vm_cont",
        "Deployment": "clean",
        "Description": "T-Rex VM - execute RFC2544 Continuous Stream from T-Rex VM and loop it back through Open vSwitch.",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
            },
            'GUEST_LOOPBACK' : ['clean',],
            'GUEST_NICS_NR' : [4],
            'GUEST_SMP' : ['sockets=1,cores=3'],
            'GUEST_CORE_BINDING' : [['6', '7', '8'],],
            'TRAFFICGEN' : 'Trex',
            'TRAFFICGEN_TREX_HOST_IP_ADDR' : _TREX_SERVER_IP,
            'TRAFFICGEN_TREX_BASE_DIR' : '/root/trex/scripts/',
            'TRAFFICGEN_TREX_USER' : 'root',
        },
        "TestSteps": TREX_VM_TEST
    },
    {
        "Name": "trex_vm_tput",
        "Deployment": "clean",
        "Description": "T-Rex VM - execute RFC2544 Throughput from T-Rex VM and loop it back through Open vSwitch.",
        "Parameters" : {
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_throughput",
            },
            'GUEST_LOOPBACK' : ['clean',],
            'GUEST_NICS_NR' : [4],
            'GUEST_SMP' : ['sockets=1,cores=3'],
            'GUEST_CORE_BINDING' : [['6', '7', '8'],],
            'TRAFFICGEN' : 'Trex',
            'TRAFFICGEN_TREX_HOST_IP_ADDR' : _TREX_SERVER_IP,
            'TRAFFICGEN_TREX_BASE_DIR' : '/root/trex/scripts/',
            'TRAFFICGEN_TREX_USER' : 'root',
        },
        "TestSteps": TREX_VM_TEST
    },
    {
        "Name": "trex_vm2vm_cont",
        "Deployment": "clean",
        "Description": "T-Rex VM2VM - execute RFC2544 Continuous Stream from T-Rex VM and loop it back through 2nd VM.",
        "Parameters" : {
            'GUEST_LOOPBACK' : ['testpmd', 'clean'],
            'GUEST_NICS_NR' : [2, 4],
            'GUEST_SMP' : ['sockets=1,cores=2', 'sockets=1,cores=3'],
            'GUEST_CORE_BINDING' : [['9', '10'],['6', '7', '8'],],
            'TRAFFICGEN' : 'Trex',
            'TRAFFICGEN_TREX_HOST_IP_ADDR' : _TREX_SERVER_IP,
            'TRAFFICGEN_TREX_BASE_DIR' : '/root/trex/scripts/',
            'TRAFFICGEN_TREX_USER' : 'root',
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_continuous",
            },
        },
        "TestSteps": TREX_VM2VM_TEST,
    },
    {
        "Name": "trex_vm2vm_tput",
        "Deployment": "clean",
        "Description": "T-Rex VM2VM - execute RFC2544 Throughput from T-Rex VM and loop it back through 2nd VM.",
        "Parameters" : {
            'GUEST_LOOPBACK' : ['testpmd', 'clean'],
            'GUEST_NICS_NR' : [2, 4],
            'GUEST_SMP' : ['sockets=1,cores=2', 'sockets=1,cores=3'],
            'GUEST_CORE_BINDING' : [['9', '10'],['6', '7', '8'],],
            'TRAFFICGEN' : 'Trex',
            'TRAFFICGEN_TREX_HOST_IP_ADDR' : _TREX_SERVER_IP,
            'TRAFFICGEN_TREX_BASE_DIR' : '/root/trex/scripts/',
            'TRAFFICGEN_TREX_USER' : 'root',
            "TRAFFIC" : {
                "traffic_type" : "rfc2544_throughput",
            },
        },
        "TestSteps": TREX_VM2VM_TEST,
    },
]