Improved image building & new PROX 44/67544/1
authorLuc Provoost <luc.provoost@intel.com>
Fri, 12 Apr 2019 09:20:58 +0000 (11:20 +0200)
committerLuc Provoost <luc.provoost@intel.com>
Fri, 12 Apr 2019 09:20:58 +0000 (11:20 +0200)
Bug fixes for the script for building an image via the packer tool. This
also installs a newer version of PROX with some bug fixes in PROX. The
*.test files have been simplified. Also introduced a new file
MachineMap.cfg to map test machines on actual VMs.

Change-Id: I69445327ef0a907bc8c1566aaa60c733418c541e
Signed-off-by: Luc Provoost <luc.provoost@intel.com>
25 files changed:
VNFs/DPPD-PROX/helper-scripts/openstackrapid/MachineMap.cfg [moved from VNFs/DPPD-PROX/helper-scripts/openstackrapid/deploycentos1.sh with 57% similarity]
VNFs/DPPD-PROX/helper-scripts/openstackrapid/README
VNFs/DPPD-PROX/helper-scripts/openstackrapid/basicrapid.test
VNFs/DPPD-PROX/helper-scripts/openstackrapid/centos.json
VNFs/DPPD-PROX/helper-scripts/openstackrapid/createrapid.py
VNFs/DPPD-PROX/helper-scripts/openstackrapid/deploycentos.sh [new file with mode: 0644]
VNFs/DPPD-PROX/helper-scripts/openstackrapid/deploycentos2.sh [deleted file]
VNFs/DPPD-PROX/helper-scripts/openstackrapid/gen.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/gen_gw.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/impair.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/impair.test
VNFs/DPPD-PROX/helper-scripts/openstackrapid/irq.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/irq.test
VNFs/DPPD-PROX/helper-scripts/openstackrapid/l2framerate.test
VNFs/DPPD-PROX/helper-scripts/openstackrapid/l2gen.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/l2swap.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/l2zeroloss.test
VNFs/DPPD-PROX/helper-scripts/openstackrapid/l3framerate.test [new file with mode: 0644]
VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_ctrl.py
VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapidVMs.vms
VNFs/DPPD-PROX/helper-scripts/openstackrapid/runrapid.py
VNFs/DPPD-PROX/helper-scripts/openstackrapid/secgw.test
VNFs/DPPD-PROX/helper-scripts/openstackrapid/secgw1.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/secgw2.cfg
VNFs/DPPD-PROX/helper-scripts/openstackrapid/swap.cfg

@@ -1,5 +1,3 @@
-#!/bin/bash
-
 ##
 ## Copyright (c) 2010-2018 Intel Corporation
 ##
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 ##
-sudo yum install deltarpm -y
-sudo yum update -y
-sudo yum-config-manager --add-repo http://www.nasm.us/nasm.repo
-sudo yum install git wget gcc unzip libpcap-devel ncurses-devel libedit-devel lua-devel kernel-devel iperf3 pciutils numactl-devel vim tuna openssl-devel nasm -y
-# Enabling root ssh access
-sudo sed -i '/disable_root: 1/c\disable_root: 0' /etc/cloud/cloud.cfg
-# Reboot, before continuing with deploycentos2.sh
-sudo reboot
+## This file contains the mapping for each test machine. The test machine will 
+## be deployed on a machine defined in the *.env file, as defined by the
+## machine_index
+
+[DEFAULT]
+machine_index=0
+
+[TestM1]
+machine_index=1
+
+[TestM2]
+machine_index=2
+
+[TestM3]
+machine_index=3
index 0dea656..43243a6 100644 (file)
@@ -21,19 +21,18 @@ rapid is a set of files offering an easy way to do a sanity check of the
 dataplane performance of an OpenStack environment.
 
 Copy the files in a directory on a machine that can run the OpenStack CLI
-commands and that can reach the OpenStack public network.
+commands and that can reach the OpenStack networks to connect to the VMs.
 
 You will need an image that has the PROX tool installed.
-The best way to do this is to use the packer tool to build an image for a target of your choice.
-You can also build this image manually by executing all the commands described in the deploycentos1.sh
-and deploycentos2.sh file.
-The default name of the qcow2 file should is rapidVM.qcow2
+A good way to do this is to use the packer tool to build an image for a target of your choice.
+You can also build this image manually by executing all the commands described in the deploycentos.sh.
+The default name of the qcow2 file is rapidVM.qcow2
 
 When using the packer tool, the first step is to upload an
-existing CentOs cloud image from the internet into OpenStack.
+existing CentOS cloud image from the internet into OpenStack.
 Check out: https://cloud.centos.org/centos/7/images/
 You should now source the proper .rc file so Packer can connect to your OpenStack.
-There are 3 files: centos.json, deploycentos1.sh and deploycentos2.sh, allowing you to create
+There are 2 files: centos.json and deploycentos.sh, allowing you to create
 an image automatically. Run
   # packer build centos.json
 Edit centos.json to reflect the settings of your environment: The following fields need to
@@ -47,7 +46,7 @@ be the ID's of your system:
   - "security_groups": ID of the security group being used
 
 Note that this procedure is not only installing the necessary tools to run PROX,
-but also does some system optimizations (tuned).
+but also does some system optimizations (tuned). Check deploycentos.sh for more details.
 
 Now you can run the createrapid.py file. Use help for more info on the usage:
   # ./createrapid.py --help
@@ -58,12 +57,11 @@ It will create a <STACK>.env file containing all info that will be used by runra
 to actually run the tests. Logging can be found in the CREATE<STACK>.log file
 You can use floating IP addresses by specifying the floating IP network
 --floating_network NETWORK
-or directly connect throught the INTERNAL_NETWORK by using the following parameter:
+or directly connect through the INTERNAL_NETWORK by using the following parameter:
 --floating_network NO
 /etc/resolv.conf will contain DNS info from the "best" interface. Since we are
 deploying VMs with multiple interface on different networks, this info might be
-taken from the "wrong" network (e.g. the dataplane network). It is good to provide
-also a working DNS on that network.
+taken from the "wrong" network (e.g. the dataplane network).
 
 Now you can run the runrapid.py file. Use help for more info on the usage:
   # ./runrapid.py --help
@@ -71,6 +69,7 @@ The script will connect to all machines that have been instantiated and it will
 PROX in all machines. This will be done through the admin IP assigned to the machines.
 Once that is done it will connect to the PROX tcp socket and start sending
 commands to run the actual test.
+Make sure the security groups allow for tcp access (ssh & prox port).
 It will print test results on the screen while running.
 The actual test that is running is described in <TEST>.test.
 
@@ -114,35 +113,37 @@ achieved using createrapid.py. Fields needed for runrapid are:
 admin_ip = none
 
 [M1]
-admin_ip = 192.168.4.130
-dp_ip = 10.10.10.6
-dp_mac = fa:16:3e:3c:1e:12
+name = rapid-VM1
+admin_ip = 10.25.1.116
+dp_ip = 10.10.10.7
+dp_mac = fa:16:3e:59:b8:28
 
 [M2]
-admin_ip = 192.168.4.140
-dp_ip = 10.10.10.9
-dp_mac = fa:16:3e:2a:00:5d
+name = rapid-VM2
+admin_ip = 10.25.1.126
+dp_ip = 10.10.10.11
+dp_mac = fa:16:3e:c9:54:c7
 
 [M3]
-admin_ip = 192.168.4.138
-dp_ip = 10.10.10.11
-dp_mac = fa:16:3e:ae:fa:86
+name = rapid-VM3
+admin_ip = 10.25.1.108
+dp_ip = 10.10.10.15
+dp_mac = fa:16:3e:72:90:3e
 
 [OpenStack]
 stack = rapid
-yaml = 3VMrapid.yaml
+vms = rapidVMs
 key = prox
-flavor = prox_flavor
 image = rapidVM
 image_file = rapidVM.qcow2
 dataplane_network = dataplane-network
 subnet = dpdk-subnet
 subnet_cidr = 10.10.10.0/24
 internal_network = admin_internal_net
-floating_network = admin_floating_net
+floating_network = floating-ip-net
 
 [rapid]
 loglevel = DEBUG
-version = 17.10.25
-total_number_of_vms = 3
+version = 19.4.15
+total_number_of_machines = 3
 
index 8d73711..b2f8f23 100644 (file)
 
 [DEFAULT]
 name = BasicSwapTesting
-number_of_tests = 3
+number_of_tests = 4
 total_number_of_test_machines = 2
-init_code=init_test()
-dest_vm = not_used
-gw_vm = not_used
-script_control = false
-group1cores = not_used
-group2cores = not_used
-group3cores = not_used
-drop_rate_treshold = 0.1
-lat_avg_treshold = 200
-lat_max_treshold = 1000
-accuracy = 0.1
-startspeed = 10
-
+prox_socket = true
+prox_launch_exit = true
 
 [TestM1]
 name = Generator
-machine_index = 1
 config_file = gen.cfg
 dest_vm = 2
-script_control = true
-group1cores = [1]
-group2cores = [3]
-group3cores = [1,3]
+gencores = [1]
+latcores = [3]
+startspeed = 10
 
 [TestM2]
 name = Swap
-machine_index = 2
 config_file = swap.cfg
-group1cores = [1]
+swapcores = [1]
+
+[BinarySearchParams]
+drop_rate_threshold = 0.1
+lat_avg_threshold = 500
+lat_max_threshold = 1000
+accuracy = 0.1
 
 [test1]
-cmd=run_speedtest(socks[0],socks[1])
+test=inittest
+
 [test2]
-cmd=run_sizetest(socks[0],socks[1])
+test=speedtest
+packetsize=64
+
 [test3]
-cmd=run_flowtest(socks[0],socks[1])
+test=sizetest
+flow=1
+packetsizes=[64,256,1024]
+
+[test4]
+test=flowtest
+packetsize=64
+# the number of flows in the list need to be powers of 2, max 2^20
+# Select from following numbers: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65535, 131072, 262144, 524280, 1048576
+flows=[1,512,1024]
index 1676f2f..237a648 100644 (file)
@@ -5,13 +5,13 @@
    {
 "type": "openstack",
 "ssh_username": "centos",
-"image_name": "PROXffc6be26-DPDK1808VM",
-"source_image": "aa0f8333-d8e1-42db-8210-6b39d9ee7267",
-"flavor": "7aaec028-eccc-4612-8f9b-29a1e039943a",
-"networks": "97bbe96f-ee1b-4789-ace8-e922f76bea3f",
+"image_name": "rapidVM",
+"source_image": "06101dd4-f162-49c0-a072-2fe32ac446a9",
+"flavor": "3ea20ea9-855c-4a6e-b454-63ad6e8e0db9",
+"networks": "451a030a-eb1e-4c74-85b8-782ef8a6ad38",
 "use_floating_ip": true,
-"floating_ip_pool": "1f564356-8c23-41e2-8292-7696ffd98adf",
-"security_groups": "8fd498fc-5bd8-4be6-94e4-a2cc3b02d151"
+"floating_ip_pool": "d629619f-8f96-4f32-9b90-1b62e5ea3809",
+"security_groups": "460b7929-c6de-4b1c-ae83-901c2042a894"
    }
 ],
 "provisioners": [
    },
    {
    "type": "shell",
-   "script": "deploycentos1.sh",
-   "expect_disconnect": true
-   },
-   {
-   "type": "shell",
-   "script": "deploycentos2.sh",
-   "pause_before": "20s"
+   "script": "deploycentos.sh"
    }
 ]
 }
index 06e2f23..a1c1de6 100755 (executable)
@@ -31,7 +31,7 @@ from logging import handlers
 from prox_ctrl import prox_ctrl
 import ConfigParser
 
-version="19.1.10"
+version="19.4.15"
 stack = "rapid" #Default string for stack. This is not an OpenStack Heat stack, just a group of VMs
 vms = "rapidVMs" #Default string for vms file
 key = "prox" # default name for kay
@@ -56,7 +56,7 @@ def usage():
        print("                   [--subnet DP_SUBNET]")
        print("                   [--subnet_cidr SUBNET_CIDR]")
        print("                   [--internal_network ADMIN_NETWORK]")
-       print("                   [--floating_network ADMIN_NETWORK]")
+       print("                   [--floating_network FLOATING_NETWORK]")
        print("                   [--log DEBUG|INFO|WARNING|ERROR|CRITICAL]")
        print("                   [-h] [--help]")
        print("")
@@ -363,21 +363,23 @@ for vm in range(1, int(total_number_of_VMs)+1):
 if floating_network <> 'NO':
        for vm in range(0, int(total_number_of_VMs)):
                if ServerToBeCreated[vm] =="yes":
