summaryrefslogtreecommitdiffstats
path: root/VNFs/DPPD-PROX/helper-scripts/openstackrapid
diff options
context:
space:
mode:
Diffstat (limited to 'VNFs/DPPD-PROX/helper-scripts/openstackrapid')
-rw-r--r--VNFs/DPPD-PROX/helper-scripts/openstackrapid/README57
-rw-r--r--VNFs/DPPD-PROX/helper-scripts/openstackrapid/gen.cfg64
-rw-r--r--VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_ctrl.py218
-rw-r--r--VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_gen_user_data.sh24
-rw-r--r--VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_sut_user_data.sh24
-rwxr-xr-xVNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.py445
-rw-r--r--VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.yaml105
-rw-r--r--VNFs/DPPD-PROX/helper-scripts/openstackrapid/sut.cfg51
8 files changed, 988 insertions, 0 deletions
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/README b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/README
new file mode 100644
index 00000000..49d819d8
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/README
@@ -0,0 +1,57 @@
+##
+## Copyright (c) 2010-2017 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.
+##
+
+rapid (Rapid Automated Performance Indication for Dataplane)
+************************************************************
+
+rapid is a set of files offering an easy way to do a sanity check of the
+dataplane performance of an OpenStack environment.
+
+Copy the files in a directory on a machine that can run the OpenStack CLI
+commands and that can reach the OpenStack public network. Also create a qcow2
+image in the same directory with the following characteristics:
+* Name of the qcow2 file should be: rapidVM.qcow2
+ This default name can be changed on the rapid command line
+* Should have DPDK and PROX installed. PROX should be in /root/prox/ directory
+* Image should have cloud-init installed
+
+Source the openrc file of the OpenStack environment so that the OpenStack CLI
+commands can be run:
+ # source openrc
+Now you can run the rapid.py file. Use help for more info on the usage:
+ # ./rapid.py --help
+
+rapid will use the OpenStack CLI to create the flavor, key-pair, network, image,
+stack, ...
+Then it will connect to the 2 VMs that have been instantiated and it will launch
+PROX in both VMs.
+Once that is done it will connect to the PROX tcp socket and start sending
+commands to run the actual test.
+It will print test results on the screen while running.
+The PROX instance in the Generator VM will generate packets which will arrive in
+the PROX instance running on the SUT (System Under Test) VM. The SUT will then
+send the packets back to the generator by swapping source and destination.
+
+Notes about prox_gen_user_data.sh and prox_sut_user_data.sh scripts:
+- These scripts contain commands that will be executed using cloud-init at
+ startup of the VMs. They contain a hard-coded PCI address for the DPDK
+ interface that will be used by PROX. You might want to check that this is
+ actually the right PCI address.
+- These scripts also assume some specific DPDK directory and tools which might
+ change over different DPDK release. They have been tested with DPDK-17.02.
+- These scripts are also assuming that this interface is on the "dpdk-network"
+ network managed by OpenStack.
+
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/gen.cfg b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/gen.cfg
new file mode 100644
index 00000000..522eb801
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/gen.cfg
@@ -0,0 +1,64 @@
+;;
+;; Copyright (c) 2010-2017 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.
+;;
+
+[eal options]
+-n=4 ; force number of memory channels
+no-output=no ; disable DPDK debug output
+
+[lua]
+dofile("parameters.lua")
+
+[port 0]
+name=p0
+
+[variables]
+$mbs=8
+
+[defaults]
+mempool size=4K
+
+[global]
+name=Basic Gen
+
+[core 0]
+mode=master
+
+[core 1]
+name=p0
+task=0
+mode=gen
+sub mode=l3
+rx ring=yes
+tx port=p0
+bps=1250000000
+pkt inline=00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d ${gen_hex_ip} ${sut_hex_ip} 0b b8 0b b9 00 08 55 7b
+gateway ipv4=${sut_ip}
+local ipv4=${gen_ip}
+min bulk size=$mbs
+;random=XXXXXXXXXXXXXXXX
+;random=0000000000XXXXXX ; 64 possibilities
+;rand_offset=34 ; SOURCE UDP PORT
+;random=XXXXXXXXXXXXXXXX
+;random=000000000XXXXXXX ; 128
+;rand_offset=36 ; DESTINTAITON UDP PORT
+
+[core 2]
+task=0
+mode=arp
+rx port=p0,p0,p0,p0
+tx port=p0
+tx cores=1t0
+
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_ctrl.py b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_ctrl.py
new file mode 100644
index 00000000..b384e9f0
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_ctrl.py
@@ -0,0 +1,218 @@
+##
+## Copyright (c) 2010-2017 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.
+##
+
+from __future__ import print_function
+
+import os
+import subprocess
+import socket
+
+class prox_ctrl(object):
+ def __init__(self, ip, key=None, user=None):
+ self._ip = ip
+ self._key = key
+ self._user = user
+ self._children = []
+ self._proxsock = []
+
+ def ip(self):
+ return self._ip
+
+ def connect(self):
+ """Simply try to run 'true' over ssh on remote system.
+ On failure, raise RuntimeWarning exception when possibly worth
+ retrying, and raise RuntimeError exception otherwise.
+ """
+ return self.run_cmd('true', True)
+
+ def close(self):
+ """Must be called before program termination."""
+ for prox in self._proxsock:
+ prox.quit()
+ children = len(self._children)
+ if children == 0:
+ return
+ if children > 1:
+ print('Waiting for %d child processes to complete ...' % children)
+ for child in self._children:
+ ret = os.waitpid(child[0], os.WNOHANG)
+ if ret[0] == 0:
+ print("Waiting for child process '%s' to complete ..." % child[1])
+ ret = os.waitpid(child[0], 0)
+ rc = ret[1]
+ if os.WIFEXITED(rc):
+ if os.WEXITSTATUS(rc) == 0:
+ print("Child process '%s' completed successfully" % child[1])
+ else:
+ print("Child process '%s' returned exit status %d" % (
+ child[1], os.WEXITSTATUS(rc)))
+ elif os.WIFSIGNALED(rc):
+ print("Child process '%s' exited on signal %d" % (
+ child[1], os.WTERMSIG(rc)))
+ else:
+ print("Wait status for child process '%s' is 0x%04x" % (
+ child[1], rc))
+
+ def run_cmd(self, command, _connect=False):
+ """Execute command over ssh on remote system.
+ Wait for remote command completion.
+ Return command output (combined stdout and stderr).
+ _connect argument is reserved for connect() method.
+ """
+ cmd = self._build_ssh(command)
+ try:
+ return subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as ex:
+ if _connect and ex.returncode == 255:
+ raise RuntimeWarning(ex.output.strip())
+ raise RuntimeError('ssh returned exit status %d:\n%s'
+ % (ex.returncode, ex.output.strip()))
+
+ def fork_cmd(self, command, name=None):
+ """Execute command over ssh on remote system, in a child process.
+ Do not wait for remote command completion.
+ Return child process id.
+ """
+ if name is None:
+ name = command
+ cmd = self._build_ssh(command)
+ pid = os.fork()
+ if (pid != 0):
+ # In the parent process
+ self._children.append((pid, name))
+ return pid
+ # In the child process: use os._exit to terminate
+ try:
+ # Actually ignore output on success, but capture stderr on failure
+ subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as ex:
+ raise RuntimeError("Child process '%s' failed:\n"
+ 'ssh returned exit status %d:\n%s'
+ % (name, ex.returncode, ex.output.strip()))
+ os._exit(0)
+
+ def prox_sock(self, port=8474):
+ """Connect to the PROX instance on remote system.
+ Return a prox_sock object on success, None on failure.
+ """
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ sock.connect((self._ip, port))
+ prox = prox_sock(sock)
+ self._proxsock.append(prox)
+ return prox
+ except:
+ return None
+
+ def scp_put(self, src, dst):
+ """Copy src file from local system to dst on remote system."""
+ cmd = [ 'scp',
+ '-B',
+ '-oStrictHostKeyChecking=no',
+ '-oUserKnownHostsFile=/dev/null',
+ '-oLogLevel=ERROR' ]
+ if self._key is not None:
+ cmd.extend(['-i', self._key])
+ cmd.append(src)
+ remote = ''
+ if self._user is not None:
+ remote += self._user + '@'
+ remote += self._ip + ':' + dst
+ cmd.append(remote)
+ try:
+ # Actually ignore output on success, but capture stderr on failure
+ subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as ex:
+ raise RuntimeError('scp returned exit status %d:\n%s'
+ % (ex.returncode, ex.output.strip()))
+
+ def _build_ssh(self, command):
+ cmd = [ 'ssh',
+ '-oBatchMode=yes',
+ '-oStrictHostKeyChecking=no',
+ '-oUserKnownHostsFile=/dev/null',
+ '-oLogLevel=ERROR' ]
+ if self._key is not None:
+ cmd.extend(['-i', self._key])
+ remote = ''
+ if self._user is not None:
+ remote += self._user + '@'
+ remote += self._ip
+ cmd.append(remote)
+ cmd.append(command)
+ return cmd
+
+class prox_sock(object):
+ def __init__(self, sock):
+ self._sock = sock
+ self._rcvd = b''
+
+ def quit(self):
+ if self._sock is not None:
+ self._send('quit')
+ self._sock.close()
+ self._sock = None
+
+ def start(self, cores):
+ self._send('start %s' % ','.join(map(str, cores)))
+
+ def stop(self, cores):
+ self._send('stop %s' % ','.join(map(str, cores)))
+
+ def speed(self, speed, cores, tasks=None):
+ if tasks is None:
+ tasks = [ 0 ] * len(cores)
+ elif len(tasks) != len(cores):
+ raise ValueError('cores and tasks must have the same len')
+ for (core, task) in zip(cores, tasks):
+ self._send('speed %s %s %s' % (core, task, speed))
+
+ def reset_stats(self):
+ self._send('reset stats')
+
+ def core_stats(self, cores, task=0):
+ rx = tx = drop = tsc = hz = 0
+ self._send('core stats %s %s' % (','.join(map(str, cores)), task))
+ for core in cores:
+ stats = self._recv().split(',')
+ rx += int(stats[0])
+ tx += int(stats[1])
+ drop += int(stats[2])
+ tsc = int(stats[3])
+ hz = int(stats[4])
+ return rx, tx, drop, tsc, hz
+
+ def set_random(self, cores, task, offset, mask, length):
+ self._send('set random %s %s %s %s %s' % (','.join(map(str, cores)), task, offset, mask, length))
+
+ def _send(self, cmd):
+ """Append LF and send command to the PROX instance."""
+ if self._sock is None:
+ raise RuntimeError("PROX socket closed, cannot send '%s'" % cmd)
+ self._sock.sendall(cmd.encode() + b'\n')
+
+ def _recv(self):
+ """Receive response from PROX instance, and return it with LF removed."""
+ if self._sock is None:
+ raise RuntimeError("PROX socket closed, cannot receive anymore")
+ pos = self._rcvd.find(b'\n')
+ while pos == -1:
+ self._rcvd += self._sock.recv(256)
+ pos = self._rcvd.find(b'\n')
+ rsp = self._rcvd[:pos]
+ self._rcvd = self._rcvd[pos+1:]
+ return rsp.decode()
+
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_gen_user_data.sh b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_gen_user_data.sh
new file mode 100644
index 00000000..e7f58a9f
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_gen_user_data.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+##
+## Copyright (c) 2010-2017 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.
+##
+
+echo 128 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
+mount -t hugetlbfs nodev /mnt/huge
+modprobe uio
+insmod /root/dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko
+/root/dpdk/usertools/dpdk-devbind.py --force --bind igb_uio 00:04.0
+iptables -F
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_sut_user_data.sh b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_sut_user_data.sh
new file mode 100644
index 00000000..e7f58a9f
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/prox_sut_user_data.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+##
+## Copyright (c) 2010-2017 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.
+##
+
+echo 128 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
+mount -t hugetlbfs nodev /mnt/huge
+modprobe uio
+insmod /root/dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko
+/root/dpdk/usertools/dpdk-devbind.py --force --bind igb_uio 00:04.0
+iptables -F
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.py b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.py
new file mode 100755
index 00000000..1a0ea41c
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.py
@@ -0,0 +1,445 @@
+#!/usr/bin/python
+
+##
+## Copyright (c) 2010-2017 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.
+##
+
+import sys
+import time
+import subprocess
+import getopt
+from prox_ctrl import prox_ctrl
+
+version="17.04.19"
+stack = "rapidTestEnv" #Default string for stack
+yaml = "rapid.yaml" #Default string for yaml file
+key = "prox" # This is also the default in the yaml file....
+flavor = "prox_flavor" # This is also the default in the yaml file....
+image = "rapidVM" # This is also the default in the yaml file....
+image_file = "rapidVM.qcow2"
+network = "dpdk-network" # This is also the default in the yaml file....
+subnet = "dpdk-subnet" #Hardcoded at this moment
+
+def usage():
+ print("usage: rapid [--version] [-v]")
+ print(" [--stack STACK_NAME]")
+ print(" [--yaml YAML_FILE]")
+ print(" [--key KEY_NAME]")
+ print(" [--flavor FLAVOR_NAME]")
+ print(" [--image IMAGE_NAME]")
+ print(" [--image_file IMAGE_FILE]")
+ print(" [--network NETWORK]")
+ print(" [-h] [--help]")
+ print("")
+ print("Command-line interface to RAPID")
+ print("")
+ print("optional arguments:")
+ print(" -v, --version Show program's version number and exit")
+ print(" --stack STACK_NAME Specify a name for the heat stack. Default is rapidTestEnv.")
+ print(" --yaml YAML_FILE Specify the yaml file to be used. Default is rapid.yaml.")
+ print(" --key KEY_NAME Specify the key to be used. Default is prox.")
+ print(" --flavor FLAVOR_NAME Specify the flavor to be used. Default is prox_flavor.")
+ print(" --image IMAGE_NAME Specify the image to be used. Default is rapidVM.")
+ print(" --image_file IMAGE_FILE Specify the image qcow2 file to be used. Default is rapidVM.qcow2.")
+ print(" --network NETWORK Specify the network name to be used for the dataplane. Default is dpdk-network.")
+ print(" -h, --help Show help message and exit.")
+ print("")
+ print("To delete the rapid stack, type the following command")
+ print(" openstack stack delete --yes --wait DPTestEnv")
+ print("Note that rapidTestEnv is the default stack name. Replace with STACK_NAME if needed")
+
+try:
+ opts, args = getopt.getopt(sys.argv[1:], "vh", ["version","help", "yaml=","stack=","key=","flavor=","image=","network="])
+except getopt.GetoptError as err:
+ print("===========================================")
+ print str(err)
+ print("===========================================")
+ usage()
+ sys.exit(2)
+if args:
+ usage()
+ sys.exit(2)
+for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ usage()
+ sys.exit()
+ if opt in ("-v", "--version"):
+ print("Rapid Automated Performance Indication for Dataplane "+version)
+ sys.exit()
+ if opt in ("--stack"):
+ stack = arg
+ print ("Using '"+stack+"' as name for the stack")
+ elif opt in ("--yaml"):
+ yaml = arg
+ print ("Using stack: "+yaml)
+ elif opt in ("--key"):
+ key = arg
+ print ("Using key: "+key)
+ elif opt in ("--flavor"):
+ flavor = arg
+ print ("Using flavor: "+flavor)
+ elif opt in ("--image"):
+ image = arg
+ print ("Using image: "+image)
+ elif opt in ("--image_file"):
+ image_file = arg
+ print ("Using qcow2 file: "+image_file)
+ elif opt in ("--network"):
+ network = arg
+ print ("Using network: "+ network)
+
+print("Checking image: "+image)
+cmd = 'openstack image show '+image+' |grep "status " | tr -s " " | cut -d" " -f 4'
+ImageExist = subprocess.check_output(cmd , shell=True).strip()
+if ImageExist == 'active':
+ print("Image already available")
+else:
+ print('Creating image ...')
+ cmd = 'openstack image create --disk-format qcow2 --container-format bare --public --file ./'+image_file+ ' ' +image+' |grep "status " | tr -s " " | cut -d" " -f 4'
+ ImageExist = subprocess.check_output(cmd , shell=True).strip()
+ if ImageExist == 'active':
+ print('Image created and active')
+ cmd = 'openstack image set --property hw_vif_multiqueue_enabled="true" ' +image
+ subprocess.check_call(cmd , shell=True)
+ else :
+ raise Exception("Failed to create image")
+
+print("Checking key: "+key)
+cmd = 'openstack keypair show '+key+' |grep "name " | tr -s " " | cut -d" " -f 4'
+KeyExist = subprocess.check_output(cmd , shell=True).strip()
+if KeyExist == key:
+ print("Key already installed")
+else:
+ print('Creating key ...')
+ cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
+ subprocess.check_call(cmd , shell=True)
+ cmd = 'chmod 600 ' +key+'.pem'
+ subprocess.check_call(cmd , shell=True)
+ cmd = 'openstack keypair show '+key+' |grep "name " | tr -s " " | cut -d" " -f 4'
+ KeyExist = subprocess.check_output(cmd , shell=True).strip()
+ if KeyExist == key:
+ print("Key created")
+ else :
+ raise Exception("Failed to create key: " + key)
+
+print("Checking flavor: "+flavor)
+cmd = 'openstack flavor show '+flavor+' |grep "name " | tr -s " " | cut -d" " -f 4'
+FlavorExist = subprocess.check_output(cmd , shell=True).strip()
+if FlavorExist == flavor:
+ print("Flavor already installed")
+else:
+ print('Creating flavor ...')
+ cmd = 'openstack flavor create '+flavor+' --ram 8192 --disk 80 --vcpus 4 |grep "name " | tr -s " " | cut -d" " -f 4'
+ FlavorExist = subprocess.check_output(cmd , shell=True).strip()
+ if FlavorExist == flavor:
+ cmd = 'openstack flavor set '+ flavor +' --property hw:mem_page_size="large" --property hw:cpu_policy="dedicated" --property hw:cpu_threads_policy="isolate"'
+ subprocess.check_call(cmd , shell=True)
+ print("Flavor created")
+ else :
+ raise Exception("Failed to create flavor: " + flavor)
+
+print("Checking network: "+network)
+cmd = 'openstack network show '+network+' |grep "status " | tr -s " " | cut -d" " -f 4'
+NetworkExist = subprocess.check_output(cmd , shell=True).strip()
+if NetworkExist == 'ACTIVE':
+ print("Network already active")
+else:
+ print('Creating network ...')
+ cmd = 'openstack network create '+network+' |grep "status " | tr -s " " | cut -d" " -f 4'
+ NetworkExist = subprocess.check_output(cmd , shell=True).strip()
+ if NetworkExist == 'ACTIVE':
+ print("Network created")
+ else :
+ raise Exception("Failed to create network: " + network)
+
+print("Checking subnet: "+subnet)
+cmd = 'neutron subnet-show '+ subnet+' |grep "name " | tr -s " " | cut -d" " -f 4'
+SubnetExist = subprocess.check_output(cmd , shell=True).strip()
+if SubnetExist == subnet:
+ print("Subnet already exists")
+else:
+ print('Creating subnet ...')
+ cmd = 'neutron subnet-create --name '+ subnet+ ' ' +network+' 10.10.10.0/24 |grep "name " | tr -s " " | cut -d" " -f 4'
+ SubnetExist = subprocess.check_output(cmd , shell=True).strip()
+ if SubnetExist == subnet:
+ print("Subnet created")
+ else :
+ raise Exception("Failed to create subnet: " + subnet)
+
+print("Checking Stack: "+stack)
+cmd = 'openstack stack show '+stack+' |grep "stack_status " | tr -s " " | cut -d" " -f 4'
+StackRunning = subprocess.check_output(cmd , shell=True).strip()
+if StackRunning == '':
+ print('Creating Stack ...')
+ cmd = 'openstack stack create -t '+ yaml + ' --parameter flavor="'+flavor +'" --parameter key="'+ key + '" --parameter image="'+image + '" --parameter dpdk_network="'+network+'" --wait '+stack +' |grep "stack_status " | tr -s " " | cut -d" " -f 4'
+ StackRunning = subprocess.check_output(cmd , shell=True).strip()
+if StackRunning != 'CREATE_COMPLETE':
+ raise Exception("Failed to create stack")
+
+print('Stack running')
+genName=stack+'-gen'
+sutName=stack+'-sut'
+cmd = 'nova list | grep '+ genName +' | tr -s " " | cut -d " " -f 4'
+genVMName = subprocess.check_output(cmd , shell=True).strip()
+print('Generator: '+ genVMName)
+cmd = 'nova list | grep '+ sutName +' | tr -s " " | cut -d " " -f 4'
+sutVMName = subprocess.check_output(cmd , shell=True).strip()
+print('SUT: '+ sutVMName)
+cmd='nova show ' + genVMName + ' | grep "dpdk-network" | tr -s " " | cut -d" " -f 5'
+genDPIP = subprocess.check_output(cmd , shell=True).strip()
+cmd='nova show ' + genVMName + ' | grep "admin_internal_net" | tr -s " " | cut -d" " -f 6'
+genAdminIP = subprocess.check_output(cmd , shell=True).strip()
+cmd='nova show ' + sutVMName + ' | grep "dpdk-network" | tr -s " " | cut -d" " -f 5'
+sutDPIP = subprocess.check_output(cmd , shell=True).strip()
+cmd='nova show ' + sutVMName + ' | grep "admin_internal_net" | tr -s " " | cut -d" " -f 6'
+sutAdminIP = subprocess.check_output(cmd , shell=True).strip()
+
+#========================================================================
+def connect_socket(client):
+ attempts = 1
+ print("Trying to connect to PROX (just launched) on %s, attempt: %d"
+ % (client.ip(), attempts))
+ sock = None
+ while True:
+ sock = client.prox_sock()
+ if sock is not None:
+ break
+ attempts += 1
+ if attempts > 20:
+ raise Exception("Failed to connect to PROX on %s after %d attempts"
+ % (client.ip(), attempts))
+ time.sleep(10)
+ print("Trying to connect to PROX (just launched) on %s, attempt: %d"
+ % (client.ip(), attempts))
+ print("Connected to PROX on %s" % client.ip())
+ return sock
+
+def connect_client(client):
+ attempts = 1
+ print ("Trying to connect to VM which was just launched on %s, attempt: %d"
+ % (client.ip(), attempts))
+ while True:
+ try:
+ client.connect()
+ break
+ except RuntimeWarning, ex:
+ attempts += 1
+ if attempts > 20:
+ raise Exception("Failed to connect to VM after %d attempts:\n%s"
+ % (attempts, ex))
+ time.sleep(15)
+ print ("Trying to connect to VM which was just launched on %s, attempt: %d"
+ % (client.ip(), attempts))
+ print("Connected to VM on %s" % client.ip())
+
+
+def run_testA():
+ global genclient
+ global sutclient
+ ip = genDPIP.split('.')
+ hexgenDPIP=hex(int(ip[0]))[2:].zfill(2) + ' ' + hex(int(ip[1]))[2:].zfill(2) + ' ' + hex(int(ip[2]))[2:].zfill(2) + ' ' + hex(int(ip[3]))[2:].zfill(2)
+ ip = sutDPIP.split('.')
+ hexsutDPIP=hex(int(ip[0]))[2:].zfill(2) + ' ' + hex(int(ip[1]))[2:].zfill(2) + ' ' + hex(int(ip[2]))[2:].zfill(2) + ' ' + hex(int(ip[3]))[2:].zfill(2)
+ with open("parameters.lua", "w") as f:
+ f.write('gen_hex_ip="'+hexgenDPIP+'"\n')
+ f.write('sut_hex_ip="'+hexsutDPIP+'"\n')
+ f.write('gen_ip="'+genDPIP+'"\n')
+ f.write('sut_ip="'+sutDPIP+'"\n')
+ f.close
+ genclient.scp_put('./gen.cfg', '/root/gen.cfg')
+ sutclient.scp_put('./sut.cfg', '/root/sut.cfg')
+ genclient.scp_put('./parameters.lua', '/root/parameters.lua')
+ sutclient.scp_put('./parameters.lua', '/root/parameters.lua')
+ print("Config files copied")
+ cmd = '/root/prox/build/prox -e -t -o cli -f /root/gen.cfg'
+ genclient.fork_cmd(cmd, 'PROX GEN')
+ cmd = '/root/prox/build/prox -t -o cli -f /root/sut.cfg'
+ sutclient.fork_cmd(cmd, 'PROX SUT')
+ gensock = connect_socket(genclient)
+ sutsock = connect_socket(sutclient)
+ new_speed = 100
+ attempts = 0
+ cores = [1,2]
+ gencores = [1]
+ gensock.reset_stats()
+ sutsock.reset_stats()
+ gensock.start([2])
+ print("+---------------------------------------------------------------------------------------------------------+")
+ print("| Generator is sending UDP (1 flow) packets (64 bytes) to SUT. SUT sends packets back |")
+ print("+------+-----------------+----------------+----------------+----------------+----------------+------------+")
+ print("| Test | Speed requested | Req to Generate| Sent by Gen | Forward by SUT | Rec. by Gen | Result |")
+ print("+------+-----------------+----------------+----------------+----------------+----------------+------------+")
+ while (new_speed > 0.1):
+ attempts += 1
+ # Start generating packets at requested speed (in % of a 10Gb/s link)
+ gensock.speed(new_speed, gencores)
+ gensock.start(gencores)
+ time.sleep(1)
+ # Get statistics now that the generation is stable and NO ARP messages any more
+ old_sut_rx, old_sut_tx, old_sut_drop, old_sut_tsc, sut_tsc_hz = sutsock.core_stats([1])
+ old_rx, old_tx, old_drop, old_tsc, tsc_hz = gensock.core_stats(cores)
+ time.sleep(10)
+ # Get statistics after some execution time
+ new_rx, new_tx, new_drop, new_tsc, tsc_hz = gensock.core_stats(cores)
+ new_sut_rx, new_sut_tx, new_sut_drop, new_sut_tsc, sut_tsc_hz = sutsock.core_stats([1])
+ time.sleep(1)
+ # Stop generating
+ gensock.stop(gencores)
+ drop = new_drop-old_drop # drop is all packets dropped by all tasks. This includes packets dropped at the generator task + packets dropped by the nop task. In steady state, this equals to the number of packets received by this VM
+ rx = new_rx - old_rx # rx is all packets received by the nop task = all packets received in the gen VM
+ tx = new_tx - old_tx # tx is all generated packets actually accepted by the interface
+ tsc = new_tsc - old_tsc # time difference between the 2 measurements, expressed in cycles.
+ sut_rx = new_sut_rx - old_sut_rx
+ sut_tx = new_sut_tx - old_sut_tx
+ sut_tsc = new_sut_tsc - old_sut_tsc
+ if (tx == 0):
+ raise Exception("TX = 0")
+ drop_rate = round(((drop-rx) * 100.0)/(tx+drop-rx),1)
+ pps_req_tx = round((tx+drop-rx)*tsc_hz*1.0/(tsc*1000000),5)
+ pps_tx = round(tx*tsc_hz*1.0/(tsc*1000000),5)
+ pps_rx = round(rx*tsc_hz*1.0/(tsc*1000000),5)
+ pps_sut_tx = round(sut_tx*sut_tsc_hz*1.0/(sut_tsc*1000000),5)
+ if ((drop_rate) < 1):
+ # This will stop the test when number of dropped packets is below a certain percentage
+ print("+------+-----------------+----------------+----------------+----------------+----------------+------------+")
+ print('|{:>5}'.format(str(attempts))+" | "+ '{:>14}'.format(str(new_speed)) + '% | '+ '{:>9}'.format(str(pps_req_tx))+' Mpps | '+ '{:>9}'.format(str(pps_tx)) +' Mpps | ' + '{:>9}'.format(str(pps_sut_tx)) +' Mpps | '+ '{:>9}'.format(str(pps_rx))+" Mpps | SUCCESS |")
+ print("+------+-----------------+----------------+----------------+----------------+----------------+------------+")
+ break
+ else:
+ print('|{:>5}'.format(str(attempts))+" | "+ '{:>14}'.format(str(new_speed)) + '% | '+ '{:>9}'.format(str(pps_req_tx))+' Mpps | '+ '{:>9}'.format(str(pps_tx)) +' Mpps | ' + '{:>9}'.format(str(pps_sut_tx)) +' Mpps | '+ '{:>9}'.format(str(pps_rx))+" Mpps | FAILED |")
+ # Following calculates the ratio for the new speed to be applied
+ # On the Y axis, we will find the ratio, a number between 0 and 1
+ # On the x axis, we find the % of dropped packets, a number between 0 and 100
+ # 2 lines are drawn and we take the minumun of these lines to calculate the ratio
+ # One line goes through (0,y0) and (p,q)
+ # The second line goes through (p,q) and (100,y100)
+ y0=0.99
+ y100=0.1
+ p=15
+ q=.9
+ ratio = min((q-y0)/p*drop_rate+y0,(q-y100)/(p-100)*drop_rate+q-p*(q-y100)/(p-100))
+ new_speed = (int(new_speed*ratio*100)+0.5)/100
+ gensock.quit()
+ sutsock.quit()
+ time.sleep(2)
+ print("")
+
+def run_testB():
+ global genclient
+ global sutclient
+ ip = genDPIP.split('.')
+ hexgenDPIP=hex(int(ip[0]))[2:].zfill(2) + ' ' + hex(int(ip[1]))[2:].zfill(2) + ' ' + hex(int(ip[2]))[2:].zfill(2) + ' ' + hex(int(ip[3]))[2:].zfill(2)
+ ip = sutDPIP.split('.')
+ hexsutDPIP=hex(int(ip[0]))[2:].zfill(2) + ' ' + hex(int(ip[1]))[2:].zfill(2) + ' ' + hex(int(ip[2]))[2:].zfill(2) + ' ' + hex(int(ip[3]))[2:].zfill(2)
+ with open("parameters.lua", "w") as f:
+ f.write('gen_hex_ip="'+hexgenDPIP+'"\n')
+ f.write('sut_hex_ip="'+hexsutDPIP+'"\n')
+ f.write('gen_ip="'+genDPIP+'"\n')
+ f.write('sut_ip="'+sutDPIP+'"\n')
+ f.close
+ genclient.scp_put('./gen.cfg', '/root/gen.cfg')
+ sutclient.scp_put('./sut.cfg', '/root/sut.cfg')
+ genclient.scp_put('./parameters.lua', '/root/parameters.lua')
+ sutclient.scp_put('./parameters.lua', '/root/parameters.lua')
+ print("Config files copied")
+ cmd = '/root/prox/build/prox -e -t -o cli -f /root/gen.cfg'
+ genclient.fork_cmd(cmd, 'PROX GEN')
+ cmd = '/root/prox/build/prox -t -o cli -f /root/sut.cfg'
+ sutclient.fork_cmd(cmd, 'PROX SUT')
+ gensock = connect_socket(genclient)
+ sutsock = connect_socket(sutclient)
+ print("+----------------------------------------------------------------------------------------------+")
+ print("| UDP, 64 bytes, different number of flows by randomizing SRC & DST UDP port |")
+ print("+--------+-----------------+----------------+----------------+----------------+----------------+")
+ print("| Flows | Speed requested | Req to Generate| Sent by Gen | Forward by SUT | Rec. by Gen |")
+ print("+--------+-----------------+----------------+----------------+----------------+----------------+")
+ cores = [1,2]
+ gencores = [1]
+ gensock.start([2])
+ new_speed = 100
+ # To generate a desired number of flows, PROX will randomize the bits in source and destination ports, as specified by the bit masks in the flows variable.
+ flows={128:['0000000000000XXX','000000000000XXXX'],1024:['00000000000XXXXX','00000000000XXXXX'],8192:['0000000000XXXXXX','000000000XXXXXXX'],65535:['00000000XXXXXXXX','00000000XXXXXXXX'],524280:['0000000XXXXXXXXX','000000XXXXXXXXXX']}
+ for flow_number in sorted(flows.iterkeys()):
+ #new_speed = 100 Commented out: Not starting from 100% since we are trying more flows, so speed will not be higher than the speed achieved in previous loop
+ attempts = 0
+ gensock.reset_stats()
+ sutsock.reset_stats()
+ source_port,destination_port = flows[flow_number]
+ gensock.set_random(gencores,0,34,source_port,2)
+ gensock.set_random(gencores,0,36,destination_port,2)
+ while (new_speed > 0.1):
+ attempts += 1
+ # Start generating packets at requested speed (in % of a 10Gb/s link)
+ gensock.speed(new_speed, gencores)
+ gensock.start(gencores)
+ time.sleep(1)
+ # Get statistics now that the generation is stable and NO ARP messages any more
+ old_sut_rx, old_sut_tx, old_sut_drop, old_sut_tsc, sut_tsc_hz = sutsock.core_stats([1])
+ old_rx, old_tx, old_drop, old_tsc, tsc_hz = gensock.core_stats(cores)
+ time.sleep(10)
+ # Get statistics after some execution time
+ new_rx, new_tx, new_drop, new_tsc, tsc_hz = gensock.core_stats(cores)
+ new_sut_rx, new_sut_tx, new_sut_drop, new_sut_tsc, sut_tsc_hz = sutsock.core_stats([1])
+ time.sleep(1)
+ # Stop generating
+ gensock.stop(gencores)
+ drop = new_drop-old_drop # drop is all packets dropped by all tasks. This includes packets dropped at the generator task + packets dropped by the nop task. In steady state, this equals to the number of packets received by this VM
+ rx = new_rx - old_rx # rx is all packets received by the nop task = all packets received in the gen VM
+ tx = new_tx - old_tx # tx is all generated packets actually accepted by the interface
+ tsc = new_tsc - old_tsc # time difference between the 2 measurements, expressed in cycles.
+ sut_rx = new_sut_rx - old_sut_rx
+ sut_tx = new_sut_tx - old_sut_tx
+ sut_tsc = new_sut_tsc - old_sut_tsc
+ if (tx == 0):
+ raise Exception("TX = 0")
+ drop_rate = round(((drop-rx) * 100.0)/(tx+drop-rx),1)
+ pps_req_tx = round((tx+drop-rx)*tsc_hz*1.0/(tsc*1000000),5)
+ pps_tx = round(tx*tsc_hz*1.0/(tsc*1000000),5)
+ pps_rx = round(rx*tsc_hz*1.0/(tsc*1000000),5)
+ pps_sut_tx = round(sut_tx*sut_tsc_hz*1.0/(sut_tsc*1000000),5)
+ if ((drop_rate) < 1):
+ # This will stop the test when number of dropped packets is below a certain percentage
+ print('|{:>7}'.format(str(flow_number))+" | "+ '{:>14}'.format(str(new_speed)) + '% | '+ '{:>9}'.format(str(pps_req_tx))+' Mpps | '+ '{:>9}'.format(str(pps_tx)) +' Mpps | ' + '{:>9}'.format(str(pps_sut_tx)) +' Mpps | '+ '{:>9}'.format(str(pps_rx))+" Mpps |")
+ print("+--------+-----------------+----------------+----------------+----------------+----------------+")
+ break
+ # Following calculates the ratio for the new speed to be applied
+ # On the Y axis, we will find the ratio, a number between 0 and 1
+ # On the x axis, we find the % of dropped packets, a number between 0 and 100
+ # 2 lines are drawn and we take the minumun of these lines to calculate the ratio
+ # One line goes through (0,y0) and (p,q)
+ # The second line goes through (p,q) and (100,y100)
+ y0=0.99
+ y100=0.1
+ p=15
+ q=.9
+ ratio = min((q-y0)/p*drop_rate+y0,(q-y100)/(p-100)*drop_rate+q-p*(q-y100)/(p-100))
+ new_speed = (int(new_speed*ratio*100)+0.5)/100
+ gensock.quit()
+ sutsock.quit()
+ time.sleep(2)
+ print("")
+
+#========================================================================
+genclient = prox_ctrl(genAdminIP, key+'.pem')
+connect_client(genclient)
+sutclient = prox_ctrl(sutAdminIP, key+'.pem')
+connect_client(sutclient)
+#####################################################################################
+run_testA()
+run_testB()
+#####################################################################################
+genclient.close()
+sutclient.close()
+
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.yaml b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.yaml
new file mode 100644
index 00000000..eab957f5
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/rapid.yaml
@@ -0,0 +1,105 @@
+##
+## Copyright (c) 2010-2017 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.
+##
+
+heat_template_version: 2016-04-08
+description: RAPID stack (Rapid Automated Performance Indication for Dataplane)
+parameters:
+ image:
+ type: string
+ label: Image name or ID
+ description: Image to be used for compute instance
+ default: RapidVM
+ flavor:
+ type: string
+ label: Flavor
+ description: Type of instance (flavor) to be used
+ default: prox_flavor
+ key:
+ type: string
+ label: Key name
+ description: Name of key-pair to be used for compute instance
+ default: prox
+ dpdk_network:
+ type: string
+ label: Private network name or ID
+ description: Network to attach instance to.
+ default: dpdk-network
+ private_network:
+ type: string
+ label: Private network name or ID
+ description: Network to attach instance to.
+ default: admin_internal_net
+ availability_zone:
+ type: string
+ description: The Availability Zone to launch the instance.
+ default: nova
+
+resources:
+ sut:
+ type: OS::Nova::Server
+ properties:
+ availability_zone: { get_param: availability_zone }
+ user_data:
+ get_file: prox_sut_user_data.sh
+ key_name: { get_param: key }
+ image: { get_param: image }
+ flavor: { get_param: flavor }
+ networks:
+ - network: { get_param: private_network }
+ - network: { get_param: dpdk_network }
+ gen:
+ type: OS::Nova::Server
+ properties:
+ availability_zone: { get_param: availability_zone }
+ user_data:
+ get_file: prox_gen_user_data.sh
+ key_name: { get_param: key }
+ image: { get_param: image }
+ flavor: { get_param: flavor }
+ networks:
+ - network: { get_param: private_network }
+ - network: { get_param: dpdk_network }
+
+ sut_floating_ip:
+ type: OS::Nova::FloatingIP
+ properties:
+ pool: admin_floating_net
+
+ gen_floating_ip:
+ type: OS::Nova::FloatingIP
+ properties:
+ pool: admin_floating_net
+
+ sut_association:
+ type: OS::Nova::FloatingIPAssociation
+ properties:
+ floating_ip: { get_resource: sut_floating_ip }
+ server_id: { get_resource: sut }
+
+ gen_association:
+ type: OS::Nova::FloatingIPAssociation
+ properties:
+ floating_ip: { get_resource: gen_floating_ip }
+ server_id: { get_resource: gen }
+
+outputs:
+ sut_ip:
+ description: IP address of the instance
+ value: { get_attr: [sut, first_address] }
+ gen_ip:
+ description: IP address of the instance
+ value: { get_attr: [gen, first_address] }
+
diff --git a/VNFs/DPPD-PROX/helper-scripts/openstackrapid/sut.cfg b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/sut.cfg
new file mode 100644
index 00000000..2937a749
--- /dev/null
+++ b/VNFs/DPPD-PROX/helper-scripts/openstackrapid/sut.cfg
@@ -0,0 +1,51 @@
+;;
+;; Copyright (c) 2010-2017 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.
+;;
+
+[eal options]
+-n=4 ; force number of memory channels
+no-output=no ; disable DPDK debug output
+
+[lua]
+dofile("parameters.lua")
+
+[port 0]
+name=if0
+mac=hardware
+
+[defaults]
+mempool size=2K
+
+[global]
+name=NOP forwarding
+
+[core 0]
+mode=master
+
+[core 1]
+name=swap
+task=0
+mode=arp
+sub mode=local
+rx port=if0
+tx port=if0
+tx cores=1t1
+local ipv4=${sut_ip}
+task=1
+mode=swap
+rx ring=yes
+tx port=if0
+drop=no
+