commands and that can reach the OpenStack public network.
You will need an image that has the PROX tool installed.
-A good way to do this is to use the packer tool to build an image for a target of your choice.
+The best way to do this is to use the packer tool to build an image for a target of your choice.
You can also build this image manually by executing all the commands described in the deploycentos1.sh
and deploycentos2.sh file.
The default name of the qcow2 file should is rapidVM.qcow2
There are 3 files: centos.json, deploycentos1.sh and deploycentos2.sh, allowing you to create
an image automatically. Run
# packer build centos.json
+Edit centos.json to reflect the settings of your environment: The following fields need to
+be the ID's of your system:
+ - "source_image": Needs to be the id of the Centos cloud image
+ - "flavor": Needs to be the ID of the flavor existing in your OpenStack environment that will be used
+ to start the VM in which we will install all tools
+ - "networks": ID of the network that will be used for the VM
+ - "use_floating_ip": true or false
+ - "floating_ip_pool": ID of the floating ip pool in case floating ip are being used
+ - "security_groups": ID of the security group being used
+
Note that this procedure is not only installing the necessary tools to run PROX,
but also does some system optimizations (tuned).
-Now that the image exists in OpenStack, source the openrc file of the OpenStack
-environment so that the OpenStack CLI commands can be run:
- # source openrc
Now you can run the createrapid.py file. Use help for more info on the usage:
# ./createrapid.py --help
Notes about prox_user_data.sh script:
- The script contains commands that will be executed using cloud-init at
startup of the VMs.
-- The script also assumes some specific DPDK directory and tools which might
- change over different DPDK release. This release has been tested with DPDK-17.02.
- huge pages are allocated for DPDK on node 0 (hard-coded) in the VM.
Note on using SRIOV ports:
Note that this file can be created manually in case the stack is created in a
different way (not using the createrapid.py). This can be useful in case you are
not using OpenStack as a VIM or when using special configurations that cannot be
-achieved using creater needed for runrapid are:
+achieved using createrapid.py. Fields needed for runrapid are:
* all info in the [Mx] sections
* the key information in the [OpenStack] section
* the total_number_of_vms information in the [rapid] section
# That file could contain DNS information coming from the dataplane which might be wrong. A solution is to confire the correct DNS for the dataplne
# in OpenStack. DNS might be slowing down ssh access. We don't need that for our dataplane benchmarking purposes
# sudo sed -i '/#UseDNS yes/c\UseDNS no' /etc/ssh/sshd_config
-
+sudo sh -c '(echo "export RTE_TARGET=\"build\"";echo "export RTE_SDK=\"/root/dpdk\"";echo "export AESNI_MULTI_BUFFER_LIB_PATH=\"/home/centos/intel-ipsec-mb-0.50\"";) >> /root/.bashrc'
+export RTE_TARGET=build
+export RTE_SDK=/home/centos/dpdk
+export AESNI_MULTI_BUFFER_LIB_PATH=/home/centos/intel-ipsec-mb-0.50
# Mounting huge pages to be used by DPDK
sudo mkdir -p /mnt/huge
sudo umount `awk '/hugetlbfs/ { print $2 }' /proc/mounts` >/dev/null 2>&1
cd /home/centos
wget https://github.com/01org/intel-ipsec-mb/archive/v0.50.zip
unzip v0.50.zip
-# AESNI_MULTI_BUFFER_LIB_PATH should be already set in deploycentos1.sh
-export AESNI_MULTI_BUFFER_LIB_PATH=/home/centos/intel-ipsec-mb-0.50
cd $AESNI_MULTI_BUFFER_LIB_PATH
make
sudo make install
# Clone and compile DPDK
cd /home/centos/
git clone http://dpdk.org/git/dpdk
-cd dpdk
-git checkout v18.05
-export RTE_TARGET=build
-export RTE_SDK=/home/centos/dpdk
+# Runtime scripts are assuming /root as the directory for PROX
+sudo ln -s /home/centos/dpdk /root/dpdk
+cd $RTE_SDK
+git checkout v18.08
make config T=x86_64-native-linuxapp-gcc
# The next sed lines make sure that we can compile DPDK 17.11 with a relatively new OS. Using a newer DPDK (18.5) should also resolve this issue
#sudo sed -i '/CONFIG_RTE_LIBRTE_KNI=y/c\CONFIG_RTE_LIBRTE_KNI=n' /home/centos/dpdk/build/.config
# Compile with MB library
sed -i '/CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n/c\CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y' /home/centos/dpdk/build/.config
make
-# Runtime scripts are assuming /root as the directory for PROX
-sudo ln -s /home/centos/dpdk /root/dpdk
# Clone and compile PROX
cd /home/centos
git clone https://git.opnfv.org/samplevnf
cd /home/centos/samplevnf/VNFs/DPPD-PROX
-git checkout 4d59d3530d1c41734f15423142e64eb9c929c717
-# Compiling PROX with the crc=soft option because offloaded CRC calculation causes problems on multiple VIM environments. This will of course slow
-# down the performance of the generator.
-make crc=soft
+git checkout ffc6be26
+make
sudo ln -s /home/centos/samplevnf/VNFs/DPPD-PROX /root/prox
# Enabling tuned with the realtime-virtual-guest profile
import atexit
import csv
-version="18.10.15"
+version="19.1.10"
env = "rapid" #Default string for environment
test = "basicrapid" #Default string for test
loglevel="DEBUG" # sets log level for writing to file
return (speed * 100.0 / (8*(size+24)))
def run_speedtest(gensock,sutsock):
+ maxspeed = speed = STARTSPEED
+ minspeed = 0
+ size=175
+ attempts = 0
log.info("+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+")
- log.info("| Generator is sending UDP (1 flow) packets (64 bytes) to SUT. SUT sends packets back |")
+ log.info("| Generator is sending UDP (1 flow) packets ("+ '{:>5}'.format(size+4) +" bytes) to SUT. SUT sends packets back |")
log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+------------+")
log.info("| Test | Speed requested | Sent to NIC | Sent by Gen | Forward by SUT | Rec. by Gen | Avg. Latency | Max. Latency | Packets Lost | Loss Ratio | Result |")
log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+------------+")
- maxspeed = speed = STARTSPEED
- minspeed = 0
- size=60
- attempts = 0
endpps_sut_tx_str = 'NO_RESULTS'
gensock.set_size(gencores,0,size) # This is setting the frame size
gensock.set_value(gencores,0,16,(size-14),2) # 18 is the difference between the frame size and IP size = size of (MAC addresses, ethertype and FCS)
# Start generating packets at requested speed (in % of a 10Gb/s link)
gensock.speed(speed, gencores)
time.sleep(1)
- # Get statistics now that the generation is stable and NO ARP messages any more
+ # Get statistics now that the generation is stable and initial ARP messages are dealt with.
pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
drop_rate = 100.0*abs_dropped/abs_tx
if ((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001 and ((drop_rate < DROP_RATE_TRESHOLD) or (abs_dropped==DROP_RATE_TRESHOLD ==0)) and (lat_avg< LAT_AVG_TRESHOLD) and (lat_max < LAT_MAX_TRESHOLD):
speed_prefix = bcolors.ENDC
else:
speed_prefix = bcolors.FAIL
- log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ bcolors.ENDC + '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '% | FAILED |')
+ log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '% | FAILED |')
success = False
speed,minspeed,maxspeed = new_speed(speed,minspeed,maxspeed,success)
if endpps_sut_tx_str <> 'NO_RESULTS':
gensock.set_value(gencores,0,38,(size-34),2) # 38 is the difference between the frame size and UDP size = 18 + size of IP header (=20)
# This will only work when using sending UDP packets. For different protocls and ehternet types, we would need a differnt calculation
for flow_number in sorted(flows.iterkeys()):
+ attempts = 0
gensock.reset_stats()
if sutsock!='none':
sutsock.reset_stats()
maxspeed = speed = STARTSPEED
minspeed = 0
while (maxspeed-minspeed > ACCURACY):
+ attempts += 1
print(str(flow_number)+' flows: Measurement ongoing at speed: ' + str(round(speed,2)) + '% ',end='\r')
sys.stdout.flush()
# Start generating packets at requested speed (in % of a 10Gb/s link)
gensock.speed(speed, gencores)
time.sleep(1)
- # Get statistics now that the generation is stable and NO ARP messages any more
+ # Get statistics now that the generation is stable and initial ARP messages are dealt with
pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
drop_rate = 100.0*abs_dropped/abs_tx
if ((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001 and ((drop_rate < DROP_RATE_TRESHOLD) or (abs_dropped==DROP_RATE_TRESHOLD ==0)) and (lat_avg< LAT_AVG_TRESHOLD) and (lat_max < LAT_MAX_TRESHOLD):
+ log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us | '+ '{:>9.0f}'.format(lat_max)+' us | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '% | SUCCESS |')
endspeed = speed
endpps_req_tx = pps_req_tx
endpps_tx = pps_tx
enddrop_rate = drop_rate
success = True
else:
+ abs_drop_rate_prefix = bcolors.ENDC
+ if ((abs_dropped>0) and (DROP_RATE_TRESHOLD ==0)):
+ abs_drop_rate_prefix = bcolors.FAIL
+ if (drop_rate < DROP_RATE_TRESHOLD):
+ drop_rate_prefix = bcolors.ENDC
+ else:
+ drop_rate_prefix = bcolors.FAIL
+ if (lat_avg< LAT_AVG_TRESHOLD):
+ lat_avg_prefix = bcolors.ENDC
+ else:
+ lat_avg_prefix = bcolors.FAIL
+ if (lat_max< LAT_MAX_TRESHOLD):
+ lat_max_prefix = bcolors.ENDC
+ else:
+ lat_max_prefix = bcolors.FAIL
+ if (((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001):
+ speed_prefix = bcolors.ENDC
+ else:
+ speed_prefix = bcolors.FAIL
+ log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '% | FAILED |')
success = False
speed,minspeed,maxspeed = new_speed(speed,minspeed,maxspeed,success)
if endpps_sut_tx_str <> 'NO_RESULTS':
# sizes=[1020,508,252,124,60]
# sizes=[124,60]
for size in sizes:
+ attempts = 0
gensock.reset_stats()
if sutsock!='none':
sutsock.reset_stats()
maxspeed = speed = STARTSPEED
minspeed = 0
while (maxspeed-minspeed > ACCURACY):
+ attempts += 1
print(str(size+4)+' bytes: Measurement ongoing at speed: ' + str(round(speed,2)) + '% ',end='\r')
sys.stdout.flush()
# Start generating packets at requested speed (in % of a 10Gb/s link)
gensock.speed(speed, gencores)
- # Get statistics now that the generation is stable and NO ARP messages any more
+ # Get statistics now that the generation is stable and initial ARP messages are dealt with
pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
drop_rate = 100.0*abs_dropped/abs_tx
if ((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001 and ((drop_rate < DROP_RATE_TRESHOLD) or (abs_dropped==DROP_RATE_TRESHOLD ==0)) and (lat_avg< LAT_AVG_TRESHOLD) and (lat_max < LAT_MAX_TRESHOLD):
+ log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us | '+ '{:>9.0f}'.format(lat_max)+' us | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '% | SUCCESS |')
endspeed = speed
endpps_req_tx = pps_req_tx
endpps_tx = pps_tx
enddrop_rate = drop_rate
success = True
else:
+ abs_drop_rate_prefix = bcolors.ENDC
+ if ((abs_dropped>0) and (DROP_RATE_TRESHOLD ==0)):
+ abs_drop_rate_prefix = bcolors.FAIL
+ if (drop_rate < DROP_RATE_TRESHOLD):
+ drop_rate_prefix = bcolors.ENDC
+ else:
+ drop_rate_prefix = bcolors.FAIL
+ if (lat_avg< LAT_AVG_TRESHOLD):
+ lat_avg_prefix = bcolors.ENDC
+ else:
+ lat_avg_prefix = bcolors.FAIL
+ if (lat_max< LAT_MAX_TRESHOLD):
+ lat_max_prefix = bcolors.ENDC
+ else:
+ lat_max_prefix = bcolors.FAIL
+ if (((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001):
+ speed_prefix = bcolors.ENDC
+ else:
+ speed_prefix = bcolors.FAIL
+ log.debug('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | ' + '{:>9.3f}'.format(pps_tx) +' Mpps | '+ bcolors.ENDC + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+lat_avg_prefix+ '{:>9.0f}'.format(lat_avg)+' us | '+lat_max_prefix+ '{:>9.0f}'.format(lat_max)+' us | '+ abs_drop_rate_prefix + '{:>14d}'.format(abs_dropped)+drop_rate_prefix+ ' |''{:>9.2f}'.format(drop_rate)+bcolors.ENDC+ '% | FAILED |')
success = False
speed,minspeed,maxspeed = new_speed(speed,minspeed,maxspeed,success)
if endpps_sut_tx_str <> 'NO_RESULTS':
irq[i][j] = str(round(diff/float(runtime), 2))
log.info('\n'.join([''.join(['{:>12}'.format(item) for item in row]) for row in irq]))
-def run_impairtest(gensock,sutsock,speed):
+def run_impairtest(gensock,sutsock):
log.info("+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+")
log.info("| Generator is sending UDP (1 flow) packets (64 bytes) to SUT via GW dropping and delaying packets. SUT sends packets back. Use ctrl-c to stop the test |")
log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
gensock.set_value(gencores,0,16,(size-14),2) # 18 is the difference between the frame size and IP size = size of (MAC addresses, ethertype and FCS)
gensock.set_value(gencores,0,38,(size-34),2) # 38 is the difference between the frame size and UDP size = 18 + size of IP header (=20)
# This will only work when using sending UDP packets. For different protocols and ethernet types, we would need a different calculation
+ speed = STARTSPEED
gensock.speed(speed, gencores)
while True:
attempts += 1