-                       log.info('Creating floating IP ...')
-                       cmd = 'openstack floating ip create  ' + floating_network
-                       log.debug(cmd)
-                       cmd = cmd + ' |grep "floating_ip_address " | tr -s " " | cut -d"|" -f 3'
-                       vmAdminIP = subprocess.check_output(cmd , shell=True).strip()
-                       log.info('Associating floating IP ...')
-                       cmd = 'openstack server add floating ip %s %s'%(ServerName[vm],vmAdminIP)
-                       log.debug(cmd)
-                       output = subprocess.check_output(cmd , shell=True).strip()
+                        log.info('Creating & Associating floating IP for ('+ServerName[vm]+')...')
+                        cmd = 'openstack server show %s -c addresses -f value |grep -Eo "%s=[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | cut -d"=" -f2'%(ServerName[vm],internal_network)
+                        log.debug(cmd)
+                        vmportIP = subprocess.check_output(cmd , shell=True).strip()
+                        cmd = 'openstack port list -c ID -c "Fixed IP Addresses" | grep %s' %(vmportIP)
+                        cmd = cmd + ' | cut -d" " -f 2 '
+                        log.debug(cmd)
+                        vmportID = subprocess.check_output(cmd , shell=True).strip()
+                        cmd = 'openstack floating ip create --port %s %s'%(vmportID,floating_network)
+                        log.debug(cmd)
+                        output = subprocess.check_output(cmd , shell=True).strip()
                
 for vm in range(1, int(total_number_of_VMs)+1):
        cmd = 'openstack server show %s'%(ServerName[vm-1])
        log.debug(cmd)
        output = subprocess.check_output(cmd , shell=True).strip()
-        searchString = '.*%s.*?([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' %(dataplane_network)
+        searchString = '.*%s=([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' %(dataplane_network)
         matchObj = re.search(searchString, output, re.DOTALL)
        vmDPIP = matchObj.group(1)
         searchString = '.*%s=([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+),*\s*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)*' %(internal_network)
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/deploycentos.sh b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/deploycentos.sh
new file mode 100644 (file)
index 0000000..848520c
--- /dev/null
@@ -0,0 +1,139 @@
+#!/usr/bin/env bash
+##
+## Copyright (c) 2010-2019 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.
+##
+
+BUILD_DIR="/opt/openstackrapid"
+COPY_DIR="/home/centos" # Directory where the packer tool has copied some files
+DPDK_VERSION="18.08"
+PROX_COMMIT="af95b812"
+export RTE_SDK="${BUILD_DIR}/dpdk-${DPDK_VERSION}"
+export RTE_TARGET="x86_64-native-linuxapp-gcc"
+
+function os_pkgs_install()
+{
+       # NASM repository for AESNI MB library
+       sudo yum-config-manager --add-repo http://www.nasm.us/nasm.repo
+
+       sudo yum install -y deltarpm
+       sudo yum update -y
+       sudo yum install -y git wget gcc unzip libpcap-devel ncurses-devel \
+                        libedit-devel lua-devel kernel-devel iperf3 pciutils \
+                        numactl-devel vim tuna openssl-devel nasm
+}
+
+function os_cfg()
+{
+       # Enabling root ssh access
+       sudo sed -i '/disable_root: 1/c\disable_root: 0' /etc/cloud/cloud.cfg
+
+       # Mounting huge pages to be used by DPDK, mounting already done by CentOS
+       # sudo mkdir -p /mnt/huge
+       # sudo umount `awk '/hugetlbfs/ { print $2 }' /proc/mounts` >/dev/null 2>&1
+       # sudo mount -t hugetlbfs nodev /mnt/huge/
+       sudo sh -c '(echo "vm.nr_hugepages = 1024") > /etc/sysctl.conf'
+
+       # Enabling tuned with the realtime-virtual-guest profile
+       pushd ${BUILD_DIR} > /dev/null 2>&1
+       wget http://linuxsoft.cern.ch/cern/centos/7/rt/x86_64/Packages/tuned-profiles-realtime-2.8.0-5.el7_4.2.noarch.rpm
+       wget http://linuxsoft.cern.ch/cern/centos/7/rt/x86_64/Packages/tuned-profiles-nfv-guest-2.8.0-5.el7_4.2.noarch.rpm
+       # Install with --nodeps. The latest CentOS cloud images come with a tuned version higher than 2.8. These 2 packages however
+       # do not depend on v2.8 and also work with tuned 2.9. Need to be careful in the future
+       sudo rpm -ivh ${BUILD_DIR}/tuned-profiles-realtime-2.8.0-5.el7_4.2.noarch.rpm --nodeps
+       sudo rpm -ivh ${BUILD_DIR}/tuned-profiles-nfv-guest-2.8.0-5.el7_4.2.noarch.rpm --nodeps
+       # Although we do no know how many cores the VM will have when begin deployed for real testing, we already put a number for the
+       # isolated CPUs so we can start the realtime-virtual-guest profile. If we don't, that command will fail.
+       # When the VM will be instantiated, the check_kernel_params service will check for the real number of cores available to this VM 
+       # and update the realtime-virtual-guest-variables.conf accordingly.
+       echo "isolated_cores=1" | sudo tee -a /etc/tuned/realtime-virtual-guest-variables.conf
+       sudo tuned-adm profile realtime-virtual-guest
+
+       # Install the check_tuned_params service to make sure that the grub cmd line has the right cpus in isolcpu. The actual number of cpu's
+       # assigned to this VM depends on the flavor used. We don't know at this time what that will be.
+       sudo chmod +x ${COPY_DIR}/check_prox_system_setup.sh
+       sudo cp -r ${COPY_DIR}/check_prox_system_setup.sh /usr/local/libexec/
+       sudo cp -r ${COPY_DIR}/check-prox-system-setup.service /etc/systemd/system/
+       sudo systemctl daemon-reload
+       sudo systemctl enable check-prox-system-setup.service
+
+       popd > /dev/null 2>&1
+}
+
+function mblib_install()
+{
+       export AESNI_MULTI_BUFFER_LIB_PATH="${BUILD_DIR}/intel-ipsec-mb-0.50"
+
+       # Downloading the Multi-buffer library. Note that the version to download is linked to the DPDK version being used
+       pushd ${BUILD_DIR} > /dev/null 2>&1
+       wget https://github.com/01org/intel-ipsec-mb/archive/v0.50.zip
+       unzip v0.50.zip
+       pushd ${AESNI_MULTI_BUFFER_LIB_PATH}
+       make -j`getconf _NPROCESSORS_ONLN`
+       sudo make install
+       popd > /dev/null 2>&1
+       popd > /dev/null 2>&1
+}
+
+function dpdk_install()
+{
+       # Build DPDK for the latest kernel installed
+       LATEST_KERNEL_INSTALLED=`ls -v1 /lib/modules/ | tail -1`
+       export RTE_KERNELDIR="/lib/modules/${LATEST_KERNEL_INSTALLED}/build"
+
+       # Get and compile DPDK
+       pushd ${BUILD_DIR} > /dev/null 2>&1
+       wget http://fast.dpdk.org/rel/dpdk-${DPDK_VERSION}.tar.xz
+       tar -xf ./dpdk-${DPDK_VERSION}.tar.xz
+       popd > /dev/null 2>&1
+
+       # Runtime scripts are assuming /root as the directory for PROX
+       sudo ln -s ${RTE_SDK} /root/dpdk
+
+       pushd ${RTE_SDK} > /dev/null 2>&1
+       make config T=${RTE_TARGET}
+       # The next sed lines make sure that we can compile DPDK 17.11 with a relatively new OS. Using a newer DPDK (18.5) should also resolve this issue
+       #sudo sed -i '/CONFIG_RTE_LIBRTE_KNI=y/c\CONFIG_RTE_LIBRTE_KNI=n' ${RTE_SDK}/build/.config
+       #sudo sed -i '/CONFIG_RTE_LIBRTE_PMD_KNI=y/c\CONFIG_RTE_LIBRTE_PMD_KNI=n' ${RTE_SDK}/build/.config
+       #sudo sed -i '/CONFIG_RTE_KNI_KMOD=y/c\CONFIG_RTE_KNI_KMOD=n' ${RTE_SDK}/build/.config
+       #sudo sed -i '/CONFIG_RTE_KNI_PREEMPT_DEFAULT=y/c\CONFIG_RTE_KNI_PREEMPT_DEFAULT=n' ${RTE_SDK}/build/.config
+       # Compile with MB library
+       sed -i '/CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n/c\CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y' ${RTE_SDK}/build/.config
+       make -j`getconf _NPROCESSORS_ONLN`
+       ln -s ${RTE_SDK}/build ${RTE_SDK}/${RTE_TARGET}
+       popd > /dev/null 2>&1
+}
+
+function prox_install()
+{
+       # Clone and compile PROX
+       pushd ${BUILD_DIR} > /dev/null 2>&1
+       git clone https://git.opnfv.org/samplevnf
+       pushd ${BUILD_DIR}/samplevnf/VNFs/DPPD-PROX
+#      git checkout ffc6be26
+       git checkout ${PROX_COMMIT}
+       make -j`getconf _NPROCESSORS_ONLN`
+       sudo ln -s ${BUILD_DIR}/samplevnf/VNFs/DPPD-PROX /root/prox
+       popd > /dev/null 2>&1
+       popd > /dev/null 2>&1
+}
+
+[ ! -d ${BUILD_DIR} ] && sudo mkdir -p ${BUILD_DIR}
+sudo chmod 0777 ${BUILD_DIR}
+
+os_pkgs_install
+os_cfg
+mblib_install
+dpdk_install
+prox_install
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/deploycentos2.sh b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/deploycentos2.sh
deleted file mode 100644 (file)
index 9a3157f..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/bash
-
-##
-## Copyright (c) 2010-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.
-##
-# The following line is commented since this was a workaround for a problem with the content of /etc/resolv.conf.
-# That file could contain DNS information coming from the dataplane which might be wrong. A solution is to confire the correct DNS for the dataplne
-# in OpenStack.  DNS might be slowing down ssh access. We don't need that for our dataplane benchmarking purposes
-# sudo sed -i '/#UseDNS yes/c\UseDNS no' /etc/ssh/sshd_config
-sudo sh -c '(echo "export RTE_TARGET=\"build\"";echo "export RTE_SDK=\"/root/dpdk\"";echo "export AESNI_MULTI_BUFFER_LIB_PATH=\"/home/centos/intel-ipsec-mb-0.50\"";) >> /root/.bashrc'
-export RTE_TARGET=build
-export RTE_SDK=/home/centos/dpdk
-export AESNI_MULTI_BUFFER_LIB_PATH=/home/centos/intel-ipsec-mb-0.50
-# Mounting huge pages to be used by DPDK
-sudo mkdir -p /mnt/huge
-sudo umount `awk '/hugetlbfs/ { print $2 }' /proc/mounts` >/dev/null 2>&1
-sudo mount -t hugetlbfs nodev /mnt/huge/
-sudo sh -c '(echo "vm.nr_hugepages = 1024") > /etc/sysctl.conf'
-
-# Downloading the Multi-buffer library. Note that the version to download is linked to the DPDK version being used
-cd /home/centos
-wget https://github.com/01org/intel-ipsec-mb/archive/v0.50.zip
-unzip v0.50.zip
-cd $AESNI_MULTI_BUFFER_LIB_PATH
-make
-sudo make install
-# Clone and compile DPDK
-cd /home/centos/
-git clone http://dpdk.org/git/dpdk
-# Runtime scripts are assuming /root as the directory for PROX
-sudo ln -s /home/centos/dpdk /root/dpdk
-cd $RTE_SDK
-git checkout v18.08
-make config T=x86_64-native-linuxapp-gcc
-# The next sed lines make sure that we can compile DPDK 17.11 with a relatively new OS. Using a newer DPDK (18.5) should also resolve this issue
-#sudo sed -i '/CONFIG_RTE_LIBRTE_KNI=y/c\CONFIG_RTE_LIBRTE_KNI=n' /home/centos/dpdk/build/.config
-#sudo sed -i '/CONFIG_RTE_LIBRTE_PMD_KNI=y/c\CONFIG_RTE_LIBRTE_PMD_KNI=n' /home/centos/dpdk/build/.config
-#sudo sed -i '/CONFIG_RTE_KNI_KMOD=y/c\CONFIG_RTE_KNI_KMOD=n' /home/centos/dpdk/build/.config
-#sudo sed -i '/CONFIG_RTE_KNI_PREEMPT_DEFAULT=y/c\CONFIG_RTE_KNI_PREEMPT_DEFAULT=n' /home/centos/dpdk/build/.config
-# Compile with MB library
-sed -i '/CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n/c\CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y' /home/centos/dpdk/build/.config
-make 
-
-# Clone and compile PROX
-cd /home/centos
-git clone https://git.opnfv.org/samplevnf
-cd /home/centos/samplevnf/VNFs/DPPD-PROX
-git checkout ffc6be26
-make
-sudo ln -s /home/centos/samplevnf/VNFs/DPPD-PROX /root/prox
-
-# Enabling tuned with the realtime-virtual-guest profile
-cd /home/centos/
-wget http://linuxsoft.cern.ch/cern/centos/7/rt/x86_64/Packages/tuned-profiles-realtime-2.8.0-5.el7_4.2.noarch.rpm
-wget http://linuxsoft.cern.ch/cern/centos/7/rt/x86_64/Packages/tuned-profiles-nfv-guest-2.8.0-5.el7_4.2.noarch.rpm
-# Install with --nodeps. The latest CentOS cloud images come with a tuned version higher than 2.8. These 2 packages however
-# do not depend on v2.8 and also work with tuned 2.9. Need to be careful in the future
-sudo rpm -ivh /home/centos/tuned-profiles-realtime-2.8.0-5.el7_4.2.noarch.rpm --nodeps
-sudo rpm -ivh /home/centos/tuned-profiles-nfv-guest-2.8.0-5.el7_4.2.noarch.rpm --nodeps
-# Although we do no know how many cores the VM will have when begin deployed for real testing, we already put a number for the
-# isolated CPUs so we can start the realtime-virtual-guest profile. If we don't, that command will fail.
-# When the VM will be instantiated, the check_kernel_params service will check for the real number of cores available to this VM 
-# and update the realtime-virtual-guest-variables.conf accordingly.
-echo "isolated_cores=1" | sudo tee -a /etc/tuned/realtime-virtual-guest-variables.conf
-sudo tuned-adm profile realtime-virtual-guest
-
-# Install the check_tuned_params service to make sure that the grub cmd line has the right cpus in isolcpu. The actual number of cpu's
-# assigned to this VM depends on the flavor used. We don't know at this time what that will be.
-sudo cp -r /home/centos/check_prox_system_setup.sh /usr/local/libexec/
-sudo cp -r /home/centos/check-prox-system-setup.service /etc/systemd/system/
-sudo systemctl daemon-reload
-sudo systemctl enable check-prox-system-setup.service
index fd8eadb..42cfdc1 100644 (file)
@@ -31,7 +31,7 @@ vlan=yes
 $mbs=8
 
 [defaults]
