Adding vdev support and vfio 48/70348/2
authorLuc Provoost <luc.provoost@intel.com>
Mon, 15 Jun 2020 10:02:46 +0000 (12:02 +0200)
committerLuc Provoost <luc.provoost@intel.com>
Sun, 5 Jul 2020 20:29:50 +0000 (22:29 +0200)
Using vfio in stead of igb_uio. DPDK 2020.5 is NOT compiling the igb_uio
driver by default any more.
For the l3 mode, we are now using the new PROX vdev feature. This is
achieved by adding the vdev parameter in the port section of the PROX
config files. One of the advantages is that we can now ping a port
managed by PROX: the requests will be forwarded by PROX to the LINUX
stack, who will reply to the ping. A tap device is being created by PROX
to support this feature.
Installing old version of nasm since latest causes some issues.
If not pushgateway is being used, it should be commented out in the
config_file.
vfio is now loaded by specifying the module in /etc/modules-load.d
There is also an after_boot.sh script that will be run by
check_prox_system_setup.sh, which can be used for further configuration
of the instance after boot.
There is now also a file created /opt/rapid/system_ready_for_rapid by
the check_prox_system_setup.sh script. This file is created once all
configuration is done. The runrapid.py script will wait till this file
is created before executing any tests.

Change-Id: Ic5c41af82642066af42134c3323297f5a06f6f72
Signed-off-by: Luc Provoost <luc.provoost@intel.com>
30 files changed:
VNFs/DPPD-PROX/helper-scripts/rapid/basicrapid.test
VNFs/DPPD-PROX/helper-scripts/rapid/check-prox-system-setup.service
VNFs/DPPD-PROX/helper-scripts/rapid/check_prox_system_setup.sh
VNFs/DPPD-PROX/helper-scripts/rapid/config_file
VNFs/DPPD-PROX/helper-scripts/rapid/createrapid.py
VNFs/DPPD-PROX/helper-scripts/rapid/deploycentostools.sh
VNFs/DPPD-PROX/helper-scripts/rapid/devbind.sh
VNFs/DPPD-PROX/helper-scripts/rapid/gen.cfg
VNFs/DPPD-PROX/helper-scripts/rapid/gen_gw.cfg
VNFs/DPPD-PROX/helper-scripts/rapid/impair.cfg
VNFs/DPPD-PROX/helper-scripts/rapid/impair.test
VNFs/DPPD-PROX/helper-scripts/rapid/ipv6.test
VNFs/DPPD-PROX/helper-scripts/rapid/irq.test
VNFs/DPPD-PROX/helper-scripts/rapid/l2zeroloss.test
VNFs/DPPD-PROX/helper-scripts/rapid/l3framerate.test
VNFs/DPPD-PROX/helper-scripts/rapid/openstack-rapid.yaml
VNFs/DPPD-PROX/helper-scripts/rapid/params_rapid.yaml
VNFs/DPPD-PROX/helper-scripts/rapid/prox_ctrl.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_corestatstest.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_flowsizetest.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_impairtest.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_irqtest.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_log.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_machine.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_parser.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_portstatstest.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_test.py
VNFs/DPPD-PROX/helper-scripts/rapid/runrapid.py
VNFs/DPPD-PROX/helper-scripts/rapid/stackdeployment.py
VNFs/DPPD-PROX/helper-scripts/rapid/swap.cfg

index e0909c4..80710f3 100644 (file)
@@ -31,7 +31,7 @@ latcores = [3]
 [TestM2]
 name = Swap
 config_file = swap.cfg
-cores = [1,2]
+cores = [1]
 #prox_socket = true
 #prox_launch_exit = true
 
index 6339d3e..f52055e 100644 (file)
@@ -1,5 +1,5 @@
 [Unit]
-Description=Check PROX system setup (isolated_cores, uio)
+Description=Check PROX system setup (isolated_cores, vfio)
 DefaultDependencies=no
 After=multi-user.target
 
index 5d8ae1e..84e2f70 100755 (executable)
@@ -26,10 +26,12 @@ then
         case $line in
             isolated_cores=1-$MAXCOREID*)
                 echo "Isolated CPU(s) OK, no reboot: $line">>$logfile
-                sed -i 's/PubkeyAuthentication no/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
-                service sshd restart
-                modprobe uio
-                insmod /opt/rapid/dpdk/build/kmod/igb_uio.ko
+                FILE=/opt/rapid/after_boot.sh
+                if test -f "$FILE"; then
+                  ("$FILE")
+                  echo "Executing: $FILE">>$logfile
+                fi
+                touch /opt/rapid/system_ready_for_rapid
                 exit 0
             ;;
             isolated_cores=*)
index e599164..f31ed25 100644 (file)
@@ -5,4 +5,4 @@ heat_template= openstack-rapid.yaml
 heat_param = params_rapid.yaml
 keypair_name = rapid_key
 user = centos
-push_gateway = None
+;push_gateway = http://192.168.36.61:9091/metrics/job/
index efdf5e1..4644a02 100755 (executable)
@@ -32,6 +32,8 @@ class RapidStackManager(object):
         options = config.options(section)
         for option in options:
             rapid_stack_params[option] = config.get(section, option)
+        if 'push_gateway' not in rapid_stack_params.keys():
+            rapid_stack_params['push_gateway'] = None
         return (rapid_stack_params)
 
     @staticmethod
index 0a1a292..3837012 100644 (file)
 
 # Directory for package build
 BUILD_DIR="/opt/rapid"
