## See the License for the specific language governing permissions and
## limitations under the License.
##
-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.48\"";) >> /root/.bashrc'
-sudo yum install deltarpm -y
-sudo yum update -y
-sudo yum-config-manager --add-repo http://www.nasm.us/nasm.repo
-sudo yum install git wget gcc unzip libpcap-devel ncurses-devel libedit-devel lua-devel kernel-devel iperf3 pciutils numactl-devel vim tuna openssl-devel nasm -y
-# Enabling root ssh access
-sudo sed -i '/disable_root: 1/c\disable_root: 0' /etc/cloud/cloud.cfg
# The following line is commented since this was a workaround for a problem with the content of /etc/resolv.conf.
# That file could contain DNS information coming from the dataplane which might be wrong. A solution is to confire the correct DNS for the dataplne
# in OpenStack. DNS might be slowing down ssh access. We don't need that for our dataplane benchmarking purposes
sudo mount -t hugetlbfs nodev /mnt/huge/
sudo sh -c '(echo "vm.nr_hugepages = 1024") > /etc/sysctl.conf'
-# Downloading the Multi-buffer library
-wget https://github.com/01org/intel-ipsec-mb/archive/v0.48.zip
-unzip v0.48.zip
-export AESNI_MULTI_BUFFER_LIB_PATH=/home/centos/intel-ipsec-mb-0.48
+# Downloading the Multi-buffer library. Note that the version to download is linked to the DPDK version being used
+cd /home/centos
+wget https://github.com/01org/intel-ipsec-mb/archive/v0.50.zip
+unzip v0.50.zip
+# 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 -j8
+make
+sudo make install
# Clone and compile DPDK
cd /home/centos/
git clone http://dpdk.org/git/dpdk
cd dpdk
-git checkout v17.11
+git checkout v18.05
export RTE_TARGET=build
export RTE_SDK=/home/centos/dpdk
make config T=x86_64-native-linuxapp-gcc
# The next sed lines make sure that we can compile DPDK 17.11 with a relatively new OS. Using a newer DPDK (18.5) should also resolve this issue
-sudo sed -i '/CONFIG_RTE_LIBRTE_KNI=y/c\CONFIG_RTE_LIBRTE_KNI=n' /home/centos/dpdk/build/.config
-sudo sed -i '/CONFIG_RTE_LIBRTE_PMD_KNI=y/c\CONFIG_RTE_LIBRTE_PMD_KNI=n' /home/centos/dpdk/build/.config
-sudo sed -i '/CONFIG_RTE_KNI_KMOD=y/c\CONFIG_RTE_KNI_KMOD=n' /home/centos/dpdk/build/.config
-sudo sed -i '/CONFIG_RTE_KNI_PREEMPT_DEFAULT=y/c\CONFIG_RTE_KNI_PREEMPT_DEFAULT=n' /home/centos/dpdk/build/.config
+#sudo sed -i '/CONFIG_RTE_LIBRTE_KNI=y/c\CONFIG_RTE_LIBRTE_KNI=n' /home/centos/dpdk/build/.config
+#sudo sed -i '/CONFIG_RTE_LIBRTE_PMD_KNI=y/c\CONFIG_RTE_LIBRTE_PMD_KNI=n' /home/centos/dpdk/build/.config
+#sudo sed -i '/CONFIG_RTE_KNI_KMOD=y/c\CONFIG_RTE_KNI_KMOD=n' /home/centos/dpdk/build/.config
+#sudo sed -i '/CONFIG_RTE_KNI_PREEMPT_DEFAULT=y/c\CONFIG_RTE_KNI_PREEMPT_DEFAULT=n' /home/centos/dpdk/build/.config
# Compile with MB library
-sudo sed -i '/CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n/c\CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y' /home/centos/dpdk/build/.config
-make -j8
-cd /home/centos
-# Copy everything to root since the scripts are assuming /root as the directory for PROX
-sudo cp -r dpdk /root/
+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
-git clone https://git.opnfv.org/samplevnf
-cp -r /home/centos/samplevnf/VNFs/DPPD-PROX /home/centos/prox
-cd /home/centos/prox
-make -j8
cd /home/centos
-# Copy everything to root since the scripts are assuming /root as the directory for PROX
-sudo cp -r /home/centos/prox /root/
+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
+sudo ln -s /home/centos/samplevnf/VNFs/DPPD-PROX /root/prox
# Enabling tuned with the realtime-virtual-guest profile
+cd /home/centos/
wget http://linuxsoft.cern.ch/cern/centos/7/rt/x86_64/Packages/tuned-profiles-realtime-2.8.0-5.el7_4.2.noarch.rpm
wget http://linuxsoft.cern.ch/cern/centos/7/rt/x86_64/Packages/tuned-profiles-nfv-guest-2.8.0-5.el7_4.2.noarch.rpm
# Install with --nodeps. The latest CentOS cloud images come with a tuned version higher than 2.8. These 2 packages however
import ConfigParser
import ast
import atexit
+import csv
-version="18.6.15"
+version="18.10.15"
env = "rapid" #Default string for environment
test = "basicrapid" #Default string for test
loglevel="DEBUG" # sets log level for writing to file
loglevel = arg
print ("Log level: "+ loglevel)
+class bcolors:
+ HEADER = '\033[95m'
+ OKBLUE = '\033[94m'
+ OKGREEN = '\033[92m'
+ WARNING = '\033[93m'
+ FAIL = '\033[91m'
+ ENDC = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
# create formatters
screen_formatter = logging.Formatter("%(message)s")
# and set its log level to DEBUG
#
log_file = 'RUN' +env+'.'+test+'.log'
+data_file = 'RUN' +env+'.'+test+'.csv'
file_handler = logging.handlers.RotatingFileHandler(log_file, backupCount=10)
#file_handler = log.handlers.TimedRotatingFileHandler(log_file, 'D', 1, 5)
file_handler.setLevel(numeric_level)
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 = 100
+ maxspeed = speed = STARTSPEED
minspeed = 0
size=60
attempts = 0
# Get statistics now that the generation is stable and NO ARP messages any more
pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
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)):
+ if ((get_pps(speed,size) - pps_tx)/get_pps(speed,size))<0.001 and ((drop_rate < DROP_RATE_TRESHOLD) or (abs_dropped==DROP_RATE_TRESHOLD ==0)) and (lat_avg< LAT_AVG_TRESHOLD) and (lat_max < LAT_MAX_TRESHOLD):
log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us | '+ '{:>9.0f}'.format(lat_max)+' us | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '% | SUCCESS |')
endspeed = speed
endpps_req_tx = pps_req_tx
enddrop_rate = drop_rate
success = True
else:
- log.info('|{:>7}'.format(str(attempts))+" | " + '{:>5.1f}'.format(speed) + '% ' +'{:>6.3f}'.format(get_pps(speed,size)) + ' Mpps | '+ '{:>9.3f}'.format(pps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(pps_tx) +' Mpps | ' + '{:>9}'.format(pps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(pps_rx)+' Mpps | '+ '{:>9.0f}'.format(lat_avg)+' us | '+ '{:>9.0f}'.format(lat_max)+' us | '+ '{:>14d}'.format(abs_dropped)+ ' |''{:>9.2f}'.format(drop_rate)+ '% | FAILED |')
+ 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.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 |')
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()):
- #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
gensock.reset_stats()
if sutsock!='none':
sutsock.reset_stats()
gensock.set_random(gencores,0,34,source_port,2)
gensock.set_random(gencores,0,36,destination_port,2)
endpps_sut_tx_str = 'NO_RESULTS'
- maxspeed = speed = 100
+ maxspeed = speed = STARTSPEED
minspeed = 0
while (maxspeed-minspeed > ACCURACY):
print(str(flow_number)+' flows: Measurement ongoing at speed: ' + str(round(speed,2)) + '% ',end='\r')
# Get statistics now that the generation is stable and NO ARP messages any more
pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
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)):
+ 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):
endspeed = speed
endpps_req_tx = pps_req_tx
endpps_tx = pps_tx
if endpps_sut_tx_str <> 'NO_RESULTS':
log.info('|{:>7}'.format(str(flow_number))+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us | '+ '{:>9.0f}'.format(endlat_max)+' us | '+ '{:>14d}'.format(endabs_dropped)+ ' |'+'{:>9.2f}'.format(enddrop_rate)+ '% |')
log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
+ writer.writerow({'flow':flow_number,'size':(size+4),'endspeed':endspeed,'endspeedpps':get_pps(endspeed,size),'endpps_req_tx':endpps_req_tx,'endpps_tx':endpps_tx,'endpps_sut_tx_str':endpps_sut_tx_str,'endpps_rx':endpps_rx,'endlat_avg':endlat_avg,'endlat_max':endlat_max,'endabs_dropped':endabs_dropped,'enddrop_rate':enddrop_rate})
else:
log.info('|{:>7}'.format(str(flow_number))+" | Speed 0 or close to 0")
log.info("| Pktsize| Speed requested | Sent to NIC | Sent by Gen | Forward by SUT | Rec. by Gen | Avg. Latency | Max. Latency | Packets Lost | Loss Ratio |")
log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
# PROX will use different packet sizes as defined in sizes[]
-# sizes=[1496,1020,508,252,124,60]
- sizes=[1020,508,252,124,60]
+ sizes=[1496,1020,508,252,124,60]
+# sizes=[1020,508,252,124,60]
+# sizes=[124,60]
for size in sizes:
- #speed = 100 Commented out: Not starting from 100% since we are trying smaller packets, so speed will not be higher than the speed achieved in previous loop
gensock.reset_stats()
if sutsock!='none':
sutsock.reset_stats()
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
endpps_sut_tx_str = 'NO_RESULTS'
- maxspeed = speed = 100
+ maxspeed = speed = STARTSPEED
minspeed = 0
while (maxspeed-minspeed > ACCURACY):
print(str(size+4)+' bytes: Measurement ongoing at speed: ' + str(round(speed,2)) + '% ',end='\r')
# Get statistics now that the generation is stable and NO ARP messages any more
pps_req_tx,pps_tx,pps_sut_tx_str,pps_rx,lat_avg,lat_max, abs_dropped, abs_tx = run_iteration(gensock,sutsock)
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)):
+ 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):
endspeed = speed
endpps_req_tx = pps_req_tx
endpps_tx = pps_tx
if endpps_sut_tx_str <> 'NO_RESULTS':
log.info('|{:>7}'.format(size+4)+" | " + '{:>5.1f}'.format(endspeed) + '% ' +'{:>6.3f}'.format(get_pps(endspeed,size)) + ' Mpps | '+ '{:>9.3f}'.format(endpps_req_tx)+' Mpps | '+ '{:>9.3f}'.format(endpps_tx) +' Mpps | ' + '{:>9}'.format(endpps_sut_tx_str) +' Mpps | '+ '{:>9.3f}'.format(endpps_rx)+' Mpps | '+ '{:>9.0f}'.format(endlat_avg)+' us | '+'{:>9.0f}'.format(endlat_max)+' us | '+ '{:>14d}'.format(endabs_dropped)+ ' |'+'{:>9.2f}'.format(enddrop_rate)+ '% |')
log.info("+--------+--------------------+----------------+----------------+----------------+----------------+----------------+----------------+----------------+------------+")
+ writer.writerow({'flow':'1','size':(size+4),'endspeed':endspeed,'endspeedpps':get_pps(endspeed,size),'endpps_req_tx':endpps_req_tx,'endpps_tx':endpps_tx,'endpps_sut_tx_str':endpps_sut_tx_str,'endpps_rx':endpps_rx,'endlat_avg':endlat_avg,'endlat_max':endlat_max,'endabs_dropped':endabs_dropped,'enddrop_rate':enddrop_rate})
else:
log.debug('|{:>7}'.format(str(size))+" | Speed 0 or close to 0")
global gencores
global irqcores
global DROP_RATE_TRESHOLD
+global LAT_AVG_TRESHOLD
+global LAT_MAX_TRESHOLD
global ACCURACY
+global STARTSPEED
global required_number_of_test_machines
clients =[]
socks =[]
testconfig.read(test+'.test')
required_number_of_test_machines = testconfig.get('DEFAULT', 'total_number_of_test_machines')
DROP_RATE_TRESHOLD = float(testconfig.get('DEFAULT', 'drop_rate_treshold'))
+LAT_AVG_TRESHOLD = float(testconfig.get('DEFAULT', 'lat_avg_treshold'))
+LAT_MAX_TRESHOLD = float(testconfig.get('DEFAULT', 'lat_max_treshold'))
ACCURACY = float(testconfig.get('DEFAULT', 'accuracy'))
+STARTSPEED = float(testconfig.get('DEFAULT', 'startspeed'))
config = ConfigParser.RawConfigParser()
config.read(env+'.env')
key = config.get('OpenStack', 'key')
eval(init_code)
####################################################
# Run test cases
-# Best to run the flow test at the end since otherwise the tests coming after thatmight be influenced by the big number of entries in the switch flow tables
+# Best to run the flow test at the end since otherwise the tests coming after might be influenced by the big number of entries in the switch flow tables
####################################################
number_of_tests = testconfig.get('DEFAULT', 'number_of_tests')
-for vm in range(1, int(number_of_tests)+1):
- cmd=testconfig.get('test%d'%vm,'cmd')
- eval(cmd)
+data_file = 'RUN' +env+'.'+test+'.csv'
+data_csv_file = open(data_file,'w')
+with data_csv_file:
+ fieldnames = ['flow','size','endspeed','endspeedpps','endpps_req_tx','endpps_tx','endpps_sut_tx_str','endpps_rx','endlat_avg','endlat_max','endabs_dropped','enddrop_rate']
+ writer = csv.DictWriter(data_csv_file, fieldnames=fieldnames)
+ writer.writeheader()
+ for vm in range(1, int(number_of_tests)+1):
+ cmd=testconfig.get('test%d'%vm,'cmd')
+ eval(cmd)
####################################################