-mempool size=4K
+mempool size=8K
 
 [global]
 name=${name}
@@ -39,7 +39,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $gencores]
 name=p0
 task=0
 mode=gen
@@ -58,8 +58,9 @@ accuracy pos=46
 packet id pos=50
 signature=0x6789abcd
 signature pos=56
+;arp update time=1
 
-[core $group2]
+[core $latcores]
 name=lat
 task=0
 mode=lat
@@ -70,4 +71,6 @@ accuracy pos=46
 packet id pos=50
 signature=0x6789abcd
 signature pos=56
+accuracy limit nsec=1000000
+;arp update time=1
 
index 4d5c707..e819041 100644 (file)
@@ -31,7 +31,7 @@ vlan=yes
 $mbs=8
 
 [defaults]
-mempool size=4K
+mempool size=8K
 
 [global]
 name=${name}
@@ -39,7 +39,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $gencores]
 name=p0
 task=0
 mode=gen
@@ -58,8 +58,9 @@ accuracy pos=46
 packet id pos=50
 signature=0x6789abcd
 signature pos=56
+;arp update time=1
 
-[core $group2]
+[core $latcores]
 name=lat
 task=0
 mode=lat
@@ -70,3 +71,4 @@ accuracy pos=46
 packet id pos=50
 signature=0x6789abcd
 signature pos=56
+;arp update time=1
index c41c479..8ca9e05 100644 (file)
@@ -30,7 +30,7 @@ vlan=yes
 
 
 [defaults]
-mempool size=4K
+mempool size=8K
 
 [global]
 name=${name}
@@ -38,7 +38,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $impaircores]
 name=impair
 task=0
 mode=impair
index ff6624b..9b633d9 100644 (file)
 
 [DEFAULT]
 name = impairTesting
-number_of_tests = 1
+number_of_tests = 2
 total_number_of_test_machines = 3
-init_code=init_test()
-dest_vm = not_used
-gw_vm = not_used
-script_control = false
-group1cores = not_used
-group2cores = not_used
-group3cores = not_used
-drop_rate_treshold = 1
-lat_avg_treshold = 1200
-lat_max_treshold = 2000
-accuracy = 0.01
-startspeed = 10
+prox_socket = true
+prox_launch_exit = true
 
 [TestM1]
 name = Generator
-machine_index = 1
 config_file = gen_gw.cfg
 gw_vm = 2
 dest_vm = 3
-group1cores = [1]
-group2cores = [3]
-group3cores = [1,3]
+gencores = [1]
+latcores = [3]
+startspeed = 10
 
 [TestM2]
 name = ImpairGW
-machine_index = 2
 config_file = impair.cfg
-group1cores = [1]
+impaircores = [1]
 
 [TestM3]
 name = Swap
-machine_index = 3
 config_file = swap.cfg
-group1cores = [1]
+swapcores = [1]
+
+[BinarySearchParams]
+drop_rate_threshold = 0.1
+lat_avg_threshold = 500
+lat_max_threshold = 1000
+accuracy = 0.1
 
 [test1]
-cmd=run_impairtest(socks[0],socks[2])
+test=inittest
+
+[test2]
+test=impairtest
+packetsize=64
index 304312f..38e4b96 100644 (file)
@@ -21,14 +21,14 @@ no-output=no ; disable DPDK debug output
 [lua]
 dofile("parameters.lua")
 
-[port 0]
+[;port 0]
 name=p0
 
 [variables]
 $mbs=8
 
 [defaults]
-mempool size=4K
+mempool size=8K
 
 [global]
 name=${name}
@@ -36,7 +36,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $irqcores]
 name=irq
 task=0
 mode=irq
index d5ba9df..b8dc706 100644 (file)
 
 [DEFAULT]
 name = BasicSwapTesting
-number_of_tests = 2
-total_number_of_test_machines = 2
-init_code= not_used
-dest_vm = not_used
-gw_vm = not_used
-script_control = false
-group1cores = not_used
-group2cores = not_used
-group3cores = not_used
-drop_rate_treshold = 1
-lat_avg_treshold = 200
-lat_max_treshold = 1000
-accuracy = 0.01
-startspeed = 10
+number_of_tests = 1
+total_number_of_test_machines = 1
+prox_socket = true
+prox_launch_exit = true
 
 [TestM1]
 name = InterruptTesting
-machine_index = 1
 config_file = irq.cfg
-group1cores = [1,2,3]
-
-[TestM2]
-name = InterruptTesting
-machine_index = 2
-config_file = irq.cfg
-group1cores = [1,2,3]
+irqcores = [1,2,3]
 
 
 [test1]
-cmd=run_irqtest(socks[0])
-[test2]
-cmd=run_irqtest(socks[1])
+test=irqtest
 
index 68a3fa3..44fefdd 100644 (file)
 
 [DEFAULT]
 name = L2BasicSwapTesting
-number_of_tests = 1
+number_of_tests = 2
 total_number_of_test_machines = 2
-init_code=init_test()
-dest_vm = not_used
-gw_vm = not_used
-script_control = false
-group1cores = not_used
-group2cores = not_used
-group3cores = not_used
-drop_rate_treshold = 0
-lat_avg_treshold = 100
-lat_max_treshold = 800
-accuracy = 0.1
-startspeed = 100
+prox_socket = true
+prox_launch_exit = true
 
 [TestM1]
 name = Generator
-machine_index = 1
 config_file = l2gen.cfg
 dest_vm = 2
-script_control = true
-group1cores = [1,2,3,4]
-group2cores = [5]
-group3cores = [1,2,3,4,5]
+gencores = [1]
+latcores = [3]
+startspeed = 10
 
 [TestM2]
 name = Swap
-machine_index = 2
 config_file = l2swap.cfg
-group1cores = [2]
+swapcores = [1]
 
 [test1]
-cmd=run_max_frame_rate(socks[0],socks[1])
+test=inittest
+
+[test2]
+test=max_frame_rate
+packetsizes=[256]
index f055c6a..1469604 100644 (file)
@@ -31,7 +31,7 @@ vlan=yes
 $mbs=8
 
 [defaults]
-mempool size=4K
+mempool size=8K
 
 [global]
 name=${name}
@@ -39,7 +39,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $gencores]
 name=p0
 task=0
 mode=gen
@@ -58,7 +58,7 @@ packet id pos=50
 signature=0x6789abcd
 signature pos=56
 
-[core $group2]
+[core $latcores]
 name=lat
 task=0
 mode=lat
index 98246ab..004588c 100644 (file)
@@ -29,7 +29,7 @@ tx desc=2048
 vlan=yes
 
 [defaults]
-mempool size=4K
+mempool size=8K
 
 [global]
 name=${name}
@@ -37,7 +37,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $swapcores]
 name=swap
 task=0
 mode=swap
index 9049877..0406590 100644 (file)
 
 [DEFAULT]
 name = L2BasicSwapTesting
-number_of_tests = 3
+number_of_tests = 4
 total_number_of_test_machines = 2
-init_code=init_test()
-dest_vm = not_used
-gw_vm = not_used
-script_control = false
-group1cores = not_used
-group2cores = not_used
-group3cores = not_used
-drop_rate_treshold = 0
-lat_avg_treshold = 200
-lat_max_treshold = 1000
-accuracy = 0.1
-startspeed = 10
+prox_socket = true
+prox_launch_exit = true
 
 [TestM1]
 name = Generator
-machine_index = 1
 config_file = l2gen.cfg
 dest_vm = 2
-script_control = true
-group1cores = [1]
-group2cores = [3]
-group3cores = [1,3]
+gencores = [1]
+latcores = [3]
+startspeed = 10
 
 [TestM2]
 name = Swap
-machine_index = 2
 config_file = l2swap.cfg
-group1cores = [1]
+swapcores = [1]
+
+[BinarySearchParams]
+drop_rate_threshold = 0
+lat_avg_threshold = 500
+lat_max_threshold = 1000
+accuracy = 0.1
+
 
 [test1]
-cmd=run_speedtest(socks[0],socks[1])
+test=inittest
+
 [test2]
-cmd=run_sizetest(socks[0],socks[1])
+test=speedtest
+packetsize=64
+
 [test3]
-cmd=run_flowtest(socks[0],socks[1])
+test=sizetest
+
+[test4]
+test=flowtest
+packetsize=64
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/l3framerate.test b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/l3framerate.test
new file mode 100644 (file)
index 0000000..21bf810
--- /dev/null
@@ -0,0 +1,42 @@
+##
+## Copyright (c) 2010-2019 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.
+##
+
+[DEFAULT]
+name = L3FrameRateTesting
+number_of_tests = 2
+total_number_of_test_machines = 2
+prox_socket = true
+prox_launch_exit = true
+
+[TestM1]
+name = Generator
+config_file = gen.cfg
+dest_vm = 2
+gencores = [1]
+latcores = [3]
+startspeed = 10
+
+[TestM2]
+name = Swap
+config_file = swap.cfg
+swapcores = [1]
+
+[test1]
+test=inittest
+
+[test2]
+test=max_frame_rate
+packetsizes=[256]
index 7039509..3ee28c0 100644 (file)
@@ -40,8 +40,8 @@ class prox_ctrl(object):
 
     def close(self):
         """Must be called before program termination."""
-        for prox in self._proxsock:
-            prox.quit()
+#        for prox in self._proxsock:
+#            prox.quit()
         children = len(self._children)
         if children == 0:
             return
@@ -193,7 +193,11 @@ class prox_sock(object):
             max_lat = max(int(stats[1]),max_lat)
             avg_lat += int(stats[2])
         avg_lat = avg_lat/len(cores)
-        return min_lat, max_lat, avg_lat
+        self._send('stats latency(0).used')
+        used = float(self._recv())
+        self._send('stats latency(0).total')
+        total = float(self._recv())
+        return min_lat, max_lat, avg_lat, (used/total)
 
     def irq_stats(self, core, bucket, task=0):
         self._send('stats task.core(%s).task(%s).irq(%s)' % (core, task, bucket))
index dc22a9c..d18184d 100644 (file)
 
 [DEFAULT]
 total_number_of_vms=3