-DPDK_VERSION="19.05"
-PROX_COMMIT="b71a4cfd"
+DPDK_VERSION="20.05"
+PROX_COMMIT="7c3217fc16"
 PROX_CHECKOUT="git checkout ${PROX_COMMIT}"
 ## Next line is overruling the PROX_COMMIT and will replace the version with a very specific patch. Should be commented out
 ##     if you want to use a committed version of PROX with the COMMIT ID specified above
 ##Following line has the commit for testing IMIX, IPV6, ... It is the merge of all PROX commits on May 27th 2020
-PROX_CHECKOUT="git fetch \"https://gerrit.opnfv.org/gerrit/samplevnf\" refs/changes/23/70223/1 && git checkout FETCH_HEAD"
+#PROX_CHECKOUT="git fetch \"https://gerrit.opnfv.org/gerrit/samplevnf\" refs/changes/23/70223/1 && git checkout FETCH_HEAD"
 MULTI_BUFFER_LIB_VER="0.52"
 export RTE_SDK="${BUILD_DIR}/dpdk-${DPDK_VERSION}"
 export RTE_TARGET="x86_64-native-linuxapp-gcc"
@@ -42,13 +42,16 @@ function os_pkgs_install()
        ${SUDO} yum install -y deltarpm yum-utils
 
        # NASM repository for AESNI MB library
-       ${SUDO} yum-config-manager --add-repo http://www.nasm.us/nasm.repo
+       #${SUDO} yum-config-manager --add-repo http://www.nasm.us/nasm.repo
 
        [ "${OS_UPDATE}" == "y" ] && ${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 wireshark \
-                        make
+                        numactl-devel vim tuna openssl-devel wireshark \
+                        make driverctl
+
+       ${SUDO} wget https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/linux/nasm-2.14.02-0.fc27.x86_64.rpm
+       ${SUDO} rpm -ivh nasm-2.14.02-0.fc27.x86_64.rpm
 }
 
 function k8s_os_pkgs_runtime_install()
@@ -65,6 +68,9 @@ function os_cfg()
        # huge pages to be used by DPDK
        ${SUDO} sh -c '(echo "vm.nr_hugepages = 1024") > /etc/sysctl.conf'
 
+       ${SUDO} sh -c '(echo "options vfio enable_unsafe_noiommu_mode=1") > /etc/modprobe.d/vfio.conf'
+       ${SUDO} sh -c '(echo "vfio") > /etc/modules-load.d/vfio.conf'
+       ${SUDO} sh -c '(echo "vfio-pci") > /etc/modules-load.d/vfio.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
@@ -77,7 +83,7 @@ function os_cfg()
        # 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
+       echo "isolated_cores=1-3" | ${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
@@ -87,19 +93,6 @@ function os_cfg()
        ${SUDO} mv ${BUILD_DIR}/check-prox-system-setup.service /etc/systemd/system/
        ${SUDO} systemctl daemon-reload
        ${SUDO} systemctl enable check-prox-system-setup.service
-    # Following lines are added to fix the following issue: When the VM gets
-    # instantiated, the rapid scripts will try to ssh into the VM to start
-    # the testing. Once the script connects with ssh, it starts downloading
-    # config files and then start prox, etc... The problem is that when the VM
-    # boots, check_prox_system_setup.sh will check for some things and
-    # potentially reboot, resulting in losing the ssh connection again.
-    # To fix this issue, the following lines are disabling ssh access for the 
-    # centos user. The script will not be able to connect to the VM till ssh
-    # access is restored after a reboot. Restoring ssh is now done by
-    # check-prox-system-setup.service
-       printf "\nMatch User centos\n" | ${SUDO} tee -a /etc/ssh/sshd_config
-       printf "%sPubkeyAuthentication no\n" "    " | ${SUDO} tee -a /etc/ssh/sshd_config
-       printf "%sPasswordAuthentication no\n" "    " | ${SUDO} tee -a /etc/ssh/sshd_config
        popd > /dev/null 2>&1
 }
 
@@ -152,18 +145,16 @@ function dpdk_install()
 
        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
+       # Starting from DPDK 20.05, the IGB_UIO driver is not compiled by default.
+    # Uncomment the sed command to enable the driver compilation
+    #${SUDO} sed -i 's/CONFIG_RTE_EAL_IGB_UIO=n/c\/CONFIG_RTE_EAL_IGB_UIO=y' ${RTE_SDK}/build/.config
 
        # For Kubernetes environment we use host vfio module
        if [ "${K8S_ENV}" == "y" ]; then
                sed -i 's/CONFIG_RTE_EAL_IGB_UIO=y/CONFIG_RTE_EAL_IGB_UIO=n/g' ${RTE_SDK}/build/.config
                sed -i 's/CONFIG_RTE_LIBRTE_KNI=y/CONFIG_RTE_LIBRTE_KNI=n/g' ${RTE_SDK}/build/.config
                sed -i 's/CONFIG_RTE_KNI_KMOD=y/CONFIG_RTE_KNI_KMOD=n/g' ${RTE_SDK}/build/.config
-       fi
+    fi
 
        # 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
index f2e3fe2..fe7a5d4 100755 (executable)
@@ -2,8 +2,9 @@ link="$(sudo ip -o link | grep MACADDRESS |cut -d":" -f 2)"
 if [ -n "$link" ];
 then
        echo Need to bind
-       sudo /opt/rapid/dpdk/usertools/dpdk-devbind.py --force --bind igb_uio $(sudo /opt/rapid/dpdk/usertools/dpdk-devbind.py --status |grep  $link | cut -d" " -f 1)
+       #sudo /opt/rapid/dpdk/usertools/dpdk-devbind.py --force --bind igb_uio $(sudo /opt/rapid/dpdk/usertools/dpdk-devbind.py --status |grep  $link | cut -d" " -f 1)
+       sudo driverctl set-override $(sudo ethtool -i $link |grep bus-info | cut -d" " -f 2) vfio-pci
 else
