aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x3rd_party/ixia/GeneveIxNetTemplate.xml_ClearText.xml (renamed from tools/pkt_gen/ixnet/GeneveIxNetTemplate.xml_ClearText.xml)0
-rw-r--r--3rd_party/ixia/ixnetrfc2544.tcl (renamed from tools/pkt_gen/ixnet/ixnetrfc2544.tcl)0
-rwxr-xr-x3rd_party/ixia/ixnetrfc2544v2.tcl (renamed from tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl)0
-rwxr-xr-x3rd_party/ixia/pass_fail.tcl (renamed from tools/pkt_gen/ixia/pass_fail.tcl)6
-rw-r--r--3rd_party/readme.txt1
-rw-r--r--INFO1
-rwxr-xr-xci/build-vsperf.sh133
-rwxr-xr-xconf/01_testcases.conf13
-rw-r--r--conf/02_vswitch.conf8
-rw-r--r--conf/03_traffic.conf25
-rw-r--r--conf/04_vnf.conf38
-rw-r--r--conf/10_custom.conf4
-rw-r--r--conf/__init__.py93
-rw-r--r--conf/integration/01_testcases.conf261
-rw-r--r--conf/integration/03_traffic.conf3
-rw-r--r--core/__init__.py2
-rw-r--r--core/component_factory.py10
-rw-r--r--core/traffic_controller.py124
-rw-r--r--core/traffic_controller_rfc2544.py111
-rw-r--r--core/traffic_controller_rfc2889.py112
-rw-r--r--core/vnf_controller.py17
-rwxr-xr-xdocs/configguide/installation.rst10
-rw-r--r--docs/configguide/trafficgen.rst9
-rwxr-xr-xdocs/design/vswitchperf_design.rst3
-rwxr-xr-xdocs/requirements/ietf_draft/draft-ietf-bmwg-vswitch-opnfv-01.xml1027
-rw-r--r--docs/requirements/vswitchperf_ltp.rst2
-rw-r--r--docs/userguide/index.rst1
-rwxr-xr-xdocs/userguide/integration.rst418
-rw-r--r--docs/userguide/teststeps.rst651
-rwxr-xr-xdocs/userguide/testusage.rst314
-rwxr-xr-xsrc/dpdk/Makefile1
-rw-r--r--src/dpdk/dpdk.py8
-rwxr-xr-xsystems/rhel/7.2/build_base_machine.sh24
-rwxr-xr-xsystems/rhel/7.2/prepare_python_env.sh17
-rw-r--r--testcases/integration.py188
-rw-r--r--testcases/performance.py2
-rw-r--r--testcases/testcase.py260
-rwxr-xr-xtools/pkt_gen/ixia/ixia.py12
-rwxr-xr-xtools/pkt_gen/ixnet/ixnet.py21
-rw-r--r--tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py3
-rw-r--r--tools/pkt_gen/testcenter/testcenter-rfc2544-throughput.py3
-rw-r--r--tools/report/report.jinja1
-rw-r--r--tools/systeminfo.py5
-rw-r--r--tools/teststepstools.py90
-rw-r--r--vnfs/qemu/qemu.py127
-rwxr-xr-xvsperf58
-rw-r--r--vswitches/ovs_dpdk_vhost.py5
47 files changed, 3050 insertions, 1172 deletions
diff --git a/tools/pkt_gen/ixnet/GeneveIxNetTemplate.xml_ClearText.xml b/3rd_party/ixia/GeneveIxNetTemplate.xml_ClearText.xml
index 56539d31..56539d31 100755
--- a/tools/pkt_gen/ixnet/GeneveIxNetTemplate.xml_ClearText.xml
+++ b/3rd_party/ixia/GeneveIxNetTemplate.xml_ClearText.xml
diff --git a/tools/pkt_gen/ixnet/ixnetrfc2544.tcl b/3rd_party/ixia/ixnetrfc2544.tcl
index e70ca874..e70ca874 100644
--- a/tools/pkt_gen/ixnet/ixnetrfc2544.tcl
+++ b/3rd_party/ixia/ixnetrfc2544.tcl
diff --git a/tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl b/3rd_party/ixia/ixnetrfc2544v2.tcl
index 539c5a5b..539c5a5b 100755
--- a/tools/pkt_gen/ixnet/ixnetrfc2544v2.tcl
+++ b/3rd_party/ixia/ixnetrfc2544v2.tcl
diff --git a/tools/pkt_gen/ixia/pass_fail.tcl b/3rd_party/ixia/pass_fail.tcl
index 79b7f10d..0a5a7677 100755
--- a/tools/pkt_gen/ixia/pass_fail.tcl
+++ b/3rd_party/ixia/pass_fail.tcl
@@ -422,7 +422,11 @@ proc sendTraffic { flowSpec trafficSpec } {
udp setDefault
udp config -sourcePort $srcPort
udp config -destPort $dstPort
- set packetSize [dict get $trafficSpec_l3 packetsize]
+ if {[dict exists $trafficSpec_l3 packetsize]} {
+ set packetSize [dict get $trafficSpec_l3 packetsize]
+ } else {
+ set packetSize $frameSize
+ }
stream config -framesize $packetSize
if {[udp set $::chassis $::card $::port1]} {
errorMsg "Error setting udp on port $::chassis.$::card.$::port1"
diff --git a/3rd_party/readme.txt b/3rd_party/readme.txt
new file mode 100644
index 00000000..fc308dc8
--- /dev/null
+++ b/3rd_party/readme.txt
@@ -0,0 +1 @@
+Here are located files and scripts, which are not released under Apache 2.0 license.
diff --git a/INFO b/INFO
index 9a8889be..0ac5b18c 100644
--- a/INFO
+++ b/INFO
@@ -11,7 +11,6 @@ Repository: vswitchperf
Commiters:
maryam.tahhan@intel.com
-Eugene.Snider@huawei.com
acmorton@att.com
ctrautma@redhat.com
martinx.klozik@intel.com
diff --git a/ci/build-vsperf.sh b/ci/build-vsperf.sh
index a02de009..16e4625e 100755
--- a/ci/build-vsperf.sh
+++ b/ci/build-vsperf.sh
@@ -26,6 +26,7 @@
EXIT=0
EXIT_TC_FAILED=1
+EXIT_SANITY_TC_FAILED=2
EXIT_NO_RESULTS=10
EXIT_NO_TEST_REPORT_LOG_DIR=11
@@ -37,17 +38,18 @@ VSPERF_BIN='./vsperf'
LOG_FILE_PREFIX="/tmp/vsperf_build"
DATE=$(date -u +"%Y-%m-%d_%H-%M-%S")
BRANCH=${GIT_BRANCH##*/}
+VSPERFENV_DIR="$HOME/vsperfenv"
# CI job specific configuration
# VERIFY - run basic set of TCs with default settings
-TESTCASES_VERIFY="phy2phy_tput pvp_tput"
-TESTPARAM_VERIFY=""
+TESTCASES_VERIFY="vswitch_add_del_bridge vswitch_add_del_bridges vswitch_add_del_vport vswitch_add_del_vports vswitch_vports_add_del_flow"
+TESTPARAM_VERIFY="--integration --test-params HUGEPAGE_RAM_ALLOCATION=2097152"
# MERGE - run selected TCs with default settings
-TESTCASES_MERGE="phy2phy_tput back2back phy2phy_cont pvp_tput pvvp_tput"
-TESTPARAM_MERGE=""
+TESTCASES_MERGE="vswitch_add_del_bridge vswitch_add_del_bridges vswitch_add_del_vport vswitch_add_del_vports vswitch_vports_add_del_flow"
+TESTPARAM_MERGE="--integration --test-params HUGEPAGE_RAM_ALLOCATION=2097152"
# DAILY - run selected TCs for defined packet sizes
TESTCASES_DAILY='phy2phy_tput back2back phy2phy_tput_mod_vlan phy2phy_scalability pvp_tput pvp_back2back pvvp_tput pvvp_back2back'
-TESTPARAM_DAILY='--test-params pkt_sizes=64,128,512,1024,1518'
+TESTPARAM_DAILY='--test-params TRAFFICGEN_PKT_SIZES=(64,128,512,1024,1518)'
# check if user config file exists if not then we will use default settings
if [ -f $HOME/vsperf-${BRANCH}.conf ] ; then
# branch specific config was found
@@ -109,19 +111,17 @@ function terminate_vsperf() {
# $1 - directory with results
function print_results() {
for i in $TESTCASES ; do
- if [[ $i == *"pvp"* ]]; then
- DEPLOYMENT="pvp"
- elif [[ $i == *"pvvp"* ]]; then
- DEPLOYMENT="pvvp"
- else
- DEPLOYMENT="p2p"
- fi
- RES_FILE="result_${i}_${DEPLOYMENT}.csv"
+ RES_FILE=`ls -1 $1 | egrep "result_${i}_[0-9a-zA-Z\-]+.csv"`
- if [ -e "${1}/${RES_FILE}" ]; then
- printf " %-70s %-6s\n" $RES_FILE "OK"
+ if [ "x$RES_FILE" != "x" -a -e "${1}/${RES_FILE}" ]; then
+ if grep ^FAILED "${1}/${RES_FILE}" &> /dev/null ; then
+ printf " %-70s %-6s\n" "result_${i}" "FAILED"
+ EXIT=$EXIT_TC_FAILED
+ else
+ printf " %-70s %-6s\n" "result_${i}" "OK"
+ fi
else
- printf " %-70s %-6s\n" $RES_FILE "FAILED"
+ printf " %-70s %-6s\n" "result_${i}" "FAILED"
EXIT=$EXIT_TC_FAILED
fi
done
@@ -132,6 +132,7 @@ function print_results() {
# $1 - vswitch and vnf combination, one of OVS_vanilla, OVS_with_DPDK_and_vHost_User
# $2 - CI job type, one of verify, merge, daily
function execute_vsperf() {
+ OPNFVPOD=""
# figure out list of TCs and execution parameters
case $2 in
"verify")
@@ -143,9 +144,10 @@ function execute_vsperf() {
TESTCASES=$TESTCASES_MERGE
;;
*)
- # by default use daily build
+ # by default use daily build and upload results to the OPNFV databse
TESTPARAM=$TESTPARAM_DAILY
TESTCASES=$TESTCASES_DAILY
+ OPNFVPOD="--opnfvpod=$NODE_NAME"
;;
esac
@@ -160,16 +162,16 @@ function execute_vsperf() {
LOG_SUBDIR="OvsVanilla"
LOG_FILE="${LOG_FILE_PREFIX}_${LOG_SUBDIR}_${DATE_SUFFIX}.log"
- echo "$VSPERF_BIN --opnfvpod="$NODE_NAME" --vswitch OvsVanilla --vnf QemuVirtioNet $CONF_FILE $TESTPARAM $TESTCASES &> $LOG_FILE"
- $VSPERF_BIN --opnfvpod="$NODE_NAME" --vswitch OvsVanilla --vnf QemuVirtioNet $CONF_FILE $TESTPARAM $TESTCASES &> $LOG_FILE
+ echo " $VSPERF_BIN $OPNFVPOD --vswitch OvsVanilla --vnf QemuVirtioNet $CONF_FILE $TESTPARAM $TESTCASES &> $LOG_FILE"
+ $VSPERF_BIN $OPNFVPOD --vswitch OvsVanilla --vnf QemuVirtioNet $CONF_FILE $TESTPARAM $TESTCASES &> $LOG_FILE
;;
*)
# figure out log file name
LOG_SUBDIR="OvsDpdkVhost"
LOG_FILE="${LOG_FILE_PREFIX}_${LOG_SUBDIR}_${DATE_SUFFIX}.log"
- echo "$VSPERF_BIN --opnfvpod="$NODE_NAME" --vswitch OvsDpdkVhost --vnf QemuDpdkVhostUser $CONF_FILE $TESTPARAM $TESTCASES > $LOG_FILE"
- $VSPERF_BIN --opnfvpod="$NODE_NAME" --vswitch OvsDpdkVhost --vnf QemuDpdkVhostUser $CONF_FILE $TESTPARAM $TESTCASES &> $LOG_FILE
+ echo " $VSPERF_BIN $OPNFVPOD --vswitch OvsDpdkVhost --vnf QemuDpdkVhostUser $CONF_FILE $TESTPARAM $TESTCASES > $LOG_FILE"
+ $VSPERF_BIN $OPNFVPOD --vswitch OvsDpdkVhost --vnf QemuDpdkVhostUser $CONF_FILE $TESTPARAM $TESTCASES &> $LOG_FILE
;;
esac
@@ -178,9 +180,17 @@ function execute_vsperf() {
RES_DIR="/$(grep "Creating result directory" $LOG_FILE | cut -d'/' -f2-)"
if [[ "/" == "${RES_DIR}" ]] ; then
echo "FAILURE: Results are not available."
+ echo "-------------------------------------------------------------------"
+ cat $LOG_FILE
+ echo "-------------------------------------------------------------------"
exit $EXIT_NO_RESULTS
else
print_results "${RES_DIR}"
+ if [ "$EXIT" -eq "$EXIT_TC_FAILED" ] ; then
+ echo "-------------------------------------------------------------------"
+ cat $LOG_FILE
+ echo "-------------------------------------------------------------------"
+ fi
fi
# show detailed result figures
@@ -277,35 +287,112 @@ function initialize_logdir() {
fi
}
+# verify basic vsperf functionality
+function execute_vsperf_sanity() {
+ DATE_SUFFIX=$(date -u +"%Y-%m-%d_%H-%M-%S")
+ LOG_FILE="${LOG_FILE_PREFIX}_sanity_${DATE_SUFFIX}.log"
+ echo "Execution of VSPERF sanity checks:"
+ for PARAM in '--version' '--help' '--list-trafficgens' '--list-collectors' '--list-vswitches' '--list-fwdapps' '--list-vnfs' '--list-settings' '--list' '--integration --list'; do
+ echo -e "-------------------------------------------------------------------" >> $LOG_FILE
+ echo "$VSPERF_BIN $PARAM $CONF_FILE" >> $LOG_FILE
+ echo -e "-------------------------------------------------------------------" >> $LOG_FILE
+ $VSPERF_BIN $PARAM $CONF_FILE &>> $LOG_FILE
+ if $VSPERF_BIN $PARAM $CONF_FILE &>> $LOG_FILE ; then
+ printf " %-70s %-6s\n" "$VSPERF_BIN $PARAM" "OK"
+ else
+ printf " %-70s %-6s\n" "$VSPERF_BIN $PARAM" "FAILED"
+ EXIT=$EXIT_SANITY_TC_FAILED
+ fi
+ echo >> $LOG_FILE
+ done
+ echo "Sanity log file $LOG_FILE"
+ if [ "$EXIT" -ne "0" ] ; then
+ echo "-------------------------------------------------------------------"
+ cat $LOG_FILE
+ echo "-------------------------------------------------------------------"
+ fi
+}
+
+# check and install required packages at nodes running VERIFY and MERGE jobs
+function dependencies_check() {
+ . /etc/os-release
+ if [ $ID == "ubuntu" ] ; then
+ echo "Dependencies check"
+ echo "=================="
+ for PACKAGE in "python3-tk" "sysstat" ; do
+ if dpkg -s $PACKAGE &> /dev/null ; then
+ printf " %-70s %-6s\n" $PACKAGE "OK"
+ else
+ printf " %-70s %-6s\n" $PACKAGE "missing"
+ sudo apt-get install -y $PACKAGE
+ fi
+ done
+ echo
+ fi
+}
+
#
# main
#
+echo
+
# enter workspace dir
cd $WORKSPACE
+# create virtualenv if needed
+if [ ! -e $VSPERFENV_DIR ] ; then
+ echo "Create VSPERF environment"
+ echo "========================="
+ virtualenv --python=python3 "$VSPERFENV_DIR"
+ echo
+fi
+
+# acivate and update virtualenv
+echo "Update VSPERF environment"
+echo "========================="
+source "$VSPERFENV_DIR"/bin/activate
+pip install -r ./requirements.txt
+echo
+
+# VERFIY&MERGE job specific - check if required packages are installed
+dependencies_check
+
# initialization
initialize_logdir
# execute job based on passed parameter
case $1 in
"verify")
+ echo "================="
echo "VSPERF verify job"
echo "================="
- #execute_vsperf OVS_with_DPDK_and_vHost_User $1
+ terminate_vsperf
+ execute_vsperf_sanity
+ terminate_vsperf
+ execute_vsperf OVS_with_DPDK_and_vHost_User $1
+ terminate_vsperf
+ execute_vsperf OVS_vanilla $1
exit $EXIT
;;
"merge")
+ echo "================"
echo "VSPERF merge job"
echo "================"
- #execute_vsperf OVS_with_DPDK_and_vHost_User $1
+ terminate_vsperf
+ execute_vsperf_sanity
+ terminate_vsperf
+ execute_vsperf OVS_with_DPDK_and_vHost_User $1
+ terminate_vsperf
+ execute_vsperf OVS_vanilla $1
exit $EXIT
;;
*)
+ echo "================"
echo "VSPERF daily job"
echo "================"
diff --git a/conf/01_testcases.conf b/conf/01_testcases.conf
index 55cce1cf..f30c1912 100755
--- a/conf/01_testcases.conf
+++ b/conf/01_testcases.conf
@@ -115,11 +115,14 @@
# # stated in configuration files or value
# # specified on command line through --trafficgen
# # parameter.
-# "Parameters" : "pkt_sizes=512" # Defines list of test parameters used for test
-# # execution. It will override any values defined
-# # by TEST_PARAMS option stated in configuration
-# # files or values specified on command line through
-# # --test-params parameter.
+# "Parameters" : {'TRAFFICGEN_PKT_SIZES' : (512,)}
+# # Dictionary with testcase specific configuration
+# # environment. Specified parameters will be modified
+# # before the test execution and their original values will
+# # be restored after TC finishes. This dictionary will
+# # override any values defined by TEST_PARAMS option
+# # stated in configuration files or values specified
+# # on command line through --test-params parameter.
# "Test Modifier": [FrameMod|Other],
# "Dependency": [Test_Case_Name |None],
diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf
index f9b8f957..2b74dae9 100644
--- a/conf/02_vswitch.conf
+++ b/conf/02_vswitch.conf
@@ -23,11 +23,15 @@ OVS_CMD_TIMEOUT = 10
RTE_TARGET = 'x86_64-native-linuxapp-gcc'
# list of NIC HWIDs to which traffic generator is connected
-# In case of NIC with SRIOV suport, it is possible to define,
+# e.g. WHITELIST_NICS = ['05:00.0', '05:00.1']
+# NIC HWIDs for given network device name can be retrieved
+# by call of ehtool:
+# e.g. ethtool -i eth0
+# In case of NIC with SRIOV support, it is possible to define,
# which virtual function should be used
# e.g. value '0000:05:00.0|vf1' will configure two VFs and second VF
# will be used for testing
-WHITELIST_NICS = ['0000:05:00.0', '0000:05:00.1']
+WHITELIST_NICS = []
# vhost character device file used by dpdkvhostport QemuWrap cases
VHOST_DEV_FILE = 'ovs-vhost-net'
diff --git a/conf/03_traffic.conf b/conf/03_traffic.conf
index 04266923..d7327629 100644
--- a/conf/03_traffic.conf
+++ b/conf/03_traffic.conf
@@ -34,6 +34,15 @@ TRAFFICGEN = 'Dummy'
# Expand like this: (64, 128, 256, 512, 1024)
TRAFFICGEN_PKT_SIZES = (64,)
+TRAFFICGEN_DURATION = 30
+
+TRAFFICGEN_RFC2544_TESTS = 1
+TRAFFICGEN_RFC2889_TRIALS = 1
+TRAFFICGEN_LOSSRATE = 0.0
+
+#############################
+# IXIA Configuration -- BEGIN
+
# path to 'ixos' install path
TRAFFICGEN_IXIA_ROOT_DIR = '/opt/ixos'
@@ -61,8 +70,16 @@ TRAFFICGEN_IXNET_TESTER_RESULT_DIR = ''
# as the previous one
TRAFFICGEN_IXNET_DUT_RESULT_DIR = ''
+# directory with 3rd party scripts generated by IXIA tools
+TRAFFICGEN_IXIA_3RD_PARTY = os.path.join(ROOT_DIR, '3rd_party/ixia')
+
+# default TCL script, which will be used for IXNETWORK configuration
TRAFFICGEN_IXNET_TCL_SCRIPT = 'ixnetrfc2544.tcl'
+# IXIA Configuration -- END
+###########################
+
+
###########################################
# Spirent TestCenter Configuration -- BEGIN
@@ -109,7 +126,7 @@ TRAFFICGEN_STC_WEST_PORT_NUM = ""
TRAFFICGEN_STC_TEST_SESSION_NAME = "RFC2544 Tput"
# The directory to copy results to
-TRAFFICGEN_STC_RESULTS_DIR = "./Results"
+TRAFFICGEN_STC_RESULTS_DIR = os.path.join(ROOT_DIR, "Results")
# The prefix for the CSV results file
TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX = "RFC2544_tput"
@@ -168,6 +185,9 @@ TRAFFICGEN_STC_VERBOSE = "True"
# Spirent TestCenter Configuration -- END
#########################################
+#############################
+# Xena Configuration -- BEGIN
+
# Xena traffic generator connection info
TRAFFICGEN_XENA_IP = ''
TRAFFICGEN_XENA_PORT1 = ''
@@ -194,6 +214,9 @@ TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION = '0.5'
TRAFFICGEN_XENA_2544_TPUT_USEPASS_THRESHHOLD = 'false'
TRAFFICGEN_XENA_2544_TPUT_PASS_THRESHHOLD = '0.0'
+# Xena Configuration -- END
+###########################
+
###################################################
# MoonGen Configuration and Connection Info-- BEGIN
diff --git a/conf/04_vnf.conf b/conf/04_vnf.conf
index e0c72b10..75f107e8 100644
--- a/conf/04_vnf.conf
+++ b/conf/04_vnf.conf
@@ -15,7 +15,7 @@
# ############################
# VNF configuration
# ############################
-VNF_DIR = 'vnfs/'
+VNF_DIR = os.path.join(ROOT_DIR, 'vnfs/')
VNF = 'QemuDpdkVhostUser'
VNF_AFFINITIZATION_ON = True
@@ -90,23 +90,24 @@ GUEST_TIMEOUT = [180]
GUEST_BOOT_DRIVE_TYPE = ['scsi']
GUEST_SHARED_DRIVE_TYPE = ['scsi']
-# packet forwarding mode supported by testpmd; Please see DPDK documentation
-# for comprehensive list of modes supported by your version.
-# e.g. io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho|...
-# Note: Option "mac_retry" has been changed to "mac retry" since DPDK v16.07
-GUEST_TESTPMD_FWD_MODE = 'csum'
-
# guest loopback application method; supported options are:
# 'testpmd' - testpmd from dpdk will be built and used
# 'l2fwd' - l2fwd module provided by Huawei will be built and used
# 'linux_bridge' - linux bridge will be configured
# 'buildin' - nothing will be configured by vsperf; VM image must
# ensure traffic forwarding between its interfaces
-# This configuration option can be overridden by CLI SCALAR option
-# guest_loopback, e.g. --test-params "guest_loopback=l2fwd"
# For 2 VNFs you may use ['testpmd', 'l2fwd']
GUEST_LOOPBACK = ['testpmd']
+# guest driver binding option; support options are:
+# 'igb_uio_from_src' - build igb_uio driver from downloaded source files
+# 'uio_pci_generic' - use uio_pci_generic driver
+# 'vfio_no_iommu' - use unsafe vfio driver without iommu (requires
+# image with supported kernel 4.5 or greater and
+# dpdk 16.04 or greater. VSPerf vloop image does not
+# support this mode.
+GUEST_DPDK_BIND_DRIVER = ['igb_uio_from_src']
+
# username for guest image
GUEST_USERNAME = ['root']
@@ -189,19 +190,16 @@ GUEST_BRIDGE_IP = ['#IP(1.1.1.5)/16']
# Guest TESTPMD configuration
# ############################
+# set of configuration parameters, which will be passed to the testpmd
+# executed inside the guest
+# Note: Testpmd must be executed in interactive mode. It means, that
+# VSPERF won't work correctly if '-i' will be removed.
+GUEST_TESTPMD_PARAMS = ['-c 0x3 -n 4 --socket-mem 512 -- '
+ '--burst=64 -i --txqflags=0xf00 '
+ '--disable-hw-vlan']
+
# packet forwarding mode supported by testpmd; Please see DPDK documentation
# for comprehensive list of modes supported by your version.
# e.g. io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho|...
# Note: Option "mac_retry" has been changed to "mac retry" since DPDK v16.07
GUEST_TESTPMD_FWD_MODE = ['csum']
-
-# Set the CPU mask for testpmd loopback. To bind to specific guest CPUs use -l
-# GUEST_TESTPMD_CPU_MASK = ['-l 0,1']
-GUEST_TESTPMD_CPU_MASK = ['-c 0x3']
-
-# Testpmd multi-core config. Leave at 0's for disabled. Will not enable unless
-# GUEST_NIC_QUEUES are > 0. For bi directional traffic NB_CORES must be equal
-# to (RXQ + TXQ).
-GUEST_TESTPMD_NB_CORES = [0]
-GUEST_TESTPMD_TXQ = [0]
-GUEST_TESTPMD_RXQ = [0]
diff --git a/conf/10_custom.conf b/conf/10_custom.conf
index b3707149..929d2679 100644
--- a/conf/10_custom.conf
+++ b/conf/10_custom.conf
@@ -47,7 +47,7 @@ TRAFFICGEN_STC_WEST_INTF_GATEWAY_ADDR = "192.85.1.3"
TRAFFICGEN_IXIA_CARD = ''
TRAFFICGEN_IXIA_PORT1 = ''
TRAFFICGEN_IXIA_PORT2 = ''
-TRAFFICGEN_IXIA_LIB_PATH = '/opt/ixos/lib/ixTcl1.0'
+TRAFFICGEN_IXIA_ROOT_DIR = '/opt/ixos'
TRAFFICGEN_IXNET_LIB_PATH = '/opt/ixnet/IxTclNetwork'
# Ixia traffic generator
@@ -103,7 +103,7 @@ TRAFFICGEN_MOONGEN_LINE_SPEED_GBPS = '10'
# MoonGen Configuration and Connection Info-- END
###################################################
-#TEST_PARAMS = {'pkt_sizes':'64'}
+#TEST_PARAMS = {'TRAFFICGEN_PKT_SIZES':(64,)}
OPNFV_INSTALLER = "Fuel"
OPNFV_URL = "http://testresults.opnfv.org/testapi"
PACKAGE_LIST = "src/package-list.mk"
diff --git a/conf/__init__.py b/conf/__init__.py
index 88e8cec6..2448d390 100644
--- a/conf/__init__.py
+++ b/conf/__init__.py
@@ -29,6 +29,10 @@ import netaddr
_LOGGER = logging.getLogger(__name__)
+# Special test parameters which are not part of standard VSPERF configuration
+_EXTRA_TEST_PARAMS = ['bidirectional', 'traffic_type', 'iload', 'tunnel_type',
+ 'multistream', 'stream_type', 'pre-installed_flows']
+
# regex to parse configuration macros from 04_vnf.conf
# it will select all patterns starting with # sign
# and returns macro parameters and step
@@ -49,7 +53,13 @@ class Settings(object):
"""Return a settings item value
"""
if attr in self.__dict__:
- return getattr(self, attr)
+ if attr == 'TEST_PARAMS':
+ return getattr(self, attr)
+ else:
+ master_value = getattr(self, attr)
+ # Check if parameter value was overridden by CLI option
+ cli_value = get_test_param(attr, None)
+ return cli_value if cli_value else master_value
else:
raise AttributeError("%r object has no attribute %r" %
(self.__class__, attr))
@@ -136,6 +146,24 @@ class Settings(object):
for key in os.environ:
setattr(self, key, os.environ[key])
+ def check_test_params(self):
+ """
+ Check all parameters defined inside TEST_PARAMS for their
+ existence. In case that non existing vsperf parmeter name
+ is detected, then VSPER will raise a runtime error.
+ """
+ unknown_keys = []
+ for key in settings.getValue('TEST_PARAMS'):
+ if key == 'TEST_PARAMS':
+ raise RuntimeError('It is not allowed to define TEST_PARAMS '
+ 'as a test parameter')
+ if key not in self.__dict__ and key not in _EXTRA_TEST_PARAMS:
+ unknown_keys.append(key)
+
+ if len(unknown_keys):
+ raise RuntimeError('Test parameters contain unknown configuration '
+ 'parameter(s): {}'.format(', '.join(unknown_keys)))
+
def check_vm_settings(self, vm_number):
"""
Check all VM related settings starting with GUEST_ prefix.
@@ -145,15 +173,12 @@ class Settings(object):
"""
for key in self.__dict__:
if key.startswith('GUEST_'):
- if (isinstance(self.__dict__[key], str) and
- self.__dict__[key].find('#') >= 0):
- self.__dict__[key] = [self.__dict__[key]]
+ value = self.getValue(key)
+ if isinstance(value, str) and value.find('#') >= 0:
self._expand_vm_settings(key, 1)
- self.__dict__[key] = self.__dict__[key][0]
- if isinstance(self.__dict__[key], list):
- if (len(self.__dict__[key]) < vm_number or
- str(self.__dict__[key][0]).find('#') >= 0):
+ if isinstance(value, list):
+ if len(value) < vm_number or str(value[0]).find('#') >= 0:
# expand configuration for all VMs
self._expand_vm_settings(key, vm_number)
@@ -161,7 +186,15 @@ class Settings(object):
"""
Expand VM option with given key for given number of VMs
"""
- master_value = self.__dict__[key][0]
+ tmp_value = self.getValue(key)
+ if isinstance(tmp_value, str):
+ scalar = True
+ master_value = tmp_value
+ tmp_value = [tmp_value]
+ else:
+ scalar = False
+ master_value = tmp_value[0]
+
master_value_str = str(master_value)
if master_value_str.find('#') >= 0:
self.__dict__[key] = []
@@ -170,6 +203,7 @@ class Settings(object):
for macro, args, param, _, step in re.findall(_PARSE_PATTERN, value):
multi = int(step) if len(step) and int(step) else 1
if macro == '#EVAL':
+ # pylint: disable=eval-used
tmp_result = str(eval(param))
elif macro == '#MAC':
mac_value = netaddr.EUI(param).value
@@ -189,9 +223,12 @@ class Settings(object):
value = ast.literal_eval(value)
self.__dict__[key].append(value)
else:
- for vmindex in range(len(self.__dict__[key]), vm_number):
+ for vmindex in range(len(tmp_value), vm_number):
self.__dict__[key].append(master_value)
+ if scalar:
+ self.__dict__[key] = self.__dict__[key][0]
+
_LOGGER.debug("Expanding option: %s = %s", key, self.__dict__[key])
def __str__(self):
@@ -202,11 +239,28 @@ class Settings(object):
Returns:
A human-readable string.
"""
- return pprint.pformat(self.__dict__)
+ tmp_dict = {}
+ for key in self.__dict__:
+ tmp_dict[key] = self.getValue(key)
+ return pprint.pformat(tmp_dict)
-settings = Settings()
+ #
+ # validation methods used by step driven testcases
+ #
+ def validate_getValue(self, result, attr):
+ """Verifies, that correct value was returned
+ """
+ assert result == self.__dict__[attr]
+ return True
+ def validate_setValue(self, dummy_result, name, value):
+ """Verifies, that value was correctly set
+ """
+ assert value == self.__dict__[name]
+ return True
+
+settings = Settings()
def get_test_param(key, default=None):
"""Retrieve value for test param ``key`` if available.
@@ -217,4 +271,17 @@ def get_test_param(key, default=None):
:returns: Value for ``key`` if found, else ``default``.
"""
test_params = settings.getValue('TEST_PARAMS')
- return test_params.get(key, default) if test_params else default
+ if key in test_params:
+ if not isinstance(test_params.get(key), str):
+ return test_params.get(key)
+ else:
+ # values are passed inside string from CLI, so we must retype them accordingly
+ try:
+ return ast.literal_eval(test_params.get(key))
+ except ValueError:
+ # for backward compatibility, we have to accept strings without quotes
+ _LOGGER.warning("Adding missing quotes around string value: %s = %s",
+ key, str(test_params.get(key)))
+ return str(test_params.get(key))
+ else:
+ return default
diff --git a/conf/integration/01_testcases.conf b/conf/integration/01_testcases.conf
index a67702f8..a584845a 100644
--- a/conf/integration/01_testcases.conf
+++ b/conf/integration/01_testcases.conf
@@ -128,6 +128,48 @@ STEP_VSWITCH_PVVP_FLOWS_FINIT = [
['vswitch', 'del_flow', 'int_br0', {'in_port': '#STEP[3][1]'}],
] + STEP_VSWITCH_PVVP_FINIT
+STEP_VSWITCH_P4VP_INIT = STEP_VSWITCH_PVVP_INIT + [
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 7 vm3 ports
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 8
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 9 vm4 ports
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 10
+]
+
+STEP_VSWITCH_P4VP_FINIT = [
+ ['vswitch', 'del_port', 'int_br0', '#STEP[7][0]'], # vm3 ports
+ ['vswitch', 'del_port', 'int_br0', '#STEP[8][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[9][0]'], # vm4 ports
+ ['vswitch', 'del_port', 'int_br0', '#STEP[10][0]'],
+] + STEP_VSWITCH_PVVP_FINIT
+
+STEP_VSWITCH_P4VP_FLOWS_INIT = STEP_VSWITCH_P4VP_INIT + [
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \
+ 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[6][1]', \
+ 'actions': ['output:#STEP[7][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[8][1]', \
+ 'actions': ['output:#STEP[9][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[10][1]', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[2][1]', \
+ 'actions': ['output:#STEP[10][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[9][1]', \
+ 'actions': ['output:#STEP[8][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[7][1]', \
+ 'actions': ['output:#STEP[6][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[5][1]', \
+ 'actions': ['output:#STEP[4][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[3][1]', \
+ 'actions': ['output:#STEP[1][1]'], 'idle_timeout': '0'}],
+]
+
+STEP_VSWITCH_P4VP_FLOWS_FINIT = [
+ ['vswitch', 'dump_flows', 'int_br0'],
+ ['vswitch', 'del_flow', 'int_br0'],
+] + STEP_VSWITCH_P4VP_FINIT
+
STEP_VSWITCH_2PHY_2VM_INIT = STEP_VSWITCH_PVVP_INIT
STEP_VSWITCH_2PHY_2VM_FINIT = STEP_VSWITCH_PVVP_FINIT
@@ -286,6 +328,7 @@ INTEGRATION_TESTS = [
"The encap and decap are performed inside the "
"virtual switch itself in each direction to avoid "
"the need of ingress overlay traffic."),
+ "Parameters": {'TRAFFICGEN_IXNET_TCL_SCRIPT' : 'ixnetrfc2544v2.tcl'},
},
{
"Name": "overlay_p2p_tput",
@@ -295,6 +338,7 @@ INTEGRATION_TESTS = [
"Tunnel Type": SUPPORTED_TUNNELING_PROTO[0],
"Tunnel Operation": "encapsulation",
"Description": "Overlay Encapsulation Throughput RFC2544 Test",
+ "Parameters": {'TRAFFICGEN_IXNET_TCL_SCRIPT' : 'ixnetrfc2544v2.tcl'},
},
{
"Name": "overlay_p2p_cont",
@@ -304,6 +348,7 @@ INTEGRATION_TESTS = [
"Tunnel Type": SUPPORTED_TUNNELING_PROTO[0],
"Tunnel Operation": "encapsulation",
"Description": "Overlay Encapsulation Continuous Stream",
+ "Parameters": {'TRAFFICGEN_IXNET_TCL_SCRIPT' : 'ixnetrfc2544v2.tcl'},
},
{
"Name": "overlay_p2p_decap_tput",
@@ -313,6 +358,7 @@ INTEGRATION_TESTS = [
"Tunnel Type": SUPPORTED_TUNNELING_PROTO[0],
"Tunnel Operation": "decapsulation",
"Description": "Overlay Decapsulation Throughput RFC2544 Test",
+ "Parameters": {'TRAFFICGEN_IXNET_TCL_SCRIPT' : 'ixnetrfc2544v2.tcl'},
},
{
"Name": "overlay_p2p_decap_cont",
@@ -322,6 +368,7 @@ INTEGRATION_TESTS = [
"Tunnel Type": SUPPORTED_TUNNELING_PROTO[0],
"Tunnel Operation": "decapsulation",
"Description": "Overlay Decapsulation Continuous Stream",
+ "Parameters": {'TRAFFICGEN_IXNET_TCL_SCRIPT' : 'ixnetrfc2544v2.tcl'},
},
{
"Name": "vswitch_add_del_bridge",
@@ -407,6 +454,21 @@ INTEGRATION_TESTS = [
]
},
{
+ "Name": "vswitch_vports_add_del_flow",
+ "Deployment": "clean",
+ "Description": "vSwitch - configure switch with vports, add and delete flow",
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'],
+ ['vswitch', 'add_vport', 'int_br0'],
+ ['vswitch', 'add_vport', 'int_br0'],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'del_flow', 'int_br0', {'in_port': '#STEP[1][1]'}],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+ },
+ {
"Name": "vswitch_add_del_flows",
"Deployment": "clean",
"Description": "vSwitch - add and delete flows",
@@ -455,6 +517,21 @@ INTEGRATION_TESTS = [
STEP_VSWITCH_PVP_FINIT
},
{
+ "Name": "vswitch_vports_pvp",
+ "Deployment": "clean",
+ "Description": "vSwitch - configure switch with vports and one vnf",
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'],
+ ['vswitch', 'add_vport', 'int_br0'],
+ ['vswitch', 'add_vport', 'int_br0'],
+ ['vnf', 'start'],
+ ['vnf', 'stop'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+ },
+ {
"Name": "vswitch_pvp_tput",
"Deployment": "clean",
"Description": "vSwitch - configure switch, vnf and execute RFC2544 throughput test",
@@ -576,9 +653,108 @@ INTEGRATION_TESTS = [
STEP_VSWITCH_PVVP_FLOWS_FINIT
},
{
+ "Name": "vswitch_p4vp",
+ "Description": "Just configure 4 chained vnfs",
+ "Deployment": "clean",
+ "TestSteps": STEP_VSWITCH_P4VP_FLOWS_INIT +
+ [
+ ['vnf1', 'start'],
+ ['vnf2', 'start'],
+ ['vnf3', 'start'],
+ ['vnf4', 'start'],
+ ['vnf1', 'stop'],
+ ['vnf2', 'stop'],
+ ['vnf3', 'stop'],
+ ['vnf4', 'stop'],
+ ] +
+ STEP_VSWITCH_P4VP_FLOWS_FINIT
+ },
+ {
+ "Name": "vswitch_p4vp_tput",
+ "Description": "4 chained vnfs, execute RFC2544 throughput test",
+ "Deployment": "clean",
+ "TestSteps": STEP_VSWITCH_P4VP_FLOWS_INIT +
+ [
+ ['vnf1', 'start'],
+ ['vnf2', 'start'],
+ ['vnf3', 'start'],
+ ['vnf4', 'start'],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', \
+ 'bidir' : 'True'}],
+ ['vnf1', 'stop'],
+ ['vnf2', 'stop'],
+ ['vnf3', 'stop'],
+ ['vnf4', 'stop'],
+ ] +
+ STEP_VSWITCH_P4VP_FLOWS_FINIT
+ },
+ {
+ "Name": "vswitch_p4vp_back2back",
+ "Description": "4 chained vnfs, execute RFC2544 back2back test",
+ "Deployment": "clean",
+ "TestSteps": STEP_VSWITCH_P4VP_FLOWS_INIT +
+ [
+ ['vnf1', 'start'],
+ ['vnf2', 'start'],
+ ['vnf3', 'start'],
+ ['vnf4', 'start'],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', \
+ 'bidir' : 'True'}],
+ ['vnf1', 'stop'],
+ ['vnf2', 'stop'],
+ ['vnf3', 'stop'],
+ ['vnf4', 'stop'],
+ ] +
+ STEP_VSWITCH_P4VP_FLOWS_FINIT
+ },
+ {
+ "Name": "vswitch_p4vp_cont",
+ "Description": "4 chained vnfs, execute continuous stream test",
+ "Deployment": "clean",
+ "TestSteps": STEP_VSWITCH_P4VP_FLOWS_INIT +
+ [
+ ['vnf1', 'start'],
+ ['vnf2', 'start'],
+ ['vnf3', 'start'],
+ ['vnf4', 'start'],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
+ 'bidir' : 'True'}],
+ ['vnf1', 'stop'],
+ ['vnf2', 'stop'],
+ ['vnf3', 'stop'],
+ ['vnf4', 'stop'],
+ ] +
+ STEP_VSWITCH_P4VP_FLOWS_FINIT
+ },
+ {
+ "Name": "vswitch_p4vp_all",
+ "Description": "4 chained vnfs, execute RFC2544 throughput test",
+ "Deployment": "clean",
+ "TestSteps": STEP_VSWITCH_P4VP_FLOWS_INIT +
+ [
+ ['vnf1', 'start'],
+ ['vnf2', 'start'],
+ ['vnf3', 'start'],
+ ['vnf4', 'start'],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', \
+ 'bidir' : 'True'}],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', \
+ 'bidir' : 'True'}],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
+ 'bidir' : 'True'}],
+ ['vnf1', 'stop'],
+ ['vnf2', 'stop'],
+ ['vnf3', 'stop'],
+ ['vnf4', 'stop'],
+ ] +
+ STEP_VSWITCH_P4VP_FLOWS_FINIT
+ },
+ {
# Topology: 2 Parallel PVP connections
# To run a Linux bridge as a loopback in the Guest use:
- # --test-params "guest_loopback=linux_bridge" --integration 2pvp_udp_dest_flows
+ # --test-params "GUEST_LOOPBACK=['linux_bridge']" --integration 2pvp_udp_dest_flows
+ # or add "Parameters" option to the test definition:
+ # "Parameters" : {'GUEST_LOOPBACK' : ['linux_bridge'],},
"Name": "2pvp_udp_dest_flows",
"Description": "Continuous TC with 2 Parallel VMs, flows on UDP Dest Port",
"Deployment": "clean",
@@ -599,7 +775,9 @@ INTEGRATION_TESTS = [
{
# Topology: 4 Parallel PVP connections
# To run a Linux bridge as a loopback in the Guest use:
- # --test-params "guest_loopback=linux_bridge" --integration 4pvp_udp_dest_flows
+ # --test-params "GUEST_LOOPBACK=['linux_bridge']" --integration 4pvp_udp_dest_flows
+ # or add "Parameters" option to the test definition:
+ # "Parameters" : {'GUEST_LOOPBACK' : ['linux_bridge'],},
"Name": "4pvp_udp_dest_flows",
"Description": "Continuous TC with 4 Parallel VMs, flows on UDP Dest Port",
"Deployment": "clean",
@@ -624,7 +802,9 @@ INTEGRATION_TESTS = [
{
# Topology: 6 Parallel PVP connections
# To run a Linux bridge as a loopback in the Guest use:
- # --test-params "guest_loopback=linux_bridge" --integration 6pvp_udp_dest_flows
+ # --test-params "GUEST_LOOPBACK=['linux_bridge']" --integration 6pvp_udp_dest_flows
+ # or add "Parameters" option to the test definition:
+ # "Parameters" : {'GUEST_LOOPBACK' : ['linux_bridge'],},
"Name": "6pvp_udp_dest_flows",
"Description": "Continuous TC with 6 Parallel VMs, flows on UDP Dest Port",
"Deployment": "clean",
@@ -649,6 +829,79 @@ INTEGRATION_TESTS = [
] + STEP_VSWITCH_FLOWS_FINIT +
STEP_VSWITCH_2PHY_6VM_FINIT
},
+ {
+ # Testcase for verification of vHost User NUMA awareness feature
+ # introduced in DPDK v2.2. Test case will execute two VNFs, each
+ # pinned to different NUMA slot. After that it will verify that
+ # QEMU and PMD threads serving its interfaces are co-located
+ # at the same NUMA slot.
+ #
+ # Prerequisites:
+ # * architecture with at least 2 NUMA slots
+ # * OVS with DPDK support and DPDK v2.2 and newer
+ # * OVS configuration utilizing both NUMA slots
+ #
+ # Example of OVS configuration valid for DPDK v16.04 and cores
+ # split between NUMA slots as follows:
+ # node 0 cpus: 0 1 2 3 4 5 6 7 8 9
+ # node 1 cpus: 10 11 12 13 14 15 16 17 18 19
+ #
+ # VSWITCH_PMD_CPU_MASK = '1010'
+ # VSWITCHD_DPDK_CONFIG = {
+ # 'dpdk-init' : 'true',
+ # 'dpdk-lcore-mask' : '0x4004',
+ # 'pmd-cpu-mask' : 'FF0FF',
+ # 'dpdk-socket-mem' : '1024,1024',
+ # }
+ #
+ "Name": "vhost_numa_awareness",
+ "Deployment": "clean",
+ "Description": "vSwitch DPDK - verify that PMD threads are served "
+ "by the same NUMA slot as QEMU instances",
+ "vSwitch" : "OvsDpdkVhost",
+ "TestSteps": STEP_VSWITCH_PVVP_INIT + # STEP 0-6
+ [
+ # check that at least 2 numa slots are available
+ ['tools', 'exec', 'numactl -H', 'available: ([0-9]+)'], # STEP 7
+ ['tools', 'assert', '#STEP[-1][0]>1'], # STEP 8
+ # store last 2 cores from numa slot 0
+ ['tools', 'exec', 'numactl -H', 'node 0 cpus:.*\s+(\\d+) (\\d+)$'], # STEP 9
+ # store last 2 cores from numa slot 1
+ ['tools', 'exec', 'numactl -H', 'node 1 cpus:.*\s+(\\d+) (\\d+)$'], # STEP 10
+ # pin VNF1 to 1st NUMA slot and VNF2 to 2nd NUMA slot
+ ['settings', 'setValue', 'GUEST_CORE_BINDING', # STEP 11
+ [("#STEP[-2][0][0]", "#STEP[-2][0][1]"),
+ ("#STEP[-1][0][0]", "#STEP[-1][0][1]")]
+ ],
+ # start 2 VNFs
+ ['vnf1', 'start'], # STEP 12
+ ['vnf2', 'start'], # STEP 13
+ # read paths to ovs utilities
+ ['settings', 'getValue', 'TOOLS'], # STEP 14
+ # check that PMD thread serving VNF1 runs at NUMA slot 0
+ ## i.e. get numa slot ID serving dpdhvhostuser0...
+ ['tools', 'exec', "sudo #STEP[-1]['ovs-appctl'] " # STEP 15
+ "dpif-netdev/pmd-rxq-show | "
+ "sed -e '/dpdkvhostuser0/,$d' | tac",
+ 'pmd thread numa_id ([0-9])+'
+ ],
+ ## ...and check that it is NUMA slot 0
+ ['tools', 'assert', '#STEP[-1][0]==0'], # STEP 16
+ # check that PMD thread serving VNF2 runs at NUMA slot 1
+ ## i.e. get numa slot ID serving dpdhvhostuser2...
+ ['tools', 'exec', "sudo #STEP[-3]['ovs-appctl'] " # STEP 17
+ "dpif-netdev/pmd-rxq-show | "
+ "sed -e '/dpdkvhostuser2/,$d' | tac",
+ 'pmd thread numa_id ([0-9])+'
+ ],
+ ## ...and check that it is NUMA slot 1
+ ['tools', 'assert', '#STEP[-1][0]==1'], # STEP 18
+ # clean up
+ ['vnf2', 'stop'], # STEP 19
+ ['vnf1', 'stop'], # STEP 20
+ ] +
+ STEP_VSWITCH_PVVP_FINIT # STEP 21...
+ },
]
# Example of TC definition with exact vSwitch, VNF and TRAFFICGEN values.
@@ -659,7 +912,7 @@ INTEGRATION_TESTS = [
# "vSwitch" : "OvsVanilla",
# "VNF" : "QemuVirtioNet",
# "Trafficgen": "IxNet",
-# "Parameters": {"guest_loopback" : "linux_bridge"},
+# "Parameters": {"GUEST_LOOPBACK" : ["linux_bridge"],},
# "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT +
# [
# ['vnf', 'start'],
diff --git a/conf/integration/03_traffic.conf b/conf/integration/03_traffic.conf
index 0b46cea0..e78e2668 100644
--- a/conf/integration/03_traffic.conf
+++ b/conf/integration/03_traffic.conf
@@ -18,9 +18,6 @@ TRAFFICGEN_PORT2_MAC = '02:00:00:00:00:02'
TRAFFICGEN_PORT1_IP = '1.1.1.1'
TRAFFICGEN_PORT2_IP = '90.90.90.90'
-# To test VXLAN set the ff to ixnetrfc2544v2.tcl
-TRAFFICGEN_IXNET_TCL_SCRIPT = 'ixnetrfc2544v2.tcl'
-
# VXLAN traffic item
VXLAN_VNI = '99'
diff --git a/core/__init__.py b/core/__init__.py
index e39ec88e..d16401ea 100644
--- a/core/__init__.py
+++ b/core/__init__.py
@@ -15,5 +15,5 @@
"""Core structural interfaces and their implementations
"""
import core.component_factory
-from core.traffic_controller import (ITrafficController)
+from core.traffic_controller import (TrafficController)
from core.vswitch_controller import (IVswitchController)
diff --git a/core/component_factory.py b/core/component_factory.py
index ef7ba86f..236a61ed 100644
--- a/core/component_factory.py
+++ b/core/component_factory.py
@@ -46,7 +46,7 @@ def create_traffic(traffic_type, trafficgen_class):
:param traffic_type: Name of traffic type
:param trafficgen_class: Reference to traffic generator class to be used.
- :return: A new ITrafficController
+ :return: A new TrafficController
"""
if traffic_type.lower().startswith('rfc2889'):
return TrafficControllerRFC2889(trafficgen_class)
@@ -87,7 +87,7 @@ def create_vswitch(deployment_scenario, vswitch_class, traffic,
raise RuntimeError("Unknown deployment scenario '{}'.".format(deployment_scenario))
-def create_vnf(deployment_scenario, vnf_class):
+def create_vnf(deployment_scenario, vnf_class, extra_vnfs):
"""Return a new VnfController for the deployment_scenario.
The returned controller is configured with the given VNF class.
@@ -96,9 +96,13 @@ def create_vnf(deployment_scenario, vnf_class):
:param deployment_scenario: The deployment scenario name
:param vswitch_class: Reference to vSwitch class to be used.
+ :param extra_vnfs: The number of VNFs not involved in given
+ deployment scenario. It will be used to correctly expand
+ configuration values and initialize shared dirs. This parameter
+ is used in case, that additional VNFs are executed by TestSteps.
:return: VnfController for the deployment_scenario
"""
- return VnfController(deployment_scenario, vnf_class)
+ return VnfController(deployment_scenario, vnf_class, extra_vnfs)
def create_collector(collector_class, result_dir, test_name):
"""Return a new Collector of the given class
diff --git a/core/traffic_controller.py b/core/traffic_controller.py
index 428e91f8..b1911536 100644
--- a/core/traffic_controller.py
+++ b/core/traffic_controller.py
@@ -1,4 +1,4 @@
-# Copyright 2015 Intel Corporation.
+# Copyright 2015-2016 Intel Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,17 +12,96 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Interface to traffic controllers
+"""Base class for traffic controllers
"""
-class ITrafficController(object):
- """Abstract class which defines a traffic controller object
+import logging
+import os
+import time
+
+from core.results.results_constants import ResultsConstants
+from conf import settings
+
+class TrafficController(object):
+ """Base class which defines a common functionality for all traffic
+ controller classes.
Used to setup and control a traffic generator for a particular deployment
scenario.
"""
+ def __init__(self, traffic_gen_class):
+ """Initialization common for all types of traffic controllers
+
+ :param traffic_gen_class: The traffic generator class to be used.
+ """
+ self._type = None
+ self._logger = logging.getLogger(__name__)
+ self._logger.debug("__init__")
+ self._traffic_gen_class = traffic_gen_class()
+ self._traffic_started = False
+ self._traffic_started_call_count = 0
+ self._duration = int(settings.getValue('TRAFFICGEN_DURATION'))
+ self._lossrate = float(settings.getValue('TRAFFICGEN_LOSSRATE'))
+ self._packet_sizes = settings.getValue('TRAFFICGEN_PKT_SIZES')
+
+ self._mode = settings.getValue('mode').lower()
+ self._results = []
+
+ def __enter__(self):
+ """Call initialisation function.
+ """
+ self._traffic_gen_class.connect()
+
+ def __exit__(self, type_, value, traceback):
+ """Stop traffic, clean up.
+ """
+ if self._traffic_started:
+ self.stop_traffic()
+
+ def _append_results(self, result_dict, packet_size):
+ """Adds common values to traffic generator results.
+
+ :param result_dict: Dictionary containing results from trafficgen
+ :param packet_size: Packet size value.
+
+ :returns: dictionary of results with additional entries.
+ """
+
+ ret_value = result_dict
- def send_traffic(self, traffic):
+ ret_value[ResultsConstants.TYPE] = self._type
+ ret_value[ResultsConstants.PACKET_SIZE] = str(packet_size)
+
+ return ret_value
+
+ def traffic_required(self):
+ """Checks selected '--mode' of traffic generator and performs
+ its specific handling.
+
+ :returns: True - in case that traffic generator should be executed
+ False - if traffic generation is not required
+ """
+ if self._mode == 'trafficgen-off':
+ time.sleep(2)
+ self._logger.debug("All is set. Please run traffic generator manually.")
+ input(os.linesep + "Press Enter to terminate vswitchperf..." +
+ os.linesep + os.linesep)
+ return False
+ elif self._mode == 'trafficgen-pause':
+ time.sleep(2)
+ while True:
+ choice = input(os.linesep + 'Transmission paused, should'
+ ' transmission be resumed? [y/n]' + os.linesep).lower()
+ if choice in ('yes', 'y', 'ye'):
+ return True
+ elif choice in ('no', 'n'):
+ self._logger.info("Traffic transmission will be skipped.")
+ return False
+ else:
+ print("Please respond with 'yes', 'y', 'no' or 'n' ", end='')
+ return True
+
+ def send_traffic(self, dummy_traffic):
"""Triggers traffic to be sent from the traffic generator.
This is a blocking function.
@@ -33,7 +112,7 @@ class ITrafficController(object):
"The TrafficController does not implement",
"the \"send_traffic\" function.")
- def send_traffic_async(self, traffic, function):
+ def send_traffic_async(self, dummy_traffic, dummy_function):
"""Triggers traffic to be sent asynchronously.
This is not a blocking function.
@@ -55,6 +134,33 @@ class ITrafficController(object):
def stop_traffic(self):
"""Kills traffic being sent from the traffic generator.
"""
- raise NotImplementedError(
- "The TrafficController does not implement",
- "the \"stop_traffic\" function.")
+ self._logger.debug("stop_traffic()")
+
+ def print_results(self):
+ """IResult interface implementation.
+ """
+ counter = 0
+ for item in self._results:
+ logging.info("Record: " + str(counter))
+ counter += 1
+ for(key, value) in list(item.items()):
+ logging.info(" Key: " + str(key) +
+ ", Value: " + str(value))
+
+ def get_results(self):
+ """IResult interface implementation.
+ """
+ return self._results
+
+ def validate_send_traffic(self, dummy_result, dummy_traffic):
+ """Verify that send traffic has succeeded
+ """
+ if len(self._results):
+ if 'b2b_frames' in self._results[-1]:
+ return float(self._results[-1]['b2b_frames']) > 0
+ elif 'throughput_rx_fps' in self._results[-1]:
+ return float(self._results[-1]['throughput_rx_fps']) > 0
+ else:
+ return True
+ else:
+ return False
diff --git a/core/traffic_controller_rfc2544.py b/core/traffic_controller_rfc2544.py
index af09deff..980205f6 100644
--- a/core/traffic_controller_rfc2544.py
+++ b/core/traffic_controller_rfc2544.py
@@ -1,4 +1,4 @@
-# Copyright 2015 Intel Corporation.
+# Copyright 2015-2016 Intel Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,16 +13,12 @@
# limitations under the License.
"""RFC2544 Traffic Controller implementation.
"""
-import logging
-
-from core.traffic_controller import ITrafficController
-from core.results.results_constants import ResultsConstants
+from core.traffic_controller import TrafficController
from core.results.results import IResults
from conf import settings
-from conf import get_test_param
-class TrafficControllerRFC2544(ITrafficController, IResults):
+class TrafficControllerRFC2544(TrafficController, IResults):
"""Traffic controller for RFC2544 traffic
Used to setup and control a traffic generator for an RFC2544 deployment
@@ -34,60 +30,15 @@ class TrafficControllerRFC2544(ITrafficController, IResults):
:param traffic_gen_class: The traffic generator class to be used.
"""
- self._logger = logging.getLogger(__name__)
- self._logger.debug("__init__")
- self._traffic_gen_class = traffic_gen_class()
- self._traffic_started = False
- self._traffic_started_call_count = 0
- self._tests = int(get_test_param('rfc2544_tests', 1))
- self._duration = int(get_test_param('duration', 30))
- self._lossrate = float(get_test_param('lossrate', 0.0))
- self._results = []
-
- # If set, comma separated packet_sizes value from --test_params
- # on cli takes precedence over value in settings file.
- self._packet_sizes = None
- packet_sizes_cli = get_test_param('pkt_sizes')
- if packet_sizes_cli:
- self._packet_sizes = [int(x.strip())
- for x in packet_sizes_cli.split(',')]
- else:
- self._packet_sizes = settings.getValue('TRAFFICGEN_PKT_SIZES')
-
- def __enter__(self):
- """Call initialisation function.
- """
- self._traffic_gen_class.connect()
-
- def __exit__(self, type_, value, traceback):
- """Stop traffic, clean up.
- """
- if self._traffic_started:
- self.stop_traffic()
-
- @staticmethod
- def _append_results(result_dict, packet_size):
- """Adds common values to traffic generator results.
-
- :param result_dict: Dictionary containing results from trafficgen
- :param packet_size: Packet size value.
-
- :returns: dictionary of results with additional entries.
- """
-
- ret_value = result_dict
-
- # TODO Old TOIT controller had knowledge about scenario beeing
- # executed, should new controller also fill Configuration & ID,
- # or this should be passed to TestCase?
- ret_value[ResultsConstants.TYPE] = 'rfc2544'
- ret_value[ResultsConstants.PACKET_SIZE] = str(packet_size)
-
- return ret_value
+ super(TrafficControllerRFC2544, self).__init__(traffic_gen_class)
+ self._type = 'rfc2544'
+ self._tests = int(settings.getValue('TRAFFICGEN_RFC2544_TESTS'))
def send_traffic(self, traffic):
- """See ITrafficController for description
+ """See TrafficController for description
"""
+ if not self.traffic_required():
+ return
self._logger.debug('send_traffic with ' +
str(self._traffic_gen_class))
@@ -109,13 +60,14 @@ class TrafficControllerRFC2544(ITrafficController, IResults):
result = self._traffic_gen_class.send_rfc2544_throughput(
traffic, tests=self._tests, duration=self._duration, lossrate=self._lossrate)
- result = TrafficControllerRFC2544._append_results(result,
- packet_size)
+ result = self._append_results(result, packet_size)
self._results.append(result)
def send_traffic_async(self, traffic, function):
- """See ITrafficController for description
+ """See TrafficController for description
"""
+ if not self.traffic_required():
+ return
self._logger.debug('send_traffic_async with ' +
str(self._traffic_gen_class))
@@ -131,40 +83,5 @@ class TrafficControllerRFC2544(ITrafficController, IResults):
else:
function['function']()
result = self._traffic_gen_class.wait_rfc2544_throughput()
- result = TrafficControllerRFC2544._append_results(result,
- packet_size)
+ result = self._append_results(result, packet_size)
self._results.append(result)
-
- def stop_traffic(self):
- """Kills traffic being sent from the traffic generator.
- """
- self._logger.debug("stop_traffic()")
-
- def print_results(self):
- """IResult interface implementation.
- """
- counter = 0
- for item in self._results:
- logging.info("Record: " + str(counter))
- counter += 1
- for(key, value) in list(item.items()):
- logging.info(" Key: " + str(key) +
- ", Value: " + str(value))
-
- def get_results(self):
- """IResult interface implementation.
- """
- return self._results
-
- def validate_send_traffic(self, dummy_result, dummy_traffic):
- """Verify that send traffic has succeeded
- """
- if len(self._results):
- if 'b2b_frames' in self._results[-1]:
- return float(self._results[-1]['b2b_frames']) > 0
- elif 'throughput_rx_fps' in self._results[-1]:
- return float(self._results[-1]['throughput_rx_fps']) > 0
- else:
- return True
- else:
- return False
diff --git a/core/traffic_controller_rfc2889.py b/core/traffic_controller_rfc2889.py
index a97a47d3..210d5f5f 100644
--- a/core/traffic_controller_rfc2889.py
+++ b/core/traffic_controller_rfc2889.py
@@ -1,15 +1,24 @@
+# Copyright 2016 Spirent Communications, 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.
"""RFC2889 Traffic Controller implementation.
"""
-import logging
-
-from core.traffic_controller import ITrafficController
-from core.results.results_constants import ResultsConstants
+from core.traffic_controller import TrafficController
from core.results.results import IResults
from conf import settings
-from conf import get_test_param
-class TrafficControllerRFC2889(ITrafficController, IResults):
+class TrafficControllerRFC2889(TrafficController, IResults):
"""Traffic controller for RFC2889 traffic
Used to setup and control a traffic generator for an RFC2889 deployment
@@ -21,56 +30,15 @@ class TrafficControllerRFC2889(ITrafficController, IResults):
:param traffic_gen_class: The traffic generator class to be used.
"""
- self._logger = logging.getLogger(__name__)
- self._logger.debug("__init__")
- self._traffic_gen_class = traffic_gen_class()
- self._traffic_started = False
- self._traffic_started_call_count = 0
- self._trials = int(get_test_param('rfc2889_trials', 1))
- self._duration = int(get_test_param('duration', 30))
- self._results = []
-
- # If set, comma separated packet_sizes value from --test_params
- # on cli takes precedence over value in settings file.
- self._packet_sizes = None
- packet_sizes_cli = get_test_param('pkt_sizes')
- if packet_sizes_cli:
- self._packet_sizes = [int(x.strip())
- for x in packet_sizes_cli.split(',')]
- else:
- self._packet_sizes = settings.getValue('TRAFFICGEN_PKT_SIZES')
-
- def __enter__(self):
- """Call initialisation function.
- """
- self._traffic_gen_class.connect()
-
- def __exit__(self, type_, value, traceback):
- """Stop traffic, clean up.
- """
- if self._traffic_started:
- self.stop_traffic()
-
- @staticmethod
- def _append_results(result_dict, packet_size):
- """Adds common values to traffic generator results.
-
- :param result_dict: Dictionary containing results from trafficgen
- :param packet_size: Packet size value.
-
- :returns: dictionary of results with additional entries.
- """
-
- ret_value = result_dict
-
- ret_value[ResultsConstants.TYPE] = 'rfc2889'
- ret_value[ResultsConstants.PACKET_SIZE] = str(packet_size)
-
- return ret_value
+ super(TrafficControllerRFC2889, self).__init__(traffic_gen_class)
+ self._type = 'rfc2889'
+ self._trials = int(settings.getValue('TRAFFICGEN_RFC2889_TRIALS'))
def send_traffic(self, traffic):
- """See ITrafficController for description
+ """See TrafficController for description
"""
+ if not self.traffic_required():
+ return
self._logger.debug('send_traffic with ' +
str(self._traffic_gen_class))
@@ -92,13 +60,14 @@ class TrafficControllerRFC2889(ITrafficController, IResults):
result = self._traffic_gen_class.send_rfc2889_forwarding(
traffic, tests=self._trials, duration=self._duration)
- result = TrafficControllerRFC2889._append_results(result,
- packet_size)
+ result = self._append_results(result, packet_size)
self._results.append(result)
def send_traffic_async(self, traffic, function):
- """See ITrafficController for description
+ """See TrafficController for description
"""
+ if not self.traffic_required():
+ return
self._logger.debug('send_traffic_async with ' +
str(self._traffic_gen_class))
@@ -114,33 +83,6 @@ class TrafficControllerRFC2889(ITrafficController, IResults):
else:
function['function']()
result = self._traffic_gen_class.wait_rfc2889_forwarding(
- traffic, trials=self._trials, duration=self._duration)
- result = TrafficControllerRFC2889._append_results(result,
- packet_size)
+ traffic, trials=self._trials, duration=self._duration)
+ result = self._append_results(result, packet_size)
self._results.append(result)
-
- def stop_traffic(self):
- """Kills traffic being sent from the traffic generator.
- """
- self._logger.debug("stop_traffic()")
-
- def print_results(self):
- """IResult interface implementation.
- """
- counter = 0
- for item in self._results:
- logging.info("Record: " + str(counter))
- counter += 1
- for(key, value) in list(item.items()):
- logging.info(" Key: " + str(key) +
- ", Value: " + str(value))
-
- def get_results(self):
- """IResult interface implementation.
- """
- return self._results
-
- def validate_send_traffic(self, result, traffic):
- """Verify that send traffic has succeeded
- """
- return True
diff --git a/core/vnf_controller.py b/core/vnf_controller.py
index 3e472f04..937cd5cc 100644
--- a/core/vnf_controller.py
+++ b/core/vnf_controller.py
@@ -31,10 +31,14 @@ class VnfController(object):
_vnfs: A list of vnfs controlled by the controller.
"""
- def __init__(self, deployment, vnf_class):
+ def __init__(self, deployment, vnf_class, extra_vnfs):
"""Sets up the VNF infrastructure based on deployment scenario
:param vnf_class: The VNF class to be used.
+ :param extra_vnfs: The number of VNFs not involved in given
+ deployment scenario. It will be used to correctly expand
+ configuration values and initialize shared dirs. This parameter
+ is used in case, that additional VNFs are executed by TestSteps.
"""
# reset VNF ID counter for each testcase
IVnf.reset_vnf_counter()
@@ -57,9 +61,9 @@ class VnfController(object):
# without VNFs like p2p
vm_number = 0
- if vm_number:
- self._logger.debug('Check configuration for %s guests.', vm_number)
- settings.check_vm_settings(vm_number)
+ if vm_number + extra_vnfs > 0:
+ self._logger.debug('Check configuration for %s guests.', vm_number + extra_vnfs)
+ settings.check_vm_settings(vm_number + extra_vnfs)
# enforce that GUEST_NIC_NR is 1 or even number of NICs
updated = False
nics_nr = settings.getValue('GUEST_NICS_NR')
@@ -73,10 +77,11 @@ class VnfController(object):
'was updated to GUEST_NICS_NR = %s',
settings.getValue('GUEST_NICS_NR'))
+ if vm_number:
self._vnfs = [vnf_class() for _ in range(vm_number)]
- self._logger.debug('__init__ ' + str(len(self._vnfs)) +
- ' VNF[s] with ' + ' '.join(map(str, self._vnfs)))
+ self._logger.debug('__init__ ' + str(len(self._vnfs)) +
+ ' VNF[s] with ' + ' '.join(map(str, self._vnfs)))
def get_vnfs(self):
"""Returns a list of vnfs controlled by this controller.
diff --git a/docs/configguide/installation.rst b/docs/configguide/installation.rst
index 2f3faaeb..7ba64bba 100755
--- a/docs/configguide/installation.rst
+++ b/docs/configguide/installation.rst
@@ -13,7 +13,7 @@ Supported Operating Systems
* Fedora 20
* Fedora 21
* Fedora 22
-* RedHat 7.2
+* RedHat 7.2 Enterprise
* Ubuntu 14.04
Supported vSwitches
@@ -99,8 +99,8 @@ reside in a directory called **vsperfenv** in $HOME.
You will need to activate the virtual environment every time you start a
new shell session. Its activation is specific to your OS:
-CentOS 7
-========
+CentOS 7 and RedHat
+===================
.. code:: bash
@@ -108,8 +108,8 @@ CentOS 7
$ cd $HOME/vsperfenv
$ source bin/activate
-Fedora, RedHat and Ubuntu
-=========================
+Fedora and Ubuntu
+=================
.. code:: bash
diff --git a/docs/configguide/trafficgen.rst b/docs/configguide/trafficgen.rst
index 6ede7f2f..efcc4d83 100644
--- a/docs/configguide/trafficgen.rst
+++ b/docs/configguide/trafficgen.rst
@@ -69,7 +69,7 @@ OR from the commandline:
.. code-block:: console
- $ ./vsperf --test-params "pkt_sizes=x,y" $TESTNAME
+ $ ./vsperf --test-params "TRAFFICGEN_PKT_SIZES=(x,y)" $TESTNAME
You can also modify the traffic transmission duration and the number
of tests run by the traffic generator by extending the example
@@ -77,7 +77,8 @@ commandline above to:
.. code-block:: console
- $ ./vsperf --test-params "pkt_sizes=x,y;duration=10;rfc2544_tests=1" $TESTNAME
+ $ ./vsperf --test-params "TRAFFICGEN_PKT_SIZES=(x,y);TRAFFICGEN_DURATION=10;" \
+ "TRAFFICGEN_RFC2544_TESTS=1" $TESTNAME
Dummy Setup
------------
@@ -475,9 +476,9 @@ One can set up this ssh access by doing the following on both servers:
Configuration
~~~~~~~~~~~~~
-Connection information for your Xena Chassis must be supplied inside the
+Connection information for MoonGen must be supplied inside the
``10_custom.conf`` or ``03_custom.conf`` file. The following parameters must be
-set to allow for proper connections to the chassis.
+set to allow for proper connections to the host with MoonGen.
.. code-block:: console
diff --git a/docs/design/vswitchperf_design.rst b/docs/design/vswitchperf_design.rst
index 375fa12e..88b6ba88 100755
--- a/docs/design/vswitchperf_design.rst
+++ b/docs/design/vswitchperf_design.rst
@@ -53,7 +53,8 @@ for development purposes:
.. code-block:: console
- $ ./vsperf --test-params 'duration=10;rfc2544_tests=1;pkt_sizes=64' --tests 'pvp_tput'
+ $ ./vsperf --test-params 'TRAFFICGEN_DURATION=10;TRAFFICGEN_RFC2544_TESTS=1;' \
+ 'TRAFFICGEN_PKT_SIZES=(64,)' pvp_tput
Typical Test Sequence
=====================
diff --git a/docs/requirements/ietf_draft/draft-ietf-bmwg-vswitch-opnfv-01.xml b/docs/requirements/ietf_draft/draft-ietf-bmwg-vswitch-opnfv-01.xml
new file mode 100755
index 00000000..c8a3d99b
--- /dev/null
+++ b/docs/requirements/ietf_draft/draft-ietf-bmwg-vswitch-opnfv-01.xml
@@ -0,0 +1,1027 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
+<?rfc toc="yes"?>
+<?rfc tocompact="yes"?>
+<?rfc tocdepth="3"?>
+<?rfc tocindent="yes"?>
+<?rfc symrefs="yes"?>
+<?rfc sortrefs="yes"?>
+<?rfc comments="yes"?>
+<?rfc inline="yes"?>
+<?rfc compact="yes"?>
+<?rfc subcompact="no"?>
+<rfc category="info" docName="draft-ietf-bmwg-vswitch-opnfv-01"
+ ipr="trust200902">
+ <front>
+ <title abbrev="Benchmarking vSwitches">Benchmarking Virtual Switches in
+ OPNFV</title>
+
+ <author fullname="Maryam Tahhan" initials="M." surname="Tahhan">
+ <organization>Intel</organization>
+
+ <address>
+ <postal>
+ <street/>
+
+ <city/>
+
+ <region/>
+
+ <code/>
+
+ <country/>
+ </postal>
+
+ <phone/>
+
+ <facsimile/>
+
+ <email>maryam.tahhan@intel.com</email>
+
+ <uri/>
+ </address>
+ </author>
+
+ <author fullname="Billy O'Mahony" initials="B." surname="O'Mahony">
+ <organization>Intel</organization>
+
+ <address>
+ <postal>
+ <street/>
+
+ <city/>
+
+ <region/>
+
+ <code/>
+
+ <country/>
+ </postal>
+
+ <phone/>
+
+ <facsimile/>
+
+ <email>billy.o.mahony@intel.com</email>
+
+ <uri/>
+ </address>
+ </author>
+
+ <author fullname="Al Morton" initials="A." surname="Morton">
+ <organization>AT&amp;T Labs</organization>
+
+ <address>
+ <postal>
+ <street>200 Laurel Avenue South</street>
+
+ <city>Middletown,</city>
+
+ <region>NJ</region>
+
+ <code>07748</code>
+
+ <country>USA</country>
+ </postal>
+
+ <phone>+1 732 420 1571</phone>
+
+ <facsimile>+1 732 368 1192</facsimile>
+
+ <email>acmorton@att.com</email>
+
+ <uri>http://home.comcast.net/~acmacm/</uri>
+ </address>
+ </author>
+
+ <date day="10" month="October" year="2016"/>
+
+ <abstract>
+ <t>This memo describes the progress of the Open Platform for NFV (OPNFV)
+ project on virtual switch performance "VSWITCHPERF". This project
+ intends to build on the current and completed work of the Benchmarking
+ Methodology Working Group in IETF, by referencing existing literature.
+ The Benchmarking Methodology Working Group has traditionally conducted
+ laboratory characterization of dedicated physical implementations of
+ internetworking functions. Therefore, this memo begins to describe the
+ additional considerations when virtual switches are implemented in
+ general-purpose hardware. The expanded tests and benchmarks are also
+ influenced by the OPNFV mission to support virtualization of the "telco"
+ infrastructure.</t>
+ </abstract>
+
+ <note title="Requirements Language">
+ <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in <xref
+ target="RFC2119">RFC 2119</xref>.</t>
+
+ <t/>
+ </note>
+ </front>
+
+ <middle>
+ <section title="Introduction">
+ <t>Benchmarking Methodology Working Group (BMWG) has traditionally
+ conducted laboratory characterization of dedicated physical
+ implementations of internetworking functions. The Black-box Benchmarks
+ of Throughput, Latency, Forwarding Rates and others have served our
+ industry for many years. Now, Network Function Virtualization (NFV) has
+ the goal to transform how internetwork functions are implemented, and
+ therefore has garnered much attention.</t>
+
+ <t>This memo summarizes the progress of the Open Platform for NFV
+ (OPNFV) project on virtual switch performance characterization,
+ "VSWITCHPERF", through the Brahmaputra (second) release <xref
+ target="BrahRel"/>. This project intends to build on the current and
+ completed work of the Benchmarking Methodology Working Group in IETF, by
+ referencing existing literature. For example, currently the most often
+ referenced RFC is <xref target="RFC2544"/> (which depends on <xref
+ target="RFC1242"/>) and foundation of the benchmarking work in OPNFV is
+ common and strong.</t>
+
+ <t>See
+ https://wiki.opnfv.org/characterize_vswitch_performance_for_telco_nfv_use_cases
+ for more background, and the OPNFV website for general information:
+ https://www.opnfv.org/</t>
+
+ <t>The authors note that OPNFV distinguishes itself from other open
+ source compute and networking projects through its emphasis on existing
+ "telco" services as opposed to cloud-computing. There are many ways in
+ which telco requirements have different emphasis on performance
+ dimensions when compared to cloud computing: support for and transfer of
+ isochronous media streams is one example.</t>
+
+ <t>Note also that the move to NFV Infrastructure has resulted in many
+ new benchmarking initiatives across the industry. The authors are
+ currently doing their best to maintain alignment with many other
+ projects, and this Internet Draft is one part of the efforts. We
+ acknowledge the early work in <xref
+ target="I-D.huang-bmwg-virtual-network-performance"/>, and useful
+ discussion with the authors.</t>
+ </section>
+
+ <section title="Scope">
+ <t>The primary purpose and scope of the memo is to inform the industry
+ of work-in-progress that builds on the body of extensive BMWG literature
+ and experience, and describe the extensions needed for benchmarking
+ virtual switches. Inital feedback indicates that many of these
+ extensions may be applicable beyond the current scope (to hardware
+ switches in the NFV Infrastructure and to virtual routers, for example).
+ Additionally, this memo serves as a vehicle to include more detail and
+ commentary from BMWG and other Open Source communities, under BMWG's
+ chartered work to characterize the NFV Infrastructure (a virtual switch
+ is an important aspect of that infrastructure).</t>
+
+ <t>The benchmarking covered in this memo should be applicable to many
+ types of vswitches, and remain vswitch-agnostic to great degree. There
+ has been no attempt to track and test all features of any specific
+ vswitch implementation.</t>
+ </section>
+
+ <section title="Benchmarking Considerations">
+ <t>This section highlights some specific considerations (from <xref
+ target="I-D.ietf-bmwg-virtual-net"/>)related to Benchmarks for virtual
+ switches. The OPNFV project is sharing its present view on these areas,
+ as they develop their specifications in the Level Test Design (LTD)
+ document.</t>
+
+ <section title="Comparison with Physical Network Functions">
+ <t>To compare the performance of virtual designs and implementations
+ with their physical counterparts, identical benchmarks are needed.
+ BMWG has developed specifications for many network functions this memo
+ re-uses existing benchmarks through references, and expands them
+ during development of new methods. A key configuration aspect is the
+ number of parallel cores required to achieve comparable performance
+ with a given physical device, or whether some limit of scale was
+ reached before the cores could achieve the comparable level.</t>
+
+ <t>It's unlikely that the virtual switch will be the only application
+ running on the SUT, so CPU utilization, Cache utilization, and Memory
+ footprint should also be recorded for the virtual implementations of
+ internetworking functions.</t>
+ </section>
+
+ <section title="Continued Emphasis on Black-Box Benchmarks">
+ <t>External observations remain essential as the basis for Benchmarks.
+ Internal observations with fixed specification and interpretation will
+ be provided in parallel to assist the development of operations
+ procedures when the technology is deployed.</t>
+ </section>
+
+ <section title="New Configuration Parameters">
+ <t>A key consideration when conducting any sort of benchmark is trying
+ to ensure the consistency and repeatability of test results. When
+ benchmarking the performance of a vSwitch there are many factors that
+ can affect the consistency of results, one key factor is matching the
+ various hardware and software details of the SUT. This section lists
+ some of the many new parameters which this project believes are
+ critical to report in order to achieve repeatability.</t>
+
+ <t>Hardware details including:</t>
+
+ <t><list style="symbols">
+ <t>Platform details</t>
+
+ <t>Processor details</t>
+
+ <t>Memory information (type and size)</t>
+
+ <t>Number of enabled cores</t>
+
+ <t>Number of cores used for the test</t>
+
+ <t>Number of physical NICs, as well as their details
+ (manufacturer, versions, type and the PCI slot they are plugged
+ into)</t>
+
+ <t>NIC interrupt configuration</t>
+
+ <t>BIOS version, release date and any configurations that were
+ modified</t>
+
+ <t>CPU microcode level</t>
+
+ <t>Memory DIMM configurations (quad rank performance may not be
+ the same as dual rank) in size, freq and slot locations</t>
+
+ <t>PCI configuration parameters (payload size, early ack
+ option...)</t>
+
+ <t>Power management at all levels (ACPI sleep states, processor
+ package, OS...)</t>
+ </list>Software details including:</t>
+
+ <t><list style="symbols">
+ <t>OS parameters and behavior (text vs graphical no one typing at
+ the console on one system)</t>
+
+ <t>OS version (for host and VNF)</t>
+
+ <t>Kernel version (for host and VNF)</t>
+
+ <t>GRUB boot parameters (for host and VNF)</t>
+
+ <t>Hypervisor details (Type and version)</t>
+
+ <t>Selected vSwitch, version number or commit id used</t>
+
+ <t>vSwitch launch command line if it has been parameterised</t>
+
+ <t>Memory allocation to the vSwitch</t>
+
+ <t>which NUMA node it is using, and how many memory channels</t>
+
+ <t>DPDK or any other SW dependency version number or commit id
+ used</t>
+
+ <t>Memory allocation to a VM - if it's from Hugpages/elsewhere</t>
+
+ <t>VM storage type: snapshot/independent persistent/independent
+ non-persistent</t>
+
+ <t>Number of VMs</t>
+
+ <t>Number of Virtual NICs (vNICs), versions, type and driver</t>
+
+ <t>Number of virtual CPUs and their core affinity on the host</t>
+
+ <t>Number vNIC interrupt configuration</t>
+
+ <t>Thread affinitization for the applications (including the
+ vSwitch itself) on the host</t>
+
+ <t>Details of Resource isolation, such as CPUs designated for
+ Host/Kernel (isolcpu) and CPUs designated for specific processes
+ (taskset). - Test duration. - Number of flows.</t>
+ </list></t>
+
+ <t>Test Traffic Information:<list style="symbols">
+ <t>Traffic type - UDP, TCP, IMIX / Other</t>
+
+ <t>Packet Sizes</t>
+
+ <t>Deployment Scenario</t>
+ </list></t>
+
+ <t/>
+ </section>
+
+ <section title="Flow classification">
+ <t>Virtual switches group packets into flows by processing and
+ matching particular packet or frame header information, or by matching
+ packets based on the input ports. Thus a flow can be thought of a
+ sequence of packets that have the same set of header field values
+ (5-tuple) or have arrived on the same port. Performance results can
+ vary based on the parameters the vSwitch uses to match for a flow. The
+ recommended flow classification parameters for any vSwitch performance
+ tests are: the input port, the source IP address, the destination IP
+ address and the Ethernet protocol type field. It is essential to
+ increase the flow timeout time on a vSwitch before conducting any
+ performance tests that do not measure the flow setup time. Normally
+ the first packet of a particular stream will install the flow in the
+ virtual switch which adds an additional latency, subsequent packets of
+ the same flow are not subject to this latency if the flow is already
+ installed on the vSwitch.</t>
+ </section>
+
+ <section title="Benchmarks using Baselines with Resource Isolation">
+ <t>This outline describes measurement of baseline with isolated
+ resources at a high level, which is the intended approach at this
+ time.</t>
+
+ <t><list style="numbers">
+ <t>Baselines: <list style="symbols">
+ <t>Optional: Benchmark platform forwarding capability without
+ a vswitch or VNF for at least 72 hours (serves as a means of
+ platform validation and a means to obtain the base performance
+ for the platform in terms of its maximum forwarding rate and
+ latency). <figure>
+ <preamble>Benchmark platform forwarding
+ capability</preamble>
+
+ <artwork align="right"><![CDATA[ __
+ +--------------------------------------------------+ |
+ | +------------------------------------------+ | |
+ | | | | |
+ | | Simple Forwarding App | | Host
+ | | | | |
+ | +------------------------------------------+ | |
+ | | NIC | | |
+ +---+------------------------------------------+---+ __|
+ ^ :
+ | |
+ : v
+ +--------------------------------------------------+
+ | |
+ | traffic generator |
+ | |
+ +--------------------------------------------------+]]></artwork>
+
+ <postamble/>
+ </figure></t>
+
+ <t>Benchmark VNF forwarding capability with direct
+ connectivity (vSwitch bypass, e.g., SR/IOV) for at least 72
+ hours (serves as a means of VNF validation and a means to
+ obtain the base performance for the VNF in terms of its
+ maximum forwarding rate and latency). The metrics gathered
+ from this test will serve as a key comparison point for
+ vSwitch bypass technologies performance and vSwitch
+ performance. <figure align="right">
+ <preamble>Benchmark VNF forwarding capability</preamble>
+
+ <artwork><![CDATA[ __
+ +--------------------------------------------------+ |
+ | +------------------------------------------+ | |
+ | | | | |
+ | | VNF | | |
+ | | | | |
+ | +------------------------------------------+ | |
+ | | Passthrough/SR-IOV | | Host
+ | +------------------------------------------+ | |
+ | | NIC | | |
+ +---+------------------------------------------+---+ __|
+ ^ :
+ | |
+ : v
+ +--------------------------------------------------+
+ | |
+ | traffic generator |
+ | |
+ +--------------------------------------------------+]]></artwork>
+
+ <postamble/>
+ </figure></t>
+
+ <t>Benchmarking with isolated resources alone, with other
+ resources (both HW&amp;SW) disabled Example, vSw and VM are
+ SUT</t>
+
+ <t>Benchmarking with isolated resources alone, leaving some
+ resources unused</t>
+
+ <t>Benchmark with isolated resources and all resources
+ occupied</t>
+ </list></t>
+
+ <t>Next Steps<list style="symbols">
+ <t>Limited sharing</t>
+
+ <t>Production scenarios</t>
+
+ <t>Stressful scenarios</t>
+ </list></t>
+ </list></t>
+ </section>
+ </section>
+
+ <section title="VSWITCHPERF Specification Summary">
+ <t>The overall specification in preparation is referred to as a Level
+ Test Design (LTD) document, which will contain a suite of performance
+ tests. The base performance tests in the LTD are based on the
+ pre-existing specifications developed by BMWG to test the performance of
+ physical switches. These specifications include:</t>
+
+ <t><list style="symbols">
+ <t><xref target="RFC2544"/> Benchmarking Methodology for Network
+ Interconnect Devices</t>
+
+ <t><xref target="RFC2889"/> Benchmarking Methodology for LAN
+ Switching</t>
+
+ <t><xref target="RFC6201"/> Device Reset Characterization</t>
+
+ <t><xref target="RFC5481"/> Packet Delay Variation Applicability
+ Statement</t>
+ </list></t>
+
+ <t>Some of the above/newer RFCs are being applied in benchmarking for
+ the first time, and represent a development challenge for test equipment
+ developers. Fortunately, many members of the testing system community
+ have engaged on the VSPERF project, including an open source test
+ system.</t>
+
+ <t>In addition to this, the LTD also re-uses the terminology defined
+ by:</t>
+
+ <t><list style="symbols">
+ <t><xref target="RFC2285"/> Benchmarking Terminology for LAN
+ Switching Devices</t>
+
+ <t><xref target="RFC5481"/> Packet Delay Variation Applicability
+ Statement</t>
+ </list></t>
+
+ <t/>
+
+ <t>Specifications to be included in future updates of the LTD
+ include:<list style="symbols">
+ <t><xref target="RFC3918"/> Methodology for IP Multicast
+ Benchmarking</t>
+
+ <t><xref target="RFC4737"/> Packet Reordering Metrics</t>
+ </list></t>
+
+ <t>As one might expect, the most fundamental internetworking
+ characteristics of Throughput and Latency remain important when the
+ switch is virtualized, and these benchmarks figure prominently in the
+ specification.</t>
+
+ <t>When considering characteristics important to "telco" network
+ functions, we must begin to consider additional performance metrics. In
+ this case, the project specifications have referenced metrics from the
+ IETF IP Performance Metrics (IPPM) literature. This means that the <xref
+ target="RFC2544"/> test of Latency is replaced by measurement of a
+ metric derived from IPPM's <xref target="RFC2679"/>, where a set of
+ statistical summaries will be provided (mean, max, min, etc.). Further
+ metrics planned to be benchmarked include packet delay variation as
+ defined by <xref target="RFC5481"/> , reordering, burst behaviour, DUT
+ availability, DUT capacity and packet loss in long term testing at
+ Throughput level, where some low-level of background loss may be present
+ and characterized.</t>
+
+ <t>Tests have been (or will be) designed to collect the metrics
+ below:</t>
+
+ <t><list style="symbols">
+ <t>Throughput Tests to measure the maximum forwarding rate (in
+ frames per second or fps) and bit rate (in Mbps) for a constant load
+ (as defined by <xref target="RFC1242"/>) without traffic loss.</t>
+
+ <t>Packet and Frame Delay Distribution Tests to measure average, min
+ and max packet and frame delay for constant loads.</t>
+
+ <t>Packet Delay Tests to understand latency distribution for
+ different packet sizes and over an extended test run to uncover
+ outliers.</t>
+
+ <t>Scalability Tests to understand how the virtual switch performs
+ as the number of flows, active ports, complexity of the forwarding
+ logic&rsquo;s configuration&hellip; it has to deal with
+ increases.</t>
+
+ <t>Stream Performance Tests (TCP, UDP) to measure bulk data transfer
+ performance, i.e. how fast systems can send and receive data through
+ the switch.</t>
+
+ <t>Control Path and Datapath Coupling Tests, to understand how
+ closely coupled the datapath and the control path are as well as the
+ effect of this coupling on the performance of the DUT (example:
+ delay of the initial packet of a flow).</t>
+
+ <t>CPU and Memory Consumption Tests to understand the virtual
+ switch&rsquo;s footprint on the system, usually conducted as
+ auxiliary measurements with benchmarks above. They include: CPU
+ utilization, Cache utilization and Memory footprint.</t>
+
+ <t>The so-called "Soak" tests, where the selected test is conducted
+ over a long period of time (with an ideal duration of 24 hours, but
+ only long enough to determine that stability issues exist when
+ found; there is no requirement to continue a test when a DUT
+ exhibits instability over time). The key performance characteristics
+ and benchmarks for a DUT are determined (using short duration tests)
+ prior to conducting soak tests. The purpose of soak tests is to
+ capture transient changes in performance which may occur due to
+ infrequent processes, memory leaks, or the low probability
+ coincidence of two or more processes. The stability of the DUT is
+ the paramount consideration, so performance must be evaluated
+ periodically during continuous testing, and this results in use of
+ <xref target="RFC2889"/> Frame Rate metrics instead of <xref
+ target="RFC2544"/> Throughput (which requires stopping traffic to
+ allow time for all traffic to exit internal queues), for
+ example.</t>
+ </list></t>
+
+ <t>Future/planned test specs include:<list style="symbols">
+ <t>Request/Response Performance Tests (TCP, UDP) which measure the
+ transaction rate through the switch.</t>
+
+ <t>Noisy Neighbour Tests, to understand the effects of resource
+ sharing on the performance of a virtual switch.</t>
+
+ <t>Tests derived from examination of ETSI NFV Draft GS IFA003
+ requirements <xref target="IFA003"/> on characterization of
+ acceleration technologies applied to vswitches.</t>
+ </list>The flexibility of deployment of a virtual switch within a
+ network means that the BMWG IETF existing literature needs to be used to
+ characterize the performance of a switch in various deployment
+ scenarios. The deployment scenarios under consideration include:</t>
+
+ <t><figure>
+ <preamble>Physical port to virtual switch to physical
+ port</preamble>
+
+ <artwork><![CDATA[ __
+ +--------------------------------------------------+ |
+ | +--------------------+ | |
+ | | | | |
+ | | v | | Host
+ | +--------------+ +--------------+ | |
+ | | phy port | vSwitch | phy port | | |
+ +---+--------------+------------+--------------+---+ __|
+ ^ :
+ | |
+ : v
+ +--------------------------------------------------+
+ | |
+ | traffic generator |
+ | |
+ +--------------------------------------------------+]]></artwork>
+ </figure></t>
+
+ <t><figure>
+ <preamble>Physical port to virtual switch to VNF to virtual switch
+ to physical port</preamble>
+
+ <artwork><![CDATA[ __
+ +---------------------------------------------------+ |
+ | | |
+ | +-------------------------------------------+ | |
+ | | Application | | |
+ | +-------------------------------------------+ | |
+ | ^ : | |
+ | | | | | Guest
+ | : v | |
+ | +---------------+ +---------------+ | |
+ | | logical port 0| | logical port 1| | |
+ +---+---------------+-----------+---------------+---+ __|
+ ^ :
+ | |
+ : v __
+ +---+---------------+----------+---------------+---+ |
+ | | logical port 0| | logical port 1| | |
+ | +---------------+ +---------------+ | |
+ | ^ : | |
+ | | | | | Host
+ | : v | |
+ | +--------------+ +--------------+ | |
+ | | phy port | vSwitch | phy port | | |
+ +---+--------------+------------+--------------+---+ __|
+ ^ :
+ | |
+ : v
+ +--------------------------------------------------+
+ | |
+ | traffic generator |
+ | |
+ +--------------------------------------------------+]]></artwork>
+ </figure><figure>
+ <preamble>Physical port to virtual switch to VNF to virtual switch
+ to VNF to virtual switch to physical port</preamble>
+
+ <artwork><![CDATA[ __
+ +----------------------+ +----------------------+ |
+ | Guest 1 | | Guest 2 | |
+ | +---------------+ | | +---------------+ | |
+ | | Application | | | | Application | | |
+ | +---------------+ | | +---------------+ | |
+ | ^ | | | ^ | | |
+ | | v | | | v | | Guests
+ | +---------------+ | | +---------------+ | |
+ | | logical ports | | | | logical ports | | |
+ | | 0 1 | | | | 0 1 | | |
+ +---+---------------+--+ +---+---------------+--+__|
+ ^ : ^ :
+ | | | |
+ : v : v _
+ +---+---------------+---------+---------------+--+ |
+ | | 0 1 | | 3 4 | | |
+ | | logical ports | | logical ports | | |
+ | +---------------+ +---------------+ | |
+ | ^ | ^ | | | Host
+ | | |-----------------| v | |
+ | +--------------+ +--------------+ | |
+ | | phy ports | vSwitch | phy ports | | |
+ +---+--------------+----------+--------------+---+_|
+ ^ :
+ | |
+ : v
+ +--------------------------------------------------+
+ | |
+ | traffic generator |
+ | |
+ +--------------------------------------------------+]]></artwork>
+ </figure><figure>
+ <preamble>Physical port to virtual switch to VNF</preamble>
+
+ <artwork><![CDATA[ __
+ +---------------------------------------------------+ |
+ | | |
+ | +-------------------------------------------+ | |
+ | | Application | | |
+ | +-------------------------------------------+ | |
+ | ^ | |
+ | | | | Guest
+ | : | |
+ | +---------------+ | |
+ | | logical port 0| | |
+ +---+---------------+-------------------------------+ __|
+ ^
+ |
+ : __
+ +---+---------------+------------------------------+ |
+ | | logical port 0| | |
+ | +---------------+ | |
+ | ^ | |
+ | | | | Host
+ | : | |
+ | +--------------+ | |
+ | | phy port | vSwitch | |
+ +---+--------------+------------ -------------- ---+ __|
+ ^
+ |
+ :
+ +--------------------------------------------------+
+ | |
+ | traffic generator |
+ | |
+ +--------------------------------------------------+]]></artwork>
+ </figure><figure>
+ <preamble>VNF to virtual switch to physical port</preamble>
+
+ <artwork><![CDATA[ __
+ +---------------------------------------------------+ |
+ | | |
+ | +-------------------------------------------+ | |
+ | | Application | | |
+ | +-------------------------------------------+ | |
+ | : | |
+ | | | | Guest
+ | v | |
+ | +---------------+ | |
+ | | logical port | | |
+ +-------------------------------+---------------+---+ __|
+ :
+ |
+ v __
+ +------------------------------+---------------+---+ |
+ | | logical port | | |
+ | +---------------+ | |
+ | : | |
+ | | | | Host
+ | v | |
+ | +--------------+ | |
+ | vSwitch | phy port | | |
+ +-------------------------------+--------------+---+ __|
+ :
+ |
+ v
+ +--------------------------------------------------+
+ | |
+ | traffic generator |
+ | |
+ +--------------------------------------------------+]]></artwork>
+ </figure><figure>
+ <preamble>VNF to virtual switch to VNF</preamble>
+
+ <artwork><![CDATA[ __
+ +----------------------+ +----------------------+ |
+ | Guest 1 | | Guest 2 | |
+ | +---------------+ | | +---------------+ | |
+ | | Application | | | | Application | | |
+ | +---------------+ | | +---------------+ | |
+ | | | | ^ | |
+ | v | | | | | Guests
+ | +---------------+ | | +---------------+ | |
+ | | logical ports | | | | logical ports | | |
+ | | 0 | | | | 0 | | |
+ +---+---------------+--+ +---+---------------+--+__|
+ : ^
+ | |
+ v : _
+ +---+---------------+---------+---------------+--+ |
+ | | 1 | | 1 | | |
+ | | logical ports | | logical ports | | |
+ | +---------------+ +---------------+ | |
+ | | ^ | | Host
+ | L-----------------+ | |
+ | | |
+ | vSwitch | |
+ +------------------------------------------------+_|]]></artwork>
+ </figure></t>
+
+ <t>A set of Deployment Scenario figures is available on the VSPERF Test
+ Methodology Wiki page <xref target="TestTopo"/>.</t>
+ </section>
+
+ <section title="3x3 Matrix Coverage">
+ <t>This section organizes the many existing test specifications into the
+ "3x3" matrix (introduced in <xref target="I-D.ietf-bmwg-virtual-net"/>).
+ Because the LTD specification ID names are quite long, this section is
+ organized into lists for each occupied cell of the matrix (not all are
+ occupied, also the matrix has grown to 3x4 to accommodate scale metrics
+ when displaying the coverage of many metrics/benchmarks). The current
+ version of the LTD specification is available <xref target="LTD"/>.</t>
+
+ <t>The tests listed below assess the activation of paths in the data
+ plane, rather than the control plane.</t>
+
+ <t>A complete list of tests with short summaries is available on the
+ VSPERF "LTD Test Spec Overview" Wiki page <xref target="LTDoverV"/>.</t>
+
+ <section title="Speed of Activation">
+ <t><list style="symbols">
+ <t>Activation.RFC2889.AddressLearningRate</t>
+
+ <t>PacketLatency.InitialPacketProcessingLatency</t>
+ </list></t>
+ </section>
+
+ <section title="Accuracy of Activation section">
+ <t><list style="symbols">
+ <t>CPDP.Coupling.Flow.Addition</t>
+ </list></t>
+ </section>
+
+ <section title="Reliability of Activation">
+ <t><list style="symbols">
+ <t>Throughput.RFC2544.SystemRecoveryTime</t>
+
+ <t>Throughput.RFC2544.ResetTime</t>
+ </list></t>
+ </section>
+
+ <section title="Scale of Activation">
+ <t><list style="symbols">
+ <t>Activation.RFC2889.AddressCachingCapacity</t>
+ </list></t>
+ </section>
+
+ <section title="Speed of Operation">
+ <t><list style="symbols">
+ <t>Throughput.RFC2544.PacketLossRate</t>
+
+ <t>CPU.RFC2544.0PacketLoss</t>
+
+ <t>Throughput.RFC2544.PacketLossRateFrameModification</t>
+
+ <t>Throughput.RFC2544.BackToBackFrames</t>
+
+ <t>Throughput.RFC2889.MaxForwardingRate</t>
+
+ <t>Throughput.RFC2889.ForwardPressure</t>
+
+ <t>Throughput.RFC2889.BroadcastFrameForwarding</t>
+ </list></t>
+ </section>
+
+ <section title="Accuracy of Operation">
+ <t><list style="symbols">
+ <t>Throughput.RFC2889.ErrorFramesFiltering</t>
+
+ <t>Throughput.RFC2544.Profile</t>
+ </list></t>
+ </section>
+
+ <section title="Reliability of Operation">
+ <t><list style="symbols">
+ <t>Throughput.RFC2889.Soak</t>
+
+ <t>Throughput.RFC2889.SoakFrameModification</t>
+
+ <t>PacketDelayVariation.RFC3393.Soak</t>
+ </list></t>
+ </section>
+
+ <section title="Scalability of Operation">
+ <t><list style="symbols">
+ <t>Scalability.RFC2544.0PacketLoss</t>
+
+ <t>MemoryBandwidth.RFC2544.0PacketLoss.Scalability</t>
+ </list></t>
+ </section>
+
+ <section title="Summary">
+ <t><figure>
+ <artwork><![CDATA[|------------------------------------------------------------------------|
+| | | | | |
+| | SPEED | ACCURACY | RELIABILITY | SCALE |
+| | | | | |
+|------------------------------------------------------------------------|
+| | | | | |
+| Activation | X | X | X | X |
+| | | | | |
+|------------------------------------------------------------------------|
+| | | | | |
+| Operation | X | X | X | X |
+| | | | | |
+|------------------------------------------------------------------------|
+| | | | | |
+| De-activation | | | | |
+| | | | | |
+|------------------------------------------------------------------------|]]></artwork>
+ </figure></t>
+ </section>
+ </section>
+
+ <section title="Security Considerations">
+ <t>Benchmarking activities as described in this memo are limited to
+ technology characterization of a Device Under Test/System Under Test
+ (DUT/SUT) using controlled stimuli in a laboratory environment, with
+ dedicated address space and the constraints specified in the sections
+ above.</t>
+
+ <t>The benchmarking network topology will be an independent test setup
+ and MUST NOT be connected to devices that may forward the test traffic
+ into a production network, or misroute traffic to the test management
+ network.</t>
+
+ <t>Further, benchmarking is performed on a "black-box" basis, relying
+ solely on measurements observable external to the DUT/SUT.</t>
+
+ <t>Special capabilities SHOULD NOT exist in the DUT/SUT specifically for
+ benchmarking purposes. Any implications for network security arising
+ from the DUT/SUT SHOULD be identical in the lab and in production
+ networks.</t>
+ </section>
+
+ <section anchor="IANA" title="IANA Considerations">
+ <t>No IANA Action is requested at this time.</t>
+ </section>
+
+ <section title="Acknowledgements">
+ <t>The authors appreciate and acknowledge comments from Scott Bradner,
+ Marius Georgescu, Ramki Krishnan, Doug Montgomery, Martin Klozik,
+ Christian Trautman, and others for their reviews.</t>
+ </section>
+ </middle>
+
+ <back>
+ <references title="Normative References">
+ <?rfc ?>
+
+ <?rfc include="reference.RFC.2119"?>
+
+ <?rfc ?>
+
+ <?rfc include="reference.RFC.2330"?>
+
+ <?rfc include='reference.RFC.2544'?>
+
+ <?rfc include="reference.RFC.2679"?>
+
+ <?rfc include='reference.RFC.2680'?>
+
+ <?rfc include='reference.RFC.3393'?>
+
+ <?rfc include='reference.RFC.3432'?>
+
+ <?rfc include='reference.RFC.2681'?>
+
+ <?rfc include='reference.RFC.5905'?>
+
+ <?rfc include='reference.RFC.4689'?>
+
+ <?rfc include='reference.RFC.4737'?>
+
+ <?rfc include='reference.RFC.5357'?>
+
+ <?rfc include='reference.RFC.2889'?>
+
+ <?rfc include='reference.RFC.3918'?>
+
+ <?rfc include='reference.RFC.6201'?>
+
+ <?rfc include='reference.RFC.2285'?>
+
+ <reference anchor="NFV.PER001">
+ <front>
+ <title>Network Function Virtualization: Performance and Portability
+ Best Practices</title>
+
+ <author fullname="ETSI NFV" initials="" surname="">
+ <organization/>
+ </author>
+
+ <date month="June" year="2014"/>
+ </front>
+
+ <seriesInfo name="Group Specification"
+ value="ETSI GS NFV-PER 001 V1.1.1 (2014-06)"/>
+
+ <format type="PDF"/>
+ </reference>
+ </references>
+
+ <references title="Informative References">
+ <?rfc include='reference.RFC.1242'?>
+
+ <?rfc include='reference.RFC.5481'?>
+
+ <?rfc include='reference.RFC.6049'?>
+
+ <?rfc include='reference.RFC.6248'?>
+
+ <?rfc include='reference.RFC.6390'?>
+
+ <?rfc include='reference.I-D.ietf-bmwg-virtual-net'?>
+
+ <?rfc include='reference.I-D.huang-bmwg-virtual-network-performance'?>
+
+ <reference anchor="TestTopo">
+ <front>
+ <title>Test Topologies
+ https://wiki.opnfv.org/vsperf/test_methodology</title>
+
+ <author>
+ <organization/>
+ </author>
+
+ <date/>
+ </front>
+ </reference>
+
+ <reference anchor="LTDoverV">
+ <front>
+ <title>LTD Test Spec Overview
+ https://wiki.opnfv.org/wiki/vswitchperf_test_spec_review</title>
+
+ <author>
+ <organization/>
+ </author>
+
+ <date/>
+ </front>
+ </reference>
+
+ <reference anchor="LTD">
+ <front>
+ <title>LTD Test Specification
+ http://artifacts.opnfv.org/vswitchperf/brahmaputra/docs/requirements/index.html</title>
+
+ <author>
+ <organization/>
+ </author>
+
+ <date/>
+ </front>
+ </reference>
+
+ <reference anchor="BrahRel">
+ <front>
+ <title>Brahmaputra, Second OPNFV Release
+ https://www.opnfv.org/brahmaputra</title>
+
+ <author>
+ <organization/>
+ </author>
+
+ <date/>
+ </front>
+ </reference>
+
+ <reference anchor="IFA003">
+ <front>
+ <title>https://docbox.etsi.org/ISG/NFV/Open/Drafts/IFA003_Acceleration_-_vSwitch_Spec/</title>
+
+ <author>
+ <organization/>
+ </author>
+
+ <date/>
+ </front>
+ </reference>
+ </references>
+ </back>
+</rfc>
diff --git a/docs/requirements/vswitchperf_ltp.rst b/docs/requirements/vswitchperf_ltp.rst
index 6b2ee9bc..14303de5 100644
--- a/docs/requirements/vswitchperf_ltp.rst
+++ b/docs/requirements/vswitchperf_ltp.rst
@@ -1304,7 +1304,7 @@ vsperf CI jobs are broken down into:
* Runs everyday takes about 10 hours to complete.
* TESTCASES_DAILY='phy2phy_tput back2back phy2phy_tput_mod_vlan
phy2phy_scalability pvp_tput pvp_back2back pvvp_tput pvvp_back2back'.
- * TESTPARAM_DAILY='--test-params pkt_sizes=64,128,512,1024,1518'.
+ * TESTPARAM_DAILY='--test-params TRAFFICGEN_PKT_SIZES=(64,128,512,1024,1518)'.
* Merge job:
diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst
index 1a796dbf..a1cce262 100644
--- a/docs/userguide/index.rst
+++ b/docs/userguide/index.rst
@@ -11,5 +11,6 @@ VSPERF User Guide
:maxdepth: 3
testusage.rst
+ teststeps.rst
integration.rst
yardstick.rst
diff --git a/docs/userguide/integration.rst b/docs/userguide/integration.rst
index b0926d89..003e8adb 100755
--- a/docs/userguide/integration.rst
+++ b/docs/userguide/integration.rst
@@ -33,402 +33,6 @@ view the current test list simply execute the following command:
The standard tests included are defined inside the
``conf/integration/01_testcases.conf`` file.
-Test Steps
-----------
-
-Execution of integration tests are done on a step by step work flow starting
-with step 0 as defined inside the test case. Each step of the test increments
-the step number by one which is indicated in the log.
-
-.. code-block:: console
-
- (testcases.integration) - Step 1 - 'vswitch add_switch ['int_br1']' ... OK
-
-Each step in the test case is validated. If a step does not pass validation the
-test will fail and terminate. The test will continue until a failure is detected
-or all steps pass. A csv report file is generated after a test completes with an
-OK or FAIL result.
-
-Test Macros
------------
-
-Test profiles can include macros as part of the test step. Each step in the
-profile may return a value such as a port name. Recall macros use #STEP to
-indicate the recalled value inside the return structure. If the method the
-test step calls returns a value it can be later recalled, for example:
-
-.. code-block:: python
-
- {
- "Name": "vswitch_add_del_vport",
- "Deployment": "clean",
- "Description": "vSwitch - add and delete virtual port",
- "TestSteps": [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_vport', 'int_br0'], # STEP 1
- ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'], # STEP 2
- ['vswitch', 'del_switch', 'int_br0'], # STEP 3
- ]
- }
-
-This test profile uses the vswitch add_vport method which returns a string
-value of the port added. This is later called by the del_port method using the
-name from step 1.
-
-Also commonly used steps can be created as a separate profile.
-
-.. code-block:: python
-
- STEP_VSWITCH_PVP_INIT = [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
- ['vswitch', 'add_vport', 'int_br0'], # STEP 3
- ['vswitch', 'add_vport', 'int_br0'], # STEP 4
- ]
-
-This profile can then be used inside other testcases
-
-.. code-block:: python
-
- {
- "Name": "vswitch_pvp",
- "Deployment": "clean",
- "Description": "vSwitch - configure switch and one vnf",
- "TestSteps": STEP_VSWITCH_PVP_INIT +
- [
- ['vnf', 'start'],
- ['vnf', 'stop'],
- ] +
- STEP_VSWITCH_PVP_FINIT
- }
-
-HelloWorld and other basic Testcases
-------------------------------------
-
-The following examples are for demonstration purposes.
-You can run them by copying and pasting into the
-conf/integration/01_testcases.conf file.
-A command-line instruction is shown at the end of each
-example.
-
-HelloWorld
-^^^^^^^^^^
-
-The first example is a HelloWorld testcase.
-It simply creates a bridge with 2 physical ports, then sets up a flow to drop
-incoming packets from the port that was instantiated at the STEP #1.
-There's no interaction with the traffic generator.
-Then the flow, the 2 ports and the bridge are deleted.
-'add_phy_port' method creates a 'dpdk' type interface that will manage the
-physical port. The string value returned is the port name that will be referred
-by 'del_port' later on.
-
-.. code-block:: python
-
- {
- "Name": "HelloWorld",
- "Description": "My first testcase",
- "Deployment": "clean",
- "TestSteps": [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'actions': ['drop'], 'idle_timeout': '0'}],
- ['vswitch', 'del_flow', 'int_br0'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
- ['vswitch', 'del_switch', 'int_br0'],
- ]
-
- }
-
-To run HelloWorld test:
-
- .. code-block:: console
-
- ./vsperf --conf-file user_settings.py --integration HelloWorld
-
-Specify a Flow by the IP address
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The next example shows how to explicitly set up a flow by specifying a
-destination IP address.
-All packets received from the port created at STEP #1 that have a destination
-IP address = 90.90.90.90 will be forwarded to the port created at the STEP #2.
-
-.. code-block:: python
-
- {
- "Name": "p2p_rule_l3da",
- "Description": "Phy2Phy with rule on L3 Dest Addr",
- "Deployment": "clean",
- "biDirectional": "False",
- "TestSteps": [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_dst': '90.90.90.90', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous'}],
- ['vswitch', 'dump_flows', 'int_br0'], # STEP 5
- ['vswitch', 'del_flow', 'int_br0'], # STEP 7 == del-flows
- ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
- ['vswitch', 'del_switch', 'int_br0'],
- ]
- },
-
-To run the test:
-
- .. code-block:: console
-
- ./vsperf --conf-file user_settings.py --integration p2p_rule_l3da
-
-Multistream feature
-^^^^^^^^^^^^^^^^^^^
-
-The next testcase uses the multistream feature.
-The traffic generator will send packets with different UDP ports.
-That is accomplished by using "Stream Type" and "MultiStream" keywords.
-4 different flows are set to forward all incoming packets.
-
-.. code-block:: python
-
- {
- "Name": "multistream_l4",
- "Description": "Multistream on UDP ports",
- "Deployment": "clean",
- "Stream Type": "L4",
- "MultiStream": 4,
- "TestSteps": [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
- # Setup Flows
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '0', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '1', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '2', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '3', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- # Send mono-dir traffic
- ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
- 'bidir' : 'False'}],
- # Clean up
- ['vswitch', 'del_flow', 'int_br0'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
- ['vswitch', 'del_switch', 'int_br0'],
- ]
- },
-
-To run the test:
-
- .. code-block:: console
-
- ./vsperf --conf-file user_settings.py --integration multistream_l4
-
-PVP with a VM Replacement
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-This example launches a 1st VM in a PVP topology, then the VM is replaced
-by another VM.
-When VNF setup parameter in ./conf/04_vnf.conf is "QemuDpdkVhostUser"
-'add_vport' method creates a 'dpdkvhostuser' type port to connect a VM.
-
-.. code-block:: python
-
- {
- "Name": "ex_replace_vm",
- "Description": "PVP with VM replacement",
- "Deployment": "clean",
- "TestSteps": [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
- ['vswitch', 'add_vport', 'int_br0'], # STEP 3 vm1
- ['vswitch', 'add_vport', 'int_br0'], # STEP 4
-
- # Setup Flows
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[2][1]', \
- 'actions': ['output:#STEP[4][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[3][1]', \
- 'actions': ['output:#STEP[1][1]'], 'idle_timeout': '0'}],
-
- # Start VM 1
- ['vnf1', 'start'],
- # Now we want to replace VM 1 with another VM
- ['vnf1', 'stop'],
-
- ['vswitch', 'add_vport', 'int_br0'], # STEP 11 vm2
- ['vswitch', 'add_vport', 'int_br0'], # STEP 12
- ['vswitch', 'del_flow', 'int_br0'],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'actions': ['output:#STEP[11][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[12][1]', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
-
- # Start VM 2
- ['vnf2', 'start'],
- ['vnf2', 'stop'],
- ['vswitch', 'dump_flows', 'int_br0'],
-
- # Clean up
- ['vswitch', 'del_flow', 'int_br0'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'], # vm1
- ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[11][0]'], # vm2
- ['vswitch', 'del_port', 'int_br0', '#STEP[12][0]'],
- ['vswitch', 'del_switch', 'int_br0'],
- ]
- },
-
-To run the test:
-
- .. code-block:: console
-
- ./vsperf --conf-file user_settings.py --integration ex_replace_vm
-
-VM with a Linux bridge
-^^^^^^^^^^^^^^^^^^^^^^
-
-In this example a command-line parameter allows to set up a Linux bridge into
-the guest VM.
-That's one of the available ways to specify the guest application.
-Packets matching the flow will be forwarded to the VM.
-
-.. code-block:: python
-
- {
- "Name": "ex_pvp_rule_l3da",
- "Description": "PVP with flow on L3 Dest Addr",
- "Deployment": "clean",
- "TestSteps": [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
- ['vswitch', 'add_vport', 'int_br0'], # STEP 3 vm1
- ['vswitch', 'add_vport', 'int_br0'], # STEP 4
- # Setup Flows
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_dst': '90.90.90.90', \
- 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
- # Each pkt from the VM is forwarded to the 2nd dpdk port
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- # Start VMs
- ['vnf1', 'start'],
- ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
- 'bidir' : 'False'}],
- ['vnf1', 'stop'],
- # Clean up
- ['vswitch', 'dump_flows', 'int_br0'], # STEP 10
- ['vswitch', 'del_flow', 'int_br0'], # STEP 11
- ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'], # vm1 ports
- ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
- ['vswitch', 'del_switch', 'int_br0'],
- ]
- },
-
-To run the test:
-
- .. code-block:: console
-
- ./vsperf --conf-file user_settings.py --test-params
- "guest_loopback=linux_bridge" --integration ex_pvp_rule_l3da
-
-Forward packets based on UDP port
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-This examples launches 2 VMs connected in parallel.
-Incoming packets will be forwarded to one specific VM depending on the
-destination UDP port.
-
-.. code-block:: python
-
- {
- "Name": "ex_2pvp_rule_l4dp",
- "Description": "2 PVP with flows on L4 Dest Port",
- "Deployment": "clean",
- "Stream Type": "L4", # loop UDP ports
- "MultiStream": 2,
- "TestSteps": [
- ['vswitch', 'add_switch', 'int_br0'], # STEP 0
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
- ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
- ['vswitch', 'add_vport', 'int_br0'], # STEP 3 vm1
- ['vswitch', 'add_vport', 'int_br0'], # STEP 4
- ['vswitch', 'add_vport', 'int_br0'], # STEP 5 vm2
- ['vswitch', 'add_vport', 'int_br0'], # STEP 6
- # Setup Flows to reply ICMPv6 and similar packets, so to
- # avoid flooding internal port with their re-transmissions
- ['vswitch', 'add_flow', 'int_br0', \
- {'priority': '1', 'dl_src': '00:00:00:00:00:01', \
- 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', \
- {'priority': '1', 'dl_src': '00:00:00:00:00:02', \
- 'actions': ['output:#STEP[4][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', \
- {'priority': '1', 'dl_src': '00:00:00:00:00:03', \
- 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', \
- {'priority': '1', 'dl_src': '00:00:00:00:00:04', \
- 'actions': ['output:#STEP[6][1]'], 'idle_timeout': '0'}],
- # Forward UDP packets depending on dest port
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '0', \
- 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
- 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '1', \
- 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}],
- # Send VM output to phy port #2
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[6][1]', \
- 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
- # Start VMs
- ['vnf1', 'start'], # STEP 16
- ['vnf2', 'start'], # STEP 17
- ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
- 'bidir' : 'False'}],
- ['vnf1', 'stop'],
- ['vnf2', 'stop'],
- ['vswitch', 'dump_flows', 'int_br0'],
- # Clean up
- ['vswitch', 'del_flow', 'int_br0'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'], # vm1 ports
- ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
- ['vswitch', 'del_port', 'int_br0', '#STEP[5][0]'], # vm2 ports
- ['vswitch', 'del_port', 'int_br0', '#STEP[6][0]'],
- ['vswitch', 'del_switch', 'int_br0'],
- ]
- },
-
-To run the test:
-
- .. code-block:: console
-
- ./vsperf --conf-file user_settings.py --integration ex_2pvp_rule_l4dp
-
Executing Tunnel encapsulation tests
------------------------------------
@@ -477,21 +81,21 @@ To run VXLAN encapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
--test-params 'tunnel_type=vxlan' overlay_p2p_tput
To run GRE encapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
--test-params 'tunnel_type=gre' overlay_p2p_tput
To run GENEVE encapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
--test-params 'tunnel_type=geneve' overlay_p2p_tput
To run OVS NATIVE tunnel tests (VXLAN/GRE/GENEVE):
@@ -523,7 +127,7 @@ To run OVS NATIVE tunnel tests (VXLAN/GRE/GENEVE):
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
--test-params 'tunnel_type=vxlan' overlay_p2p_tput
@@ -585,7 +189,7 @@ To run GRE decapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --test-params 'tunnel_type=gre'
+ ./vsperf --conf-file user_settings.py --test-params 'tunnel_type=gre' \
--integration overlay_p2p_decap_cont
@@ -624,7 +228,7 @@ To import the template do:
2. Click on the Traffic menu
3. Click on the Traffic actions and click Edit Packet Templates
4. On the Template editor window, click Import. Select the template
- tools/pkt_gen/ixnet/GeneveIxNetTemplate.xml_ClearText.xml
+ located at ``3rd_party/ixia/GeneveIxNetTemplate.xml_ClearText.xml``
and click import.
5. Restart the TCL Server.
@@ -642,7 +246,7 @@ To run GENEVE decapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --test-params 'tunnel_type=geneve'
+ ./vsperf --conf-file user_settings.py --test-params 'tunnel_type=geneve' \
--integration overlay_p2p_decap_cont
@@ -726,7 +330,7 @@ To run VXLAN decapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
--test-params 'tunnel_type=vxlan' overlay_p2p_decap_cont
Executing Native/Vanilla OVS GRE decapsulation tests
@@ -785,7 +389,7 @@ To run GRE decapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
--test-params 'tunnel_type=gre' overlay_p2p_decap_cont
Executing Native/Vanilla OVS GENEVE decapsulation tests
@@ -844,7 +448,7 @@ To run GENEVE decapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
--test-params 'tunnel_type=geneve' overlay_p2p_decap_cont
@@ -894,5 +498,5 @@ To run VXLAN encapsulation+decapsulation tests:
.. code-block:: console
- ./vsperf --conf-file user_settings.py --integration
+ ./vsperf --conf-file user_settings.py --integration \
overlay_p2p_mod_tput
diff --git a/docs/userguide/teststeps.rst b/docs/userguide/teststeps.rst
new file mode 100644
index 00000000..65a25b0a
--- /dev/null
+++ b/docs/userguide/teststeps.rst
@@ -0,0 +1,651 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. (c) OPNFV, Intel Corporation, AT&T and others.
+
+Step driven tests
+=================
+
+In general, test scenarios are defined by a ``deployment`` used in the particular
+test case definition. The chosen deployment scenario will take care of the vSwitch
+configuration, deployment of VNFs and it can also affect configuration of a traffic
+generator. In order to allow a more flexible way of testcase scripting, VSPERF supports
+a detailed step driven testcase definition. It can be used to configure and
+program vSwitch, deploy and terminate VNFs, execute a traffic generator,
+modify a VSPERF configuration, execute external commands, etc.
+
+Execution of step driven tests is done on a step by step work flow starting
+with step 0 as defined inside the test case. Each step of the test increments
+the step number by one which is indicated in the log.
+
+.. code-block:: console
+
+ (testcases.integration) - Step 0 'vswitch add_vport ['br0']' start
+
+Step driven tests can be used for both performance and integration testing.
+In case of integration test, each step in the test case is validated. If a step
+does not pass validation the test will fail and terminate. The test will continue
+until a failure is detected or all steps pass. A csv report file is generated after
+a test completes with an OK or FAIL result.
+
+In case of performance test, the validation of steps is not performed and
+standard output files with results from traffic generator and underlying OS
+details are generated by vsperf.
+
+Step driven testcases can be used in two different ways:
+
+ # description of full testcase - in this case ``clean`` deployment is used
+ to indicate that vsperf should neither configure vSwitch nor deploy any VNF.
+ Test shall perform all required vSwitch configuration and programming and
+ deploy required number of VNFs.
+
+ # modification of existing deployment - in this case, any of supported
+ deployments can be used to perform initial vSwitch configuration and
+ deployment of VNFs. Additional actions defined by TestSteps can be used
+ to alter vSwitch configuration or deploy additional VNFs. After the last
+ step is processed, the test execution will continue with traffic execution.
+
+Test objects and their functions
+--------------------------------
+
+Every test step can call a function of one of the supported test objects. The list
+of supported objects and their most common functions follows:
+
+ * ``vswitch`` - provides functions for vSwitch configuration
+
+ List of supported functions:
+
+ * ``add_switch br_name`` - creates a new switch (bridge) with given ``br_name``
+ * ``del_switch br_name`` - deletes switch (bridge) with given ``br_name``
+ * ``add_phy_port br_name`` - adds a physical port into bridge specified by ``br_name``
+ * ``add_vport br_name`` - adds a virtual port into bridge specified by ``br_name``
+ * ``del_port br_name port_name`` - removes physical or virtual port specified by
+ ``port_name`` from bridge ``br_name``
+ * ``add_flow br_name flow`` - adds flow specified by ``flow`` dictionary into
+ the bridge ``br_name``; Content of flow dictionary will be passed to the vSwitch.
+ In case of Open vSwitch it will be passed to the ``ovs-ofctl add-flow`` command.
+ Please see Open vSwitch documentation for the list of supported flow parameters.
+ * ``del_flow br_name [flow]`` - deletes flow specified by ``flow`` dictionary from
+ bridge ``br_name``; In case that optional parameter ``flow`` is not specified
+ or set to an empty dictionary ``{}``, then all flows from bridge ``br_name``
+ will be deleted.
+ * ``dump_flows br_name`` - dumps all flows from bridge specified by ``br_name``
+ * ``enable_stp br_name`` - enables Spanning Tree Protocol for bridge ``br_name``
+ * ``disable_stp br_name`` - disables Spanning Tree Protocol for bridge ``br_name``
+ * ``enable_rstp br_name`` - enables Rapid Spanning Tree Protocol for bridge ``br_name``
+ * ``disable_rstp br_name`` - disables Rapid Spanning Tree Protocol for bridge ``br_name``
+
+ Examples:
+
+ .. code-block:: python
+
+ ['vswitch', 'add_switch', 'int_br0']
+
+ ['vswitch', 'del_switch', 'int_br0']
+
+ ['vswitch', 'add_phy_port', 'int_br0']
+
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]']
+
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '1', 'actions': ['output:2'],
+ 'idle_timeout': '0'}],
+
+ ['vswitch', 'enable_rstp', 'int_br0']
+
+ * ``vnf[ID]`` - provides functions for deployment and termination of VNFs; Optional
+ alfanumerical ``ID`` is used for VNF identification in case that testcase
+ deploys multiple VNFs.
+
+ List of supported functions:
+
+ * ``start`` - starts a VNF based on VSPERF configuration
+ * ``stop`` - gracefully terminates given VNF
+
+ Examples:
+
+ .. code-block:: python
+
+ ['vnf1', 'start']
+ ['vnf2', 'start']
+ ['vnf2', 'stop']
+ ['vnf1', 'stop']
+
+ * ``trafficgen`` - triggers traffic generation
+
+ List of supported functions:
+
+ * ``send_traffic traffic`` - starts a traffic based on the vsperf configuration
+ and given ``traffic`` dictionary. More details about ``traffic`` dictionary
+ and its possible values are available at `Traffic Generator Integration Guide
+ <http://artifacts.opnfv.org/vswitchperf/docs/design/trafficgen_integration_guide.html#step-5-supported-traffic-types>`__
+
+ Examples:
+
+ .. code-block:: python
+
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput'}]
+
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : 'True'}]
+
+ * ``settings`` - reads or modifies VSPERF configuration
+
+ List of supported functions:
+
+ * ``getValue param`` - returns value of given ``param``
+ * ``setValue param value`` - sets value of ``param`` to given ``value``
+
+ Examples:
+
+ .. code-block:: python
+
+ ['settings', 'getValue', 'TOOLS']
+
+ ['settings', 'setValue', 'GUEST_USERNAME', ['root']]
+
+ * ``namespace`` - creates or modifies network namespaces
+
+ List of supported functions:
+
+ * ``create_namespace name`` - creates new namespace with given ``name``
+ * ``delete_namespace name`` - deletes namespace specified by its ``name``
+ * ``assign_port_to_namespace port name [port_up]`` - assigns NIC specified by ``port``
+ into given namespace ``name``; If optional parameter ``port_up`` is set to ``True``,
+ then port will be brought up.
+ * ``add_ip_to_namespace_eth port name addr cidr`` - assigns an IP address ``addr``/``cidr``
+ to the NIC specified by ``port`` within namespace ``name``
+ * ``reset_port_to_root port name`` - returns given ``port`` from namespace ``name`` back
+ to the root namespace
+
+ Examples:
+
+ .. code-block:: python
+
+ ['namespace', 'create_namespace', 'testns']
+
+ ['namespace', 'assign_port_to_namespace', 'eth0', 'testns']
+
+ * ``veth`` - manipulates with eth and veth devices
+
+ List of supported functions:
+
+ * ``add_veth_port port peer_port`` - adds a pair of veth ports named ``port`` and
+ ``peer_port``
+ * ``del_veth_port port peer_port`` - deletes a veth port pair specified by ``port``
+ and ``peer_port``
+ * ``bring_up_eth_port eth_port [namespace]`` - brings up ``eth_port`` in (optional)
+ ``namespace``
+
+ Examples:
+
+ .. code-block:: python
+
+ ['veth', 'add_veth_port', 'veth', 'veth1']
+
+ ['veth', 'bring_up_eth_port', 'eth1']
+
+ * ``tools`` - provides a set of helper functions
+
+ List of supported functions:
+
+ * ``Assert condition`` - evaluates given ``condition`` and raises ``AssertionError``
+ in case that condition is not ``True``
+ * ``Eval expression`` - evaluates given expression as a python code and returns
+ its result
+ * ``Exec command [regex]`` - executes a shell command and filters its output by
+ (optional) regular expression
+
+ Examples:
+
+ .. code-block:: python
+
+ ['tools', 'exec', 'numactl -H', 'available: ([0-9]+)']
+ ['tools', 'assert', '#STEP[-1][0]>1']
+
+ * ``wait`` - is used for test case interruption. This object doesn't have
+ any functions. Once reached, vsperf will pause test execution and waits
+ for press of ``Enter key``. It can be used during testcase design
+ for debugging purposes.
+
+ Examples:
+
+ .. code-block:: python
+
+ ['wait']
+
+Test Macros
+-----------
+
+Test profiles can include macros as part of the test step. Each step in the
+profile may return a value such as a port name. Recall macros use #STEP to
+indicate the recalled value inside the return structure. If the method the
+test step calls returns a value it can be later recalled, for example:
+
+.. code-block:: python
+
+ {
+ "Name": "vswitch_add_del_vport",
+ "Deployment": "clean",
+ "Description": "vSwitch - add and delete virtual port",
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 1
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'], # STEP 2
+ ['vswitch', 'del_switch', 'int_br0'], # STEP 3
+ ]
+ }
+
+This test profile uses the vswitch add_vport method which returns a string
+value of the port added. This is later called by the del_port method using the
+name from step 1.
+
+It is also possible to use negative indexes in step macros. In that case
+``#STEP[-1]`` will refer to the result from previous step, ``#STEP[-2]``
+will refer to result of step called before previous step, etc. It means,
+that you could change ``STEP 2`` from previous example to achieve the same
+functionality:
+
+.. code-block:: python
+
+ ['vswitch', 'del_port', 'int_br0', '#STEP[-1][0]'], # STEP 2
+
+Also commonly used steps can be created as a separate profile.
+
+.. code-block:: python
+
+ STEP_VSWITCH_PVP_INIT = [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 3
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 4
+ ]
+
+This profile can then be used inside other testcases
+
+.. code-block:: python
+
+ {
+ "Name": "vswitch_pvp",
+ "Deployment": "clean",
+ "Description": "vSwitch - configure switch and one vnf",
+ "TestSteps": STEP_VSWITCH_PVP_INIT +
+ [
+ ['vnf', 'start'],
+ ['vnf', 'stop'],
+ ] +
+ STEP_VSWITCH_PVP_FINIT
+ }
+
+HelloWorld and other basic Testcases
+------------------------------------
+
+The following examples are for demonstration purposes.
+You can run them by copying and pasting into the
+conf/integration/01_testcases.conf file.
+A command-line instruction is shown at the end of each
+example.
+
+HelloWorld
+^^^^^^^^^^
+
+The first example is a HelloWorld testcase.
+It simply creates a bridge with 2 physical ports, then sets up a flow to drop
+incoming packets from the port that was instantiated at the STEP #1.
+There's no interaction with the traffic generator.
+Then the flow, the 2 ports and the bridge are deleted.
+'add_phy_port' method creates a 'dpdk' type interface that will manage the
+physical port. The string value returned is the port name that will be referred
+by 'del_port' later on.
+
+.. code-block:: python
+
+ {
+ "Name": "HelloWorld",
+ "Description": "My first testcase",
+ "Deployment": "clean",
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'actions': ['drop'], 'idle_timeout': '0'}],
+ ['vswitch', 'del_flow', 'int_br0'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+
+ },
+
+To run HelloWorld test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file user_settings.py --integration HelloWorld
+
+Specify a Flow by the IP address
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The next example shows how to explicitly set up a flow by specifying a
+destination IP address.
+All packets received from the port created at STEP #1 that have a destination
+IP address = 90.90.90.90 will be forwarded to the port created at the STEP #2.
+
+.. code-block:: python
+
+ {
+ "Name": "p2p_rule_l3da",
+ "Description": "Phy2Phy with rule on L3 Dest Addr",
+ "Deployment": "clean",
+ "biDirectional": "False",
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_dst': '90.90.90.90', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous'}],
+ ['vswitch', 'dump_flows', 'int_br0'], # STEP 5
+ ['vswitch', 'del_flow', 'int_br0'], # STEP 7 == del-flows
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+ },
+
+To run the test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file user_settings.py --integration p2p_rule_l3da
+
+Multistream feature
+^^^^^^^^^^^^^^^^^^^
+
+The next testcase uses the multistream feature.
+The traffic generator will send packets with different UDP ports.
+That is accomplished by using "Stream Type" and "MultiStream" keywords.
+4 different flows are set to forward all incoming packets.
+
+.. code-block:: python
+
+ {
+ "Name": "multistream_l4",
+ "Description": "Multistream on UDP ports",
+ "Deployment": "clean",
+ "Stream Type": "L4",
+ "MultiStream": 4,
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ # Setup Flows
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '0', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '1', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '2', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '3', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ # Send mono-dir traffic
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
+ 'bidir' : 'False'}],
+ # Clean up
+ ['vswitch', 'del_flow', 'int_br0'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+ },
+
+To run the test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file user_settings.py --integration multistream_l4
+
+PVP with a VM Replacement
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This example launches a 1st VM in a PVP topology, then the VM is replaced
+by another VM.
+When VNF setup parameter in ./conf/04_vnf.conf is "QemuDpdkVhostUser"
+'add_vport' method creates a 'dpdkvhostuser' type port to connect a VM.
+
+.. code-block:: python
+
+ {
+ "Name": "ex_replace_vm",
+ "Description": "PVP with VM replacement",
+ "Deployment": "clean",
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 3 vm1
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 4
+
+ # Setup Flows
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[2][1]', \
+ 'actions': ['output:#STEP[4][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[3][1]', \
+ 'actions': ['output:#STEP[1][1]'], 'idle_timeout': '0'}],
+
+ # Start VM 1
+ ['vnf1', 'start'],
+ # Now we want to replace VM 1 with another VM
+ ['vnf1', 'stop'],
+
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 11 vm2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 12
+ ['vswitch', 'del_flow', 'int_br0'],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'actions': ['output:#STEP[11][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[12][1]', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+
+ # Start VM 2
+ ['vnf2', 'start'],
+ ['vnf2', 'stop'],
+ ['vswitch', 'dump_flows', 'int_br0'],
+
+ # Clean up
+ ['vswitch', 'del_flow', 'int_br0'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'], # vm1
+ ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[11][0]'], # vm2
+ ['vswitch', 'del_port', 'int_br0', '#STEP[12][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+ },
+
+To run the test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file user_settings.py --integration ex_replace_vm
+
+VM with a Linux bridge
+^^^^^^^^^^^^^^^^^^^^^^
+
+This example setups a PVP topology and routes traffic to the VM based on
+the destination IP address. A command-line parameter is used to select a Linux
+bridge as a guest loopback application. It is also possible to select a guest
+loopback application by a configuration option ``GUEST_LOOPBACK``.
+
+.. code-block:: python
+
+ {
+ "Name": "ex_pvp_rule_l3da",
+ "Description": "PVP with flow on L3 Dest Addr",
+ "Deployment": "clean",
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 3 vm1
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 4
+ # Setup Flows
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_dst': '90.90.90.90', \
+ 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
+ # Each pkt from the VM is forwarded to the 2nd dpdk port
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ # Start VMs
+ ['vnf1', 'start'],
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
+ 'bidir' : 'False'}],
+ ['vnf1', 'stop'],
+ # Clean up
+ ['vswitch', 'dump_flows', 'int_br0'], # STEP 10
+ ['vswitch', 'del_flow', 'int_br0'], # STEP 11
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'], # vm1 ports
+ ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+ },
+
+To run the test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file user_settings.py --test-params \
+ "GUEST_LOOPBACK=['linux_bridge']" --integration ex_pvp_rule_l3da
+
+Forward packets based on UDP port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This examples launches 2 VMs connected in parallel.
+Incoming packets will be forwarded to one specific VM depending on the
+destination UDP port.
+
+.. code-block:: python
+
+ {
+ "Name": "ex_2pvp_rule_l4dp",
+ "Description": "2 PVP with flows on L4 Dest Port",
+ "Deployment": "clean",
+ "Stream Type": "L4", # loop UDP ports
+ "MultiStream": 2,
+ "TestSteps": [
+ ['vswitch', 'add_switch', 'int_br0'], # STEP 0
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 1
+ ['vswitch', 'add_phy_port', 'int_br0'], # STEP 2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 3 vm1
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 4
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 5 vm2
+ ['vswitch', 'add_vport', 'int_br0'], # STEP 6
+ # Setup Flows to reply ICMPv6 and similar packets, so to
+ # avoid flooding internal port with their re-transmissions
+ ['vswitch', 'add_flow', 'int_br0', \
+ {'priority': '1', 'dl_src': '00:00:00:00:00:01', \
+ 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', \
+ {'priority': '1', 'dl_src': '00:00:00:00:00:02', \
+ 'actions': ['output:#STEP[4][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', \
+ {'priority': '1', 'dl_src': '00:00:00:00:00:03', \
+ 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', \
+ {'priority': '1', 'dl_src': '00:00:00:00:00:04', \
+ 'actions': ['output:#STEP[6][1]'], 'idle_timeout': '0'}],
+ # Forward UDP packets depending on dest port
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '0', \
+ 'actions': ['output:#STEP[3][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[1][1]', \
+ 'dl_type': '0x0800', 'nw_proto': '17', 'udp_dst': '1', \
+ 'actions': ['output:#STEP[5][1]'], 'idle_timeout': '0'}],
+ # Send VM output to phy port #2
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[4][1]', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'int_br0', {'in_port': '#STEP[6][1]', \
+ 'actions': ['output:#STEP[2][1]'], 'idle_timeout': '0'}],
+ # Start VMs
+ ['vnf1', 'start'], # STEP 16
+ ['vnf2', 'start'], # STEP 17
+ ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', \
+ 'bidir' : 'False'}],
+ ['vnf1', 'stop'],
+ ['vnf2', 'stop'],
+ ['vswitch', 'dump_flows', 'int_br0'],
+ # Clean up
+ ['vswitch', 'del_flow', 'int_br0'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[1][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[2][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[3][0]'], # vm1 ports
+ ['vswitch', 'del_port', 'int_br0', '#STEP[4][0]'],
+ ['vswitch', 'del_port', 'int_br0', '#STEP[5][0]'], # vm2 ports
+ ['vswitch', 'del_port', 'int_br0', '#STEP[6][0]'],
+ ['vswitch', 'del_switch', 'int_br0'],
+ ]
+ },
+
+To run the test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file user_settings.py --integration ex_2pvp_rule_l4dp
+
+Modification of existing PVVP deployment
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is an example of modification of a standard deployment scenario with additional TestSteps.
+Standard PVVP scenario is used to configure a vSwitch and to deploy two VNFs connected
+in series. Additional TestSteps will deploy a 3rd VNF and connect it in parallel to
+already configured VNFs. Traffic generator is instructed (by Multistream feature) to send
+two separate traffic streams. One stream will be sent to the standalone VNF and second
+to two chained VNFs.
+
+In case, that test is defined as a performance test, then traffic results will be collected
+and available in both csv and rst report files.
+
+.. code-block:: python
+
+ {
+ "Name": "pvvp_pvp_cont",
+ "Traffic Type": "continuous",
+ "Deployment": "pvvp",
+ "Description": "PVVP and PVP in parallel with Continuous Stream",
+ "biDirectional": "True",
+ "iLoad": "100",
+ "MultiStream": "2",
+ "TestSteps": [
+ ['vswitch', 'add_vport', 'br0'],
+ ['vswitch', 'add_vport', 'br0'],
+ # priority must be higher than default 32768, otherwise flows won't match
+ ['vswitch', 'add_flow', 'br0',
+ {'in_port': '1', 'actions': ['output:#STEP[-2][1]'], 'idle_timeout': '0', 'dl_type':'0x800',
+ 'nw_proto':'17', 'tp_dst':'0', 'priority': '33000'}],
+ ['vswitch', 'add_flow', 'br0',
+ {'in_port': '2', 'actions': ['output:#STEP[-2][1]'], 'idle_timeout': '0', 'dl_type':'0x800',
+ 'nw_proto':'17', 'tp_dst':'0', 'priority': '33000'}],
+ ['vswitch', 'add_flow', 'br0', {'in_port': '#STEP[-4][1]', 'actions': ['output:1'],
+ 'idle_timeout': '0'}],
+ ['vswitch', 'add_flow', 'br0', {'in_port': '#STEP[-4][1]', 'actions': ['output:2'],
+ 'idle_timeout': '0'}],
+ ['vswitch', 'dump_flows', 'br0'],
+ ['vnf1', 'start'],
+ ]
+ },
+
+To run the test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file user_settings.py pvvp_pvp_cont
+
diff --git a/docs/userguide/testusage.rst b/docs/userguide/testusage.rst
index 3c5cc4d4..f446f261 100755
--- a/docs/userguide/testusage.rst
+++ b/docs/userguide/testusage.rst
@@ -105,14 +105,61 @@ or via another command line argument will override both the default and
your custom configuration files. This "priority hierarchy" can be
described like so (1 = max priority):
-1. Command line arguments
-2. Environment variables
-3. Configuration file(s)
+1. Testcase definition section ``Parameters``
+2. Command line arguments
+3. Environment variables
+4. Configuration file(s)
Further details about configuration files evaluation and special behaviour
of options with ``GUEST_`` prefix could be found at `design document
<http://artifacts.opnfv.org/vswitchperf/docs/design/vswitchperf_design.html#configuration>`__.
+Overriding values defined in configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration items can be overridden by command line argument
+``--test-params``. In this case, the configuration items and
+their values should be passed in form of ``item=value`` and separated
+by semicolon.
+
+Example:
+
+.. code:: console
+
+ $ ./vsperf --test-params "TRAFFICGEN_DURATION=10;TRAFFICGEN_PKT_SIZES=(128,);" \
+ "GUEST_LOOPBACK=['testpmd','l2fwd']" pvvp_tput
+
+The second option is to override configuration items by ``Parameters`` section
+of the test case definition. The configuration items can be added into ``Parameters``
+dictionary with their new values. These values will override values defined in
+configuration files or specified by ``--test-params`` command line argument.
+
+Example:
+
+.. code:: python
+
+ "Parameters" : {'TRAFFICGEN_PKT_SIZES' : (128,),
+ 'TRAFFICGEN_DURATION' : 10,
+ 'GUEST_LOOPBACK' : ['testpmd','l2fwd'],
+ }
+
+**NOTE:** In both cases, configuration item names and their values must be specified
+in the same form as they are defined inside configuration files. Parameter names
+must be specified in uppercase and data types of original and new value must match.
+Python syntax rules related to data types and structures must be followed.
+For example, parameter ``TRAFFICGEN_PKT_SIZES`` above is defined as a tuple
+with a single value ``128``. In this case trailing comma is mandatory, otherwise
+value can be wrongly interpreted as a number instead of a tuple and vsperf
+execution would fail. Please check configuration files for default values and their
+types and use them as a basis for any customized values. In case of any doubt, please
+check official python documentation related to data structures like tuples, lists
+and dictionaries.
+
+**NOTE:** Vsperf execution will terminate with runtime error in case, that unknown
+parameter name is passed via ``--test-params`` CLI argument or defined in ``Parameters``
+section of test case definition. It is also forbidden to redefine a value of
+``TEST_PARAMS`` configuration item via CLI or ``Parameters`` section.
+
vloop_vnf
^^^^^^^^^
@@ -131,6 +178,7 @@ installation instructions for information on these images
vloop_vnf forwards traffic through a VM using one of:
+
* DPDK testpmd
* Linux Bridge
* l2fwd kernel Module.
@@ -147,6 +195,9 @@ IP addresses. l2fwd can be found in <vswitchperf_dir>/src/l2fwd
Executing tests
^^^^^^^^^^^^^^^
+All examples inside these docs assume, that user is inside the VSPERF
+directory. VSPERF can be executed from any directory.
+
Before running any tests make sure you have root permissions by adding
the following line to /etc/sudoers:
@@ -188,9 +239,9 @@ Some tests allow for configurable parameters, including test duration
.. code:: bash
- $ ./vsperf --conf-file user_settings.py
- --tests RFC2544Tput
- --test-params "duration=10;pkt_sizes=128"
+ $ ./vsperf --conf-file user_settings.py \
+ --tests RFC2544Tput \
+ --test-params "TRAFFICGEN_DURATION=10;TRAFFICGEN_PKT_SIZES=(128,)"
For all available options, check out the help dialog:
@@ -203,35 +254,30 @@ Executing Vanilla OVS tests
1. If needed, recompile src for all OVS variants
-.. code-block:: console
-
- $ cd src
- $ make distclean
- $ make
+ .. code-block:: console
-2. Update your ''10_custom.conf'' file to use the appropriate variables
-for Vanilla OVS:
+ $ cd src
+ $ make distclean
+ $ make
-.. code-block:: console
+2. Update your ``10_custom.conf`` file to use Vanilla OVS:
- VSWITCH = 'OvsVanilla'
+ .. code-block:: python
-Where $PORT1 and $PORT2 are the Linux interfaces you'd like to bind
-to the vswitch.
+ VSWITCH = 'OvsVanilla'
3. Run test:
-.. code-block:: console
+ .. code-block:: console
- $ ./vsperf --conf-file=<path_to_custom_conf>
+ $ ./vsperf --conf-file=<path_to_custom_conf>
-Please note if you don't want to configure Vanilla OVS through the
-configuration file, you can pass it as a CLI argument; BUT you must
-set the ports.
+ Please note if you don't want to configure Vanilla OVS through the
+ configuration file, you can pass it as a CLI argument.
-.. code-block:: console
+ .. code-block:: console
- $ ./vsperf --vswitch OvsVanilla
+ $ ./vsperf --vswitch OvsVanilla
Executing tests with VMs
@@ -241,24 +287,24 @@ To run tests using vhost-user as guest access method:
1. Set VHOST_METHOD and VNF of your settings file to:
-.. code-block:: console
+ .. code-block:: python
- VSWITCH = 'OvsDpdkVhost'
- VNF = 'QemuDpdkVhost'
+ VSWITCH = 'OvsDpdkVhost'
+ VNF = 'QemuDpdkVhost'
2. If needed, recompile src for all OVS variants
-.. code-block:: console
+ .. code-block:: console
- $ cd src
- $ make distclean
- $ make
+ $ cd src
+ $ make distclean
+ $ make
3. Run test:
-.. code-block:: console
+ .. code-block:: console
- $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf
+ $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf
Executing tests with VMs using Vanilla OVS
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -267,39 +313,42 @@ To run tests using Vanilla OVS:
1. Set the following variables:
-.. code-block:: console
+ .. code-block:: python
- VSWITCH = 'OvsVanilla'
- VNF = 'QemuVirtioNet'
+ VSWITCH = 'OvsVanilla'
+ VNF = 'QemuVirtioNet'
- VANILLA_TGEN_PORT1_IP = n.n.n.n
- VANILLA_TGEN_PORT1_MAC = nn:nn:nn:nn:nn:nn
+ VANILLA_TGEN_PORT1_IP = n.n.n.n
+ VANILLA_TGEN_PORT1_MAC = nn:nn:nn:nn:nn:nn
- VANILLA_TGEN_PORT2_IP = n.n.n.n
- VANILLA_TGEN_PORT2_MAC = nn:nn:nn:nn:nn:nn
+ VANILLA_TGEN_PORT2_IP = n.n.n.n
+ VANILLA_TGEN_PORT2_MAC = nn:nn:nn:nn:nn:nn
- VANILLA_BRIDGE_IP = n.n.n.n
+ VANILLA_BRIDGE_IP = n.n.n.n
- or use --test-param
+ or use ``--test-params`` option
- $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf
- --test-params "vanilla_tgen_tx_ip=n.n.n.n;
- vanilla_tgen_tx_mac=nn:nn:nn:nn:nn:nn"
+ .. code-block:: console
+ $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf \
+ --test-params "VANILLA_TGEN_PORT1_IP=n.n.n.n;" \
+ "VANILLA_TGEN_PORT1_MAC=nn:nn:nn:nn:nn:nn;" \
+ "VANILLA_TGEN_PORT2_IP=n.n.n.n;" \
+ "VANILLA_TGEN_PORT2_MAC=nn:nn:nn:nn:nn:nn"
2. If needed, recompile src for all OVS variants
-.. code-block:: console
+ .. code-block:: console
- $ cd src
- $ make distclean
- $ make
+ $ cd src
+ $ make distclean
+ $ make
3. Run test:
-.. code-block:: console
+ .. code-block:: console
- $ ./vsperf --conf-file<path_to_custom_conf>/10_custom.conf
+ $ ./vsperf --conf-file<path_to_custom_conf>/10_custom.conf
.. _vfio-pci:
@@ -309,7 +358,7 @@ Using vfio_pci with DPDK
To use vfio with DPDK instead of igb_uio add into your custom configuration
file the following parameter:
-.. code-block:: console
+.. code-block:: python
PATHS['dpdk']['src']['modules'] = ['uio', 'vfio-pci']
@@ -389,7 +438,7 @@ Execution of test with PCI passthrough with vswitch disabled:
.. code-block:: console
- $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf
+ $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf \
--vswitch none --vnf QemuPciPassthrough pvp_tput
Any of supported guest-loopback-application_ can be used inside VM with
@@ -403,19 +452,19 @@ deployment.
Selection of loopback application for tests with VMs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-To select loopback application, which will perform traffic forwarding
-inside VM, following configuration parameter should be configured:
+To select the loopback applications which will forward packets inside VMs,
+the following parameter should be configured:
-.. code-block:: console
+.. code-block:: python
GUEST_LOOPBACK = ['testpmd']
-or use --test-param
+or use ``--test-params`` CLI argument:
.. code-block:: console
- $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf
- --test-params "guest_loopback=testpmd"
+ $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf \
+ --test-params "GUEST_LOOPBACK=['testpmd']"
Supported loopback applications are:
@@ -431,37 +480,69 @@ Guest loopback application must be configured, otherwise traffic
will not be forwarded by VM and testcases with VM related deployments
will fail. Guest loopback application is set to 'testpmd' by default.
-Note: In case that only 1 or more than 2 NICs are configured for VM,
+**NOTE:** In case that only 1 or more than 2 NICs are configured for VM,
then 'testpmd' should be used. As it is able to forward traffic between
multiple VM NIC pairs.
-Note: In case of linux_bridge, all guest NICs are connected to the same
+**NOTE:** In case of linux_bridge, all guest NICs are connected to the same
bridge inside the guest.
+Selection of dpdk binding driver for tests with VMs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To select dpdk binding driver, which will specify which driver the vm NICs will
+use for dpdk bind, the following configuration parameter should be configured:
+
+.. code-block:: console
+
+ GUEST_DPDK_BIND_DRIVER = ['igb_uio_from_src']
+
+The supported dpdk guest bind drivers are:
+
+.. code-block:: console
+
+ 'uio_pci_generic' - Use uio_pci_generic driver
+ 'igb_uio_from_src' - Build and use the igb_uio driver from the dpdk src
+ files
+ 'vfio_no_iommu' - Use vfio with no iommu option. This requires custom
+ guest images that support this option. The default
+ vloop image does not support this driver.
+
+Note: uio_pci_generic does not support sr-iov testcases with guests attached.
+This is because uio_pci_generic only supports legacy interrupts. In case
+uio_pci_generic is selected with the vnf as QemuPciPassthrough it will be
+modified to use igb_uio_from_src instead.
+
+Note: vfio_no_iommu requires kernels equal to or greater than 4.5 and dpdk
+16.04 or greater. Using this option will also taint the kernel.
+
+Please refer to the dpdk documents at http://dpdk.org/doc/guides for more
+information on these drivers.
+
Multi-Queue Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^
VSPerf currently supports multi-queue with the following limitations:
- 1. Requires QEMU 2.5 or greater and any OVS version higher than 2.5. The
- default upstream package versions installed by VSPerf satisfies this
- requirement.
+1. Requires QEMU 2.5 or greater and any OVS version higher than 2.5. The
+ default upstream package versions installed by VSPerf satisfies this
+ requirement.
- 2. Guest image must have ethtool utility installed if using l2fwd or linux
- bridge inside guest for loopback.
+2. Guest image must have ethtool utility installed if using l2fwd or linux
+ bridge inside guest for loopback.
- 3. If using OVS versions 2.5.0 or less enable old style multi-queue as shown
- in the ''02_vswitch.conf'' file.
+3. If using OVS versions 2.5.0 or less enable old style multi-queue as shown
+ in the ''02_vswitch.conf'' file.
- .. code-block:: console
+ .. code-block:: python
- OVS_OLD_STYLE_MQ = True
+ OVS_OLD_STYLE_MQ = True
To enable multi-queue for dpdk modify the ''02_vswitch.conf'' file.
- .. code-block:: console
+.. code-block:: python
- VSWITCH_DPDK_MULTI_QUEUES = 2
+ VSWITCH_DPDK_MULTI_QUEUES = 2
**NOTE:** you should consider using the switch affinity to set a pmd cpu mask
that can optimize your performance. Consider the numa of the NIC in use if this
@@ -475,9 +556,9 @@ port by port option.
To enable multi-queue on the guest modify the ''04_vnf.conf'' file.
- .. code-block:: console
+.. code-block:: python
- GUEST_NIC_QUEUES = 2
+ GUEST_NIC_QUEUES = [2]
Enabling multi-queue at the guest will add multiple queues to each NIC port when
qemu launches the guest.
@@ -489,13 +570,12 @@ multi-queue on the guest is sufficient for Vanilla OVS multi-queue.
Testpmd should be configured to take advantage of multi-queue on the guest if
using DPDKVhostUser. This can be done by modifying the ''04_vnf.conf'' file.
- .. code-block:: console
-
- GUEST_TESTPMD_CPU_MASK = '-l 0,1,2,3,4'
+.. code-block:: python
- GUEST_TESTPMD_NB_CORES = 4
- GUEST_TESTPMD_TXQ = 2
- GUEST_TESTPMD_RXQ = 2
+ GUEST_TESTPMD_PARAMS = ['-l 0,1,2,3,4 -n 4 --socket-mem 512 -- '
+ '--burst=64 -i --txqflags=0xf00 '
+ '--nb-cores=4 --rxq=2 --txq=2 '
+ '--disable-hw-vlan']
**NOTE:** The guest SMP cores must be configured to allow for testpmd to use the
optimal number of cores to take advantage of the multiple guest queues.
@@ -505,11 +585,11 @@ by binding vhost-net threads to cpus. This can be done by enabling the affinity
in the ''04_vnf.conf'' file. This can be done to non multi-queue enabled
configurations as well as there will be 2 vhost-net threads.
- .. code-block:: console
+.. code-block:: python
- VSWITCH_VHOST_NET_AFFINITIZATION = True
+ VSWITCH_VHOST_NET_AFFINITIZATION = True
- VSWITCH_VHOST_CPU_MAP = [4,5,8,11]
+ VSWITCH_VHOST_CPU_MAP = [4,5,8,11]
**NOTE:** This method of binding would require a custom script in a real
environment.
@@ -521,51 +601,53 @@ assigned at least (nb_cores +1) total cores with the cpu mask.
Executing Packet Forwarding tests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-To select application, which will perform packet forwarding,
-following configuration parameter should be configured:
+To select the applications which will forward packets,
+the following parameters should be configured:
- .. code-block:: console
+.. code-block:: python
+
+ VSWITCH = 'none'
+ PKTFWD = 'TestPMD'
- VSWITCH = 'none'
- PKTFWD = 'TestPMD'
+or use ``--vswitch`` and ``--fwdapp`` CLI arguments:
- or use --vswitch and --fwdapp
+.. code-block:: console
- $ ./vsperf --conf-file user_settings.py
- --vswitch none
- --fwdapp TestPMD
+ $ ./vsperf --conf-file user_settings.py \
+ --vswitch none \
+ --fwdapp TestPMD
Supported Packet Forwarding applications are:
- .. code-block:: console
+.. code-block:: console
- 'testpmd' - testpmd from dpdk
+ 'testpmd' - testpmd from dpdk
1. Update your ''10_custom.conf'' file to use the appropriate variables
-for selected Packet Forwarder:
-
- .. code-block:: console
-
- # testpmd configuration
- TESTPMD_ARGS = []
- # packet forwarding mode supported by testpmd; Please see DPDK documentation
- # for comprehensive list of modes supported by your version.
- # e.g. io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho|...
- # Note: Option "mac_retry" has been changed to "mac retry" since DPDK v16.07
- TESTPMD_FWD_MODE = 'csum'
- # checksum calculation layer: ip|udp|tcp|sctp|outer-ip
- TESTPMD_CSUM_LAYER = 'ip'
- # checksum calculation place: hw (hardware) | sw (software)
- TESTPMD_CSUM_CALC = 'sw'
- # recognize tunnel headers: on|off
- TESTPMD_CSUM_PARSE_TUNNEL = 'off'
+ for selected Packet Forwarder:
+
+ .. code-block:: python
+
+ # testpmd configuration
+ TESTPMD_ARGS = []
+ # packet forwarding mode supported by testpmd; Please see DPDK documentation
+ # for comprehensive list of modes supported by your version.
+ # e.g. io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho|...
+ # Note: Option "mac_retry" has been changed to "mac retry" since DPDK v16.07
+ TESTPMD_FWD_MODE = 'csum'
+ # checksum calculation layer: ip|udp|tcp|sctp|outer-ip
+ TESTPMD_CSUM_LAYER = 'ip'
+ # checksum calculation place: hw (hardware) | sw (software)
+ TESTPMD_CSUM_CALC = 'sw'
+ # recognize tunnel headers: on|off
+ TESTPMD_CSUM_PARSE_TUNNEL = 'off'
2. Run test:
- .. code-block:: console
+ .. code-block:: console
- $ ./vsperf --conf-file <path_to_settings_py>
+ $ ./vsperf --conf-file <path_to_settings_py>
VSPERF modes of operation
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -587,7 +669,7 @@ Mode of operation is driven by configuration parameter -m or --mode
"trafficgen-pause" - execute vSwitch and VNF but wait before traffic transmission
In case, that VSPERF is executed in "trafficgen" mode, then configuration
-of traffic generator should be configured through --test-params option.
+of traffic generator should be configured through ``--test-params`` option.
Supported CLI options useful for traffic generator configuration are:
.. code-block:: console
@@ -614,7 +696,7 @@ Example of execution of VSPERF in "trafficgen" mode:
.. code-block:: console
- $ ./vsperf -m trafficgen --trafficgen IxNet --conf-file vsperf.conf
+ $ ./vsperf -m trafficgen --trafficgen IxNet --conf-file vsperf.conf \
--test-params "traffic_type=continuous;bidirectional=True;iload=60"
Code change verification by pylint
@@ -650,7 +732,7 @@ By default the vswitchd is launched with 1Gb of memory, to change
this, modify --socket-mem parameter in conf/02_vswitch.conf to allocate
an appropriate amount of memory:
-.. code-block:: console
+.. code-block:: python
VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4', '--socket-mem 1024,0']
VSWITCHD_DPDK_CONFIG = {
diff --git a/src/dpdk/Makefile b/src/dpdk/Makefile
index 1cd85e3e..29967029 100755
--- a/src/dpdk/Makefile
+++ b/src/dpdk/Makefile
@@ -72,6 +72,7 @@ ifdef CONFIG_FILE_BASE
$(AT)sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST_USER=.\+/CONFIG_RTE_LIBRTE_VHOST_USER=$(VHOST_USER)/g' $(CONFIG_FILE_BASE)
$(AT)sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST=./CONFIG_RTE_LIBRTE_VHOST=y/g' $(CONFIG_FILE_BASE)
$(AT)sed -i -e 's/CONFIG_RTE_LIBRTE_KNI=./CONFIG_RTE_LIBRTE_KNI=n/g' $(CONFIG_FILE_BASE)
+ $(AT)sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST_NUMA=./CONFIG_RTE_LIBRTE_VHOST_NUMA=y/g' $(CONFIG_FILE_BASE)
else
$(AT)sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST_USER=.\+/CONFIG_RTE_LIBRTE_VHOST_USER=$(VHOST_USER)/g' $(CONFIG_FILE_LINUXAPP)
$(AT)sed -i -e 's/CONFIG_RTE_BUILD_COMBINE_LIBS=./CONFIG_RTE_BUILD_COMBINE_LIBS=y/g' $(CONFIG_FILE_LINUXAPP)
diff --git a/src/dpdk/dpdk.py b/src/dpdk/dpdk.py
index 16223915..0c5ed9f4 100644
--- a/src/dpdk/dpdk.py
+++ b/src/dpdk/dpdk.py
@@ -139,6 +139,9 @@ def _vhost_user_cleanup():
def _bind_nics():
"""Bind NICs using the Intel DPDK ``dpdk*bind.py`` tool.
"""
+ if not len(_NICS_PCI):
+ _LOGGER.info('NICs are not configured - nothing to bind')
+ return
try:
_driver = 'igb_uio'
if 'vfio-pci' in S.getValue('TOOLS')['dpdk_modules']:
@@ -151,7 +154,7 @@ def _bind_nics():
True)
tasks.run_task(['sudo', S.getValue('TOOLS')['bind-tool'],
- '--bind=' + _driver] +
+ '--bind=' + _driver] +
_NICS_PCI, _LOGGER,
'Binding NICs %s...' % _NICS_PCI,
True)
@@ -161,6 +164,9 @@ def _bind_nics():
def _unbind_nics():
"""Unbind NICs using the Intel DPDK ``dpdk*bind.py`` tool.
"""
+ if not len(_NICS_PCI):
+ _LOGGER.info('NICs are not configured - nothing to unbind')
+ return
try:
tasks.run_task(['sudo', S.getValue('TOOLS')['bind-tool'], '--unbind'] +
_NICS_PCI, _LOGGER,
diff --git a/systems/rhel/7.2/build_base_machine.sh b/systems/rhel/7.2/build_base_machine.sh
index 2319535b..d57cf9c0 100755
--- a/systems/rhel/7.2/build_base_machine.sh
+++ b/systems/rhel/7.2/build_base_machine.sh
@@ -78,23 +78,15 @@ if [ "${#failedinstall[*]}" -gt 0 ]; then
exit 1
fi
-# python34 is not yet available to Red Hat customers so we will just build
-# it as an alternate install in usr/local for use with VSPerf. This prevents
-# any functionality issues with pre-installed packages using python.
-wget https://www.python.org/ftp/python/3.4.2/Python-3.4.2.tar.xz
-tar -xf Python-3.4.2.tar.xz
-cd Python-3.4.2
-./configure
-make
-make altinstall
-cd ..
+# install SCL for python33
+wget https://www.softwarecollections.org/en/scls/rhscl/python33/epel-7-x86_64/download/rhscl-python33-epel-7-x86_64.noarch.rpm
+rpm -i rhscl-python33-epel-7-x86_64.noarch.rpm
-# cleanup
-rm -Rf Python-3.4.2
-rm -f Python-3.4.2.tar.xz
-
-# need virtualenv
-pip3.4 install virtualenv
+# install python33 packages and git-review tool
+yum -y install $(echo "
+python33
+python33-python-tkinter
+" | grep -v ^#)
# Create hugepage dirs
mkdir -p /dev/hugepages
diff --git a/systems/rhel/7.2/prepare_python_env.sh b/systems/rhel/7.2/prepare_python_env.sh
index 1d51380a..bd468d80 100755
--- a/systems/rhel/7.2/prepare_python_env.sh
+++ b/systems/rhel/7.2/prepare_python_env.sh
@@ -17,18 +17,13 @@
# limitations under the License.
if [ -d "$VSPERFENV_DIR" ] ; then
- echo "Directory $VSPERFENV_DIR already exists. Skipping python virtualenv \
-creation."
+ echo "Directory $VSPERFENV_DIR already exists. Skipping python virtualenv creation."
exit
fi
-# enable virtual environment in a subshell, so QEMU build can use python 2.7
-# Also make sure we know which virtualenv was installed. I've seen the file
-# name change pending on what type of installation was done.
-virtualenv_file=$(ls /usr/local/bin | awk '/virtualenv/')
-
-($virtualenv_file "$VSPERFENV_DIR"
+scl enable python33 "
+virtualenv "$VSPERFENV_DIR"
source "$VSPERFENV_DIR"/bin/activate
-pip3.4 install -r ../requirements.txt
-pip3.4 install pylint
-) \ No newline at end of file
+pip install -r ../requirements.txt
+pip install pylint
+" \ No newline at end of file
diff --git a/testcases/integration.py b/testcases/integration.py
index 88a6f12c..f2a5fecf 100644
--- a/testcases/integration.py
+++ b/testcases/integration.py
@@ -14,20 +14,10 @@
"""IntegrationTestCase class
"""
-import os
-import time
import logging
-import copy
-from testcases import TestCase
-from conf import settings as S
from collections import OrderedDict
-from tools import namespace
-from tools import veth
-from core.loader import Loader
-
-CHECK_PREFIX = 'validate_'
-
+from testcases import TestCase
class IntegrationTestCase(TestCase):
"""IntegrationTestCase class
@@ -39,180 +29,20 @@ class IntegrationTestCase(TestCase):
self._type = 'integration'
super(IntegrationTestCase, self).__init__(cfg)
self._logger = logging.getLogger(__name__)
- self._inttest = None
-
- def report_status(self, label, status):
- """ Log status of test step
- """
- self._logger.info("%s ... %s", label, 'OK' if status else 'FAILED')
-
- def run_initialize(self):
- """ Prepare test execution environment
- """
- super(IntegrationTestCase, self).run_initialize()
- self._inttest = {'status' : True, 'details' : ''}
-
- def run(self):
- """Run the test
-
- All setup and teardown through controllers is included.
- """
- def eval_step_params(params, step_result):
- """ Evaluates referrences to results from previous steps
- """
- def eval_param(param, STEP):
- """ Helper function
- """
- if isinstance(param, str):
- tmp_param = ''
- # evaluate every #STEP reference inside parameter itself
- for chunk in param.split('#'):
- if chunk.startswith('STEP['):
- tmp_param = tmp_param + str(eval(chunk))
- else:
- tmp_param = tmp_param + chunk
- return tmp_param
- elif isinstance(param, list) or isinstance(param, tuple):
- tmp_list = []
- for item in param:
- tmp_list.append(eval_param(item, STEP))
- return tmp_list
- elif isinstance(param, dict):
- tmp_dict = {}
- for (key, value) in param.items():
- tmp_dict[key] = eval_param(value, STEP)
- return tmp_dict
- else:
- return param
-
- eval_params = []
- # evaluate all parameters if needed
- for param in params:
- eval_params.append(eval_param(param, step_result))
- return eval_params
-
- # prepare test execution environment
- self.run_initialize()
-
- try:
- with self._vswitch_ctl, self._loadgen:
- with self._vnf_ctl, self._collector:
- if not self._vswitch_none:
- self._add_flows()
-
- # run traffic generator if requested, otherwise wait for manual termination
- if S.getValue('mode') == 'trafficgen-off':
- time.sleep(2)
- self._logger.debug("All is set. Please run traffic generator manually.")
- input(os.linesep + "Press Enter to terminate vswitchperf..." + os.linesep + os.linesep)
- else:
- with self._traffic_ctl:
- if not self.test:
- self._traffic_ctl.send_traffic(self._traffic)
- else:
- vnf_list = {}
- loader = Loader()
- # execute test based on TestSteps definition
- if self.test:
- # initialize list with results
- step_result = [None] * len(self.test)
-
- # count how many VNFs are involved in the test
- for step in self.test:
- if step[0].startswith('vnf'):
- vnf_list[step[0]] = None
-
- # check/expand GUEST configuration and copy data to shares
- if len(vnf_list):
- S.check_vm_settings(len(vnf_list))
- self._copy_fwd_tools_for_all_guests(len(vnf_list))
-
- # run test step by step...
- for i, step in enumerate(self.test):
- step_ok = False
- if step[0] == 'vswitch':
- test_object = self._vswitch_ctl.get_vswitch()
- elif step[0] == 'namespace':
- test_object = namespace
- elif step[0] == 'veth':
- test_object = veth
- elif step[0] == 'trafficgen':
- test_object = self._traffic_ctl
- # in case of send_traffic method, ensure that specified
- # traffic values are merged with existing self._traffic
- if step[1] == 'send_traffic':
- tmp_traffic = copy.deepcopy(self._traffic)
- tmp_traffic.update(step[2])
- step[2] = tmp_traffic
- elif step[0].startswith('vnf'):
- if not vnf_list[step[0]]:
- # initialize new VM
- vnf_list[step[0]] = loader.get_vnf_class()()
- test_object = vnf_list[step[0]]
- else:
- self._logger.error("Unsupported test object %s", step[0])
- self._inttest = {'status' : False, 'details' : ' '.join(step)}
- self.report_status("Step '{}'".format(' '.join(step)), self._inttest['status'])
- break
-
- test_method = getattr(test_object, step[1])
- test_method_check = getattr(test_object, CHECK_PREFIX + step[1])
-
- step_params = []
- if test_method and test_method_check and \
- callable(test_method) and callable(test_method_check):
-
- try:
- step_params = eval_step_params(step[2:], step_result)
- step_log = '{} {}'.format(' '.join(step[:2]), step_params)
- step_result[i] = test_method(*step_params)
- self._logger.debug("Step %s '%s' results '%s'", i,
- step_log, step_result[i])
- time.sleep(5)
- step_ok = test_method_check(step_result[i], *step_params)
- except AssertionError:
- self._inttest = {'status' : False, 'details' : step_log}
- self._logger.error("Step %s raised assertion error", i)
- # stop vnfs in case of error
- for vnf in vnf_list:
- vnf_list[vnf].stop()
- break
- except IndexError:
- self._inttest = {'status' : False, 'details' : step_log}
- self._logger.error("Step %s result index error %s", i,
- ' '.join(step[2:]))
- # stop vnfs in case of error
- for vnf in vnf_list:
- vnf_list[vnf].stop()
- break
-
- self.report_status("Step {} - '{}'".format(i, step_log), step_ok)
- if not step_ok:
- self._inttest = {'status' : False, 'details' : step_log}
- # stop vnfs in case of error
- for vnf in vnf_list:
- vnf_list[vnf].stop()
- break
-
- # dump vswitch flows before they are affected by VNF termination
- if not self._vswitch_none:
- self._vswitch_ctl.dump_vswitch_flows()
- finally:
- # tear down test execution environment and log results
- self.run_finalize()
-
- # report test results
- self.run_report()
+ # enforce check of step result for step driven testcases
+ self._step_check = True
def run_report(self):
""" Report test results
"""
if self.test:
results = OrderedDict()
- results['status'] = 'OK' if self._inttest['status'] else 'FAILED'
- results['details'] = self._inttest['details']
+ results['status'] = 'OK' if self._step_status['status'] else 'FAILED'
+ results['details'] = self._step_status['details']
TestCase.write_result_to_file([results], self._output_file)
- self.report_status("Test '{}'".format(self.name), self._inttest['status'])
+ self.step_report_status("Test '{}'".format(self.name), self._step_status['status'])
# inform vsperf about testcase failure
- if not self._inttest['status']:
+ if not self._step_status['status']:
raise Exception
+ else:
+ super(IntegrationTestCase, self).run_report()
diff --git a/testcases/performance.py b/testcases/performance.py
index a4769a28..240d04a9 100644
--- a/testcases/performance.py
+++ b/testcases/performance.py
@@ -34,5 +34,5 @@ class PerformanceTestCase(TestCase):
def run_report(self):
super(PerformanceTestCase, self).run_report()
- if S.getValue('mode') != 'trafficgen-off':
+ if self._tc_results:
report.generate(self._output_file, self._tc_results, self._collector.get_results(), self._type)
diff --git a/testcases/testcase.py b/testcases/testcase.py
index 7f22c18f..18ad4240 100644
--- a/testcases/testcase.py
+++ b/testcases/testcase.py
@@ -32,8 +32,12 @@ from core.results.results_constants import ResultsConstants
from tools import tasks
from tools import hugepages
from tools import functions
+from tools import namespace
+from tools import veth
+from tools.teststepstools import TestStepsTools
from tools.pkt_gen.trafficgen.trafficgenhelper import TRAFFIC_DEFAULTS
+CHECK_PREFIX = 'validate_'
class TestCase(object):
"""TestCase base class
@@ -60,6 +64,12 @@ class TestCase(object):
self._settings_original = {}
self._settings_paths_modified = False
self._testcast_run_time = None
+ # initialization of step driven specific members
+ self._step_check = False # by default don't check result for step driven testcases
+ self._step_vnf_list = {}
+ self._step_result = []
+ self._step_status = None
+ self._testcase_run_time = None
# store all GUEST_ specific settings to keep original values before their expansion
for key in S.__dict__:
@@ -69,14 +79,21 @@ class TestCase(object):
self._update_settings('VSWITCH', cfg.get('vSwitch', S.getValue('VSWITCH')))
self._update_settings('VNF', cfg.get('VNF', S.getValue('VNF')))
self._update_settings('TRAFFICGEN', cfg.get('Trafficgen', S.getValue('TRAFFICGEN')))
- self._update_settings('TEST_PARAMS', cfg.get('Parameters', S.getValue('TEST_PARAMS')))
+ test_params = copy.deepcopy(S.getValue('TEST_PARAMS'))
+ tc_test_params = cfg.get('Parameters', S.getValue('TEST_PARAMS'))
+ test_params.update(tc_test_params)
+ self._update_settings('TEST_PARAMS', test_params)
+ S.check_test_params()
+
+ # override all redefined GUEST_ values to have them expanded correctly
+ tmp_test_params = copy.deepcopy(S.getValue('TEST_PARAMS'))
+ for key in tmp_test_params:
+ if key.startswith('GUEST_'):
+ S.setValue(key, S.getValue(key))
+ S.getValue('TEST_PARAMS').pop(key)
# update global settings
functions.settings_update_paths()
- guest_loopback = get_test_param('guest_loopback', None)
- if guest_loopback:
- # we can put just one item, it'll be expanded automatically for all VMs
- self._update_settings('GUEST_LOOPBACK', [guest_loopback])
# set test parameters; CLI options take precedence to testcase settings
self._logger = logging.getLogger(__name__)
@@ -162,7 +179,9 @@ class TestCase(object):
self._traffic['l2'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L2')
self._traffic['l3'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L3')
self._traffic['l4'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L4')
- elif S.getValue('NICS')[0]['type'] == 'vf' or S.getValue('NICS')[1]['type'] == 'vf':
+ elif len(S.getValue('NICS')) and \
+ (S.getValue('NICS')[0]['type'] == 'vf' or
+ S.getValue('NICS')[1]['type'] == 'vf'):
mac1 = S.getValue('NICS')[0]['mac']
mac2 = S.getValue('NICS')[1]['mac']
if mac1 and mac2:
@@ -170,6 +189,12 @@ class TestCase(object):
else:
self._logger.debug("MAC addresses can not be read")
+ # count how many VNFs are involved in TestSteps
+ if self.test:
+ for step in self.test:
+ if step[0].startswith('vnf'):
+ self._step_vnf_list[step[0]] = None
+
def run_initialize(self):
""" Prepare test execution environment
"""
@@ -186,26 +211,31 @@ class TestCase(object):
self._vnf_ctl = component_factory.create_vnf(
self.deployment,
- loader.get_vnf_class())
+ loader.get_vnf_class(),
+ len(self._step_vnf_list))
# verify enough hugepages are free to run the testcase
if not self._check_for_enough_hugepages():
raise RuntimeError('Not enough hugepages free to run test.')
# perform guest related handling
- if self._vnf_ctl.get_vnfs_number():
+ tmp_vm_count = self._vnf_ctl.get_vnfs_number() + len(self._step_vnf_list)
+ if tmp_vm_count:
# copy sources of l2 forwarding tools into VM shared dir if needed
- self._copy_fwd_tools_for_all_guests(self._vnf_ctl.get_vnfs_number())
+ self._copy_fwd_tools_for_all_guests(tmp_vm_count)
# in case of multi VM in parallel, set the number of streams to the number of VMs
if self.deployment.startswith('pvpv'):
# for each VM NIC pair we need an unique stream
streams = 0
- for vm_nic in S.getValue('GUEST_NICS_NR')[:self._vnf_ctl.get_vnfs_number()]:
+ for vm_nic in S.getValue('GUEST_NICS_NR')[:tmp_vm_count]:
streams += int(vm_nic / 2) if vm_nic > 1 else 1
self._logger.debug("VMs with parallel connection were detected. "
"Thus Number of streams was set to %s", streams)
- self._traffic.update({'multistream': streams})
+ # update streams if needed; In case of additional VNFs deployed by TestSteps
+ # user can define a proper stream count manually
+ if 'multistream' not in self._traffic or self._traffic['multistream'] < streams:
+ self._traffic.update({'multistream': streams})
# OVS Vanilla requires guest VM MAC address and IPs to work
if 'linux_bridge' in S.getValue('GUEST_LOOPBACK'):
@@ -235,11 +265,16 @@ class TestCase(object):
self._output_file = os.path.join(self._results_dir, "result_" + self.name +
"_" + self.deployment + ".csv")
+ self._step_status = {'status' : True, 'details' : ''}
+
self._logger.debug("Setup:")
def run_finalize(self):
""" Tear down test execution environment and record test results
"""
+ # Stop all VNFs started by TestSteps in case that something went wrong
+ self.step_stop_vnfs()
+
# umount hugepages if mounted
self._umount_hugepages()
@@ -248,22 +283,20 @@ class TestCase(object):
# cleanup any namespaces created
if os.path.isdir('/tmp/namespaces'):
- import tools.namespace
namespace_list = os.listdir('/tmp/namespaces')
if len(namespace_list):
self._logger.info('Cleaning up namespaces')
for name in namespace_list:
- tools.namespace.delete_namespace(name)
+ namespace.delete_namespace(name)
os.rmdir('/tmp/namespaces')
# cleanup any veth ports created
if os.path.isdir('/tmp/veth'):
- import tools.veth
veth_list = os.listdir('/tmp/veth')
if len(veth_list):
self._logger.info('Cleaning up veth ports')
for eth in veth_list:
port1, port2 = eth.split('-')
- tools.veth.del_veth_port(port1, port2)
+ veth.del_veth_port(port1, port2)
os.rmdir('/tmp/veth')
def run_report(self):
@@ -272,11 +305,12 @@ class TestCase(object):
self._logger.debug("self._collector Results:")
self._collector.print_results()
- if S.getValue('mode') != 'trafficgen-off':
+ results = self._traffic_ctl.get_results()
+ if results:
self._logger.debug("Traffic Results:")
self._traffic_ctl.print_results()
- self._tc_results = self._append_results(self._traffic_ctl.get_results())
+ self._tc_results = self._append_results(results)
TestCase.write_result_to_file(self._tc_results, self._output_file)
def run(self):
@@ -287,39 +321,35 @@ class TestCase(object):
# prepare test execution environment
self.run_initialize()
- with self._vswitch_ctl, self._loadgen:
- with self._vnf_ctl, self._collector:
- if not self._vswitch_none:
- self._add_flows()
+ try:
+ with self._vswitch_ctl, self._loadgen:
+ with self._vnf_ctl, self._collector:
+ if not self._vswitch_none:
+ self._add_flows()
- # run traffic generator if requested, otherwise wait for manual termination
- if S.getValue('mode') == 'trafficgen-off':
- time.sleep(2)
- self._logger.debug("All is set. Please run traffic generator manually.")
- input(os.linesep + "Press Enter to terminate vswitchperf..." + os.linesep + os.linesep)
- else:
- if S.getValue('mode') == 'trafficgen-pause':
- time.sleep(2)
- true_vals = ('yes', 'y', 'ye', None)
- while True:
- choice = input(os.linesep + 'Transmission paused, should'
- ' transmission be resumed? ' + os.linesep).lower()
- if not choice or choice not in true_vals:
- print('Please respond with \'yes\' or \'y\' ', end='')
- else:
- break
with self._traffic_ctl:
- self._traffic_ctl.send_traffic(self._traffic)
+ # execute test based on TestSteps definition if needed...
+ if self.step_run():
+ # ...and continue with traffic generation, but keep
+ # in mind, that clean deployment does not configure
+ # OVS nor executes the traffic
+ if self.deployment != 'clean':
+ self._traffic_ctl.send_traffic(self._traffic)
- # dump vswitch flows before they are affected by VNF termination
- if not self._vswitch_none:
- self._vswitch_ctl.dump_vswitch_flows()
+ # dump vswitch flows before they are affected by VNF termination
+ if not self._vswitch_none:
+ self._vswitch_ctl.dump_vswitch_flows()
+
+ # garbage collection for case that TestSteps modify existing deployment
+ self.step_stop_vnfs()
- # tear down test execution environment and log results
- self.run_finalize()
+ finally:
+ # tear down test execution environment and log results
+ self.run_finalize()
self._testcase_run_time = time.strftime("%H:%M:%S",
- time.gmtime(time.time() - self._testcase_start_time))
+ time.gmtime(time.time() -
+ self._testcase_start_time))
logging.info("Testcase execution time: " + self._testcase_run_time)
# report test results
self.run_report()
@@ -334,7 +364,7 @@ class TestCase(object):
"""
orig_value = S.getValue(param)
if orig_value != value:
- self._settings_original[param] = orig_value
+ self._settings_original[param] = copy.deepcopy(orig_value)
S.setValue(param, value)
def _append_results(self, results):
@@ -635,3 +665,143 @@ class TestCase(object):
vswitch.add_flow(bridge, flow)
else:
pass
+
+
+ #
+ # TestSteps realted methods
+ #
+ def step_report_status(self, label, status):
+ """ Log status of test step
+ """
+ self._logger.info("%s ... %s", label, 'OK' if status else 'FAILED')
+
+ def step_stop_vnfs(self):
+ """ Stop all VNFs started by TestSteps
+ """
+ for vnf in self._step_vnf_list:
+ self._step_vnf_list[vnf].stop()
+
+ @staticmethod
+ def step_eval_param(param, STEP):
+ # pylint: disable=invalid-name
+ """ Helper function for #STEP macro evaluation
+ """
+ if isinstance(param, str):
+ # evaluate every #STEP reference inside parameter itself
+ macros = re.findall(r'#STEP\[[\w\[\]\-\'\"]+\]', param)
+ if macros:
+ for macro in macros:
+ # pylint: disable=eval-used
+ tmp_val = str(eval(macro[1:]))
+ param = param.replace(macro, tmp_val)
+ return param
+ elif isinstance(param, list) or isinstance(param, tuple):
+ tmp_list = []
+ for item in param:
+ tmp_list.append(TestCase.step_eval_param(item, STEP))
+ return tmp_list
+ elif isinstance(param, dict):
+ tmp_dict = {}
+ for (key, value) in param.items():
+ tmp_dict[key] = TestCase.step_eval_param(value, STEP)
+ return tmp_dict
+ else:
+ return param
+
+ @staticmethod
+ def step_eval_params(params, step_result):
+ """ Evaluates referrences to results from previous steps
+ """
+ eval_params = []
+ # evaluate all parameters if needed
+ for param in params:
+ eval_params.append(TestCase.step_eval_param(param, step_result))
+ return eval_params
+
+ def step_run(self):
+ """ Execute actions specified by TestSteps list
+
+ :return: False if any error was detected
+ True otherwise
+ """
+ # anything to do?
+ if not self.test:
+ return True
+
+ # required for VNFs initialization
+ loader = Loader()
+ # initialize list with results
+ self._step_result = [None] * len(self.test)
+
+ # run test step by step...
+ for i, step in enumerate(self.test):
+ step_ok = not self._step_check
+ if step[0] == 'vswitch':
+ test_object = self._vswitch_ctl.get_vswitch()
+ elif step[0] == 'namespace':
+ test_object = namespace
+ elif step[0] == 'veth':
+ test_object = veth
+ elif step[0] == 'settings':
+ test_object = S
+ elif step[0] == 'tools':
+ test_object = TestStepsTools()
+ step[1] = step[1].title()
+ elif step[0] == 'trafficgen':
+ test_object = self._traffic_ctl
+ # in case of send_traffic or send_traffic_async methods, ensure
+ # that specified traffic values are merged with existing self._traffic
+ if step[1].startswith('send_traffic'):
+ tmp_traffic = copy.deepcopy(self._traffic)
+ tmp_traffic.update(step[2])
+ step[2] = tmp_traffic
+ elif step[0].startswith('vnf'):
+ if not self._step_vnf_list[step[0]]:
+ # initialize new VM
+ self._step_vnf_list[step[0]] = loader.get_vnf_class()()
+ test_object = self._step_vnf_list[step[0]]
+ elif step[0] == 'wait':
+ input(os.linesep + "Step {}: Press Enter to continue with "
+ "the next step...".format(i) + os.linesep + os.linesep)
+ continue
+ else:
+ self._logger.error("Unsupported test object %s", step[0])
+ self._step_status = {'status' : False, 'details' : ' '.join(step)}
+ self.step_report_status("Step '{}'".format(' '.join(step)),
+ self._step_status['status'])
+ return False
+
+ test_method = getattr(test_object, step[1])
+ if self._step_check:
+ test_method_check = getattr(test_object, CHECK_PREFIX + step[1])
+ else:
+ test_method_check = None
+
+ step_params = []
+ try:
+ # eval parameters, but use only valid step_results
+ # to support negative indexes
+ step_params = TestCase.step_eval_params(step[2:], self._step_result[:i])
+ step_log = '{} {}'.format(' '.join(step[:2]), step_params)
+ self._logger.debug("Step %s '%s' start", i, step_log)
+ self._step_result[i] = test_method(*step_params)
+ self._logger.debug("Step %s '%s' results '%s'", i,
+ step_log, self._step_result[i])
+ time.sleep(5)
+ if self._step_check:
+ step_ok = test_method_check(self._step_result[i], *step_params)
+ except (AssertionError, AttributeError, IndexError) as ex:
+ step_ok = False
+ self._logger.error("Step %s raised %s", i, type(ex).__name__)
+
+ if self._step_check:
+ self.step_report_status("Step {} - '{}'".format(i, step_log), step_ok)
+
+ if not step_ok:
+ self._step_status = {'status' : False, 'details' : step_log}
+ # Stop all VNFs started by TestSteps
+ self.step_stop_vnfs()
+ return False
+
+ # all steps processed without any issue
+ return True
diff --git a/tools/pkt_gen/ixia/ixia.py b/tools/pkt_gen/ixia/ixia.py
index cd14a2a7..5c5fb3df 100755
--- a/tools/pkt_gen/ixia/ixia.py
+++ b/tools/pkt_gen/ixia/ixia.py
@@ -19,7 +19,7 @@ lifting".
This requires the following settings in your config file:
-* TRAFFICGEN_IXIA_LIB_PATH
+* TRAFFICGEN_IXIA_ROOT_DIR
IXIA libraries path
* TRAFFICGEN_IXIA_HOST
IXIA chassis IP address
@@ -39,6 +39,7 @@ import logging
import os
from collections import OrderedDict
+from tools import systeminfo
from tools.pkt_gen import trafficgen
from conf import settings
from core.results.results_constants import ResultsConstants
@@ -76,7 +77,7 @@ def configure_env():
os.environ['IXIA_LOGS_DIR'] = '/tmp/Ixia/Logs'
os.environ['IXIA_TCL_DIR'] = os.path.expandvars('$IxiaLibPath')
os.environ['IXIA_SAMPLES'] = os.path.expandvars('$IxiaLibPath/ixTcl1.0')
- os.environ['IXIA_VERSION'] = '6.60.1000.11'
+ os.environ['IXIA_VERSION'] = systeminfo.get_version('Ixia')['version']
def _build_set_cmds(values, prefix='dict set'):
@@ -131,7 +132,8 @@ class Ixia(trafficgen.ITrafficGenerator):
Runs different traffic generator tests through an Ixia traffic
generator chassis by generating TCL scripts from templates.
"""
- _script = os.path.join(os.path.dirname(__file__), 'pass_fail.tcl')
+ _script = os.path.join(settings.getValue('TRAFFICGEN_IXIA_3RD_PARTY'),
+ 'pass_fail.tcl')
_tclsh = tkinter.Tcl()
_logger = logging.getLogger(__name__)
@@ -298,8 +300,8 @@ class Ixia(trafficgen.ITrafficGenerator):
# metrics so we have to return dummy values for these metrics
result_dict[ResultsConstants.THROUGHPUT_RX_FPS] = result[4]
result_dict[ResultsConstants.TX_RATE_FPS] = result[5]
- result_dict[ResultsConstants.THROUGHPUT_RX_MBPS] = result[6]
- result_dict[ResultsConstants.TX_RATE_MBPS] = result[7]
+ result_dict[ResultsConstants.THROUGHPUT_RX_MBPS] = str(round(int(result[6]) / 1000000, 3))
+ result_dict[ResultsConstants.TX_RATE_MBPS] = str(round(int(result[7]) / 1000000, 3))
result_dict[ResultsConstants.FRAME_LOSS_PERCENT] = loss_rate
result_dict[ResultsConstants.TX_RATE_PERCENT] = \
ResultsConstants.UNKNOWN_VALUE
diff --git a/tools/pkt_gen/ixnet/ixnet.py b/tools/pkt_gen/ixnet/ixnet.py
index 5e4ae569..6262a10a 100755
--- a/tools/pkt_gen/ixnet/ixnet.py
+++ b/tools/pkt_gen/ixnet/ixnet.py
@@ -151,16 +151,17 @@ class IxNet(trafficgen.ITrafficGenerator):
Currently only the RFC2544 tests are implemented.
"""
- if settings.getValue('TRAFFICGEN_IXNET_TCL_SCRIPT') == '':
- _script = os.path.join(os.path.dirname(__file__), 'ixnetrfc2544.tcl')
- else:
- _script = os.path.join(os.path.dirname(__file__),
- settings.getValue('TRAFFICGEN_IXNET_TCL_SCRIPT'))
- _tclsh = tkinter.Tcl()
- _cfg = None
- _logger = logging.getLogger(__name__)
- _params = None
- _bidir = None
+
+ def __init__(self):
+ """Initialize IXNET members
+ """
+ self._script = os.path.join(settings.getValue('TRAFFICGEN_IXIA_3RD_PARTY'),
+ settings.getValue('TRAFFICGEN_IXNET_TCL_SCRIPT'))
+ self._tclsh = tkinter.Tcl()
+ self._cfg = None
+ self._logger = logging.getLogger(__name__)
+ self._params = None
+ self._bidir = None
def run_tcl(self, cmd):
"""Run a TCL script using the TCL interpreter found in ``tkinter``.
diff --git a/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py b/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py
index 91f7e27f..538d8a8a 100644
--- a/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py
+++ b/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py
@@ -22,6 +22,7 @@ TestCenter REST APIs. This test supports Python 3.4
import argparse
import logging
import os
+from conf import settings
logger = logging.getLogger(__name__)
@@ -141,7 +142,7 @@ def main():
dest="test_user_name")
optional_named.add_argument("--results_dir",
required=False,
- default="./Results",
+ default=settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
help="The directory to copy results to",
dest="results_dir")
optional_named.add_argument("--csv_results_file_prefix",
diff --git a/tools/pkt_gen/testcenter/testcenter-rfc2544-throughput.py b/tools/pkt_gen/testcenter/testcenter-rfc2544-throughput.py
index becf7877..239fd109 100644
--- a/tools/pkt_gen/testcenter/testcenter-rfc2544-throughput.py
+++ b/tools/pkt_gen/testcenter/testcenter-rfc2544-throughput.py
@@ -22,6 +22,7 @@ TestCenter command sequencer. This test supports Python 2.7.
from __future__ import print_function
import argparse
import os
+from conf import settings
def create_dir(path):
@@ -129,7 +130,7 @@ def main():
dest="test_session_name")
optionalnamed.add_argument("--results_dir",
required=False,
- default="./Results",
+ default=settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
help="The directory to copy results to",
dest="results_dir")
optionalnamed.add_argument("--csv_results_file_prefix",
diff --git a/tools/report/report.jinja b/tools/report/report.jinja
index 8354835c..c9588565 100644
--- a/tools/report/report.jinja
+++ b/tools/report/report.jinja
@@ -138,7 +138,6 @@ The following are the metrics obtained during this test:
The following system statistics were collected during testcase execution:
{% for process in test.stats %}
-| --------------------------------------------------------------- |
| Process: {{ "%-54s |"|format('_'.join(process.split('_')[:-1])) }}
| ------------------------------ | ------------------------------ |
| Statistic | Value |
diff --git a/tools/systeminfo.py b/tools/systeminfo.py
index fb1616d4..1d193159 100644
--- a/tools/systeminfo.py
+++ b/tools/systeminfo.py
@@ -228,6 +228,7 @@ def get_version(app_name):
'loopback_testpmd' : os.path.join(S.getValue('TOOLS')['dpdk_src'],
'lib/librte_eal/common/include/rte_version.h'),
'ixnet' : os.path.join(S.getValue('TRAFFICGEN_IXNET_LIB_PATH'), 'pkgIndex.tcl'),
+ 'ixia' : os.path.join(S.getValue('TRAFFICGEN_IXIA_ROOT_DIR'), 'lib/ixTcl1.0/ixTclHal.tcl'),
}
@@ -301,6 +302,10 @@ def get_version(app_name):
app_version = match_line(app_version_file['ixnet'], 'package provide IxTclNetwork')
if app_version:
app_version = app_version.split(' ')[3]
+ elif app_name.lower() == 'ixia':
+ app_version = match_line(app_version_file['ixia'], 'package provide IxTclHal')
+ if app_version:
+ app_version = app_version.split(' ')[3]
elif app_name.lower() == 'xena':
try:
app_version = S.getValue('XENA_VERSION')
diff --git a/tools/teststepstools.py b/tools/teststepstools.py
new file mode 100644
index 00000000..d39f7f40
--- /dev/null
+++ b/tools/teststepstools.py
@@ -0,0 +1,90 @@
+# Copyright 2016 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.
+
+"""Various helper functions for step driven testcases
+"""
+
+import re
+import logging
+import subprocess
+import locale
+
+class TestStepsTools(object):
+ """ Various tools and functions used by step driven testcases
+ """
+ # Functions use nonstandard names to avoid conflicts with
+ # standard python keywords.
+ # pylint: disable=invalid-name
+ def __init__(self):
+ """ TestStepsTools initialization
+ """
+ self._logger = logging.getLogger(__name__)
+
+ def Assert(self, condition):
+ """ Evaluate given `condition' and raise AssertionError
+ in case, that evaluation fails
+ """
+ try:
+ assert self.Eval(condition)
+ except AssertionError:
+ self._logger.error('Condition %s is not True', condition)
+ raise
+
+ return True
+
+ @staticmethod
+ def validate_Assert(result, dummy_condition):
+ """ Validate evaluation of given `condition'
+ """
+ return result
+
+ @staticmethod
+ def Eval(expression):
+ """ Evaluate python `expression' and return its result
+ """
+ # pylint: disable=eval-used
+ return eval(expression)
+
+ @staticmethod
+ def validate_Eval(result, dummy_expression):
+ """ Validate result of python `expression' evaluation
+ """
+ return result is not None
+
+ @staticmethod
+ def Exec(command, regex=None):
+ """ Execute a shell `command' and return its output filtered
+ out by optional `regex' expression.
+ """
+ try:
+ output = subprocess.check_output(command, shell=True)
+ except OSError:
+ return None
+
+ output = output.decode(locale.getdefaultlocale()[1])
+
+ if regex:
+ for line in output.split('\n'):
+ result = re.findall(regex, line)
+ if result:
+ return result
+ return []
+
+ return output
+
+ @staticmethod
+ def validate_Exec(result, dummy_command, dummy_regex=None):
+ """ validate result of shell `command' execution
+ """
+ return result is not None
diff --git a/vnfs/qemu/qemu.py b/vnfs/qemu/qemu.py
index 01c16a0f..997f93e0 100644
--- a/vnfs/qemu/qemu.py
+++ b/vnfs/qemu/qemu.py
@@ -24,7 +24,6 @@ import time
import pexpect
from conf import settings as S
-from conf import get_test_param
from vnfs.vnf.vnf import IVnf
class IVnfQemu(IVnf):
@@ -69,7 +68,6 @@ class IVnfQemu(IVnf):
self._nics = S.getValue('GUEST_NICS')[self._number][:nics_nr]
# set guest loopback application based on VNF configuration
- # cli option take precedence to config file values
self._guest_loopback = S.getValue('GUEST_LOOPBACK')[self._number]
self._testpmd_fwd_mode = S.getValue('GUEST_TESTPMD_FWD_MODE')[self._number]
@@ -83,9 +81,11 @@ class IVnfQemu(IVnf):
name = 'Client%d' % self._number
vnc = ':%d' % self._number
- # don't use taskset to affinize main qemu process; It causes hangup
- # of 2nd VM in case of DPDK. It also slows down VM responsivnes.
- self._cmd = ['sudo', '-E', S.getValue('TOOLS')['qemu-system'],
+ # NOTE: affinization of main qemu process can cause hangup of 2nd VM
+ # in case of DPDK usage. It can also slow down VM response time.
+ cpumask = ",".join(S.getValue('GUEST_CORE_BINDING')[self._number])
+ self._cmd = ['sudo', '-E', 'taskset', '-c', cpumask,
+ S.getValue('TOOLS')['qemu-system'],
'-m', S.getValue('GUEST_MEMORY')[self._number],
'-smp', str(S.getValue('GUEST_SMP')[self._number]),
'-cpu', 'host,migratable=off',
@@ -144,27 +144,28 @@ class IVnfQemu(IVnf):
"""
Stops VNF instance gracefully first.
"""
- try:
- # exit testpmd if needed
- if self._guest_loopback == 'testpmd':
- self.execute_and_wait('stop', 120, "Done")
- self.execute_and_wait('quit', 120, "[bB]ye")
+ if self.is_running():
+ try:
+ # exit testpmd if needed
+ if self._guest_loopback == 'testpmd':
+ self.execute_and_wait('stop', 120, "Done")
+ self.execute_and_wait('quit', 120, "[bB]ye")
- # turn off VM
- self.execute_and_wait('poweroff', 120, "Power down")
+ # turn off VM
+ self.execute_and_wait('poweroff', 120, "Power down")
- except pexpect.TIMEOUT:
- self.kill()
+ except pexpect.TIMEOUT:
+ self.kill()
- # wait until qemu shutdowns
- self._logger.debug('Wait for QEMU to terminate')
- for dummy in range(30):
- time.sleep(1)
- if not self.is_running():
- break
+ # wait until qemu shutdowns
+ self._logger.debug('Wait for QEMU to terminate')
+ for dummy in range(30):
+ time.sleep(1)
+ if not self.is_running():
+ break
- # just for case that graceful shutdown failed
- super(IVnfQemu, self).stop()
+ # just for case that graceful shutdown failed
+ super(IVnfQemu, self).stop()
# helper functions
@@ -340,7 +341,6 @@ class IVnfQemu(IVnf):
self.execute_and_wait("{} -t {} -F".format(iptables, table))
self.execute_and_wait("{} -t {} -X".format(iptables, table))
-
def _configure_testpmd(self):
"""
Configure VM to perform L2 forwarding between NICs by DPDK's testpmd
@@ -372,16 +372,11 @@ class IVnfQemu(IVnf):
for nic in self._nics:
self.execute_and_wait('ifdown ' + nic['device'])
- # build and insert igb_uio and rebind interfaces to it
- self.execute_and_wait('make RTE_OUTPUT=$RTE_SDK/$RTE_TARGET -C '
- '$RTE_SDK/lib/librte_eal/linuxapp/igb_uio')
- self.execute_and_wait('modprobe uio')
- self.execute_and_wait('insmod %s/kmod/igb_uio.ko' %
- S.getValue('RTE_TARGET'))
self.execute_and_wait('./tools/dpdk*bind.py --status')
pci_list = ' '.join([nic['pci'] for nic in self._nics])
self.execute_and_wait('./tools/dpdk*bind.py -u ' + pci_list)
- self.execute_and_wait('./tools/dpdk*bind.py -b igb_uio ' + pci_list)
+ self._bind_dpdk_driver(S.getValue(
+ 'GUEST_DPDK_BIND_DRIVER')[self._number], pci_list)
self.execute_and_wait('./tools/dpdk*bind.py --status')
# build and run 'test-pmd'
@@ -389,25 +384,13 @@ class IVnfQemu(IVnf):
'/DPDK/app/test-pmd')
self.execute_and_wait('make clean')
self.execute_and_wait('make')
- if int(S.getValue('GUEST_NIC_QUEUES')[self._number]):
- self.execute_and_wait(
- './testpmd {} -n4 --socket-mem 512 --'.format(
- S.getValue('GUEST_TESTPMD_CPU_MASK')[self._number]) +
- ' --burst=64 -i --txqflags=0xf00 ' +
- '--nb-cores={} --rxq={} --txq={} '.format(
- S.getValue('GUEST_TESTPMD_NB_CORES')[self._number],
- S.getValue('GUEST_TESTPMD_TXQ')[self._number],
- S.getValue('GUEST_TESTPMD_RXQ')[self._number]) +
- '--disable-hw-vlan', 60, "Done")
- else:
- self.execute_and_wait(
- './testpmd {} -n 4 --socket-mem 512 --'.format(
- S.getValue('GUEST_TESTPMD_CPU_MASK')[self._number]) +
- ' --burst=64 -i --txqflags=0xf00 ' +
- '--disable-hw-vlan', 60, "Done")
+
+ # get testpmd settings from CLI
+ testpmd_params = S.getValue('GUEST_TESTPMD_PARAMS')[self._number]
+
+ self.execute_and_wait('./testpmd {}'.format(testpmd_params), 60, "Done")
self.execute('set fwd ' + self._testpmd_fwd_mode, 1)
- self.execute_and_wait('start', 20,
- 'TX RS bit threshold=.+ - TXQ flags=0xf00')
+ self.execute_and_wait('start', 20, 'testpmd>')
def _configure_l2fwd(self):
"""
@@ -463,17 +446,13 @@ class IVnfQemu(IVnf):
# Add the arp entries for the IXIA ports and the bridge you are using.
# Use command line values if provided.
- trafficgen_mac = get_test_param('vanilla_tgen_port1_mac',
- S.getValue('VANILLA_TGEN_PORT1_MAC'))
- trafficgen_ip = get_test_param('vanilla_tgen_port1_ip',
- S.getValue('VANILLA_TGEN_PORT1_IP'))
+ trafficgen_mac = S.getValue('VANILLA_TGEN_PORT1_MAC')
+ trafficgen_ip = S.getValue('VANILLA_TGEN_PORT1_IP')
self.execute('arp -s ' + trafficgen_ip + ' ' + trafficgen_mac)
- trafficgen_mac = get_test_param('vanilla_tgen_port2_mac',
- S.getValue('VANILLA_TGEN_PORT2_MAC'))
- trafficgen_ip = get_test_param('vanilla_tgen_port2_ip',
- S.getValue('VANILLA_TGEN_PORT2_IP'))
+ trafficgen_mac = S.getValue('VANILLA_TGEN_PORT2_MAC')
+ trafficgen_ip = S.getValue('VANILLA_TGEN_PORT2_IP')
self.execute('arp -s ' + trafficgen_ip + ' ' + trafficgen_mac)
@@ -486,6 +465,42 @@ class IVnfQemu(IVnf):
for nic in self._nics:
self.execute('sysctl -w net.ipv4.conf.' + nic['device'] + '.rp_filter=0')
+ def _bind_dpdk_driver(self, driver, pci_slots):
+ """
+ Bind the virtual nics to the driver specific in the conf file
+ :return: None
+ """
+ if driver == 'uio_pci_generic':
+ if S.getValue('VNF') == 'QemuPciPassthrough':
+ # unsupported config, bind to igb_uio instead and exit the
+ # outer function after completion.
+ self._logger.error('SR-IOV does not support uio_pci_generic. '
+ 'Igb_uio will be used instead.')
+ self._bind_dpdk_driver('igb_uio_from_src', pci_slots)
+ return
+ self.execute_and_wait('modprobe uio_pci_generic')
+ self.execute_and_wait('./tools/dpdk*bind.py -b uio_pci_generic '+
+ pci_slots)
+ elif driver == 'vfio_no_iommu':
+ self.execute_and_wait('modprobe -r vfio')
+ self.execute_and_wait('modprobe -r vfio_iommu_type1')
+ self.execute_and_wait('modprobe vfio enable_unsafe_noiommu_mode=Y')
+ self.execute_and_wait('modprobe vfio-pci')
+ self.execute_and_wait('./tools/dpdk*bind.py -b vfio-pci ' +
+ pci_slots)
+ elif driver == 'igb_uio_from_src':
+ # build and insert igb_uio and rebind interfaces to it
+ self.execute_and_wait('make RTE_OUTPUT=$RTE_SDK/$RTE_TARGET -C '
+ '$RTE_SDK/lib/librte_eal/linuxapp/igb_uio')
+ self.execute_and_wait('modprobe uio')
+ self.execute_and_wait('insmod %s/kmod/igb_uio.ko' %
+ S.getValue('RTE_TARGET'))
+ self.execute_and_wait('./tools/dpdk*bind.py -b igb_uio ' + pci_slots)
+ else:
+ self._logger.error(
+ 'Unknown driver for binding specified, defaulting to igb_uio')
+ self._bind_dpdk_driver('igb_uio_from_src', pci_slots)
+
def _set_multi_queue_nic(self):
"""
Enable multi-queue in guest kernel with ethool.
diff --git a/vsperf b/vsperf
index a12560da..ee494dcd 100755
--- a/vsperf
+++ b/vsperf
@@ -21,6 +21,7 @@ import logging
import os
import sys
import argparse
+import re
import time
import datetime
import shutil
@@ -54,12 +55,15 @@ VERBOSITY_LEVELS = {
'critical': logging.CRITICAL
}
-_TEMPLATE_RST = {'head' : 'tools/report/report_head.rst',
- 'foot' : 'tools/report/report_foot.rst',
+_CURR_DIR = os.path.dirname(os.path.realpath(__file__))
+
+_TEMPLATE_RST = {'head' : os.path.join(_CURR_DIR, 'tools/report/report_head.rst'),
+ 'foot' : os.path.join(_CURR_DIR, 'tools/report/report_foot.rst'),
'final' : 'test_report.rst',
- 'tmp' : 'tools/report/report_tmp_caption.rst'
+ 'tmp' : os.path.join(_CURR_DIR, 'tools/report/report_tmp_caption.rst')
}
+
_LOGGER = logging.getLogger()
def parse_arguments():
@@ -72,21 +76,19 @@ def parse_arguments():
This expects either 'x=y', 'x=y,z' or 'x' (implicit true)
values. For multiple overrides use a ; separated list for
- e.g. --test-params 'x=z; y=a,b'
+ e.g. --test-params 'x=z; y=(a,b)'
"""
def __call__(self, parser, namespace, values, option_string=None):
results = {}
- for value in values.split(';'):
- result = [key.strip() for key in value.split('=')]
- if len(result) == 1:
- results[result[0]] = True
- elif len(result) == 2:
- results[result[0]] = result[1]
- else:
- raise argparse.ArgumentTypeError(
- 'expected \'%s\' to be of format \'key=val\' or'
- ' \'key\'' % result)
+ for param, _, value in re.findall('([^;=]+)(=([^;]+))?', values):
+ param = param.strip()
+ value = value.strip()
+ if len(param):
+ if len(value):
+ results[param] = value
+ else:
+ results[param] = True
setattr(namespace, self.dest, results)
@@ -178,9 +180,9 @@ def parse_arguments():
group.add_argument('--conf-file', action=_ValidateFileAction,
help='settings file')
group.add_argument('--test-params', action=_SplitTestParamsAction,
- help='csv list of test parameters: key=val; e.g.'
- 'including pkt_sizes=x,y; duration=x; '
- 'rfc2544_tests=x ...')
+ help='csv list of test parameters: key=val; e.g. '
+ 'TRAFFICGEN_PKT_SIZES=(64,128);TRAFICGEN_DURATION=30; '
+ 'GUEST_LOOPBACK=["l2fwd"] ...')
group.add_argument('--opnfvpod', help='name of POD in opnfv')
args = vars(parser.parse_args())
@@ -482,11 +484,11 @@ def main():
# configure settings
- settings.load_from_dir('conf')
+ settings.load_from_dir(os.path.join(_CURR_DIR, 'conf'))
# Load non performance/integration tests
if args['integration']:
- settings.load_from_dir('conf/integration')
+ settings.load_from_dir(os.path.join(_CURR_DIR, 'conf/integration'))
# load command line parameters first in case there are settings files
# to be used
@@ -582,14 +584,6 @@ def main():
# for backward compatibility
settings.setValue('WHITELIST_NICS', list(nic['pci'] for nic in nic_list))
- # update global settings
- guest_loopback = get_test_param('guest_loopback', None)
- if guest_loopback:
- tmp_gl = []
- for dummy_i in range(len(settings.getValue('GUEST_LOOPBACK'))):
- tmp_gl.append(guest_loopback)
- settings.setValue('GUEST_LOOPBACK', tmp_gl)
-
settings.setValue('mode', args['mode'])
# generate results directory name
@@ -609,11 +603,11 @@ def main():
loader = Loader()
# set traffic details, so they can be passed to traffic ctl
traffic = copy.deepcopy(TRAFFIC_DEFAULTS)
- traffic.update({'traffic_type': get_test_param('traffic_type', 'rfc2544'),
- 'bidir': get_test_param('bidirectional', 'False'),
- 'multistream': int(get_test_param('multistream', 0)),
- 'stream_type': get_test_param('stream_type', 'L4'),
- 'frame_rate': int(get_test_param('iload', 100))})
+ traffic.update({'traffic_type': get_test_param('traffic_type', TRAFFIC_DEFAULTS['traffic_type']),
+ 'bidir': get_test_param('bidirectional', TRAFFIC_DEFAULTS['bidir']),
+ 'multistream': int(get_test_param('multistream', TRAFFIC_DEFAULTS['multistream'])),
+ 'stream_type': get_test_param('stream_type', TRAFFIC_DEFAULTS['stream_type']),
+ 'frame_rate': int(get_test_param('iload', TRAFFIC_DEFAULTS['frame_rate']))})
traffic_ctl = component_factory.create_traffic(
traffic['traffic_type'],
diff --git a/vswitches/ovs_dpdk_vhost.py b/vswitches/ovs_dpdk_vhost.py
index 327a697d..67011d20 100644
--- a/vswitches/ovs_dpdk_vhost.py
+++ b/vswitches/ovs_dpdk_vhost.py
@@ -17,7 +17,6 @@
import logging
import subprocess
-import os
from src.ovs import OFBridge
from src.dpdk import dpdk
@@ -114,8 +113,8 @@ class OvsDpdkVhost(IVSwitchOvs):
if int(settings.getValue('VSWITCH_DPDK_MULTI_QUEUES')) and \
not settings.getValue('OVS_OLD_STYLE_MQ'):
- params += ['options:n_rxq={}'.format(
- settings.getValue('VSWITCH_DPDK_MULTI_QUEUES'))]
+ params += ['options:n_rxq={}'.format(
+ settings.getValue('VSWITCH_DPDK_MULTI_QUEUES'))]
of_port = bridge.add_port(port_name, params)
return (port_name, of_port)