-flavor_info=--ram 4096 --disk 20 --vcpus 4
+flavor_info=--ram 4096 --disk 40 --vcpus 4
 ;flavor_meta_data=--property hw:mem_page_size=large --property hw:cpu_policy=dedicated --property hw:cpu_thread_policy=isolate --property hw:numa_nodes=1 --property hw:numa_cpus.0=0,1,2,3 --property hw:numa_mempolicy=strict --property hw:numa_mem.0=4096
 ;flavor_meta_data=--property hw:mem_page_size=large --property hw:cpu_policy=dedicated --property hw:cpu_thread_policy=isolate
-;flavor_meta_data=--property hw:mem_page_size=large --property hw:cpu_policy=dedicated
-flavor_meta_data=--property hw:mem_page_size=large --property hw:cpu_policy=dedicated --property hw:cpu_realtime=yes --property hw:cpu_realtime_mask=^0
+flavor_meta_data=--property hw:mem_page_size=large --property hw:cpu_policy=dedicated
+;flavor_meta_data=--property hw:mem_page_size=large --property hw:cpu_policy=dedicated --property hw:cpu_realtime=yes --property hw:cpu_realtime_mask=^0
 ;boot_info=--availability-zone nova --security-group default
-boot_info=--availability-zone L27 --security-group default
+boot_info=--availability-zone nova --security-group prox
 SRIOV_port=NO
 
 [VM1]
index e625c4d..3b0eeb8 100755 (executable)
@@ -34,9 +34,10 @@ import ast
 import atexit
 import csv
 
-version="19.1.10"
+version="19.4.15"
 env = "rapid" #Default string for environment
 test = "basicrapid" #Default string for test
+machine_map_file = "MachineMap" #Default string for machine map file
 loglevel="DEBUG" # sets log level for writing to file
 runtime=10 # time in seconds for 1 test run
 configonly = False # IF True, the system will upload all the necessary config fiels to the VMs, but not start PROX and the actual testing
@@ -45,6 +46,7 @@ def usage():
        print("usage: runrapid    [--version] [-v]")
        print("                   [--env ENVIRONMENT_NAME]")
        print("                   [--test TEST_NAME]")
+       print("                   [--map MACHINE_MAP_FILE]")
        print("                   [--runtime TIME_FOR_TEST]")
        print("                   [--configonly False|True]")
        print("                   [--log DEBUG|INFO|WARNING|ERROR|CRITICAL]")
@@ -56,6 +58,7 @@ def usage():
        print("  -v,  --version                 Show program's version number and exit")
        print("  --env ENVIRONMENT_NAME         Parameters will be read from ENVIRONMENT_NAME.env Default is %s."%env)
        print("  --test TEST_NAME               Test cases will be read from TEST_NAME.test Default is %s."%test)
+       print("  --map MACHINE_MAP_FILE Machine mapping will be read from MACHINE_MAP_FILE.cfg Default is %s."%machine_map_file)
        print("  --runtime                      Specify time in seconds for 1 test run")
        print("  --configonly                   If True, only upload all config files to the VMs, do not run the tests. Default is %s."%configonly)
        print("  --log                          Specify logging level for log file output, screen output level is hard coded")
@@ -63,7 +66,7 @@ def usage():
        print("")
 
 try:
-       opts, args = getopt.getopt(sys.argv[1:], "vh", ["version","help", "env=", "test=","runtime=","configonly=","log="])
+       opts, args = getopt.getopt(sys.argv[1:], "vh", ["version","help", "env=", "test=", "map=", "runtime=","configonly=","log="])
 except getopt.GetoptError as err:
        print("===========================================")
        print(str(err))
@@ -86,6 +89,9 @@ for opt, arg in opts:
        if opt in ("--test"):
                test = arg
                print ("Using '"+test+".test' for test case definition")
+       if opt in ("--map"):
+               machine_map_file = arg
+               print ("Using '"+machine_map_file+".cfg' for machine mapping")
        if opt in ("--runtime"):
                runtime = arg
                print ("Runtime: "+ runtime)
@@ -131,8 +137,7 @@ console_handler.setFormatter(screen_formatter)
 # create a file handler
 # and set its log level to DEBUG
 #
-log_file = 'RUN' +env+'.'+test+'.log'
-data_file = 'RUN' +env+'.'+test+'.csv'
+log_file = 'RUN{}.{}.log'.format(env,test)
 file_handler = logging.handlers.RotatingFileHandler(log_file, backupCount=10)
 #file_handler = log.handlers.TimedRotatingFileHandler(log_file, 'D', 1, 5)
 file_handler.setLevel(numeric_level)
@@ -203,8 +208,24 @@ def run_iteration(gensock,sutsock):
        if sutsock!='none':
                old_sut_rx, old_sut_tx, old_sut_drop, old_sut_tsc, sut_tsc_hz = sutsock.core_stats(sutstatcores)
        old_rx, old_tx, old_drop, old_tsc, tsc_hz = gensock.core_stats(genstatcores)
-       time.sleep(float(runtime))
-       lat_min, lat_max, lat_avg = gensock.lat_stats(latcores)
+       # Measure latency statistics per second
+        n_loops = 0
+        lat_min = 0
+        lat_max = 0
+        lat_avg = 0
+       used_avg = 0
+        while n_loops < float(runtime):
+                n_loops +=1
+                time.sleep(1)
+                lat_min_sample, lat_max_sample, lat_avg_sample, used_sample = gensock.lat_stats(latcores)
+                if lat_min > lat_min_sample:
+                        lat_min = lat_min_sample
+                if lat_max < lat_max_sample:
+                        lat_max = lat_max_sample
+                lat_avg = lat_avg + lat_avg_sample
+               used_avg = used_avg + used_sample
+        lat_avg = lat_avg / n_loops
+       used_avg = used_avg / n_loops
        # Get statistics after some execution time
        new_rx, new_tx, new_drop, new_tsc, tsc_hz = gensock.core_stats(genstatcores)
        if sutsock!='none':
@@ -233,21 +254,9 @@ def run_iteration(gensock,sutsock):
        if (tx == 0):
                log.critical("TX = 0. Test interrupted since no packet has been sent.")
                raise Exception("TX = 0")
-       return(pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max,abs_dropped,(abs_new_tx - abs_old_tx))
+       return(pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max,abs_dropped,(abs_new_tx - abs_old_tx),lat_min,used_avg)
 
 def new_speed(speed,minspeed,maxspeed,success):
-       # Following calculates the ratio for the new speed to be applied
-       # On the Y axis, we will find the ratio, a number between 0 and 1
-       # On the x axis, we find the % of dropped packets, a number between 0 and 100
-       # 2 lines are drawn and we take the minumun of these lines to calculate the ratio
-       # One line goes through (0,y0) and (p,q)
-       # The second line goes through (p,q) and (100,y100)
-#      y0=0.99
-#      y100=0.1
-#      p=1
-#      q=.99
-#      ratio = min((q-y0)/p*drop_rate+y0,(q-y100)/(p-100)*drop_rate+q-p*(q-y100)/(p-100))
-#      return (int(speed*ratio*100)+0.5)/100.0
        if success:
                minspeed = speed
        else:
@@ -261,7 +270,7 @@ def get_pps(speed,size):
 def run_speedtest(gensock,sutsock):
        maxspeed = speed = STARTSPEED
        minspeed = 0
-       size=175
+       size=PACKETSIZE-4
        attempts = 0
         log.info("+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+")
         log.info("| Generator is sending UDP (1 flow) packets ("+ '{:>5}'.format(size+4) +" bytes) to SUT. SUT sends packets back                                                                                       |")
@@ -273,18 +282,23 @@ def run_speedtest(gensock,sutsock):
        gensock.set_value(gencores,0,16,(size-14),2) # 18 is the difference between the frame size and IP size = size of (MAC addresses, ethertype and FCS)
        gensock.set_value(gencores,0,38,(size-34),2) # 38 is the difference between the frame size and UDP size = 18 + size of IP header (=20)
        # This will only work when using sending UDP packets. For different protocols and ethernet types, we would need a different calculation
+       gensock.start(latcores)
         while (maxspeed-minspeed > ACCURACY):
                 attempts += 1
                 print('Measurement ongoing at speed: ' + str(round(speed,2)) + '%      ',end='\r')
                 sys.stdout.flush()
                 # Start generating packets at requested speed (in % of a 10Gb/s link)
-                gensock.speed(speed, gencores)
+               gensock.speed(speed / len(gencores), gencores)
                 time.sleep(1)
                 # Get statistics now that the generation is stable and initial ARP messages are dealt with.
-               pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
+               pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx, lat_min, lat_used = run_iteration(gensock,sutsock)
                drop_rate = 100.0*abs_dropped/abs_tx
+               if lat_used < 0.95:
+                       lat_warning = bcolors.FAIL + ' Potential latency accuracy problem: {:>3.0f}%'.format(lat_used*100) +  bcolors.ENDC
+               else:
+                       lat_warning = ''
                if ((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001 and ((drop_rate < DROP_RATE_TRESHOLD) or (abs_dropped==DROP_RATE_TRESHOLD ==0)) and (lat_avg< LAT_AVG_TRESHOLD) and (lat_max < LAT_MAX_TRESHOLD):
-                       log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+  '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  | SUCCESS    |')
+                       log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+  '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  | SUCCESS    |'+lat_warning)
                        endspeed = speed
                        endpps_req_tx = pps_req_tx
                        endpps_tx = pps_tx
@@ -294,6 +308,7 @@ def run_speedtest(gensock,sutsock):
                        endlat_max = lat_max
                        endabs_dropped = abs_dropped
                        enddrop_rate = drop_rate
+                       endwarning = lat_warning
                        success = True 
                else:
                        abs_drop_rate_prefix = bcolors.ENDC
@@ -315,31 +330,54 @@ def run_speedtest(gensock,sutsock):
                                speed_prefix = bcolors.ENDC
                        else:
                                speed_prefix = bcolors.FAIL
-                       log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC  + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us   | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us   | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '%  | FAILED     |')
+                       log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC  + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us   | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us   | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '%  | FAILED     |'+lat_warning)
                        success = False 
                speed,minspeed,maxspeed = new_speed(speed,minspeed,maxspeed,success)
        if endpps_sut_tx_str <>  'NO_RESULTS':
                log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+------------+")