-       echo Assuming port is already bound to DPDK
+       echo Assuming port is already bound to vfio-pci
 fi
 exit 0
index 852eed3..1827395 100644 (file)
@@ -27,6 +27,9 @@ name=p0
 rx desc=2048
 tx desc=2048
 vlan=yes
+vdev=gen_tap
+local ipv4=${local_ip1}
+
 
 [variables]
 $mbs=8
@@ -50,8 +53,6 @@ tx port=p0
 bps=1250000000
 pkt inline=00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 00 2e 00 01 00 00 40 11 f7 7d ${local_hex_ip1} ${dest_hex_ip1} 0b b8 0b b9 00 1a 55 7b
 pkt size=60
-;gateway ipv4=${gw_ip1}
-local ipv4=${local_ip1}
 min bulk size=$mbs
 max bulk size=16
 drop=yes
index 3b95875..fc3b6a6 100644 (file)
@@ -27,6 +27,8 @@ name=p0
 rx desc=2048
 tx desc=2048
 vlan=yes
+vdev=gen_tap
+local ipv4=${local_ip1}
 
 [variables]
 $mbs=8
@@ -51,7 +53,6 @@ bps=1250000000
 pkt inline=00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 00 2e 00 01 00 00 40 11 f7 7d ${local_hex_ip1} ${dest_hex_ip1} 0b b8 0b b9 00 1a 55 7b
 pkt size=60
 gateway ipv4=${gw_ip1}
-local ipv4=${local_ip1}
 min bulk size=$mbs
 max bulk size=16
 drop=yes
index 26c4b4e..d9d8628 100644 (file)
@@ -28,6 +28,8 @@ mac=hardware
 rx desc=2048
 tx desc=2048
 vlan=yes
+vdev=impair_tap
+local ipv4=${local_ip1}
 
 
 [defaults]
@@ -48,4 +50,3 @@ rx port=if0
 tx port=if0
 delay us=1000
 probability=100
-local ipv4=${local_ip1}
index 02e3852..a1d5c7b 100644 (file)
@@ -31,6 +31,7 @@ latcores = [3]
 name = ImpairGW
 config_file = impair.cfg
 cores = [1]
+monitor = False
 
 [TestM3]
 name = Swap
index f854c6a..966c073 100644 (file)
@@ -31,7 +31,7 @@ latcores = [3]
 [TestM2]
 name = Swap
 config_file = swapv6.cfg
-cores = [1,2]
+cores = [1]
 #prox_socket = true
 #prox_launch_exit = true
 
index 6ab5b45..e77ae03 100644 (file)
@@ -17,7 +17,7 @@
 [TestParameters]
 name = IRQTesting
 number_of_tests = 1
-total_number_of_test_machines = 2
+total_number_of_test_machines = 2 
 
 [TestM1]
 name = InterruptTestMachine1
index b25038d..2f61df5 100644 (file)
@@ -40,12 +40,25 @@ warmuptime=2
 
 [test2]
 test=flowsizetest