-                log.info('|{:>7}'.format('END')+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us   | '+ '{:>9.0f}'.format(endlat_max)+' us   | '+'{:>14d}'.format(endabs_dropped)+ ' |''{:>9.2f}'.format(enddrop_rate)+ '%  | SUCCESS    |')
+                log.info('|{:>7}'.format('END')+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us   | '+ '{:>9.0f}'.format(endlat_max)+' us   | '+'{:>14d}'.format(endabs_dropped)+ ' |''{:>9.2f}'.format(enddrop_rate)+ '%  | SUCCESS    |'+endwarning)
                log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+------------+")
+               writer.writerow({'flow':'1','size':(size+4),'endspeed':endspeed,'endspeedpps':get_pps(endspeed,size),'endpps_req_tx':endpps_req_tx,'endpps_tx':endpps_tx,'endpps_sut_tx_str':endpps_sut_tx_str,'endpps_rx':endpps_rx,'endlat_avg':endlat_avg,'endlat_max':endlat_max,'endabs_dropped':endabs_dropped,'enddrop_rate':enddrop_rate})
        else:
                log.info('| Speed 0 or close to 0')
+       gensock.stop(latcores)
 
 def run_flowtest(gensock,sutsock):
+       size=PACKETSIZE-4
        log.info("+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+")
-       log.info("| UDP, 64 bytes, different number of flows by randomizing SRC & DST UDP port                                                                                      |")
+       log.info("| UDP, "+ '{:>5}'.format(size+4) +" bytes, different number of flows by randomizing SRC & DST UDP port                                                                                   |")
        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
        log.info("| Flows  |  Speed requested   | Sent to NIC    |  Sent by Gen   | Forward by SUT |  Rec. by Gen   |  Avg. Latency  |  Max. Latency  |  Packets Lost  | Loss Ratio |")
        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
-       size=60
        # To generate a desired number of flows, PROX will randomize the bits in source and destination ports, as specified by the bit masks in the flows variable. 
-       flows={128:['1000000000000XXX','100000000000XXXX'],1024:['10000000000XXXXX','10000000000XXXXX'],8192:['1000000000XXXXXX','100000000XXXXXXX'],65535:['10000000XXXXXXXX','10000000XXXXXXXX'],524280:['1000000XXXXXXXXX','100000XXXXXXXXXX']}
-#      flows={524280:['1000000XXXXXXXXX','100000XXXXXXXXXX']}
+       flows={\
+       1:      ['1000000000000000','1000000000000000'],\
+       2:      ['1000000000000000','100000000000000X'],\
+       4:      ['100000000000000X','100000000000000X'],\
+       8:      ['100000000000000X','10000000000000XX'],\
+       16:     ['10000000000000XX','10000000000000XX'],\
+       32:     ['10000000000000XX','1000000000000XXX'],\
+       64:     ['1000000000000XXX','1000000000000XXX'],\
+       128:    ['1000000000000XXX','100000000000XXXX'],\
+       256:    ['100000000000XXXX','100000000000XXXX'],\
+       512:    ['100000000000XXXX','10000000000XXXXX'],\
+       1024:   ['10000000000XXXXX','10000000000XXXXX'],\
+       2048:   ['10000000000XXXXX','1000000000XXXXXX'],\
+       4096:   ['1000000000XXXXXX','1000000000XXXXXX'],\
+       8192:   ['1000000000XXXXXX','100000000XXXXXXX'],\
+       16384:  ['100000000XXXXXXX','100000000XXXXXXX'],\
+       32768:  ['100000000XXXXXXX','10000000XXXXXXXX'],\
+       65535:  ['10000000XXXXXXXX','10000000XXXXXXXX'],\
+       131072: ['10000000XXXXXXXX','1000000XXXXXXXXX'],\
+       262144: ['1000000XXXXXXXXX','1000000XXXXXXXXX'],\
+       524280: ['1000000XXXXXXXXX','100000XXXXXXXXXX'],\
+       1048576:['100000XXXXXXXXXX','100000XXXXXXXXXX'],}
        gensock.set_size(gencores,0,size) # This is setting the frame size
        gensock.set_value(gencores,0,16,(size-14),2) # 18 is the difference between the frame size and IP size = size of (MAC addresses, ethertype and FCS)
        gensock.set_value(gencores,0,38,(size-34),2) # 38 is the difference between the frame size and UDP size = 18 + size of IP header (=20)
        # This will only work when using sending UDP packets. For different protocls and ehternet types, we would need a differnt calculation
-       for flow_number in sorted(flows.iterkeys()):
+       gensock.start(latcores)
+       for flow_number in flow_size_list:
                attempts = 0
                gensock.reset_stats()
                if sutsock!='none':
@@ -355,13 +393,17 @@ def run_flowtest(gensock,sutsock):
                        print(str(flow_number)+' flows: Measurement ongoing at speed: ' + str(round(speed,2)) + '%      ',end='\r')
                        sys.stdout.flush()
                        # Start generating packets at requested speed (in % of a 10Gb/s link)
-                       gensock.speed(speed, gencores)
+                       gensock.speed(speed / len(gencores), gencores)
                        time.sleep(1)
                        # Get statistics now that the generation is stable and initial ARP messages are dealt with
-                       pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
+                       pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx, lat_min, lat_used = run_iteration(gensock,sutsock)
                        drop_rate = 100.0*abs_dropped/abs_tx
+                       if lat_used < 0.95:
+                               lat_warning = bcolors.FAIL + ' Potential latency accuracy problem: {:>3.0f}%'.format(lat_used*100) +  bcolors.ENDC
+                       else:
+                               lat_warning = ''
                        if ((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001 and ((drop_rate < DROP_RATE_TRESHOLD) or (abs_dropped==DROP_RATE_TRESHOLD ==0)) and (lat_avg< LAT_AVG_TRESHOLD) and (lat_max < LAT_MAX_TRESHOLD):
-                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+  '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  | SUCCESS    |')
+                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+  '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  | SUCCESS    |'+lat_warning)
                                endspeed = speed
                                endpps_req_tx = pps_req_tx
                                endpps_tx = pps_tx
@@ -371,6 +413,7 @@ def run_flowtest(gensock,sutsock):
                                endlat_max = lat_max 
                                endabs_dropped = abs_dropped
                                enddrop_rate = drop_rate
+                               endwarning = lat_warning
                                success = True
                        else:
                                abs_drop_rate_prefix = bcolors.ENDC
@@ -392,15 +435,16 @@ def run_flowtest(gensock,sutsock):
                                        speed_prefix = bcolors.ENDC
                                else:
                                        speed_prefix = bcolors.FAIL
-                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC  + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us   | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us   | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '%  | FAILED     |')
+                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC  + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us   | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us   | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '%  | FAILED     |'+lat_warning)
                                success = False 
                        speed,minspeed,maxspeed = new_speed(speed,minspeed,maxspeed,success)
                if endpps_sut_tx_str <>  'NO_RESULTS':
-                       log.info('|{:>7}'.format(str(flow_number))+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us   | '+ '{:>9.0f}'.format(endlat_max)+' us   | '+ '{:>14d}'.format(endabs_dropped)+ ' |'+'{:>9.2f}'.format(enddrop_rate)+ '%  |')
+                       log.info('|{:>7}'.format(str(flow_number))+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us   | '+ '{:>9.0f}'.format(endlat_max)+' us   | '+ '{:>14d}'.format(endabs_dropped)+ ' |'+'{:>9.2f}'.format(enddrop_rate)+ '%  |'+endwarning)
                        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
                        writer.writerow({'flow':flow_number,'size':(size+4),'endspeed':endspeed,'endspeedpps':get_pps(endspeed,size),'endpps_req_tx':endpps_req_tx,'endpps_tx':endpps_tx,'endpps_sut_tx_str':endpps_sut_tx_str,'endpps_rx':endpps_rx,'endlat_avg':endlat_avg,'endlat_max':endlat_max,'endabs_dropped':endabs_dropped,'enddrop_rate':enddrop_rate})
                else:
                        log.info('|{:>7}'.format(str(flow_number))+" | Speed 0 or close to 0")
+       gensock.stop(latcores)
 
 def run_sizetest(gensock,sutsock):
        log.info("+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+")
@@ -408,11 +452,9 @@ def run_sizetest(gensock,sutsock):
        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
        log.info("| Pktsize|  Speed requested   | Sent to NIC    |  Sent by Gen   | Forward by SUT |  Rec. by Gen   |  Avg. Latency  |  Max. Latency  |  Packets Lost  | Loss Ratio |")
        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
-       # PROX will use different packet sizes as defined in sizes[]
-       sizes=[1496,1020,508,252,124,60]
-#      sizes=[1020,508,252,124,60]
-#      sizes=[124,60]
-       for size in sizes:
+       gensock.start(latcores)
+       for size in packet_size_list:
+               size = size-4
                attempts = 0
                gensock.reset_stats()
                if sutsock!='none':
@@ -429,12 +471,16 @@ def run_sizetest(gensock,sutsock):
                        print(str(size+4)+' bytes: Measurement ongoing at speed: ' + str(round(speed,2)) + '%      ',end='\r')
                        sys.stdout.flush()
                        # Start generating packets at requested speed (in % of a 10Gb/s link)
-                       gensock.speed(speed, gencores)
+                       gensock.speed(speed / len(gencores), gencores)
                        # Get statistics now that the generation is stable and initial ARP messages are dealt with
-                       pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
+                       pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx, lat_min, lat_used = run_iteration(gensock,sutsock)
                        drop_rate = 100.0*abs_dropped/abs_tx
+                       if lat_used < 0.95:
+                               lat_warning = bcolors.FAIL + ' Potential latency accuracy problem: {:>3.0f}%'.format(lat_used*100) +  bcolors.ENDC
+                       else:
+                               lat_warning = ''
                        if ((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001 and ((drop_rate < DROP_RATE_TRESHOLD) or (abs_dropped==DROP_RATE_TRESHOLD ==0)) and (lat_avg< LAT_AVG_TRESHOLD) and (lat_max < LAT_MAX_TRESHOLD):
-                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+  '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  | SUCCESS    |')
+                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+  '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  | SUCCESS    |'+lat_warning)
                                endspeed = speed
                                endpps_req_tx = pps_req_tx
                                endpps_tx = pps_tx
@@ -444,6 +490,7 @@ def run_sizetest(gensock,sutsock):
                                endlat_max = lat_max 
                                endabs_dropped = abs_dropped
                                enddrop_rate = drop_rate
+                               endwarning = lat_warning
                                success = True
                        else:
                                abs_drop_rate_prefix = bcolors.ENDC
@@ -465,113 +512,129 @@ def run_sizetest(gensock,sutsock):
                                        speed_prefix = bcolors.ENDC
                                else:
                                        speed_prefix = bcolors.FAIL
-                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC  + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us   | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us   | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '%  | FAILED     |')
+                               log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC  + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us   | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us   | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '%  | FAILED     |'+ lat_warning)
                                success = False 
                        speed,minspeed,maxspeed = new_speed(speed,minspeed,maxspeed,success)
                if endpps_sut_tx_str <>  'NO_RESULTS':
-                       log.info('|{:>7}'.format(size+4)+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us   | '+'{:>9.0f}'.format(endlat_max)+' us   | '+ '{:>14d}'.format(endabs_dropped)+ ' |'+'{:>9.2f}'.format(enddrop_rate)+ '%  |')
+                       log.info('|{:>7}'.format(size+4)+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us   | '+'{:>9.0f}'.format(endlat_max)+' us   | '+ '{:>14d}'.format(endabs_dropped)+ ' |'+'{:>9.2f}'.format(enddrop_rate)+ '%  |'+ endwarning)
                        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
                        writer.writerow({'flow':'1','size':(size+4),'endspeed':endspeed,'endspeedpps':get_pps(endspeed,size),'endpps_req_tx':endpps_req_tx,'endpps_tx':endpps_tx,'endpps_sut_tx_str':endpps_sut_tx_str,'endpps_rx':endpps_rx,'endlat_avg':endlat_avg,'endlat_max':endlat_max,'endabs_dropped':endabs_dropped,'enddrop_rate':enddrop_rate})
                else:
                        log.debug('|{:>7}'.format(str(size))+" | Speed 0 or close to 0")
-
+       gensock.stop(latcores)
 
 def run_max_frame_rate(gensock,sutsock):
-       log.info("+-----------------------------------------------------------------------------------------------------------------------------------------------------------+")
-       log.info("| UDP, 1 flow, different packet sizes                                                                                                                       |")
-       log.info("+-----+------------------+-------------+-------------+-------------+-------------+-------------+-------------+-----------+-----------+---------+------------+")
-       log.info("|Pktsz| Speed requested  | Sent to NIC | Sent by Gen | Fwrd by SUT | Rec. by Gen | Avg. Latency| Max. Latency|   Sent    |  Received |  Lost   | Total Lost |")
-       log.info("+-----+------------------+-------------+-------------+-------------+-------------+-------------+-------------+-----------+-----------+---------+------------+")
-       # PROX will use different packet sizes as defined in sizes[]
-       sizes=[1496,1020,508,252,124,60]
-       sleep_time = 3
-       for size in sizes:
-               # Sleep_time is needed to be able to do accurate measurements to check for packet loss. We need to make this time large enough so that we do not take the first measurement while some packets from the previous tests migth still be in flight
-               time.sleep(sleep_time)
-               gensock.reset_stats()
-               if sutsock!='none':
-                       sutsock.reset_stats()
-               gensock.set_size(gencores,0,size) # This is setting the frame size
-               gensock.set_value(gencores,0,16,(size-14),2) # 18 is the difference between the frame size and IP size = size of (MAC addresses, ethertype and FCS)
-               gensock.set_value(gencores,0,38,(size-34),2) # 38 is the difference between the frame size and UDP size = 18 + size of IP header (=20)
-               # This will only work when using sending UDP packets. For different protocls and ehternet types, we would need a differnt calculation
-               pps_sut_tx_str = 'NO_RESULTS'
-               speed = STARTSPEED 
-               # Start generating packets at requested speed (in % of a 10Gb/s link)
-               gensock.speed(speed / len(gencores), gencores)
-               duration = float(runtime)
-               first = 1
-               tot_drop = 0
-               if sutsock!='none':
-                       old_sut_rx, old_sut_tx, old_sut_drop, old_sut_tsc, sut_tsc_hz = sutsock.core_stats(sutstatcores)
-               old_rx, old_tx, old_drop, old_tsc, tsc_hz = gensock.core_stats(genstatcores)
-               gensock.start(gencores)
-               while (duration > 0):
-                       duration = duration - 1
-                       time.sleep(1)
-                       lat_min, lat_max, lat_avg = gensock.lat_stats(latcores)
-                       # Get statistics after some execution time
-                       new_rx, new_tx, new_drop, new_tsc, tsc_hz = gensock.core_stats(genstatcores)
-                       if sutsock!='none':
-                               new_sut_rx, new_sut_tx, new_sut_drop, new_sut_tsc, sut_tsc_hz = sutsock.core_stats(sutstatcores)
-                       drop = new_drop-old_drop # drop is all packets dropped by all tasks. This includes packets dropped at the generator task + packets dropped by the nop task. In steady state, this equals to the number of packets received by this VM
-                       rx = new_rx - old_rx     # rx is all packets received by the nop task = all packets received in the gen VM
-                       tx = new_tx - old_tx     # tx is all generated packets actually accepted by the interface
-                       tsc = new_tsc - old_tsc  # time difference between the 2 measurements, expressed in cycles.
-                       old_drop = new_drop
-                       old_rx = new_rx
-                       old_tx = new_tx
-                       old_tsc = new_tsc
-                       pps_req_tx = (tx+drop-rx)*tsc_hz*1.0/(tsc*1000000)
-                       pps_tx = tx*tsc_hz*1.0/(tsc*1000000)
-                       pps_rx = rx*tsc_hz*1.0/(tsc*1000000)
-                       if sutsock!='none':
-                               sut_rx = new_sut_rx - old_sut_rx
-                               sut_tx = new_sut_tx - old_sut_tx
-                               sut_tsc = new_sut_tsc - old_sut_tsc
-                               old_sut_tx = new_sut_tx
-                               old_sut_rx = new_sut_rx
-                               old_sut_tsc= new_sut_tsc
-                               pps_sut_tx = sut_tx*sut_tsc_hz*1.0/(sut_tsc*1000000)
-                               pps_sut_tx_str = '{:>7.3f}'.format(pps_sut_tx)
-                       else:
-                               pps_sut_tx = 0
-                               pps_sut_tx_str = 'NO MEAS.'
-                       if (tx == 0):
-                               log.critical("TX = 0. Test interrupted since no packet has been sent.")
-                               raise Exception("TX = 0")
-                       tot_drop = tot_drop + tx - rx
-               
-                       if pps_sut_tx_str <>  'NO_RESULTS':
-                               # First second mpps are not valid as there is no alignement between time the generator is started and per seconds stats
-                               if (first):
-                                       log.info('|{:>4}'.format(size+4)+" |" + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps|'+'             |' +'             |'  +'             |'+ '             |'+ '{:>8.0f}'.format(lat_avg)+' us  |'+'{:>8.0f}'.format(lat_max)+' us  | ' + '{:>9.0f}'.format(tx) + ' | '+ '{:>9.0f}'.format(rx) + ' | '+ '{:>7.0f}'.format(tx-rx) + ' | '+'{:>7.0f}'.format(tot_drop) +' |  ')
-                               else:
-                                       log.info('|{:>4}'.format(size+4)+" |" + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps|'+ '{:>7.3f}'.format(pps_req_tx)+' Mpps |'+ '{:>7.3f}'.format(pps_tx) +' Mpps |' + '{:>7}'.format(pps_sut_tx_str) +' Mpps |'+ '{:>7.3f}'.format(pps_rx)+' Mpps |'+ '{:>8.0f}'.format(lat_avg)+' us  |'+'{:>8.0f}'.format(lat_max)+' us  | ' + '{:>9.0f}'.format(tx) + ' | '+ '{:>9.0f}'.format(rx) + ' | '+ '{:>7.0f}'.format(tx-rx) + ' | '+ '{:>7.0f}'.format(tot_drop) +' |  ')
+        log.info("+-----------------------------------------------------------------------------------------------------------------------------------------------------------+")
+        log.info("| UDP, 1 flow, different packet sizes                                                                                                                       |")
+        log.info("+-----+------------------+-------------+-------------+-------------+-------------+-------------+-------------+-----------+-----------+---------+------------+")
+        log.info("|Pktsz| Speed requested  | Sent to NIC | Sent by Gen | Fwrd by SUT | Rec. by Gen | Avg. Latency| Max. Latency|   Sent    |  Received |  Lost   | Total Lost |")
+        log.info("+-----+------------------+-------------+-------------+-------------+-------------+-------------+-------------+-----------+-----------+---------+------------+")
+        sleep_time = 3
+       gensock.start(latcores)
+       for size in packet_size_list:
+                # Sleep_time is needed to be able to do accurate measurements to check for packet loss. We need to make this time large enough so that we do not take the first measurement while some packets from the previous tests migth still be in flight
+                time.sleep(sleep_time)
+               size = size-4
+                gensock.reset_stats()
+                if sutsock!='none':
+                        sutsock.reset_stats()
+                gensock.set_size(gencores,0,size) # This is setting the frame size
+                gensock.set_value(gencores,0,16,(size-14),2) # 18 is the difference between the frame size and IP size = size of (MAC addresses, ethertype and FCS)
+                gensock.set_value(gencores,0,38,(size-34),2) # 38 is the difference between the frame size and UDP size = 18 + size of IP header (=20)
+                # This will only work when using sending UDP packets. For different protocls and ehternet types, we would need a differnt calculation
+                pps_sut_tx_str = 'NO_RESULTS'
+                speed = STARTSPEED
+                # Start generating packets at requested speed (in % of a 10Gb/s link)
+                gensock.speed(speed / len(gencores), gencores)
+                duration = float(runtime)
+                first = 1
+                tot_drop = 0
+                if sutsock!='none':
+                        old_sut_rx, old_sut_tx, old_sut_drop, old_sut_tsc, sut_tsc_hz = sutsock.core_stats(sutstatcores)
+                old_rx, old_tx, old_drop, old_tsc, tsc_hz = gensock.core_stats(genstatcores)
+                gensock.start(gencores)
+                while (duration > 0):
+                        time.sleep(0.5)
+                        lat_min, lat_max, lat_avg, lat_used = gensock.lat_stats(latcores)
+                       if lat_used < 0.95:
+                               lat_warning = bcolors.FAIL + ' Potential latency accuracy problem: {:>3.0f}%'.format(lat_used*100) +  bcolors.ENDC
                        else:
-                               log.debug('|{:>7}'.format(str(size))+" | Speed 0 or close to 0")
-                       first = 0
-                       if (duration <= 0):
-                               #Stop generating
-                               gensock.stop(gencores)
-                               time.sleep(sleep_time)
-                               lat_min, lat_max, lat_avg = gensock.lat_stats(latcores)
-                               # Get statistics after some execution time
-                               new_rx, new_tx, new_drop, new_tsc, tsc_hz = gensock.core_stats(genstatcores)
-                               if sutsock!='none':
-                                       new_sut_rx, new_sut_tx, new_sut_drop, new_sut_tsc, sut_tsc_hz = sutsock.core_stats(sutstatcores)
-                               drop = new_drop-old_drop # drop is all packets dropped by all tasks. This includes packets dropped at the generator task + packets dropped by the nop task. In steady state, this equals to the number of packets received by this VM
-                               rx = new_rx - old_rx     # rx is all packets received by the nop task = all packets received in the gen VM
-                               tx = new_tx - old_tx     # tx is all generated packets actually accepted by the interface
-                               tsc = new_tsc - old_tsc  # time difference between the 2 measurements, expressed in cycles.
-                               tot_drop = tot_drop + tx - rx
-                               if sutsock!='none':
-                                       sut_rx = new_sut_rx - old_sut_rx
-                                       sut_tx = new_sut_tx - old_sut_tx
-                                       sut_tsc = new_sut_tsc - old_sut_tsc
-                               if pps_sut_tx_str <>  'NO_RESULTS':
-                                       log.info('|{:>4}'.format(size+4)+" |" + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps|'+'             |' +'             |'  +'             |'+ '             |'+ '{:>8.0f}'.format(lat_avg)+' us  |'+'{:>8.0f}'.format(lat_max)+' us  | ' + '{:>9.0f}'.format(tx) + ' | '+ '{:>9.0f}'.format(rx) + ' | '+ '{:>7.0f}'.format(tx-rx) + ' | '+ '{:>7.0f}'.format(tot_drop) +'  | ')
-               log.info("+-----+------------------+-------------+-------------+-------------+-------------+-------------+-------------+-----------+-----------+---------+------------+")
+                               lat_warning = ''
+                        # Get statistics after some execution time
+                        new_rx, new_tx, new_drop, new_tsc, tsc_hz = gensock.core_stats(genstatcores)
+                        if sutsock!='none':
+                                new_sut_rx, new_sut_tx, new_sut_drop, new_sut_tsc, sut_tsc_hz = sutsock.core_stats(sutstatcores)
+                        drop = new_drop-old_drop # drop is all packets dropped by all tasks. This includes packets dropped at the generator task + packets dropped by the nop task. In steady state, this equals to the number of packets received by this VM
+                        rx = new_rx - old_rx     # rx is all packets received by the nop task = all packets received in the gen VM
+                        tx = new_tx - old_tx     # tx is all generated packets actually accepted by the interface
+                        tsc = new_tsc - old_tsc  # time difference between the 2 measurements, expressed in cycles.
+                       if tsc == 0 :
+                               continue
+                        if sutsock!='none':
+                                sut_rx = new_sut_rx - old_sut_rx
+                                sut_tx = new_sut_tx - old_sut_tx
+                                sut_tsc = new_sut_tsc - old_sut_tsc
+                               if sut_tsc == 0 :
+                                       continue
+                        duration = duration - 1
+                        old_drop = new_drop
+                        old_rx = new_rx
+                        old_tx = new_tx
+                        old_tsc = new_tsc
+                        pps_req_tx = (tx+drop-rx)*tsc_hz*1.0/(tsc*1000000)
+                        pps_tx = tx*tsc_hz*1.0/(tsc*1000000)
+                        pps_rx = rx*tsc_hz*1.0/(tsc*1000000)
+                        if sutsock!='none':
+                                old_sut_tx = new_sut_tx
+                                old_sut_rx = new_sut_rx
+                                old_sut_tsc= new_sut_tsc
+                                pps_sut_tx = sut_tx*sut_tsc_hz*1.0/(sut_tsc*1000000)
+                                pps_sut_tx_str = '{:>7.3f}'.format(pps_sut_tx)
+                        else:
+                                pps_sut_tx = 0
+                                pps_sut_tx_str = 'NO MEAS.'
+                        if (tx == 0):
+                                log.critical("TX = 0. Test interrupted since no packet has been sent.")
+                                raise Exception("TX = 0")
+                        tot_drop = tot_drop + tx - rx
+
+                        if pps_sut_tx_str <>  'NO_RESULTS':
+                                # First second mpps are not valid as there is no alignement between time the generator is started and per seconds stats
+                                if (first):
+                                        log.info('|{:>4}'.format(size+4)+" |" + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps|'+'             |' +'             |'  +'             |'+ '             |'+ '{:>8.0f}'.format(lat_avg)+' us  |'+'{:>8.0f}'.format(lat_max)+' us  | ' + '{:>9.0f}'.format(tx) + ' | '+ '{:>9.0f}'.format(rx) + ' | '+ '{:>7.0f}'.format(tx-rx) + ' | '+'{:>7.0f}'.format(tot_drop) +'    |'+lat_warning)
+                                else:
+                                        log.info('|{:>4}'.format(size+4)+" |" + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps|'+ '{:>7.3f}'.format(pps_req_tx)+' Mpps |'+ '{:>7.3f}'.format(pps_tx) +' Mpps |' + '{:>7}'.format(pps_sut_tx_str) +' Mpps |'+ '{:>7.3f}'.format(pps_rx)+' Mpps |'+ '{:>8.0f}'.format(lat_avg)+' us  |'+'{:>8.0f}'.format(lat_max)+' us  | ' + '{:>9.0f}'.format(tx) + ' | '+ '{:>9.0f}'.format(rx) + ' | '+ '{:>7.0f}'.format(tx-rx) + ' | '+ '{:>7.0f}'.format(tot_drop) +'    |'+lat_warning)
+                        else:
+                                log.debug('|{:>7}'.format(str(size))+" | Speed 0 or close to 0")
+                        first = 0
+                        if (duration <= 0):
+                                #Stop generating
+                                gensock.stop(gencores)
+                                time.sleep(sleep_time)
+                                lat_min, lat_max, lat_avg, lat_used = gensock.lat_stats(latcores)
+                               if lat_used < 0.95:
+                                       lat_warning = bcolors.FAIL + ' Potential latency accuracy problem: {:>3.0f}%'.format(lat_used*100) +  bcolors.ENDC
+                               else:
+                                       lat_warning = ''
+                                # Get statistics after some execution time
+                                new_rx, new_tx, new_drop, new_tsc, tsc_hz = gensock.core_stats(genstatcores)
+                                if sutsock!='none':
+                                        new_sut_rx, new_sut_tx, new_sut_drop, new_sut_tsc, sut_tsc_hz = sutsock.core_stats(sutstatcores)
+                                drop = new_drop-old_drop # drop is all packets dropped by all tasks. This includes packets dropped at the generator task + packets dropped by the nop task. In steady state, this equals to the number of packets received by this VM
+                                rx = new_rx - old_rx     # rx is all packets received by the nop task = all packets received in the gen VM
+                                tx = new_tx - old_tx     # tx is all generated packets actually accepted by the interface
+                                tsc = new_tsc - old_tsc  # time difference between the 2 measurements, expressed in cycles.
+                                tot_drop = tot_drop + tx - rx
+                                if sutsock!='none':
+                                        sut_rx = new_sut_rx - old_sut_rx
+                                        sut_tx = new_sut_tx - old_sut_tx
+                                        sut_tsc = new_sut_tsc - old_sut_tsc
+                                if pps_sut_tx_str <>  'NO_RESULTS':
+                                        log.info('|{:>4}'.format(size+4)+" |" + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps|'+'             |' +'             |'  +'             |'+ '             |'+ '{:>8.0f}'.format(lat_avg)+' us  |'+'{:>8.0f}'.format(lat_max)+' us  | ' + '{:>9.0f}'.format(tx) + ' | '+ '{:>9.0f}'.format(rx) + ' | '+ '{:>7.0f}'.format(tx-rx) + ' | '+ '{:>7.0f}'.format(tot_drop) +'    |'+lat_warning)
+                log.info("+-----+------------------+-------------+-------------+-------------+-------------+-------------+-------------+-----------+-----------+---------+------------+")
+       gensock.stop(latcores)
+
+
 
 def run_irqtest(sock):
         log.info("+----------------------------------------------------------------------------------------------------------------------------")
@@ -606,72 +669,83 @@ def run_irqtest(sock):
                                irq[i][j] = '0'
                        else:
                                irq[i][j] = str(round(diff/float(runtime), 2))
-       log.info('\n'.join([''.join(['{:>12}'.format(item) for item in row]) for row in irq]))
+       for row in irq:
+               log.info(''.join(['{:>12}'.format(item) for item in row]))
+#      log.info('\n'.join([''.join(['{:>12}'.format(item) for item in row]) for row in irq]))
 
 def run_impairtest(gensock,sutsock):
+       size=PACKETSIZE-4
         log.info("+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+")
-        log.info("| Generator is sending UDP (1 flow) packets (64 bytes) to SUT via GW dropping and delaying packets. SUT sends packets back. Use ctrl-c to stop the test           |")
+        log.info("| Generator is sending UDP (1 flow) packets ("+ '{:>5}'.format(size+4) +" bytes) to SUT via GW dropping and delaying packets. SUT sends packets back. Use ctrl-c to stop the test        |")
        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
        log.info("| Test   |  Speed requested   | Sent to NIC    |  Sent by Gen   | Forward by SUT |  Rec. by Gen   |  Avg. Latency  |  Max. Latency  |  Packets Lost  | Loss Ratio |")
        log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
-       size=60
        attempts = 0
        gensock.set_size(gencores,0,size) # This is setting the frame size
        gensock.set_value(gencores,0,16,(size-14),2) # 18 is the difference between the frame size and IP size = size of (MAC addresses, ethertype and FCS)
        gensock.set_value(gencores,0,38,(size-34),2) # 38 is the difference between the frame size and UDP size = 18 + size of IP header (=20)
        # This will only work when using sending UDP packets. For different protocols and ethernet types, we would need a different calculation
+       gensock.start(latcores)
        speed = STARTSPEED
-        gensock.speed(speed, gencores)
+       gensock.speed(speed / len(gencores), gencores)
         while True:
                 attempts += 1
                 print('Measurement ongoing at speed: ' + str(round(speed,2)) + '%      ',end='\r')
                 sys.stdout.flush()
                 time.sleep(1)
                 # Get statistics now that the generation is stable and NO ARP messages any more
-               pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
+               pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx, lat_min, lat_used = run_iteration(gensock,sutsock)
                drop_rate = 100.0*abs_dropped/abs_tx
-               log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+ '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  |')
+               if lat_used < 0.95:
+                       lat_warning = bcolors.FAIL + ' Potential latency accuracy problem: {:>3.0f}%'.format(lat_used*100) +  bcolors.ENDC
+               else:
+                       lat_warning = ''
+               log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us   | '+ '{:>9.0f}'.format(lat_max)+' us   | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '%  |'+lat_warning)
+               writer.writerow({'flow':'1','size':(size+4),'endspeed':speed,'endspeedpps':get_pps(speed,size),'endpps_req_tx':pps_req_tx,'endpps_tx':pps_tx,'endpps_sut_tx_str':pps_sut_tx_str,'endpps_rx':pps_rx,'endlat_avg':lat_avg,'endlat_max':lat_max,'endabs_dropped':abs_dropped,'enddrop_rate':drop_rate})
+       gensock.stop(latcores)
 
-def init_test():
+def run_inittest(gensock):
 # Running at low speed to make sure the ARP messages can get through.
 # If not doing this, the ARP message could be dropped by a switch in overload and then the test will not give proper results
 # Note hoever that if we would run the test steps during a very long time, the ARP would expire in the switch.
 # PROX will send a new ARP request every seconds so chances are very low that they will all fail to get through
-       socks[0].speed(0.01, gencores)
-       socks[0].start(genstatcores)
+       gensock.speed(0.01 / len(gencores), gencores)
+       gensock.start(genstatcores)
        time.sleep(2)
-       socks[0].stop(gencores)
+       gensock.stop(genstatcores)
 
 global sutstatcores
 global genstatcores
 global latcores
 global gencores
 global irqcores
-global DROP_RATE_TRESHOLD
-global LAT_AVG_TRESHOLD
-global LAT_MAX_TRESHOLD
-global ACCURACY
-global STARTSPEED
+global PACKETSIZE
+global packet_size_list
+global flow_size_list
 global required_number_of_test_machines
 clients =[]
 socks =[]
+socks_control =[]
 vmDPIP =[]
 vmAdminIP =[]
 vmDPmac =[]
 hexDPIP =[]
 config_file =[]
-script_control =[]
+prox_socket =[]
+prox_launch_exit =[]
+auto_start =[]
+mach_type =[]
+sock_type =[]
 
+data_file = 'RUN{}.{}.csv'.format(env,test)
+data_csv_file = open(data_file,'w')
 testconfig = ConfigParser.RawConfigParser()
 testconfig.read(test+'.test')
 required_number_of_test_machines = testconfig.get('DEFAULT', 'total_number_of_test_machines')
-DROP_RATE_TRESHOLD = float(testconfig.get('DEFAULT', 'drop_rate_treshold'))
-LAT_AVG_TRESHOLD = float(testconfig.get('DEFAULT', 'lat_avg_treshold'))
-LAT_MAX_TRESHOLD = float(testconfig.get('DEFAULT', 'lat_max_treshold'))
-ACCURACY = float(testconfig.get('DEFAULT', 'accuracy'))
-STARTSPEED = float(testconfig.get('DEFAULT', 'startspeed'))
 config = ConfigParser.RawConfigParser()
 config.read(env+'.env')
+machine_map = ConfigParser.RawConfigParser()
+machine_map.read(machine_map_file +'.cfg')
 key = config.get('OpenStack', 'key')
 total_number_of_machines = config.get('rapid', 'total_number_of_machines')
 if int(required_number_of_test_machines) > int(total_number_of_machines):
@@ -685,108 +759,169 @@ for vm in range(1, int(total_number_of_machines)+1):
        hexDPIP.append(hex(int(ip[0]))[2:].zfill(2) + ' ' + hex(int(ip[1]))[2:].zfill(2) + ' ' + hex(int(ip[2]))[2:].zfill(2) + ' ' + hex(int(ip[3]))[2:].zfill(2))
 machine_index = []
 for vm in range(1, int(required_number_of_test_machines)+1):
-       machine_index.append(int(testconfig.get('TestM%d'%vm, 'machine_index'))-1)
+       machine_index.append(int(machine_map.get('TestM%d'%vm, 'machine_index'))-1)
+       prox_socket.append(testconfig.getboolean('TestM%d'%vm, 'prox_socket'))
 for vm in range(1, int(required_number_of_test_machines)+1):
-       config_file.append(testconfig.get('TestM%d'%vm, 'config_file'))
-       script_control.append(testconfig.get('TestM%d'%vm, 'script_control'))
-        group1cores=testconfig.get('TestM%d'%vm, 'group1cores')
-       if group1cores <> 'not_used':
-               group1cores=ast.literal_eval(group1cores)
-        group2cores=testconfig.get('TestM%d'%vm, 'group2cores')
-       if group2cores <> 'not_used':
-               group2cores=ast.literal_eval(group2cores)
-        group3cores=testconfig.get('TestM%d'%vm, 'group3cores')
-       if group3cores <> 'not_used':
-               group3cores=ast.literal_eval(group3cores)
-       with open("parameters%d.lua"%vm, "w") as f:
-               f.write('name="%s"\n'% testconfig.get('TestM%d'%vm, 'name'))
-               f.write('local_ip="%s"\n'% vmDPIP[machine_index[vm-1]])
-               f.write('local_hex_ip="%s"\n'% hexDPIP[machine_index[vm-1]])
-               gwVM = testconfig.get('TestM%d'%vm, 'gw_vm')
-               if gwVM <> 'not_used':
-                       gwVMindex = int(gwVM)-1
-                       f.write('gw_ip="%s"\n'% vmDPIP[machine_index[gwVMindex]])
-                       f.write('gw_hex_ip="%s"\n'% hexDPIP[machine_index[gwVMindex]])
-               destVM = testconfig.get('TestM%d'%vm, 'dest_vm')
-               if destVM <> 'not_used':
-                       destVMindex = int(destVM)-1
-                       f.write('dest_ip="%s"\n'% vmDPIP[machine_index[destVMindex]])
-                       f.write('dest_hex_ip="%s"\n'% hexDPIP[machine_index[destVMindex]])
-                       f.write('dest_hex_mac="%s"\n'% vmDPmac[machine_index[destVMindex]].replace(':',' '))
-                if group1cores <> 'not_used':
-                        f.write('group1="%s"\n'% ','.join(map(str, group1cores)))
-                if group2cores <> 'not_used':
-                        f.write('group2="%s"\n'% ','.join(map(str, group2cores)))
-                if group3cores <> 'not_used':
-                        f.write('group3="%s"\n'% ','.join(map(str, group3cores)))
-       if re.match('(l2){0,1}gen.*\.cfg',config_file[-1]):
-               gencores = group1cores
-               latcores = group2cores
-               genstatcores = group3cores
-       elif config_file[-1] == 'gen_gw.cfg':
-               gencores = group1cores
-               latcores = group2cores
-               genstatcores = group3cores
-       elif  re.match('(l2){0,1}swap.*\.cfg',config_file[-1]):
-               sutstatcores = group1cores
-       elif config_file[-1] == 'secgw2.cfg':
-               sutstatcores = group1cores
-       elif config_file[-1] == 'irq.cfg':
-               irqcores = group1cores
-       f.close
+       if prox_socket[vm-1]:
+               prox_launch_exit.append(testconfig.getboolean('TestM%d'%vm, 'prox_launch_exit'))
+               config_file.append(testconfig.get('TestM%d'%vm, 'config_file'))
+               with open('{}_{}_parameters{}.lua'.format(env,test,vm), "w") as f:
+                       f.write('name="%s"\n'% testconfig.get('TestM%d'%vm, 'name'))
+                       f.write('local_ip="%s"\n'% vmDPIP[machine_index[vm-1]])
+                       f.write('local_hex_ip="%s"\n'% hexDPIP[machine_index[vm-1]])
+                       if re.match('(l2){0,1}gen\.cfg',config_file[-1]):
+                               gencores = ast.literal_eval(testconfig.get('TestM%d'%vm, 'gencores'))
+                               latcores = ast.literal_eval(testconfig.get('TestM%d'%vm, 'latcores'))
+                               STARTSPEED = float(testconfig.get('TestM%d'%vm, 'startspeed'))
+                               genstatcores = gencores + latcores
+                               auto_start.append(False)
+                               mach_type.append('gen')
+                               f.write('gencores="%s"\n'% ','.join(map(str, gencores)))
+                               f.write('latcores="%s"\n'% ','.join(map(str, latcores)))
+                               destVMindex = int(testconfig.get('TestM%d'%vm, 'dest_vm'))-1
+                               f.write('dest_ip="%s"\n'% vmDPIP[machine_index[destVMindex]])
+                               f.write('dest_hex_ip="%s"\n'% hexDPIP[machine_index[destVMindex]])
+                               f.write('dest_hex_mac="%s"\n'% vmDPmac[machine_index[destVMindex]].replace(':',' '))
+                       elif re.match('(l2){0,1}gen_gw\.cfg',config_file[-1]):
+                               gencores = ast.literal_eval(testconfig.get('TestM%d'%vm, 'gencores'))
+                               latcores = ast.literal_eval(testconfig.get('TestM%d'%vm, 'latcores'))
+                               STARTSPEED = float(testconfig.get('TestM%d'%vm, 'startspeed'))
+                               genstatcores = gencores + latcores
+                               auto_start.append(False)
+                               mach_type.append('gen')
+                               f.write('gencores="%s"\n'% ','.join(map(str, gencores)))
+                               f.write('latcores="%s"\n'% ','.join(map(str, latcores)))
+                               gwVMindex = int(testconfig.get('TestM%d'%vm, 'gw_vm')) -1
+                               f.write('gw_ip="%s"\n'% vmDPIP[machine_index[gwVMindex]])
+                               f.write('gw_hex_ip="%s"\n'% hexDPIP[machine_index[gwVMindex]])
+                               destVMindex = int(testconfig.get('TestM%d'%vm, 'dest_vm'))-1
+                               f.write('dest_ip="%s"\n'% vmDPIP[machine_index[destVMindex]])
+                               f.write('dest_hex_ip="%s"\n'% hexDPIP[machine_index[destVMindex]])
+                               f.write('dest_hex_mac="%s"\n'% vmDPmac[machine_index[destVMindex]].replace(':',' '))
+                       elif  re.match('(l2){0,1}swap.*\.cfg',config_file[-1]):
+                               sutstatcores = ast.literal_eval(testconfig.get('TestM%d'%vm, 'swapcores'))
+                               auto_start.append(True)
+                               mach_type.append('sut')
+                               f.write('swapcores="%s"\n'% ','.join(map(str, sutstatcores)))
+                       elif config_file[-1] == 'secgw1.cfg':
+                               auto_start.append(True)
+                               mach_type.append('none')
+                               f.write('secgwcores="%s"\n'% ','.join(map(str, ast.literal_eval(testconfig.get('TestM%d'%vm, 'secgwcores')))))
+                               destVMindex = int(testconfig.get('TestM%d'%vm, 'dest_vm'))-1
+                               f.write('dest_ip="%s"\n'% vmDPIP[machine_index[destVMindex]])
+                               f.write('dest_hex_ip="%s"\n'% hexDPIP[machine_index[destVMindex]])
+                               f.write('dest_hex_mac="%s"\n'% vmDPmac[machine_index[destVMindex]].replace(':',' '))
+                       elif config_file[-1] == 'secgw2.cfg':
+                               sutstatcores = ast.literal_eval(testconfig.get('TestM%d'%vm, 'secgwcores'))
+                               auto_start.append(True)
+                               mach_type.append('sut')
+                               f.write('secgwcores="%s"\n'% ','.join(map(str, sutstatcores)))
+                       elif config_file[-1] == 'impair.cfg':
+                               auto_start.append(True)
+                               mach_type.append('none')
+                               f.write('impaircores="%s"\n'% ','.join(map(str, ast.literal_eval(testconfig.get('TestM%d'%vm, 'impaircores')))))
+                       elif config_file[-1] == 'irq.cfg':
+                               irqcores = ast.literal_eval(testconfig.get('TestM%d'%vm, 'irqcores'))
+                               auto_start.append(False)
+                               mach_type.append('irq')
+                               f.write('irqcores="%s"\n'% ','.join(map(str, irqcores)))
+               f.close
 #####################################################################################
 def exit_handler():
        log.debug ('exit cleanup')
-       for sock in socks:
-               sock.quit()
+       for index, sock in enumerate(socks):
+               if socks_control[index]:
+                       sock.quit()
        for client in clients:
                client.close()
+       data_csv_file.close
        sys.exit(0)
 
 atexit.register(exit_handler)
 
 for vm in range(0, int(required_number_of_test_machines)):
-       clients.append(prox_ctrl(vmAdminIP[machine_index[vm]], key+'.pem','root'))
-       connect_client(clients[-1])
+       if prox_socket[vm]:
+               clients.append(prox_ctrl(vmAdminIP[machine_index[vm]], key+'.pem','root'))
+               connect_client(clients[-1])
 # Creating script to bind the right network interface to the poll mode driver
-       devbindfile = "devbindvm%d.sh"%(vm+1)
-       with open("devbind.sh") as f:
-               newText=f.read().replace('MACADDRESS', vmDPmac[machine_index[vm]])
-               with open(devbindfile, "w") as f:
-                       f.write(newText)
-       st = os.stat(devbindfile)
-       os.chmod(devbindfile, st.st_mode | stat.S_IEXEC)
-       clients[-1].scp_put('./%s'%devbindfile, '/root/devbind.sh')
-       cmd = '/root/devbind.sh'
-       clients[-1].run_cmd(cmd)
-       log.debug("devbind.sh running on VM%d"%(vm+1))
-       clients[-1].scp_put('./%s'%config_file[vm], '/root/%s'%config_file[vm])
-       clients[-1].scp_put('./parameters%d.lua'%(vm+1), '/root/parameters.lua')
-       log.debug("Starting PROX on VM%d"%(vm+1))
-       if script_control[vm] == 'true':
-               cmd = '/root/prox/build/prox -e -t -o cli -f /root/%s'%config_file[vm]
-       else:
-               cmd = '/root/prox/build/prox -t -o cli -f /root/%s'%config_file[vm]
-       if configonly == False:
-               clients[-1].fork_cmd(cmd, 'PROX Testing on TestM%d'%(vm+1))
-               socks.append(connect_socket(clients[-1]))
+               devbindfile = '{}_{}_devbindvm{}.sh'.format(env,test, vm+1)
+               with open("devbind.sh") as f:
+                       newText=f.read().replace('MACADDRESS', vmDPmac[machine_index[vm]])
+                       with open(devbindfile, "w") as f:
+                               f.write(newText)
+               st = os.stat(devbindfile)
+               os.chmod(devbindfile, st.st_mode | stat.S_IEXEC)
+               clients[-1].scp_put('./%s'%devbindfile, '/root/devbind.sh')
+               cmd = '/root/devbind.sh'
+               clients[-1].run_cmd(cmd)
+               log.debug("devbind.sh running on VM%d"%(vm+1))
+               clients[-1].scp_put('./%s'%config_file[vm], '/root/%s'%config_file[vm])
+               clients[-1].scp_put('./{}_{}_parameters{}.lua'.format(env,test, vm+1), '/root/parameters.lua')
+               if not configonly:
+                       if prox_launch_exit[vm]:
+                               log.debug("Starting PROX on VM%d"%(vm+1))
+                               if auto_start[vm]:
+                                       cmd = '/root/prox/build/prox -t -o cli -f /root/%s'%config_file[vm]
+                               else:
+                                       cmd = '/root/prox/build/prox -e -t -o cli -f /root/%s'%config_file[vm]
+                               clients[-1].fork_cmd(cmd, 'PROX Testing on TestM%d'%(vm+1))
+                       socks_control.append(prox_launch_exit[vm])
+                       socks.append(connect_socket(clients[-1]))
+                       sock_type.append(mach_type[vm])
+socks.append('none')
+socks_control.append(False)
+
+def get_BinarySearchParams() :
+       global DROP_RATE_TRESHOLD
+       global LAT_AVG_TRESHOLD
+       global LAT_MAX_TRESHOLD
+       global ACCURACY
+       global STARTSPEED
+       DROP_RATE_TRESHOLD = float(testconfig.get('BinarySearchParams', 'drop_rate_threshold'))
+       LAT_AVG_TRESHOLD = float(testconfig.get('BinarySearchParams', 'lat_avg_threshold'))
+       LAT_MAX_TRESHOLD = float(testconfig.get('BinarySearchParams', 'lat_max_threshold'))
+       ACCURACY = float(testconfig.get('BinarySearchParams', 'accuracy'))
+       
 if configonly:
        sys.exit()
-init_code = testconfig.get('DEFAULT', 'init_code')
-if init_code <> 'not_used':
-       eval(init_code)
 ####################################################
 # Run test cases
 # Best to run the flow test at the end since otherwise the tests coming after might be influenced by the big number of entries in the switch flow tables
 ####################################################
+gensock_index = sock_type.index('gen') if 'gen' in sock_type else -1
+sutsock_index = sock_type.index('sut') if 'sut' in sock_type else -1
+irqsock_index = sock_type.index('irq') if 'irq' in sock_type else -1
 number_of_tests = testconfig.get('DEFAULT', 'number_of_tests')
-data_file = 'RUN' +env+'.'+test+'.csv'
-data_csv_file = open(data_file,'w')
 with data_csv_file:
        fieldnames = ['flow','size','endspeed','endspeedpps','endpps_req_tx','endpps_tx','endpps_sut_tx_str','endpps_rx','endlat_avg','endlat_max','endabs_dropped','enddrop_rate']
        writer = csv.DictWriter(data_csv_file, fieldnames=fieldnames)
        writer.writeheader()
-       for vm in range(1, int(number_of_tests)+1):
-               cmd=testconfig.get('test%d'%vm,'cmd')
-               eval(cmd)
+       for test_nr in range(1, int(number_of_tests)+1):
+               test=testconfig.get('test%d'%test_nr,'test')
+               log.info(test)
+               if test == 'speedtest':
+                       get_BinarySearchParams()
+                       PACKETSIZE = int(testconfig.get('test%d'%test_nr, 'packetsize'))
+                       run_speedtest(socks[gensock_index],socks[sutsock_index])
+               elif test == 'flowtest':
+                       get_BinarySearchParams()
+                       PACKETSIZE = int(testconfig.get('test%d'%test_nr, 'packetsize'))
+                       flow_size_list = ast.literal_eval(testconfig.get('test%d'%test_nr, 'flows'))
+                       run_flowtest(socks[gensock_index],socks[sutsock_index])
+               elif test == 'sizetest':
+                       get_BinarySearchParams()
+                       packet_size_list = ast.literal_eval(testconfig.get('test%d'%test_nr, 'packetsizes'))
+                       run_sizetest(socks[gensock_index],socks[sutsock_index])
+               elif test == 'max_frame_rate':
+#                      PACKETSIZE = int(testconfig.get('test%d'%test_nr, 'packetsize'))
+                       packet_size_list = ast.literal_eval(testconfig.get('test%d'%test_nr, 'packetsizes'))
+                       run_max_frame_rate(socks[gensock_index],socks[sutsock_index])
+               elif test == 'impairtest':
+                       get_BinarySearchParams()
+                       PACKETSIZE = int(testconfig.get('test%d'%test_nr, 'packetsize'))
+                       run_impairtest(socks[gensock_index],socks[sutsock_index])
+               elif test == 'irqtest':
+                       run_irqtest(socks[irqsock_index])
+               elif test == 'inittest':
+                       run_inittest(socks[gensock_index])
 ####################################################
index 7cfa7e6..cf1b552 100644 (file)
 
 [DEFAULT]
 name = GWTesting
-number_of_tests = 1
+number_of_tests = 2
 total_number_of_test_machines = 3
-init_code=init_test()
-dest_vm = not_used
-gw_vm = not_used
-script_control = false
-group1cores = not_used
-group2cores = not_used
-group3cores = not_used
-drop_rate_treshold = 0.01
-lat_avg_treshold = 200
-lat_max_treshold = 1000
-accuracy = 0.01
-startspeed = 10
+prox_socket = true
+prox_launch_exit = true
 
 [TestM1]
 name = Generator
-machine_index = 1
 config_file = gen_gw.cfg
 dest_vm = 3
 gw_vm = 2
-script_control = true
-group1cores = [1]
-group2cores = [3]
-group3cores = [1,3]
+gencores = [1]
+latcores = [3]
+startspeed = 10
 
 [TestM2]
 name = GW1
-machine_index = 2
 config_file = secgw1.cfg
 dest_vm = 3
-group1cores = [1]
+secgwcores = [1]
 
 [TestM3]
 name = GW2
-machine_index = 3
 config_file = secgw2.cfg
-group1cores = [1]
+secgwcores = [1]
+
+[BinarySearchParams]
+drop_rate_threshold = 0.1
+lat_avg_threshold = 500
+lat_max_threshold = 1000
+accuracy = 0.1
 
 [test1]
-cmd=run_speedtest(socks[0],socks[2])
+test=inittest
+
+[test2]
+test=speedtest
+packetsize=64
index 7788b38..301a138 100644 (file)
@@ -43,7 +43,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $secgwcores]
 name=esp_enc
 task=0
 mode=esp_enc
index dfaf253..9c970e8 100644 (file)
@@ -42,7 +42,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $secgwcores]
 name=esp_dec
 task=0
 mode=esp_dec
index 2f736b1..47cb0b0 100644 (file)
@@ -34,7 +34,7 @@ name=${name}
 [core 0]
 mode=master
 
-[core $group1]
+[core $swapcores]
 name=swap
 task=0
 mode=swap
@@ -43,4 +43,4 @@ rx port=if0
 tx port=if0
 local ipv4=${local_ip}
 drop=no
-
+;arp update time=1