+# Following parameter defines the success criterium for the test.
+# When this test uses multiple combinations of packet size and flows,
+# all combinations must be meeting the same threshold
+# The threshold is expressed in Mpps
+pass_threshold=0.1
+# Each element in the imix list will result in a separate test. Each element
+# is on its turn a list of packet sizes which will be used during one test
+# execution. If you only want to test 1 size, define a list with only one
+# element.
 imixs=[[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, 65536, 131072, 262144, 524288, 1048576
-flows=[512,1]
+# the number of flows in the list need to be powers of 2, max 2^30
+# If not a power of 2, we will use the lowest power of 2 that is larger than
+# the requested number of flows. e.g. 9 will result in 16 flows
+flows=[512]
+# Setting one of the following thresholds to infinity (inf)
+# results in the criterion not being evaluated to rate the test as succesful
 drop_rate_threshold = 0
 lat_avg_threshold = 500
+lat_perc_threshold = 800
 lat_max_threshold = 1000
 accuracy = 0.1
 startspeed = 10
index 67a57ce..1d890d1 100644 (file)
@@ -40,6 +40,11 @@ warmuptime=2
 
 [test2]
 test=fixed_rate
+# Following parameter defines the success criterium for the test.
+# When this test uses multiple combinations of packet size and flows,
+# all combinations must be meeting the same threshold
+# The threshold is expressed in Mpps
+pass_threshold=0.1
 imixs=[[64],[128]]
 # the number of flows in the list need to be powers of 2, max 2^20
 # If not a power of 2, we will use the lowest power of 2 that is larger than
index 1c6fbee..16df087 100644 (file)
@@ -1,7 +1,7 @@
 heat_template_version: 2015-10-15
 
 description: >
-  Template for deploying n PROX instances. Teh template allows for deploying
+  Template for deploying n PROX instances. The template allows for deploying
   multiple groups of PROX VMs. You can create a first group with certain
   flavors, availability groups, etc... Another group can be created with
   different characteristics.
@@ -50,7 +50,8 @@ resources:
           PROX_mgmt_net_id: {get_param: mgmt_net_name}
           PROX_data_net_id: {get_param: data_net_name}
           PROX_config: {get_resource: MyConfig}
-    depends_on: MyConfig
+    depends_on:
+      - MyConfig
   
   PROX2VMs:
     type: OS::Heat::ResourceGroup
@@ -69,7 +70,8 @@ resources:
           PROX_mgmt_net_id: {get_param: mgmt_net_name}
           PROX_data_net_id: {get_param: data_net_name}
           PROX_config: {get_resource: MyConfig}
-    depends_on: MyConfig
+    depends_on:
+      - MyConfig
   
   MyConfig:
     type: OS::Heat::CloudConfig
@@ -88,6 +90,24 @@ resources:
           list:  |
               rapid:rapid
           expire: False
+        write_files:
+        - path: /opt/rapid/after_boot_do_not_run.sh
+          # after_boot.sh is ran by check_prox_system_setup.sh, if it exists
+          # This can be used to fix some issues, like in the example below
+          # Remove this section or rename the file, if you do not want to run
+          # this after booting
+          content: |
+            OLDIFS="${IFS}"
+            IFS=$'\n'
+            list="$(ip route | grep via | grep -v 'dev eth0')"
+            # Delete all routes using gateway on other interfaces than eth0
+            for item in ${list}
+              do /bin/bash -c "sudo ip route del ${item}"
+            done
+            /bin/bash -c "sudo ip route add default via 10.6.6.1 dev eth0"
+            /bin/bash -c "echo nameserver 8.8.8.8 > /etc/resolv.conf"
+            IFS="${OLDIFS}"
+          permissions: '0777'
 
 outputs:
   number_of_servers:
index 7c1884e..6d48d19 100644 (file)
@@ -1,6 +1,6 @@
 parameters:\r
   public_net_name: admin_floating_net\r
   data_net_name: dataplane-network\r
-  PROX_image: rapidVM\r
+  PROX_image: testrapidVM\r
   my_availability_zone: nova\r
   security_group: prox_security_group\r
index 43f7f14..3ee4e83 100644 (file)
@@ -46,7 +46,7 @@ class prox_ctrl(object):
         On failure, raise RuntimeWarning exception when possibly worth
         retrying, and raise RuntimeError exception otherwise.
         """
-        return self.run_cmd('true', True)
+        return self.run_cmd('test -e /opt/rapid/system_ready_for_rapid', True)
 
     def connect(self):
         attempts = 1
@@ -129,7 +129,8 @@ class prox_ctrl(object):
         try:
             return subprocess.check_output(cmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as ex:
-            if _connect and ex.returncode == 255:
+            #if _connect and ex.returncode == 255:
+            if _connect:
                 raise RuntimeWarning(ex.output.strip())
             raise RuntimeError('ssh returned exit status %d:\n%s'
                     % (ex.returncode, ex.output.strip()))
index 037aa12..dddd29c 100644 (file)
@@ -19,6 +19,7 @@
 
 import sys
 import time
+import requests
 from rapid_log import RapidLog
 from rapid_test import RapidTest
 
@@ -26,10 +27,8 @@ class CoreStatsTest(RapidTest):
     """
     Class to manage the corestatstesting
     """
-    def __init__(self, runtime, pushgateway, environment_file, machines):
-        self.runtime = runtime
-        self.pushgateway = pushgateway
-        self.environment_file = environment_file
+    def __init__(self, test_param,  runtime, pushgateway, environment_file, machines):
+        super().__init__(test_param, runtime, pushgateway, environment_file)
         self.machines = machines 
 
     def run(self):
@@ -41,7 +40,7 @@ class CoreStatsTest(RapidTest):
         RapidLog.info("+-----------+-----------+------------+------------+------------+------------+------------+------------+------------+")
         RapidLog.info("| PROX ID   |    Time   |    RX      |     TX     | non DP RX  | non DP TX  |   TX - RX  | nonDP TX-RX|  DROP TOT  |")
         RapidLog.info("+-----------+-----------+------------+------------+------------+------------+------------+------------+------------+")
-        duration = self.runtime
+        duration = self.test['runtime']
         tot_drop = []
         old_rx = []; old_non_dp_rx = []; old_tx = []; old_non_dp_tx = []; old_drop = []; old_tx_fail = []; old_tsc = []
         new_rx = []; new_non_dp_rx = []; new_tx = []; new_non_dp_tx = []; new_drop = []; new_tx_fail = []; new_tsc = []
@@ -75,8 +74,8 @@ class CoreStatsTest(RapidTest):
                 tot_drop[i] = tot_drop[i] + tx - rx
                 RapidLog.info('|{:>10.0f}'.format(i)+ ' |{:>10.0f}'.format(duration)+' | ' + '{:>10.0f}'.format(rx) + ' | ' +'{:>10.0f}'.format(tx) + ' | '+'{:>10.0f}'.format(non_dp_rx)+' | '+'{:>10.0f}'.format(non_dp_tx)+' | ' + '{:>10.0f}'.format(tx-rx) + ' | '+ '{:>10.0f}'.format(non_dp_tx-non_dp_rx) + ' | '+'{:>10.0f}'.format(tot_drop[i]) +' |')
     #            writer.writerow({'PROXID':i,'Time':duration,'Received':rx,'Sent':tx,'NonDPReceived':non_dp_rx,'NonDPSent':non_dp_tx,'Delta':tx-rx,'NonDPDelta':non_dp_tx-non_dp_rx,'Dropped':tot_drop[i]})
-                if self.pushgateway:
-                    URL = self.pushgateway+ '/metrics/job/' + TestName + '/instance/' + self.environment_file + str(i)
+                if self.test['pushgateway']:
+                    URL = self.test['pushgateway'] + self.test['test']+ '/instance/' + self.test['environment_file'] + str(i)
                     DATA = 'PROXID {}\nTime {}\n Received {}\nSent {}\nNonDPReceived {}\nNonDPSent {}\nDelta {}\nNonDPDelta {}\nDropped {}\n'.format(i,duration,rx,tx,non_dp_rx,non_dp_tx,tx-rx,non_dp_tx-non_dp_rx,tot_drop[i])
                     HEADERS = {'X-Requested-With': 'Python requests', 'Content-type': 'text/xml'}
                     response = requests.post(url=URL, data=DATA,headers=HEADERS)
index 0c5f809..da53742 100644 (file)
@@ -19,6 +19,7 @@
 
 import sys
 import time
+import requests
 from math import ceil
 from statistics import mean
 from past.utils import old_div
@@ -33,21 +34,17 @@ class FlowSizeTest(RapidTest):
     """
     def __init__(self, test_param, lat_percentile, runtime, pushgateway,
             environment_file, gen_machine, sut_machine, background_machines):
-        self.test = test_param
+        super().__init__(test_param, runtime, pushgateway, environment_file)
         self.gen_machine = gen_machine
         self.sut_machine = sut_machine
         self.background_machines = background_machines
         self.test['lat_percentile'] = lat_percentile
-        self.test['runtime'] = runtime
-        self.test['pushgateway'] = pushgateway
-        self.test['environment_file'] = environment_file
-        if 'maxr' not in self.test.keys():
-            self.test['maxr'] = 1
-        if 'maxz' not in self.test.keys():
-            self.test['maxz'] = inf
         if self.test['test'] == 'TST009test':
-            # This test implements some of the testing as defined in https://docbox.etsi.org/ISG/NFV/open/Publications_pdf/Specs-Reports/NFV-TST%20009v3.2.1%20-%20GS%20-%20NFVI_Benchmarks.pdf
-            self.test['TST009_n'] = int(ceil(old_div(self.test['maxframespersecondallingress'], self.test['stepsize'])))
+            # This test implements some of the testing as defined in
+            # https://docbox.etsi.org/ISG/NFV/open/Publications_pdf/Specs-Reports/NFV-TST%20009v3.2.1%20-%20GS%20-%20NFVI_Benchmarks.pdf
+            self.test['TST009_n'] = int(ceil(old_div(
+                self.test['maxframespersecondallingress'],
+                self.test['stepsize'])))
             self.test['TST009'] = True
             self.test['TST009_L'] = 0
             self.test['TST009_R'] = self.test['TST009_n'] - 1
@@ -58,7 +55,8 @@ class FlowSizeTest(RapidTest):
             self.test['lat_perc_threshold'] = inf
             self.test['lat_max_threshold'] = inf
         elif self.test['test'] == 'fixed_rate':
-            for key in['drop_rate_threshold','lat_avg_threshold','lat_perc_threshold','lat_max_threshold']:
+            for key in['drop_rate_threshold','lat_avg_threshold',
+                    'lat_perc_threshold','lat_max_threshold']:
                 self.test[key] = inf
 
     def new_speed(self, speed,size,success):
@@ -244,7 +242,7 @@ class FlowSizeTest(RapidTest):
                     RapidLog.info("+--------+------------------+-------------+-------------+-------------+------------------------+----------+----------+----------+-----------+-----------+-----------+-----------+-------+----+")
     #                writer.writerow({'Flows':flow_number,'PacketSize':(size+4),'RequestedPPS':self.get_pps(endspeed,size),'GeneratedPPS':endpps_req_tx,'SentPPS':endpps_tx,'ForwardedPPS':endpps_sut_tx,'ReceivedPPS':endpps_rx,'AvgLatencyUSEC':endlat_avg,'MaxLatencyUSEC':endlat_max,'Sent':endabs_tx,'Received':endabs_rx,'Lost':endabs_dropped,'LostTotal':endabs_dropped})
                     if self.test['pushgateway']:
-                        URL = self.test['pushgateway'] + '/metrics/job/' + self.test['test']+ '/instance/' + self.test['environment_file']
+                        URL = self.test['pushgateway'] + self.test['test']+ '/instance/' + self.test['environment_file']
                         if endabs_dropped == None:
                             ead = 0
                         else:
index 748dcf3..8206729 100644 (file)
 
 import sys
 import time
+import requests
 from rapid_log import RapidLog
 from rapid_test import RapidTest
+from statistics import mean
 
 class ImpairTest(RapidTest):
     """
     Class to manage the impair testing
     """
     def __init__(self, test_param, lat_percentile, runtime, pushgateway,
-            environment_file, gen_machine):
-        self.test = test_param
+            environment_file, gen_machine, sut_machine):
+        super().__init__(test_param, runtime, pushgateway, environment_file)
         self.gen_machine = gen_machine
         self.sut_machine = sut_machine
         self.test['lat_percentile'] = lat_percentile
-        self.test['runtime'] = runtime
-        self.test['pushgateway'] = pushgateway
-        self.test['environment_file'] = environment_file
 
     def run(self):
     #    fieldnames = ['Flows','PacketSize','RequestedPPS','GeneratedPPS','SentPPS','ForwardedPPS','ReceivedPPS','AvgLatencyUSEC','MaxLatencyUSEC','Dropped','DropRate']
@@ -47,11 +46,12 @@ class ImpairTest(RapidTest):
         self.gen_machine.set_udp_packet_size(imix)
         flow_number = self.gen_machine.set_flows(flow_number)
         self.gen_machine.start_latency_cores()
-        RapidLog.info("+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+")
-        RapidLog.info("| Generator is sending UDP ("+'{:>5}'.format(flow_number)+" flow) packets ("+ '{:>5}'.format(size) +" bytes) to SUT via GW dropping and delaying packets. SUT sends packets back. Use ctrl-c to stop the test    |")
-        RapidLog.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
-        RapidLog.info("| Test   |  Speed requested   | Sent to NIC    |  Sent by Gen   | Forward by SUT |  Rec. by Gen   |  Avg. Latency  |  Max. Latency  |  Packets Lost  | Loss Ratio |")
-        RapidLog.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
+        RapidLog.info("+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+")
+        RapidLog.info("| Generator is sending UDP ({:>5} flow) packets ({:>5} bytes) to SUT via GW dropping and delaying packets. SUT sends packets back. Use ctrl-c to stop the test                               |".format(flow_number,size))
+        RapidLog.info("+--------+------------------+-------------+-------------+-------------+------------------------+----------+----------+----------+-----------+-----------+-----------+-----------+-------+----+")
+        RapidLog.info('| Test   | Speed requested  | Gen by core | Sent by NIC | Fwrd by SUT | Rec. by core           | Avg. Lat.|{:.0f} Pcentil| Max. Lat.|   Sent    |  Received |    Lost   | Total Lost|L.Ratio|Time|'.format(self.test['lat_percentile']*100))
+        RapidLog.info("+--------+------------------+-------------+-------------+-------------+------------------------+----------+----------+----------+-----------+-----------+-----------+-----------+-------+----+")
+
         speed = self.test['startspeed']
         self.gen_machine.set_generator_speed(speed)
         while True:
@@ -60,17 +60,18 @@ class ImpairTest(RapidTest):
             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_perc, lat_perc_max, lat_max, abs_dropped, abs_tx_fail, abs_tx, lat_min, lat_used, r, actual_duration = run_iteration(float(self.test['runtime']),flow_number,size,speed)
-            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
+            pps_req_tx,pps_tx,pps_sut_tx,pps_rx,lat_avg, lat_perc, lat_perc_max, lat_max, abs_tx, abs_rx, abs_dropped, abs_tx_fail, drop_rate, lat_min, lat_used, r, actual_duration = self.run_iteration(float(self.test['runtime']),flow_number,size,speed)
+            # Drop rate is expressed in percentage. lat_used is a ratio (0 to 1). The sum of these 2 should be 100%.
+            # If the sum is lower than 95, it means that more than 5% of the latency measurements where dropped for accuracy reasons.
+            if (drop_rate + lat_used * 100) < 95:
+                lat_warning = bcolors.WARNING + ' Latency accuracy issue?: {:>3.0f}%'.format(lat_used*100) +  bcolors.ENDC
             else:
                 lat_warning = ''
-            RapidLog.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({'Flows':flow_number,'PacketSize':(size+4),'RequestedPPS':get_pps(speed,size),'GeneratedPPS':pps_req_tx,'SentPPS':pps_tx,'ForwardedPPS':pps_sut_tx_str,'ReceivedPPS':pps_rx,'AvgLatencyUSEC':lat_avg,'MaxLatencyUSEC':lat_max,'Dropped':abs_dropped,'DropRate':drop_rate})
+            RapidLog.info(self.report_result(attempts,size,speed,pps_req_tx,pps_tx,pps_sut_tx,pps_rx,lat_avg,lat_perc,lat_perc_max,lat_max,abs_tx,abs_rx,abs_dropped,actual_duration))
+#        writer.writerow({'Flows':flow_number,'PacketSize':(size+4),'RequestedPPS':self.get_pps(speed,size),'GeneratedPPS':pps_req_tx,'SentPPS':pps_tx,'ForwardedPPS':pps_sut_tx_str,'ReceivedPPS':pps_rx,'AvgLatencyUSEC':lat_avg,'MaxLatencyUSEC':lat_max,'Dropped':abs_dropped,'DropRate':drop_rate})
             if self.test['pushgateway']:
-                URL     = self.test['pushgateway'] + '/metrics/job/' + TestName + '/instance/' + self.test['environment_file'] 
-                DATA = 'Flows {}\nPacketSize {}\nRequestedPPS {}\nGeneratedPPS {}\nSentPPS {}\nForwardedPPS {}\nReceivedPPS {}\nAvgLatencyUSEC {}\nMaxLatencyUSEC {}\nDropped {}\nDropRate {}\n'.format(flow_number,size+4,get_pps(speed,size),pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max,abs_dropped,drop_rate)
+                URL     = self.test['pushgateway'] + self.test['test'] + '/instance/' + self.test['environment_file'] 
+                DATA = 'Flows {}\nPacketSize {}\nRequestedPPS {}\nGeneratedPPS {}\nSentPPS {}\nForwardedPPS {}\nReceivedPPS {}\nAvgLatencyUSEC {}\nMaxLatencyUSEC {}\nDropped {}\nDropRate {}\n'.format(flow_number,size+4,self.get_pps(speed,size),pps_req_tx,pps_tx,pps_sut_tx,pps_rx,lat_avg,lat_max,abs_dropped,drop_rate)
                 HEADERS = {'X-Requested-With': 'Python requests', 'Content-type': 'text/xml'}
                 response = requests.post(url=URL, data=DATA,headers=HEADERS)
                 if (response.status_code != 202) and (response.status_code != 200):
index 5134d22..feabe65 100644 (file)
@@ -20,6 +20,7 @@
 from past.utils import old_div
 import sys
 import time
+import requests
 from rapid_log import RapidLog
 from rapid_test import RapidTest
 
@@ -27,8 +28,9 @@ class IrqTest(RapidTest):
     """
     Class to manage the irq testing
     """
-    def __init__(self, runtime, machines):
-        self.runtime = runtime
+    def __init__(self, test_param, runtime, pushgateway, environment_file,
+            machines):
+        super().__init__(test_param, runtime, pushgateway, environment_file)
         self.machines = machines
 
     def run(self):
@@ -55,17 +57,29 @@ class IrqTest(RapidTest):
             for j,bucket in enumerate(buckets,start=1):
                 for i,irqcore in enumerate(machine.get_cores(),start=1):
                     old_irq[i][j] = machine.socket.irq_stats(irqcore,j-1)
-            time.sleep(float(self.runtime))
+            time.sleep(float(self.test['runtime']))
             machine.stop()
             for i,irqcore in enumerate(machine.get_cores(),start=1):
-                irq[i][0]='core %s '%irqcore
+                irq[i][0]='core %s'%irqcore
                 for j,bucket in enumerate(buckets,start=1):
                     diff =  machine.socket.irq_stats(irqcore,j-1) - old_irq[i][j]
                     if diff == 0:
                         irq[i][j] = '0'
                     else:
-                        irq[i][j] = str(round(old_div(diff,float(self.runtime)), 2))
+                        irq[i][j] = str(round(old_div(diff,float(self.test['runtime'])), 2))
             RapidLog.info('Results for PROX instance %s'%machine.name)
             for row in irq:
                 RapidLog.info(''.join(['{:>12}'.format(item) for item in row]))
+            if self.test['pushgateway']:
+                URL = self.test['pushgateway'] + self.test['test']+ '/instance/' + self.test['environment_file']
+                HEADERS = {'X-Requested-With': 'Python requests', 'Content-type': 'text/xml'}
+                #DATA = 'Machine {}\n'.format(machine.name)
+                for i,irqcore in enumerate(machine.get_cores(),start=1):
+                    DATA = '{}\n'.format(irq[i][0])
+                    for j,bucket in enumerate(buckets,start=1):
+                        DATA = DATA + 'B{} {}\n'.format(irq[0][j].replace(">","M").replace("<","").replace(" ",""),irq[i][j])
+                    response = requests.post(url=URL, data=DATA,headers=HEADERS)
+                    if (response.status_code != 202) and (response.status_code != 200):
+                        RapidLog.info('Cannot send metrics to {}'.format(URL))
+                        RapidLog.info(DATA)
         return (True)
index 2b9e047..9c79458 100644 (file)
@@ -96,7 +96,7 @@ class RapidLog(object):
         # Add timestamp
         log.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
 
-        log.debug("runrapid.py version: " + version)
+        log.debug("rapid version: " + version)
         RapidLog.log = log
 
     @staticmethod
index c45ea65..7a5ebd4 100644 (file)
@@ -115,4 +115,4 @@ class RapidMachine(object):
         return (self.socket.core_stats(self.get_cores(), self.all_tasks_for_this_cfg))
 
     def multi_port_stats(self):
-        return (self.socket.multi_port_stats(self.self.dpdk_port_index))
+        return (self.socket.multi_port_stats(self.dpdk_port_index))
index 6dd2e21..df71811 100644 (file)
@@ -40,15 +40,16 @@ class RapidConfigParser(object):
             test_params['lat_percentile'] = old_div(float(testconfig.get('TestParameters', 'lat_percentile')),100.0)
         else:
             test_params['lat_percentile'] = 0.99
-        RapidLog.info('Latency percentile measured at {:.0f}%'.format(test_params['lat_percentile']*100))
+        RapidLog.info('Latency percentile at {:.0f}%'.format(test_params['lat_percentile']*100))
         config = configparser.RawConfigParser()
         config.read(test_params['environment_file'])
         test_params['vim_type'] = config.get('Varia', 'vim')
         test_params['key'] = config.get('ssh', 'key')
         test_params['user'] = config.get('ssh', 'user')
         test_params['total_number_of_machines'] = int(config.get('rapid', 'total_number_of_machines'))
-        if config.has_option('TestParameters', 'pushgateway'):
-            test_params['pushgateway'] = config.get('TestParameters', 'pushgateway')
+        #if config.has_option('TestParameters', 'pushgateway'):
+        if config.has_option('Varia', 'pushgateway'):
+            test_params['pushgateway'] = config.get('Varia', 'pushgateway')
             RapidLog.info('Measurements will be pushed to %s'%test_params['pushgateway'])
         else:
             test_params['pushgateway'] = None
@@ -62,7 +63,7 @@ class RapidConfigParser(object):
                 if option in ['imix','imixs','flows']:
                     test[option] = ast.literal_eval(testconfig.get(section, option))
 #                    test[option] = [int(i) for i in test[option]]
-                elif option in ['maxframespersecondallingress','stepsize']:
+                elif option in ['maxframespersecondallingress','stepsize','flowsize']:
                     test[option] = int(testconfig.get(section, option))
                 elif option in ['startspeed','drop_rate_threshold','lat_avg_threshold','lat_perc_threshold','lat_max_threshold','accuracy','maxr','maxz','pass_threshold']:
                     test[option] = float(testconfig.get(section, option))
@@ -126,7 +127,7 @@ class RapidConfigParser(object):
                 while True:
                     gw_ip_key = 'dp_ip{}'.format(index)
                     if gw_ip_key in machines[int(machine['gw_vm'])-1].keys():
-                        gw_ip = machines[int(machine['dest_vm'])-1][gw_ip_key]
+                        gw_ip = machines[int(machine['gw_vm'])-1][gw_ip_key]
                         gw_ips.append(gw_ip)
                         index += 1
                     else:
index afafe8e..6991e87 100644 (file)
@@ -19,6 +19,7 @@
 
 import sys
 import time
+import requests
 from rapid_log import RapidLog
 from rapid_test import RapidTest
 
@@ -26,10 +27,9 @@ class PortStatsTest(RapidTest):
     """
     Class to manage the portstatstesting
     """
-    def __init__(self, runtime, pushgateway, environment_file, machines):
-        self.runtime = runtime
-        self.pushgateway = pushgateway
-        self.environment_file = environment_file
+    def __init__(self, test_param, runtime, pushgateway, environment_file,
+            machines):
+        super().__init__(test_param, runtime, pushgateway, environment_file)
         self.machines = machines 
 
     def run(self):
@@ -41,7 +41,7 @@ class PortStatsTest(RapidTest):
         RapidLog.info("+-----------+-----------+------------+------------+------------+------------+")
         RapidLog.info("| PROX ID   |    Time   |    RX      |     TX     | no MBUFS   | ierr&imiss |")
         RapidLog.info("+-----------+-----------+------------+------------+------------+------------+")
-        duration = float(runtime)
+        duration = float(self.test['runtime'])
         old_rx = []; old_tx = []; old_no_mbufs = []; old_errors = []; old_tsc = []
         new_rx = []; new_tx = []; new_no_mbufs = []; new_errors = []; new_tsc = []
         machines_to_go = len (self.machines)
@@ -70,8 +70,8 @@ class PortStatsTest(RapidTest):
                 old_tsc[i] = new_tsc[i]
                 RapidLog.info('|{:>10.0f}'.format(i)+ ' |{:>10.0f}'.format(duration)+' | ' + '{:>10.0f}'.format(rx) + ' | ' +'{:>10.0f}'.format(tx) + ' | '+'{:>10.0f}'.format(no_mbufs)+' | '+'{:>10.0f}'.format(errors)+' |')
     #            writer.writerow({'PROXID':i,'Time':duration,'Received':rx,'Sent':tx,'NoMbufs':no_mbufs,'iErrMiss':errors})
-                if self.pushgateway:
-                    URL     = self.pushgateway + '/metrics/job/' + TestName + '/instance/' + self.environment_file + str(i)
+                if self.test['pushgateway']:
+                    URL     = self.test['pushgateway'] + self.test['test'] + '/instance/' + self.test['environment_file'] + str(i)
                     DATA = 'PROXID {}\nTime {}\n Received {}\nSent {}\nNoMbufs {}\niErrMiss {}\n'.format(i,duration,rx,tx,no_mbufs,errors)
                     HEADERS = {'X-Requested-With': 'Python requests', 'Content-type': 'text/xml'}
                     response = requests.post(url=URL, data=DATA,headers=HEADERS)
index 8703034..0b0b204 100644 (file)
@@ -21,11 +21,22 @@ import time
 from past.utils import old_div
 from rapid_log import RapidLog
 from rapid_log import bcolors
+inf = float("inf")
 
 class RapidTest(object):
     """
-    Class to manage the flowsizetesting
+    Class to manage the testing
     """
+    def __init__(self, test_param,  runtime, pushgateway, environment_file ):
+        self.test = test_param
+        self.test['runtime'] = runtime
+        self.test['pushgateway'] = pushgateway
+        self.test['environment_file'] = environment_file
+        if 'maxr' not in self.test.keys():
+            self.test['maxr'] = 1
+        if 'maxz' not in self.test.keys():
+            self.test['maxz'] = inf
+
     @staticmethod
     def get_percentageof10Gbps(pps_speed,size):
         # speed is given in pps, returning % of 10Gb/s
index 67eeea9..db4e969 100755 (executable)
@@ -92,11 +92,11 @@ class RapidTestManager(object):
                         test_params['environment_file'], gen_machine,
                         sut_machine, background_machines)
             elif test_param['test'] in ['corestats']:
-                test = CoreStatsTest(test_params['runtime'],
+                test = CoreStatsTest(test_param, test_params['runtime'],
                         test_params['pushgateway'],
                         test_params['environment_file'], machines)
             elif test_param['test'] in ['portstats']:
-                test = PortStatsTest(test_params['runtime'],
+                test = PortStatsTest(test_param, test_params['runtime'],
                         test_params['pushgateway'],
                         test_params['environment_file'], machines)
             elif test_param['test'] in ['impairtest']:
@@ -105,7 +105,9 @@ class RapidTestManager(object):
                         test_params['environment_file'], gen_machine,
                         sut_machine)
             elif test_param['test'] in ['irqtest']:
-                test = IrqTest(test_params['runtime'], machines)
+                test = IrqTest(test_param, test_params['runtime'],
+                        test_params['pushgateway'],
+                        test_params['environment_file'], machines)
             elif test_param['test'] in ['warmuptest']:
                 test = WarmupTest(test_param, gen_machine)
             else:
index 3d05ee7..525cff1 100755 (executable)
@@ -106,7 +106,8 @@ class StackDeployment(object):
             env_file.write('[Varia]\n')
             env_file.write('vim = OpenStack\n')
             env_file.write('stack = {}\n'.format(self.stack.stack_name))
-            env_file.write('pushgateway = {}\n'.format(push_gateway))
+            if push_gateway:
+                env_file.write('pushgateway = {}\n'.format(push_gateway))
 
     def create_stack(self, stack_name, stack_file_path, param_file):
         files, template = template_utils.process_template_path(stack_file_path)
index a3d4d26..0cca80c 100644 (file)
@@ -26,6 +26,8 @@ eal=--proc-type auto ${eal}
 name=if0
 mac=hardware
 vlan=yes
+vdev=swap_tap
+local ipv4=${local_ip1}
 
 [defaults]
 mempool size=8K
@@ -43,6 +45,5 @@ mode=swap
 sub mode=l3
 rx port=if0
 tx port=if0
-local ipv4=${local_ip1}
 drop=no
 ;arp update time=1