diff options
author | Deepak S <deepak.s@linux.intel.com> | 2017-07-13 21:26:50 -0700 |
---|---|---|
committer | Deepak S <deepak.s@linux.intel.com> | 2017-07-14 04:58:47 -0700 |
commit | 7286b2518ec8e4398b512ce95def9166a7af2e4a (patch) | |
tree | c93ef65d9e73e8893ccecb720152e16aae96a8b6 /VNFs/DPPD-PROX/helper-scripts/testvRouter | |
parent | adcb79da90176b27224eeb1d00aa0e611ef85a9b (diff) |
Adding PROX(Packet pROcessing eXecution engine) VNF to sampleVNF
JIRA: SAMPLEVNF-55
PROX is a DPDK-based application implementing Telco use-cases such as
a simplified BRAS/BNG, light-weight AFTR... It also allows configuring
finer grained network functions like QoS, Routing, load-balancing...
(We are moving PROX version v039 to sampleVNF
https://01.org/intel-data-plane-performance-demonstrators/prox-overview)
Change-Id: Ia3cb02cf0e49ac5596e922c197ff7e010293d033
Signed-off-by: Deepak S <deepak.s@linux.intel.com>
Diffstat (limited to 'VNFs/DPPD-PROX/helper-scripts/testvRouter')
5 files changed, 1966 insertions, 0 deletions
diff --git a/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_BNG_8ports.py b/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_BNG_8ports.py new file mode 100755 index 00000000..f26d0db6 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_BNG_8ports.py @@ -0,0 +1,457 @@ +#!/bin/env 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 socket +import sys +import os +from time import * +from datetime import datetime +from optparse import OptionParser +import time +from remote_system import * +from math import log + +# General parameters +accuracy = 0.1 # in percent of line rate +max_dropped = 0.1 # in percent +all_pkt_size = [64,128,256,512,1024,1280,1494] +all_ip_src = [0,6,12,18] +all_ip_dst = [0,6,12,18] + +# Stear parameters +step_time = 0.001 # in seconds +step_delta = 10 # in percent of line rate + +##### Use case 1: packet loss and latency ##### +low_steps_delta_for_loss = 0.01 # Use increment of 0.01% from 0 to low_steps +medium_steps_delta_for_loss = 0.1 # Use increment of 0.1% from low_steps to medium_steps +normal_steps_delta_for_loss = 1.0 # Use increment of 1% from medium_steps till 100% +low_steps = 0.1 +medium_steps = 1.0 + +# Prox parameters +tx_port0 = [4] +tx_port1 = [6] +tx_port2 = [8] +tx_port3 = [10] +tx_port4 = [12] +tx_port5 = [14] +tx_port6 = [16] +tx_port7 = [18] +tx_task = 0 + +all_rx_cores = [20,22,24,26,28,30,32,34] +rx_lat_cores = [20,22,24,26,28,30,32,34] +rx_task = 0 + +# Some variables, do not change + +# Program arguments +parser = OptionParser() +parser.add_option("-d", "--duration", dest="test_duration", help="Duration of each steps", metavar="integer", default=10) +parser.add_option("-s", "--speed", dest="init_speed", help="Initial speed", metavar="integer", default=100) +parser.add_option("-r", "--run", dest="run", help="Run test", metavar="integer", default=0) +parser.add_option("-c", "--configure", dest="configure", help="Configure Test", metavar="integer", default=0) +(options, args) = parser.parse_args() + +init_speed = int(options.init_speed) +test_duration = int(options.test_duration) +configure = int(options.configure) +run = int(options.run) + +nb_cores_per_interface = len(tx_port0) +max_speed = (100.0/nb_cores_per_interface) +init_speed = (init_speed * 1.0/nb_cores_per_interface) +accuracy = (accuracy * 1.0/nb_cores_per_interface) +normal_steps_delta_for_loss = (normal_steps_delta_for_loss /nb_cores_per_interface) +medium_steps_delta_for_loss = (medium_steps_delta_for_loss /nb_cores_per_interface) +low_steps_delta_for_loss = (low_steps_delta_for_loss /nb_cores_per_interface) +medium_steps = (medium_steps /nb_cores_per_interface) +low_steps = (low_steps /nb_cores_per_interface) + +max_dropped = max_dropped / 100 + +def to_str(arr): + ret = "" + first = 1; + for a in arr: + if (first == 0): + ret += "," + + ret += str(a) + first = 0; + return ret; + +tx_cores_cpe = tx_port0 + tx_port1 + tx_port2 + tx_port3 +tx_cores_inet = tx_port4 + tx_port5 + tx_port6 + tx_port7 +tx_cores = tx_cores_cpe + tx_cores_inet + +def send_all_pkt_size(cores, pkt_size): + for c in cores: + sock.sendall("pkt_size " + str(c) + " 0 " + str(pkt_size) + "\n"); + +def send_all_value(cores, offset, value, len): + for c in cores: + sock.sendall("set value " + str(c) + " 0 " + str(offset) + " " + str(value) + " " + str(len)+ "\n"); + +def send_all_random(cores, offset, rand_str, len): + for c in cores: + sock.sendall("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); + #print("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); + +def send_all_speed(cores, speed_perc): + for c in cores: + sock.sendall("speed " + str(c) + " 0 " + str(speed_perc) + "\n"); + +def send_reset_random(): + sock.sendall("reset randoms all" + "\n"); + +def send_reset_value(): + sock.sendall("reset values all" + "\n"); + +def rx_stats(tx_cores, tx_task, rx_cores, rx_task): + rx = tx = drop = tsc = tsc_hs = ierrors = 0 + for e in tx_cores: + sock.sendall("core stats " + str(e) + " " + str(tx_task) + "\n") + recv = recv_once() + rx += int(recv.split(",")[0]) + tx += int(recv.split(",")[1]) + drop += int(recv.split(",")[2]) + tsc = int(recv.split(",")[3]) + tsc_hz = int(recv.split(",")[4]) + for e in rx_cores: + sock.sendall("core stats " + str(e) + " " + str(rx_task) + "\n") + recv = recv_once() + rx += int(recv.split(",")[0]) + tx += int(recv.split(",")[1]) + drop += int(recv.split(",")[2]) + tsc = int(recv.split(",")[3]) + tsc_hz = int(recv.split(",")[4]) + # Also get the ierrors as generators might be the bottleneck... + sock.sendall("tot ierrors tot\n") + recv = recv_once() + ierrors += int(recv.split(",")[0]) + rx+=ierrors + return rx,tx,drop,tsc,tsc_hz + +def lat_stats(cores,task): + lat_min = [0 for e in range(127)] + lat_max = [0 for e in range(127)] + lat_avg = [0 for e in range(127)] + for e in cores: + sock.sendall("lat stats " + str(e) + " " + str(task) + " " + "\n") + recv = recv_once() + lat_min[e] = int(recv.split(",")[0]) + lat_max[e] = int(recv.split(",")[1]) + lat_avg[e] = int(recv.split(",")[2]) + return lat_min, lat_max, lat_avg + +def recv_once(): + ret_str = ""; + done = 0; + while done == 0: + dat = sock.recv(256); + i = 0; + while(i < len(dat)): + if (dat[i] == '\n'): + done = 1 + else: + ret_str += dat[i]; + i = i + 1; + return ret_str + +def set_pkt_sizes(tx_cores, p): + send_all_pkt_size(tx_cores, p-4) + # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size + send_all_value(tx_cores, 16, p - 18, 2) # 14 for MAC (12) EthType (2) + send_all_value(tx_cores, 38, p - 38, 2) # 34 for MAC (12) EthType (2) IP (20) + +def set_pkt_sizes_cpe(tx_cores, p): + send_all_pkt_size(tx_cores, p-4) + # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size + send_all_value(tx_cores, 24, p - 26, 2) # 22 for QinQ (8) MAC (12) EthType (2) + send_all_value(tx_cores, 46, p - 46, 2) # 42 for QinQ (8) MAC (12) EthType (2) IP (20) + +def set_pkt_sizes_inet(tx_cores, p): + send_all_pkt_size(tx_cores, p+24-4) + # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size + send_all_value(tx_cores, 20, p + 2, 2) # 14 for MAC (12) EthType (2) + send_all_value(tx_cores, 48, p - 26, 2) # 14 for MAC (12) EthType (2) + send_all_value(tx_cores, 70, p - 46, 2) # 34 for MAC (12) EthType (2) IP (20) + +def run_measure_throughput(speed, speed_cpe): + done = 0 + # Intialize tests by stopping cores and resetting stats + step=0 + steps_done = 0 + sock.sendall("start " + to_str(all_rx_cores) + "\n") + sleep(2) + sock.sendall("stop " + to_str(all_rx_cores) + "\n") + sock.sendall("reset stats\n") + print "Speed = " + str(speed * nb_cores_per_interface) + sleep(1); + + send_all_speed(tx_cores, step); + + # Now starting the steps. First go to the common speed, then increase steps for the faster one. + sock.sendall("start " + to_str(tx_cores) + "," + to_str(rx_lat_cores) + "\n") + while (steps_done == 0): + sleep(step_time) + if (step + step_delta <= speed): + step+=step_delta + else: + steps_done = 1; + send_all_speed(tx_cores, step) + + # Steps are now OK. Set speed + send_all_speed(tx_cores_inet, speed); + send_all_speed(tx_cores_cpe, speed_cpe); + sleep(2); + + # Getting statistics to calculate PPS at right speed.... + rx_pps_beg,tx_pps_beg,drop_pps_beg,tsc_pps_beg,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + sleep(test_duration); + + # Collect statistics before test stops...and stop the test. Important to get stats before stopping as stops take some time... + rx_pps_end,tx_pps_end,drop_pps_end,tsc_pps_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + lat_min,lat_max,lat_avg = lat_stats(rx_lat_cores, rx_task) + sock.sendall("stop " + to_str(tx_cores) + "\n") + sock.sendall("start " + to_str(all_rx_cores) + "\n") + sleep(3); + sock.sendall("stop " + to_str(all_rx_cores) + "\n") + + rx_end, tx_end,drop_end,tsc_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + rx = rx_pps_end - rx_pps_beg + tsc = tsc_pps_end - tsc_pps_beg + mpps = rx / (tsc/float(tsc_hz)) / 1000000 + tx = tx_pps_end - tx_pps_beg + tx_mpps = tx / (tsc/float(tsc_hz)) / 1000000 + + #print "Runtime = " + str((tsc)/float(tsc_hz)); + if (tx_end == 0): + dropped_tot = tx_end - rx_end + dropped_pct = 0 + else: + dropped_tot = tx_end - rx_end + dropped_pct = ((dropped_tot) * 1.0) / tx_end + + if (dropped_tot > 0): + if (dropped_pct >= max_dropped): + print "** FAILED **: lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + else: + print "OK but lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + else: + if (dropped_tot < 0): + print "Something wrong happened - received more packets than transmitted" + else: + print "** OK **: RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + print "MPPS = " + str(mpps) + print "====================================================" + return dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg + +def write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg): + f.write(str(pkt_size) + "; " + str(tx_mpps) + "; " + str(mpps) + "; " + str(100 * dropped_pct) + "; " + str(dropped_tot) + "; " + str(speed * nb_cores_per_interface) + "; " + str(number_flows) + "; " ) + for e in rx_lat_cores: + f.write(str(lat_min[e]) + "; " + str(lat_max[e]) + "; " + str(lat_avg[e]) + "; ") + f.write("\n"); + f.flush() + +def run_dicho_search(number_flows, pkt_size): + previous_success_speed = 0.0 + previous_error_speed = max_speed + speed = init_speed * 1.0 + done = 0; + good_tx_mpps = 0 + good_mpps = 0 + good_dropped_pct = 0 + good_dropped_tot = 0 + good_speed = 0 + good_lat_min = [0 for e in range(127)] + good_lat_max = [0 for e in range(127)] + good_lat_avg = [0 for e in range(127)] + + while done == 0: + speed_cpe = (speed * (pkt_size + 20)) / (pkt_size + 24 + 20) + dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed, speed_cpe) + if ((dropped_tot >= 0) and (dropped_pct <= max_dropped)): + good_tx_mpps = tx_mpps + good_mpps = mpps + good_dropped_pct = dropped_pct + good_dropped_tot = dropped_tot + good_speed = speed + good_lat_min = lat_min + good_lat_max = lat_max + good_lat_avg = lat_avg + write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg); + write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg); + else: + write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg); + + if ((speed == max_speed) and (dropped_pct <= max_dropped)): + write_results(f_minimal, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg); + done = 1 + if (dropped_pct <= max_dropped): + previous_success_speed = speed + if (speed > max_speed - accuracy): + speed = max_speed + else: + if (previous_error_speed - speed < accuracy): + write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_flows, good_lat_min, good_lat_max, good_lat_avg); + done = 1 + else: + speed = speed + (previous_error_speed - speed)/2; + else: + previous_error_speed = speed + if (speed - previous_success_speed < accuracy): + write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_flows, good_lat_min, good_lat_max, good_lat_avg); + done = 1 + else: + speed = speed - (speed - previous_success_speed) / 2; + + +def set_source_destination_ip(nb_sources, nb_destinations): + # Destination addressese: "00XXXXXX" "XXXXXXXX" "XXXXXXXX" "XXXXXX10" + # Starting with 00 to be in class A and skipping 0.x.y.z and 127.x.y.z + # Ending with 10 to avoid x.y.z.0 and x.y.z.255 + + dst_mask = "10" + for i in range (nb_destinations): + dst_mask = "X" + str(dst_mask) + for i in range (32 - nb_destinations - 2): + dst_mask = "0" + str(dst_mask) + + src_mask = "10" + for i in range (nb_sources): + src_mask = "X" + str(src_mask) + for i in range (32 - nb_sources - 2): + src_mask = "0" + str(src_mask) + + for c in tx_port0: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + for c in tx_port1: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + for c in tx_port2: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + for c in tx_port3: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + for c in tx_port4: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + for c in tx_port5: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + for c in tx_port6: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + for c in tx_port7: + send_all_random([c], 26, src_mask, 4) + send_all_random([c], 30, dst_mask, 4) + +#======================================================================== +class TestDefinition(): + "Stores test parameters" + def __init__(self, number_ip_src, number_ip_dst, pkt_size): + self.number_ip_src = number_ip_src + self.number_ip_dst = number_ip_dst + self.pkt_size = pkt_size + +#======================================================================== +def run_use_case(number_ip_src, number_ip_dst, pkt_size): + number_flows = (2 ** number_ip_src) * (2 ** number_ip_dst) +# send_reset_random() +# send_reset_value() +# set_source_destination_ip(number_ip_src, number_ip_dst) + set_pkt_sizes_inet(tx_cores_inet, pkt_size) + set_pkt_sizes_cpe(tx_cores_cpe, pkt_size) + print "Running test with pkt size= " + str(pkt_size) + " number_ip_src = " + str(number_ip_src) + " number_ip_dst = " + str(number_ip_dst) + " Number flows = " + str(number_flows) + "; \n" + run_dicho_search(number_flows, pkt_size) + sleep(3) + +#======================================================================== +def run_all_use_cases(): + use_case_nb = 1 + # Connect to dppd + file_path = '/tmp/prox.sock' + sock.connect(file_path) + + f.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f_all.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f_minimal.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f.flush(); + f_all.flush(); + f_minimal.flush(); + + # Starting tests + print "Stopping all cores and resetting all values and randoms before starting\n" + sock.sendall("stop " + to_str(all_rx_cores) + "\n") + sock.sendall("stop " + to_str(tx_cores) + "\n") + #sock.sendall("stop all") + sock.sendall("reset stats\n") + sleep(3); + for line in file_tests: + info = line.split(';') + if (info[0][0] == '#'): + continue + if (info[0][0] == ''): + break + number_ip_src = int(info[0]) + number_ip_dst = int(info[1]) + pkt_size = int(info[2]) + run_use_case(number_ip_src, number_ip_dst, pkt_size) + +#======================================================================== +def configure_use_case(): + Tests = [] + number_ip_dst = 0 + number_ip_src = 0 + for pkt_size in all_pkt_size: + Tests.append(TestDefinition(number_ip_src, number_ip_dst, pkt_size)) + + pkt_size = 64 + while (pkt_size < 1494): + Tests.append(TestDefinition(number_ip_src, number_ip_dst, pkt_size)) + pkt_size = (pkt_size *11) / 10 + + file_tests = open('test_description.txt', 'w') + file_tests.write("# Number_ip_src; number_ip_dst; pkt_size; \n") + for test in Tests: + file_tests.write(str(test.number_ip_src) + "; " + str(test.number_ip_dst) + "; " + str(test.pkt_size) + "; " + ";\n") + file_tests.close() + +#======================================================================== +if ((configure == 0) and (run == 0)): + print "Nothing to do - please use -r 1 or -c 1" +if (configure == 1): + configure_use_case() +if (run == 1): + print "****************************************************************************************************************" + print "** Running Characterization with " + str(test_duration) + " seconds steps and starting at " + str(init_speed) + " percent of line rate **" + print "****************************************************************************************************************" + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + f_all = open('all_results.txt', 'w') + f = open('detailed_results.txt', 'w') + f_minimal = open('minimal_results.txt', 'w') + file_tests = open('test_description.txt', 'r') + run_all_use_cases() + f.close(); + sock.close(); + diff --git a/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_vRouter.py b/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_vRouter.py new file mode 100755 index 00000000..f4d211f6 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_vRouter.py @@ -0,0 +1,681 @@ +#!/bin/env 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 socket +import sys +import os +from time import * +from datetime import datetime +from optparse import OptionParser +import time +from remote_system import * +from math import log + +# General parameters +accuracy = 0.1 # in percent of line rate +max_dropped = 0.001 # in percent +all_pkt_size = [64,128,256,512,1024,1280,1518] +#all_pkt_size = [64] + +# vRouter parameters, in case commands must be sent +vRouter_host = "192.168.1.96" + +# Stear parameters +step_time = 0.01 # in seconds +step_delta = 0.025 # in percent of line rate + +# Use case dependent parameters +##### Use case 0: influence of number of routes and next hops ##### +max_number_next_hops = 256 # Maximum number of next-hops per interface +max_number_routes = 8192 # Maximum number of routes per interface +max_number_addresses_local_network = 262144 + +##### Use case 1: packet loss and latency ##### +low_steps_delta_for_loss = 0.01 # Use increment of 0.01% from 0 to low_steps +medium_steps_delta_for_loss = 0.1 # Use increment of 0.1% from low_steps to medium_steps +normal_steps_delta_for_loss = 1.0 # Use increment of 1% from medium_steps till 100% +low_steps = 0.1 +medium_steps = 1.0 + +# Prox parameters +tx_port4 = [19,27,55,63] +tx_port5 = [20,28,56,64] +tx_port6 = [21,29,57,65] +tx_port7 = [22,30,58,66] +tx_port2 = [23,31,59,67] +tx_port3 = [24,32,60,68] +tx_port0 = [25,33,61,69] +tx_port1 = [26,34,62,70] +tx_task = 0 + +all_rx_cores = [1,2,3,4,5,6,7,10] +rx_lat_cores = [1,2,3,4,5,6,7,10] +rx_task = 1 + +# Some variables, do not change + +# Program arguments +parser = OptionParser() +parser.add_option("-d", "--duration", dest="test_duration", help="Duration of each steps", metavar="integer", default=10) +parser.add_option("-s", "--speed", dest="init_speed", help="Initial speed", metavar="integer", default=100) +parser.add_option("-u", "--use-case", dest="use_case", help="Use Case Number", metavar="integer", default=0) +parser.add_option("-r", "--run", dest="run", help="Run test", metavar="integer", default=0) +parser.add_option("-c", "--configure", dest="configure", help="Configure Test", metavar="integer", default=0) +(options, args) = parser.parse_args() + +init_speed = int(options.init_speed) +test_duration = int(options.test_duration) +use_case = int(options.use_case) +configure = int(options.configure) +run = int(options.run) + +nb_cores_per_interface = len(tx_port0) +max_speed = (100.0/nb_cores_per_interface) +init_speed = (init_speed * 1.0/nb_cores_per_interface) +accuracy = (accuracy * 1.0/nb_cores_per_interface) +normal_steps_delta_for_loss = (normal_steps_delta_for_loss /nb_cores_per_interface) +medium_steps_delta_for_loss = (medium_steps_delta_for_loss /nb_cores_per_interface) +low_steps_delta_for_loss = (low_steps_delta_for_loss /nb_cores_per_interface) +medium_steps = (medium_steps /nb_cores_per_interface) +low_steps = (low_steps /nb_cores_per_interface) + +max_dropped = max_dropped / 100 + +def to_str(arr): + ret = "" + first = 1; + for a in arr: + if (first == 0): + ret += "," + + ret += str(a) + first = 0; + return ret; + +tx_cores = tx_port0 + tx_port1 + tx_port2 + tx_port3 + tx_port4 + tx_port5 + tx_port6 + tx_port7 + +def send_all_pkt_size(cores, pkt_size): + for c in cores: + sock.sendall("pkt_size " + str(c) + " 0 " + str(pkt_size) + "\n"); + +def send_all_value(cores, offset, value, len): + for c in cores: + sock.sendall("set value " + str(c) + " 0 " + str(offset) + " " + str(value) + " " + str(len)+ "\n"); + +def send_all_random(cores, offset, rand_str, len): + for c in cores: + sock.sendall("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); + #print("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); + +def send_all_speed(cores, speed_perc): + for c in cores: + sock.sendall("speed " + str(c) + " 0 " + str(speed_perc) + "\n"); + +def send_reset_random(): + sock.sendall("reset randoms all" + "\n"); + +def send_reset_value(): + sock.sendall("reset values all" + "\n"); + +def rx_stats(tx_cores, tx_task, rx_cores, rx_task): + rx = tx = drop = tsc = tsc_hs = ierrors = 0 + for e in tx_cores: + sock.sendall("core stats " + str(e) + " " + str(tx_task) + "\n") + recv = recv_once() + rx += int(recv.split(",")[0]) + tx += int(recv.split(",")[1]) + drop += int(recv.split(",")[2]) + tsc = int(recv.split(",")[3]) + tsc_hz = int(recv.split(",")[4]) + for e in rx_cores: + sock.sendall("core stats " + str(e) + " " + str(rx_task) + "\n") + recv = recv_once() + rx += int(recv.split(",")[0]) + tx += int(recv.split(",")[1]) + drop += int(recv.split(",")[2]) + tsc = int(recv.split(",")[3]) + tsc_hz = int(recv.split(",")[4]) + # Also get the ierrors as generators might be the bottleneck... + sock.sendall("tot ierrors tot\n") + recv = recv_once() + ierrors += int(recv.split(",")[0]) + rx+=ierrors + return rx,tx,drop,tsc,tsc_hz + +def lat_stats(cores,task): + lat_min = [0 for e in range(127)] + lat_max = [0 for e in range(127)] + lat_avg = [0 for e in range(127)] + for e in cores: + sock.sendall("lat stats " + str(e) + " " + str(task) + " " + "\n") + recv = recv_once() + lat_min[e] = int(recv.split(",")[0]) + lat_max[e] = int(recv.split(",")[1]) + lat_avg[e] = int(recv.split(",")[2]) + return lat_min, lat_max, lat_avg + +def recv_once(): + ret_str = ""; + done = 0; + while done == 0: + dat = sock.recv(256); + i = 0; + while(i < len(dat)): + if (dat[i] == '\n'): + done = 1 + else: + ret_str += dat[i]; + i = i + 1; + return ret_str + +def wait_vRouter_restarted(host): + while (1): + ret = os.system("ping " + host + " -c 1 > /dev/null") + if ret == 0: + print "still up..." + else: + break; + sleep(1) + + while (1): + ret = os.system("ping " + host + " -c 1 > /dev/null") + if (ret == 0): + print "UP" + break; + else: + print "still down..." + sleep(1) + +def reload_vRouter_config(config): + print "connecting to vRouter...and copying " + str(config) + sut = remote_system("root", vRouter_host) + cmd = "cp /config/prox/" + str(config) + " /config/config.boot" + sut.run(cmd) + print "Rebooting system at " + str(datetime.now().time()) + sut.run_forked("reboot") + sleep(5) + wait_vRouter_restarted(vRouter_host) + print "Waiting for last startup scripts to start..." + last_script = "l2tp" + while(1): + dmesg = str(sut.run("dmesg")) + if last_script in dmesg: + print "found l2tp - UP" + break; + sleep(1) + print "vRouter started - waiting 5 last seconds before starting test" + sleep(5) + print datetime.now().time() + +def set_pkt_sizes(tx_cores, p): + send_all_pkt_size(tx_cores, p-4) + # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size + send_all_value(tx_cores, 16, p - 18, 2) # 14 for MAC (12) EthType (2) + send_all_value(tx_cores, 38, p - 38, 2) # 34 for MAC (12) EthType (2) IP (20) + +def run_measure_throughput(speed): + done = 0 + # Intialize tests by stopping cores and resetting stats + step=0 + steps_done = 0 + sock.sendall("start " + to_str(all_rx_cores) + "\n") + sleep(2) + sock.sendall("stop " + to_str(all_rx_cores) + "\n") + sock.sendall("reset stats\n") + print "Speed = " + str(speed * nb_cores_per_interface) + sleep(1); + + send_all_speed(tx_cores, step); + + # Now starting the steps. First go to the common speed, then increase steps for the faster one. + sock.sendall("start " + to_str(tx_cores) + "," + to_str(rx_lat_cores) + "\n") + while (steps_done == 0): + sleep(step_time) + if (step + step_delta <= speed): + step+=step_delta + else: + steps_done = 1; + send_all_speed(tx_cores, step) + + # Steps are now OK. Set speed + send_all_speed(tx_cores, speed); + sleep(2); + + # Getting statistics to calculate PPS at right speed.... + rx_pps_beg,tx_pps_beg,drop_pps_beg,tsc_pps_beg,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + sleep(test_duration); + + # Collect statistics before test stops...and stop the test. Important to get stats before stopping as stops take some time... + rx_pps_end,tx_pps_end,drop_pps_end,tsc_pps_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + lat_min,lat_max,lat_avg = lat_stats(rx_lat_cores, rx_task) + sock.sendall("stop " + "," + to_str(tx_cores) + "\n") + sock.sendall("start " + to_str(all_rx_cores) + "\n") + sleep(3); + sock.sendall("stop " + to_str(all_rx_cores) + "\n") + + rx_end, tx_end,drop_end,tsc_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + rx = rx_pps_end - rx_pps_beg + tsc = tsc_pps_end - tsc_pps_beg + mpps = rx / (tsc/float(tsc_hz)) / 1000000 + tx = tx_pps_end - tx_pps_beg + tx_mpps = tx / (tsc/float(tsc_hz)) / 1000000 + + #print "Runtime = " + str((tsc)/float(tsc_hz)); + if (tx_end == 0): + dropped_tot = tx_end - rx_end + dropped_pct = 0 + else: + dropped_tot = tx_end - rx_end + dropped_pct = ((dropped_tot) * 1.0) / tx_end + + if (dropped_tot > 0): + if (dropped_pct >= max_dropped): + print "** FAILED **: lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + else: + print "OK but lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + else: + if (dropped_tot < 0): + print "Something wrong happened - received more packets than transmitted" + else: + print "** OK **: RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + print "MPPS = " + str(mpps) + print "====================================================" + return dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg + +def write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg): + f.write(str(pkt_size) + "; " + str(tx_mpps) + "; " + str(mpps) + "; " + str(100 * dropped_pct) + "; " + str(dropped_tot) + "; " + str(speed * nb_cores_per_interface) + "; " + str(number_next_hops) + "; " + str(number_routes) + "; " + str(traffic) + "; ") + for e in rx_lat_cores: + f.write(str(lat_min[e]) + "; " + str(lat_max[e]) + "; " + str(lat_avg[e]) + "; ") + f.write("\n"); + f.flush() + +def run_loss_graph(number_next_hops, number_routes, pkt_size, traffic): + speed = init_speed * 1.0 + done = 0; + while done == 0: + dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed) + write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + if (speed <= low_steps_delta_for_loss): + done = 1 + return + if (speed >= (medium_steps+normal_steps_delta_for_loss)): + speed -= normal_steps_delta_for_loss + else: + if (speed >= (low_steps+medium_steps_delta_for_loss)): + speed -= medium_steps_delta_for_loss + else: + speed -= low_steps_delta_for_loss + +def run_dicho_search(number_next_hops, number_routes, pkt_size, traffic): + previous_success_speed = 0.0 + previous_error_speed = max_speed + speed = init_speed * 1.0 + done = 0; + good_tx_mpps = 0 + good_mpps = 0 + good_dropped_pct = 0 + good_dropped_tot = 0 + good_speed = 0 + good_lat_min = [0 for e in range(127)] + good_lat_max = [0 for e in range(127)] + good_lat_avg = [0 for e in range(127)] + + while done == 0: + dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed) + if ((dropped_tot >= 0) and (dropped_pct <= max_dropped)): + good_tx_mpps = tx_mpps + good_mpps = mpps + good_dropped_pct = dropped_pct + good_dropped_tot = dropped_tot + good_speed = speed + good_lat_min = lat_min + good_lat_max = lat_max + good_lat_avg = lat_avg + write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + else: + write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + + if ((speed == max_speed) and (dropped_pct <= max_dropped)): + write_results(f_minimal, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + done = 1 + if (dropped_pct <= max_dropped): + previous_success_speed = speed + if (speed > max_speed - accuracy): + speed = max_speed + else: + if (previous_error_speed - speed < accuracy): + write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, good_lat_min, good_lat_max, good_lat_avg); + done = 1 + else: + speed = speed + (previous_error_speed - speed)/2; + else: + previous_error_speed = speed + if (speed - previous_success_speed < accuracy): + write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, good_lat_min, good_lat_max, good_lat_avg); + done = 1 + else: + speed = speed - (speed - previous_success_speed) / 2; + + +def set_destination_ip(use_case, nb_destinations, traffic): + # minimmum 8 routes i.e. 1 per interface + # Destination addressese: "00XXXYY1" "Z00ZZ0ZZ" "AA0AA0AA" "BBBBBB10" + # Where X = interface id. Starting with 00 to be in class A and skipping 0.x.y.z and 127.x.y.z + # Y, Z and A = additional routes + # B = IP in routes. 10 to avoid x.y.z.0 and x.y.z.255 + # Gaps in A and B to void "too good" distributions e.g. using LPM and + # First changing Y + + mask = "" + for i in range (2): + mask = str(mask)+"0" + end_mask = "" + if (use_case != 2): + end_mask = "XXXXXX10" # Last 8 bits + + if (nb_destinations == 1): + end_mask = "0010000000000000000" + str(end_mask) + if (nb_destinations == 2): + end_mask = "X010000000000000000" + str(end_mask) + if (nb_destinations == 4): + end_mask = "XX10000000000000000" + str(end_mask) + if (nb_destinations == 8): + end_mask = "XX1X000000000000000" + str(end_mask) + elif (nb_destinations == 16): + end_mask = "XX1X00X000000000000" + str(end_mask) + elif (nb_destinations == 32): + end_mask = "XX1X00XX00000000000" + str(end_mask) + elif (nb_destinations == 64): + end_mask = "XX1X00XX0X000000000" + str(end_mask) + elif (nb_destinations == 128): + end_mask = "XX1X00XX0XX00000000" + str(end_mask) + elif (nb_destinations == 256): + end_mask = "XX1X00XX0XXX0000000" + str(end_mask) + elif (nb_destinations == 512): + end_mask = "XX1X00XX0XXXX000000" + str(end_mask) + elif (nb_destinations == 1024): + end_mask = "XX1X00XX0XXXX0X0000" + str(end_mask) + elif (nb_destinations == 2048): + end_mask = "XX1X00XX0XXXX0XX000" + str(end_mask) + elif (nb_destinations == 4096): + end_mask = "XX1X00XX0XXXX0XX0X0" + str(end_mask) + elif (nb_destinations == 8192): + end_mask = "XX1X00XX0XXXX0XX0XX" + str(end_mask) + else: + if (nb_destinations <= 64 * 1): + end_mask = "0010000000000000000" + n_dest = int(log(nb_destinations, 2)) + for i in range (n_dest): + end_mask = str(end_mask) + "X" + for i in range (6 - n_dest): + end_mask = str(end_mask) + "0" + end_mask = str(end_mask) + "10" + else: + end_mask = "XXXXXX10" # Last 8 bits + + if (nb_destinations == 64 * 2): + end_mask = "001X000000000000000" + str(end_mask) + elif (nb_destinations == 64 * 4): + end_mask = "001X00X000000000000" + str(end_mask) + elif (nb_destinations == 64 * 8): + end_mask = "001X00XX00000000000" + str(end_mask) + elif (nb_destinations == 64 * 16): + end_mask = "001X00XX0X000000000" + str(end_mask) + elif (nb_destinations == 64 * 32): + end_mask = "001X00XX0XX00000000" + str(end_mask) + elif (nb_destinations == 64 * 64): + end_mask = "001X00XX0XXX0000000" + str(end_mask) + elif (nb_destinations == 64 * 128): + end_mask = "001X00XX0XXXX000000" + str(end_mask) + elif (nb_destinations == 64 * 256): + end_mask = "001X00XX0XXXX0X0000" + str(end_mask) + elif (nb_destinations == 64 * 512): + end_mask = "001X00XX0XXXX0XX000" + str(end_mask) + elif (nb_destinations == 64 * 1024): + end_mask = "001X00XX0XXXX0XX0X0" + str(end_mask) + elif (nb_destinations == 64 * 2048): + end_mask = "001X00XX0XXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 4096): + end_mask = "001XX0XX0XXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 8192): + end_mask = "001XXXXX0XXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 16384): + end_mask = "001XXXXXXXXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 32768): + end_mask = "001XXXXXXXXXXXXX0XX" + str(end_mask) + elif (nb_destinations == 64 * 65536): + end_mask = "001XXXXXXXXXXXXXXXX" + str(end_mask) + + if (traffic == 0): # One-to-one. From odd interface to even interface and vice versa, no QPI cross + mask1 = str(mask) + "001" + str(end_mask) + mask2 = str(mask) + "000" + str(end_mask) + mask3 = str(mask) + "011" + str(end_mask) + mask4 = str(mask) + "010" + str(end_mask) + mask5 = str(mask) + "101" + str(end_mask) + mask6 = str(mask) + "100" + str(end_mask) + mask7 = str(mask) + "111" + str(end_mask) + mask8 = str(mask) + "110" + str(end_mask) + + elif (traffic == 1): # Full mesh within QPI (i.e. 1 to 4) + mask1 = str(mask) + "0XX" + str(end_mask) + mask2 = str(mask) + "0XX" + str(end_mask) + mask3 = str(mask) + "0XX" + str(end_mask) + mask4 = str(mask) + "0XX" + str(end_mask) + mask5 = str(mask) + "1XX" + str(end_mask) + mask6 = str(mask) + "1XX" + str(end_mask) + mask7 = str(mask) + "1XX" + str(end_mask) + mask8 = str(mask) + "1XX" + str(end_mask) + + elif (traffic == 2): # One to one, crossing QPI (100% QPI) + mask1 = str(mask) + "100" + str(end_mask) + mask2 = str(mask) + "101" + str(end_mask) + mask3 = str(mask) + "110" + str(end_mask) + mask4 = str(mask) + "111" + str(end_mask) + mask5 = str(mask) + "000" + str(end_mask) + mask6 = str(mask) + "001" + str(end_mask) + mask7 = str(mask) + "010" + str(end_mask) + mask8 = str(mask) + "011" + str(end_mask) + + elif (traffic == 3): # 1 to 4 crossing QPI (100% QPI) + mask1 = str(mask) + "1XX" + str(end_mask) + mask2 = str(mask) + "1XX" + str(end_mask) + mask3 = str(mask) + "1XX" + str(end_mask) + mask4 = str(mask) + "1XX" + str(end_mask) + mask5 = str(mask) + "0XX" + str(end_mask) + mask6 = str(mask) + "0XX" + str(end_mask) + mask7 = str(mask) + "0XX" + str(end_mask) + mask8 = str(mask) + "0XX" + str(end_mask) + + elif (traffic == 4): # 1 to 4 (50% QPI) + mask1 = str(mask) + "XX1" + str(end_mask) + mask2 = str(mask) + "XX0" + str(end_mask) + mask3 = str(mask) + "XX1" + str(end_mask) + mask4 = str(mask) + "XX0" + str(end_mask) + mask5 = str(mask) + "XX1" + str(end_mask) + mask6 = str(mask) + "XX0" + str(end_mask) + mask7 = str(mask) + "XX1" + str(end_mask) + mask8 = str(mask) + "XX0" + str(end_mask) + + elif (traffic == 5): # Full mesh (50% QPI) + mask1 = str(mask) + "XXX" + str(end_mask) + mask2 = str(mask) + "XXX" + str(end_mask) + mask3 = str(mask) + "XXX" + str(end_mask) + mask4 = str(mask) + "XXX" + str(end_mask) + mask5 = str(mask) + "XXX" + str(end_mask) + mask6 = str(mask) + "XXX" + str(end_mask) + mask7 = str(mask) + "XXX" + str(end_mask) + mask8 = str(mask) + "XXX" + str(end_mask) + + for c in tx_port0: + send_all_random([c], 30, mask1, 4) + for c in tx_port1: + send_all_random([c], 30, mask2, 4) + for c in tx_port2: + send_all_random([c], 30, mask3, 4) + for c in tx_port3: + send_all_random([c], 30, mask4, 4) + for c in tx_port4: + send_all_random([c], 30, mask5, 4) + for c in tx_port5: + send_all_random([c], 30, mask6, 4) + for c in tx_port6: + send_all_random([c], 30, mask7, 4) + for c in tx_port7: + send_all_random([c], 30, mask8, 4) + for c in tx_cores: + send_all_random([c], 34, "0XXXXXXXXXXXXX10", 2) + send_all_random([c], 36, "0XXXXXXXXXXXXX10", 2) + +#======================================================================== +class TestDefinition(): + "Stores test parameters" + def __init__(self, use_case, next_hops, number_routes, pkt_size, traffic, reload): + self.use_case = use_case + self.next_hops = next_hops + self.number_routes = number_routes + self.pkt_size = pkt_size + self.traffic = traffic + self.reload = reload + +#======================================================================== +# Use case 0 increases input load and measure output load => show dropped packets at low loads, show overload behavior +# Use case 1 and use case 2 run dichotomic searches, searching for 0 packet loss (or whaever loss is configured) +# Use case 1 shows the effect of number of routes and next-hops +# Use case 2 shows the effect of the number of destination, using a fixed (low) number of routes and next-hops +#======================================================================== +def run_use_case(use_case, number_next_hops, number_routes, pkt_size, traffic, reload): + if (reload): + if (use_case == 2): + config = "config.1_1" + "_" + str(use_case) + ".boot" + else: + config = "config." + str(number_routes) + "_" + str(number_next_hops) + ".boot" + reload_vRouter_config(config) + send_reset_random() + send_reset_value() + set_destination_ip(use_case, number_routes, traffic) + set_pkt_sizes(tx_cores, pkt_size) + print "Running test with pkt size= " + str(pkt_size) + " Next hops = " + str(number_next_hops) + "; number of routes = " + str(number_routes) + "; Traffic = " + str(traffic) + " \n" + if (use_case == 0): + run_loss_graph(number_next_hops, number_routes, pkt_size, traffic) + else: + run_dicho_search(number_next_hops, number_routes, pkt_size, traffic) + sleep(3) + +#======================================================================== +def run_all_use_cases(): + use_case_nb = 1 + # Connect to dppd + file_path = '/tmp/prox.sock' + sock.connect(file_path) + + f.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f_all.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f_minimal.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f.flush(); + f_all.flush(); + f_minimal.flush(); + + # Starting tests + print "Stopping all cores and resetting all values and randoms before starting\n" + sock.sendall("stop all") + sock.sendall("reset stats\n") + sleep(3); + for line in file_tests: + info = line.split(';') + if (info[0][0] == '#'): + continue + if (info[0][0] == ''): + break + use_case = int(info[0]) + next_hops = int(info[1]) + number_routes = int(info[2]) + pkt_size = int(info[3]) + traffic = int(info[4]) + reload = int(info[5]) + print str(use_case_nb) + " : Running use case " + str(use_case) + " next_hops = " + str(next_hops) + " routes = " + str(number_routes) + " pkt_size = " + str(pkt_size) + " traffic = " + str(traffic) + " reload = " + str(reload) + run_use_case(use_case, next_hops, number_routes, pkt_size, traffic, reload) + use_case_nb = use_case_nb + 1 + +#======================================================================== +def configure_use_case(use_case): + Tests = [] + if (use_case == 0): + for pkt_size in all_pkt_size: + Tests.append(TestDefinition("0", "1", "1", pkt_size, "0", "1")) + for pkt_size in all_pkt_size: + Tests.append(TestDefinition("0", "1", "1", pkt_size, "1", "1")) + if (use_case == 1): + number_next_hops = 1 + reload = 0 + + number_routes = number_next_hops # At least same number of routes that number of next hops + while number_routes <= max_number_routes: + reload = 1 + for traffic in range(6): + for pkt_size in all_pkt_size: + Tests.append(TestDefinition(use_case, number_next_hops, number_routes, pkt_size, traffic, reload)) + reload = 0 + if (number_routes < max_number_routes / 2): + number_routes = number_routes * 4 + else: + number_routes = number_routes * 2 + + number_routes = max_number_next_hops + while number_next_hops <= max_number_next_hops: + reload = 1 + for traffic in range(6): + for pkt_size in all_pkt_size: + Tests.append(TestDefinition(use_case, number_next_hops, number_routes, pkt_size, traffic, reload)) + reload = 0 + number_next_hops = number_next_hops * 2 + if (use_case == 2): + number_next_hops = 1 + reload = 1 + for traffic in range(6): + nb_destinations = 1 + while nb_destinations <= max_number_addresses_local_network: + for pkt_size in all_pkt_size: + Tests.append(TestDefinition(use_case, number_next_hops, nb_destinations, pkt_size, traffic, reload)) + reload = 0 + nb_destinations = nb_destinations * 2 + reload = 1 + + file_tests = open('test_description.txt', 'w') + file_tests.write("# Use case; next_hops; routes; pkt_size; traffic; reload;\n") + for test in Tests: + file_tests.write(str(test.use_case) + "; " + str(test.next_hops) + "; " + str(test.number_routes) + "; " + str(test.pkt_size) + "; " + str(test.traffic) + "; " + str(test.reload) + ";\n") + file_tests.close() + +#======================================================================== +if ((configure == 0) and (run == 0)): + print "Nothing to do - please use -r 1 or -c 1" +if (configure == 1): + configure_use_case(use_case) +if (run == 1): + print "****************************************************************************************************************" + print "** Running vRouter Characterization with " + str(test_duration) + " seconds steps and starting at " + str(init_speed) + " percent of line rate **" + print "****************************************************************************************************************" + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + f_all = open('all_results.txt', 'w') + f = open('detailed_results.txt', 'w') + f_minimal = open('minimal_results.txt', 'w') + file_tests = open('test_description.txt', 'r') + run_all_use_cases() + f.close(); + sock.close(); diff --git a/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_vRouter_4_ports.py b/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_vRouter_4_ports.py new file mode 100755 index 00000000..95eb9811 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/testvRouter/characterize_vRouter_4_ports.py @@ -0,0 +1,681 @@ +#!/bin/env 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 socket +import sys +import os +from time import * +from datetime import datetime +from optparse import OptionParser +import time +from remote_system import * +from math import log + +# General parameters +accuracy = 0.1 # in percent of line rate +max_dropped = 0.001 # in percent +all_pkt_size = [64,128,256,512,1024,1280,1518] +#all_pkt_size = [64] + +# vRouter parameters, in case commands must be sent +vRouter_host = "192.168.1.96" + +# Stear parameters +step_time = 0.01 # in seconds +step_delta = 0.025 # in percent of line rate + +# Use case dependent parameters +##### Use case 0: influence of number of routes and next hops ##### +max_number_next_hops = 256 # Maximum number of next-hops per interface +max_number_routes = 8192 # Maximum number of routes per interface +max_number_addresses_local_network = 262144 + +##### Use case 1: packet loss and latency ##### +low_steps_delta_for_loss = 0.01 # Use increment of 0.01% from 0 to low_steps +medium_steps_delta_for_loss = 0.1 # Use increment of 0.1% from low_steps to medium_steps +normal_steps_delta_for_loss = 1.0 # Use increment of 1% from medium_steps till 100% +low_steps = 0.1 +medium_steps = 1.0 + +# Prox parameters +tx_port0 = [19,27,55,63] +tx_port1 = [20,28,56,64] +tx_port2 = [21,29,57,65] +tx_port3 = [22,30,58,66] +tx_port4 = [] +tx_port5 = [] +tx_port6 = [] +tx_port7 = [] +tx_task = 0 + +all_rx_cores = [23,24,25,26] +rx_lat_cores = [23,24,25,26] +rx_task = 1 + +# Some variables, do not change + +# Program arguments +parser = OptionParser() +parser.add_option("-d", "--duration", dest="test_duration", help="Duration of each steps", metavar="integer", default=10) +parser.add_option("-s", "--speed", dest="init_speed", help="Initial speed", metavar="integer", default=100) +parser.add_option("-u", "--use-case", dest="use_case", help="Use Case Number", metavar="integer", default=0) +parser.add_option("-r", "--run", dest="run", help="Run test", metavar="integer", default=0) +parser.add_option("-c", "--configure", dest="configure", help="Configure Test", metavar="integer", default=0) +(options, args) = parser.parse_args() + +init_speed = int(options.init_speed) +test_duration = int(options.test_duration) +use_case = int(options.use_case) +configure = int(options.configure) +run = int(options.run) + +nb_cores_per_interface = len(tx_port0) +max_speed = (100.0/nb_cores_per_interface) +init_speed = (init_speed * 1.0/nb_cores_per_interface) +accuracy = (accuracy * 1.0/nb_cores_per_interface) +normal_steps_delta_for_loss = (normal_steps_delta_for_loss /nb_cores_per_interface) +medium_steps_delta_for_loss = (medium_steps_delta_for_loss /nb_cores_per_interface) +low_steps_delta_for_loss = (low_steps_delta_for_loss /nb_cores_per_interface) +medium_steps = (medium_steps /nb_cores_per_interface) +low_steps = (low_steps /nb_cores_per_interface) + +max_dropped = max_dropped / 100 + +def to_str(arr): + ret = "" + first = 1; + for a in arr: + if (first == 0): + ret += "," + + ret += str(a) + first = 0; + return ret; + +tx_cores = tx_port0 + tx_port1 + tx_port2 + tx_port3 + tx_port4 + tx_port5 + tx_port6 + tx_port7 + +def send_all_pkt_size(cores, pkt_size): + for c in cores: + sock.sendall("pkt_size " + str(c) + " 0 " + str(pkt_size) + "\n"); + +def send_all_value(cores, offset, value, len): + for c in cores: + sock.sendall("set value " + str(c) + " 0 " + str(offset) + " " + str(value) + " " + str(len)+ "\n"); + +def send_all_random(cores, offset, rand_str, len): + for c in cores: + sock.sendall("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); + #print("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); + +def send_all_speed(cores, speed_perc): + for c in cores: + sock.sendall("speed " + str(c) + " 0 " + str(speed_perc) + "\n"); + +def send_reset_random(): + sock.sendall("reset randoms all" + "\n"); + +def send_reset_value(): + sock.sendall("reset values all" + "\n"); + +def rx_stats(tx_cores, tx_task, rx_cores, rx_task): + rx = tx = drop = tsc = tsc_hs = ierrors = 0 + for e in tx_cores: + sock.sendall("core stats " + str(e) + " " + str(tx_task) + "\n") + recv = recv_once() + rx += int(recv.split(",")[0]) + tx += int(recv.split(",")[1]) + drop += int(recv.split(",")[2]) + tsc = int(recv.split(",")[3]) + tsc_hz = int(recv.split(",")[4]) + for e in rx_cores: + sock.sendall("core stats " + str(e) + " " + str(rx_task) + "\n") + recv = recv_once() + rx += int(recv.split(",")[0]) + tx += int(recv.split(",")[1]) + drop += int(recv.split(",")[2]) + tsc = int(recv.split(",")[3]) + tsc_hz = int(recv.split(",")[4]) + # Also get the ierrors as generators might be the bottleneck... + sock.sendall("tot ierrors tot\n") + recv = recv_once() + ierrors += int(recv.split(",")[0]) + rx+=ierrors + return rx,tx,drop,tsc,tsc_hz + +def lat_stats(cores,task): + lat_min = [0 for e in range(127)] + lat_max = [0 for e in range(127)] + lat_avg = [0 for e in range(127)] + for e in cores: + sock.sendall("lat stats " + str(e) + " " + str(task) + " " + "\n") + recv = recv_once() + lat_min[e] = int(recv.split(",")[0]) + lat_max[e] = int(recv.split(",")[1]) + lat_avg[e] = int(recv.split(",")[2]) + return lat_min, lat_max, lat_avg + +def recv_once(): + ret_str = ""; + done = 0; + while done == 0: + dat = sock.recv(256); + i = 0; + while(i < len(dat)): + if (dat[i] == '\n'): + done = 1 + else: + ret_str += dat[i]; + i = i + 1; + return ret_str + +def wait_vRouter_restarted(host): + while (1): + ret = os.system("ping " + host + " -c 1 > /dev/null") + if ret == 0: + print "still up..." + else: + break; + sleep(1) + + while (1): + ret = os.system("ping " + host + " -c 1 > /dev/null") + if (ret == 0): + print "UP" + break; + else: + print "still down..." + sleep(1) + +def reload_vRouter_config(config): + print "connecting to vRouter...and copying " + str(config) + sut = remote_system("root", vRouter_host) + cmd = "cp /config/prox/" + str(config) + " /config/config.boot" + sut.run(cmd) + print "Rebooting system at " + str(datetime.now().time()) + sut.run_forked("reboot") + sleep(5) + wait_vRouter_restarted(vRouter_host) + print "Waiting for last startup scripts to start..." + last_script = "l2tp" + while(1): + dmesg = str(sut.run("dmesg")) + if last_script in dmesg: + print "found l2tp - UP" + break; + sleep(1) + print "vRouter started - waiting 5 last seconds before starting test" + sleep(5) + print datetime.now().time() + +def set_pkt_sizes(tx_cores, p): + send_all_pkt_size(tx_cores, p-4) + # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size + send_all_value(tx_cores, 16, p - 18, 2) # 14 for MAC (12) EthType (2) + send_all_value(tx_cores, 38, p - 38, 2) # 34 for MAC (12) EthType (2) IP (20) + +def run_measure_throughput(speed): + done = 0 + # Intialize tests by stopping cores and resetting stats + step=0 + steps_done = 0 + sock.sendall("start " + to_str(all_rx_cores) + "\n") + sleep(2) + sock.sendall("stop " + to_str(all_rx_cores) + "\n") + sock.sendall("reset stats\n") + print "Speed = " + str(speed * nb_cores_per_interface) + sleep(1); + + send_all_speed(tx_cores, step); + + # Now starting the steps. First go to the common speed, then increase steps for the faster one. + sock.sendall("start " + to_str(tx_cores) + "," + to_str(rx_lat_cores) + "\n") + while (steps_done == 0): + sleep(step_time) + if (step + step_delta <= speed): + step+=step_delta + else: + steps_done = 1; + send_all_speed(tx_cores, step) + + # Steps are now OK. Set speed + send_all_speed(tx_cores, speed); + sleep(2); + + # Getting statistics to calculate PPS at right speed.... + rx_pps_beg,tx_pps_beg,drop_pps_beg,tsc_pps_beg,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + sleep(test_duration); + + # Collect statistics before test stops...and stop the test. Important to get stats before stopping as stops take some time... + rx_pps_end,tx_pps_end,drop_pps_end,tsc_pps_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + lat_min,lat_max,lat_avg = lat_stats(rx_lat_cores, rx_task) + sock.sendall("stop " + "," + to_str(tx_cores) + "\n") + sock.sendall("start " + to_str(all_rx_cores) + "\n") + sleep(3); + sock.sendall("stop " + to_str(all_rx_cores) + "\n") + + rx_end, tx_end,drop_end,tsc_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); + rx = rx_pps_end - rx_pps_beg + tsc = tsc_pps_end - tsc_pps_beg + mpps = rx / (tsc/float(tsc_hz)) / 1000000 + tx = tx_pps_end - tx_pps_beg + tx_mpps = tx / (tsc/float(tsc_hz)) / 1000000 + + #print "Runtime = " + str((tsc)/float(tsc_hz)); + if (tx_end == 0): + dropped_tot = tx_end - rx_end + dropped_pct = 0 + else: + dropped_tot = tx_end - rx_end + dropped_pct = ((dropped_tot) * 1.0) / tx_end + + if (dropped_tot > 0): + if (dropped_pct >= max_dropped): + print "** FAILED **: lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + else: + print "OK but lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + else: + if (dropped_tot < 0): + print "Something wrong happened - received more packets than transmitted" + else: + print "** OK **: RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) + print "MPPS = " + str(mpps) + print "====================================================" + return dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg + +def write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg): + f.write(str(pkt_size) + "; " + str(tx_mpps) + "; " + str(mpps) + "; " + str(100 * dropped_pct) + "; " + str(dropped_tot) + "; " + str(speed * nb_cores_per_interface) + "; " + str(number_next_hops) + "; " + str(number_routes) + "; " + str(traffic) + "; ") + for e in rx_lat_cores: + f.write(str(lat_min[e]) + "; " + str(lat_max[e]) + "; " + str(lat_avg[e]) + "; ") + f.write("\n"); + f.flush() + +def run_loss_graph(number_next_hops, number_routes, pkt_size, traffic): + speed = init_speed * 1.0 + done = 0; + while done == 0: + dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed) + write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + if (speed <= low_steps_delta_for_loss): + done = 1 + return + if (speed >= (medium_steps+normal_steps_delta_for_loss)): + speed -= normal_steps_delta_for_loss + else: + if (speed >= (low_steps+medium_steps_delta_for_loss)): + speed -= medium_steps_delta_for_loss + else: + speed -= low_steps_delta_for_loss + +def run_dicho_search(number_next_hops, number_routes, pkt_size, traffic): + previous_success_speed = 0.0 + previous_error_speed = max_speed + speed = init_speed * 1.0 + done = 0; + good_tx_mpps = 0 + good_mpps = 0 + good_dropped_pct = 0 + good_dropped_tot = 0 + good_speed = 0 + good_lat_min = [0 for e in range(127)] + good_lat_max = [0 for e in range(127)] + good_lat_avg = [0 for e in range(127)] + + while done == 0: + dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed) + if ((dropped_tot >= 0) and (dropped_pct <= max_dropped)): + good_tx_mpps = tx_mpps + good_mpps = mpps + good_dropped_pct = dropped_pct + good_dropped_tot = dropped_tot + good_speed = speed + good_lat_min = lat_min + good_lat_max = lat_max + good_lat_avg = lat_avg + write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + else: + write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + + if ((speed == max_speed) and (dropped_pct <= max_dropped)): + write_results(f_minimal, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, lat_min, lat_max, lat_avg); + done = 1 + if (dropped_pct <= max_dropped): + previous_success_speed = speed + if (speed > max_speed - accuracy): + speed = max_speed + else: + if (previous_error_speed - speed < accuracy): + write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, good_lat_min, good_lat_max, good_lat_avg); + done = 1 + else: + speed = speed + (previous_error_speed - speed)/2; + else: + previous_error_speed = speed + if (speed - previous_success_speed < accuracy): + write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_next_hops, number_routes, traffic, good_lat_min, good_lat_max, good_lat_avg); + done = 1 + else: + speed = speed - (speed - previous_success_speed) / 2; + + +def set_destination_ip(use_case, nb_destinations, traffic): + # minimmum 8 routes i.e. 1 per interface + # Destination addressese: "00XXXYY1" "Z00ZZ0ZZ" "AA0AA0AA" "BBBBBB10" + # Where X = interface id. Starting with 00 to be in class A and skipping 0.x.y.z and 127.x.y.z + # Y, Z and A = additional routes + # B = IP in routes. 10 to avoid x.y.z.0 and x.y.z.255 + # Gaps in A and B to void "too good" distributions e.g. using LPM and + # First changing Y + + mask = "" + for i in range (2): + mask = str(mask)+"0" + end_mask = "" + if (use_case != 2): + end_mask = "XXXXXX10" # Last 8 bits + + if (nb_destinations == 1): + end_mask = "0010000000000000000" + str(end_mask) + if (nb_destinations == 2): + end_mask = "X010000000000000000" + str(end_mask) + if (nb_destinations == 4): + end_mask = "XX10000000000000000" + str(end_mask) + if (nb_destinations == 8): + end_mask = "XX1X000000000000000" + str(end_mask) + elif (nb_destinations == 16): + end_mask = "XX1X00X000000000000" + str(end_mask) + elif (nb_destinations == 32): + end_mask = "XX1X00XX00000000000" + str(end_mask) + elif (nb_destinations == 64): + end_mask = "XX1X00XX0X000000000" + str(end_mask) + elif (nb_destinations == 128): + end_mask = "XX1X00XX0XX00000000" + str(end_mask) + elif (nb_destinations == 256): + end_mask = "XX1X00XX0XXX0000000" + str(end_mask) + elif (nb_destinations == 512): + end_mask = "XX1X00XX0XXXX000000" + str(end_mask) + elif (nb_destinations == 1024): + end_mask = "XX1X00XX0XXXX0X0000" + str(end_mask) + elif (nb_destinations == 2048): + end_mask = "XX1X00XX0XXXX0XX000" + str(end_mask) + elif (nb_destinations == 4096): + end_mask = "XX1X00XX0XXXX0XX0X0" + str(end_mask) + elif (nb_destinations == 8192): + end_mask = "XX1X00XX0XXXX0XX0XX" + str(end_mask) + else: + if (nb_destinations <= 64 * 1): + end_mask = "0010000000000000000" + n_dest = int(log(nb_destinations, 2)) + for i in range (n_dest): + end_mask = str(end_mask) + "X" + for i in range (6 - n_dest): + end_mask = str(end_mask) + "0" + end_mask = str(end_mask) + "10" + else: + end_mask = "XXXXXX10" # Last 8 bits + + if (nb_destinations == 64 * 2): + end_mask = "001X000000000000000" + str(end_mask) + elif (nb_destinations == 64 * 4): + end_mask = "001X00X000000000000" + str(end_mask) + elif (nb_destinations == 64 * 8): + end_mask = "001X00XX00000000000" + str(end_mask) + elif (nb_destinations == 64 * 16): + end_mask = "001X00XX0X000000000" + str(end_mask) + elif (nb_destinations == 64 * 32): + end_mask = "001X00XX0XX00000000" + str(end_mask) + elif (nb_destinations == 64 * 64): + end_mask = "001X00XX0XXX0000000" + str(end_mask) + elif (nb_destinations == 64 * 128): + end_mask = "001X00XX0XXXX000000" + str(end_mask) + elif (nb_destinations == 64 * 256): + end_mask = "001X00XX0XXXX0X0000" + str(end_mask) + elif (nb_destinations == 64 * 512): + end_mask = "001X00XX0XXXX0XX000" + str(end_mask) + elif (nb_destinations == 64 * 1024): + end_mask = "001X00XX0XXXX0XX0X0" + str(end_mask) + elif (nb_destinations == 64 * 2048): + end_mask = "001X00XX0XXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 4096): + end_mask = "001XX0XX0XXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 8192): + end_mask = "001XXXXX0XXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 16384): + end_mask = "001XXXXXXXXXX0XX0XX" + str(end_mask) + elif (nb_destinations == 64 * 32768): + end_mask = "001XXXXXXXXXXXXX0XX" + str(end_mask) + elif (nb_destinations == 64 * 65536): + end_mask = "001XXXXXXXXXXXXXXXX" + str(end_mask) + + if (traffic == 0): # One-to-one. From odd interface to even interface and vice versa, no QPI cross + mask1 = str(mask) + "001" + str(end_mask) + mask2 = str(mask) + "000" + str(end_mask) + mask3 = str(mask) + "011" + str(end_mask) + mask4 = str(mask) + "010" + str(end_mask) + mask5 = str(mask) + "101" + str(end_mask) + mask6 = str(mask) + "100" + str(end_mask) + mask7 = str(mask) + "111" + str(end_mask) + mask8 = str(mask) + "110" + str(end_mask) + + elif (traffic == 1): # Full mesh within QPI (i.e. 1 to 4) + mask1 = str(mask) + "0XX" + str(end_mask) + mask2 = str(mask) + "0XX" + str(end_mask) + mask3 = str(mask) + "0XX" + str(end_mask) + mask4 = str(mask) + "0XX" + str(end_mask) + mask5 = str(mask) + "1XX" + str(end_mask) + mask6 = str(mask) + "1XX" + str(end_mask) + mask7 = str(mask) + "1XX" + str(end_mask) + mask8 = str(mask) + "1XX" + str(end_mask) + + elif (traffic == 2): # One to one, crossing QPI (100% QPI) + mask1 = str(mask) + "100" + str(end_mask) + mask2 = str(mask) + "101" + str(end_mask) + mask3 = str(mask) + "110" + str(end_mask) + mask4 = str(mask) + "111" + str(end_mask) + mask5 = str(mask) + "000" + str(end_mask) + mask6 = str(mask) + "001" + str(end_mask) + mask7 = str(mask) + "010" + str(end_mask) + mask8 = str(mask) + "011" + str(end_mask) + + elif (traffic == 3): # 1 to 4 crossing QPI (100% QPI) + mask1 = str(mask) + "1XX" + str(end_mask) + mask2 = str(mask) + "1XX" + str(end_mask) + mask3 = str(mask) + "1XX" + str(end_mask) + mask4 = str(mask) + "1XX" + str(end_mask) + mask5 = str(mask) + "0XX" + str(end_mask) + mask6 = str(mask) + "0XX" + str(end_mask) + mask7 = str(mask) + "0XX" + str(end_mask) + mask8 = str(mask) + "0XX" + str(end_mask) + + elif (traffic == 4): # 1 to 4 (50% QPI) + mask1 = str(mask) + "XX1" + str(end_mask) + mask2 = str(mask) + "XX0" + str(end_mask) + mask3 = str(mask) + "XX1" + str(end_mask) + mask4 = str(mask) + "XX0" + str(end_mask) + mask5 = str(mask) + "XX1" + str(end_mask) + mask6 = str(mask) + "XX0" + str(end_mask) + mask7 = str(mask) + "XX1" + str(end_mask) + mask8 = str(mask) + "XX0" + str(end_mask) + + elif (traffic == 5): # Full mesh (50% QPI) + mask1 = str(mask) + "XXX" + str(end_mask) + mask2 = str(mask) + "XXX" + str(end_mask) + mask3 = str(mask) + "XXX" + str(end_mask) + mask4 = str(mask) + "XXX" + str(end_mask) + mask5 = str(mask) + "XXX" + str(end_mask) + mask6 = str(mask) + "XXX" + str(end_mask) + mask7 = str(mask) + "XXX" + str(end_mask) + mask8 = str(mask) + "XXX" + str(end_mask) + + for c in tx_port0: + send_all_random([c], 30, mask1, 4) + for c in tx_port1: + send_all_random([c], 30, mask2, 4) + for c in tx_port2: + send_all_random([c], 30, mask3, 4) + for c in tx_port3: + send_all_random([c], 30, mask4, 4) + for c in tx_port4: + send_all_random([c], 30, mask5, 4) + for c in tx_port5: + send_all_random([c], 30, mask6, 4) + for c in tx_port6: + send_all_random([c], 30, mask7, 4) + for c in tx_port7: + send_all_random([c], 30, mask8, 4) + for c in tx_cores: + send_all_random([c], 34, "0XXXXXXXXXXXXX10", 2) + send_all_random([c], 36, "0XXXXXXXXXXXXX10", 2) + +#======================================================================== +class TestDefinition(): + "Stores test parameters" + def __init__(self, use_case, next_hops, number_routes, pkt_size, traffic, reload): + self.use_case = use_case + self.next_hops = next_hops + self.number_routes = number_routes + self.pkt_size = pkt_size + self.traffic = traffic + self.reload = reload + +#======================================================================== +# Use case 0 increases input load and measure output load => show dropped packets at low loads, show overload behavior +# Use case 1 and use case 2 run dichotomic searches, searching for 0 packet loss (or whaever loss is configured) +# Use case 1 shows the effect of number of routes and next-hops +# Use case 2 shows the effect of the number of destination, using a fixed (low) number of routes and next-hops +#======================================================================== +def run_use_case(use_case, number_next_hops, number_routes, pkt_size, traffic, reload): + if (reload): + if (use_case == 2): + config = "config.1_1" + "_" + str(use_case) + ".boot" + else: + config = "config." + str(number_routes) + "_" + str(number_next_hops) + ".boot" + reload_vRouter_config(config) + send_reset_random() + send_reset_value() + set_destination_ip(use_case, number_routes, traffic) + set_pkt_sizes(tx_cores, pkt_size) + print "Running test with pkt size= " + str(pkt_size) + " Next hops = " + str(number_next_hops) + "; number of routes = " + str(number_routes) + "; Traffic = " + str(traffic) + " \n" + if (use_case == 0): + run_loss_graph(number_next_hops, number_routes, pkt_size, traffic) + else: + run_dicho_search(number_next_hops, number_routes, pkt_size, traffic) + sleep(3) + +#======================================================================== +def run_all_use_cases(): + use_case_nb = 1 + # Connect to dppd + file_path = '/tmp/prox.sock' + sock.connect(file_path) + + f.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f_all.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f_minimal.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") + f.flush(); + f_all.flush(); + f_minimal.flush(); + + # Starting tests + print "Stopping all cores and resetting all values and randoms before starting\n" + sock.sendall("stop all") + sock.sendall("reset stats\n") + sleep(3); + for line in file_tests: + info = line.split(';') + if (info[0][0] == '#'): + continue + if (info[0][0] == ''): + break + use_case = int(info[0]) + next_hops = int(info[1]) + number_routes = int(info[2]) + pkt_size = int(info[3]) + traffic = int(info[4]) + reload = int(info[5]) + print str(use_case_nb) + " : Running use case " + str(use_case) + " next_hops = " + str(next_hops) + " routes = " + str(number_routes) + " pkt_size = " + str(pkt_size) + " traffic = " + str(traffic) + " reload = " + str(reload) + run_use_case(use_case, next_hops, number_routes, pkt_size, traffic, reload) + use_case_nb = use_case_nb + 1 + +#======================================================================== +def configure_use_case(use_case): + Tests = [] + if (use_case == 0): + for pkt_size in all_pkt_size: + Tests.append(TestDefinition("0", "1", "1", pkt_size, "0", "1")) + for pkt_size in all_pkt_size: + Tests.append(TestDefinition("0", "1", "1", pkt_size, "1", "1")) + if (use_case == 1): + number_next_hops = 1 + reload = 0 + + number_routes = number_next_hops # At least same number of routes that number of next hops + while number_routes <= max_number_routes: + reload = 1 + for traffic in range(6): + for pkt_size in all_pkt_size: + Tests.append(TestDefinition(use_case, number_next_hops, number_routes, pkt_size, traffic, reload)) + reload = 0 + if (number_routes < max_number_routes / 2): + number_routes = number_routes * 4 + else: + number_routes = number_routes * 2 + + number_routes = max_number_next_hops + while number_next_hops <= max_number_next_hops: + reload = 1 + for traffic in range(6): + for pkt_size in all_pkt_size: + Tests.append(TestDefinition(use_case, number_next_hops, number_routes, pkt_size, traffic, reload)) + reload = 0 + number_next_hops = number_next_hops * 2 + if (use_case == 2): + number_next_hops = 1 + reload = 1 + for traffic in range(6): + nb_destinations = 1 + while nb_destinations <= max_number_addresses_local_network: + for pkt_size in all_pkt_size: + Tests.append(TestDefinition(use_case, number_next_hops, nb_destinations, pkt_size, traffic, reload)) + reload = 0 + nb_destinations = nb_destinations * 2 + reload = 1 + + file_tests = open('test_description.txt', 'w') + file_tests.write("# Use case; next_hops; routes; pkt_size; traffic; reload;\n") + for test in Tests: + file_tests.write(str(test.use_case) + "; " + str(test.next_hops) + "; " + str(test.number_routes) + "; " + str(test.pkt_size) + "; " + str(test.traffic) + "; " + str(test.reload) + ";\n") + file_tests.close() + +#======================================================================== +if ((configure == 0) and (run == 0)): + print "Nothing to do - please use -r 1 or -c 1" +if (configure == 1): + configure_use_case(use_case) +if (run == 1): + print "****************************************************************************************************************" + print "** Running vRouter Characterization with " + str(test_duration) + " seconds steps and starting at " + str(init_speed) + " percent of line rate **" + print "****************************************************************************************************************" + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + f_all = open('all_results.txt', 'w') + f = open('detailed_results.txt', 'w') + f_minimal = open('minimal_results.txt', 'w') + file_tests = open('test_description.txt', 'r') + run_all_use_cases() + f.close(); + sock.close(); diff --git a/VNFs/DPPD-PROX/helper-scripts/testvRouter/create_interfaces_and_routes.pl b/VNFs/DPPD-PROX/helper-scripts/testvRouter/create_interfaces_and_routes.pl new file mode 100755 index 00000000..b8baa46b --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/testvRouter/create_interfaces_and_routes.pl @@ -0,0 +1,90 @@ +#!/bin/env perl + +## +## 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. +## + +# This script creates four sets of files: 2 sets for use case 0 and 1 +# (which use the same configuration) and 2 for use case 2. +# Each use case is defined by 2 sets of configuration files. +# interface.txt contains the IP addresses of the DPDK fast path interfaces. +# route.x.y.txt contains the routing table for different configurations +# with x being number of routes and y number of next_hops. +# Those interface.txt and route.x.y.txt files should then be converted +# to fit the syntax of vRouter configuration files. + +use strict; +my $max_nb_routes = 8192; +my $max_nb_next_hops = 1024; +my $max_nb_interfaces = 4; +my $nb_next_hops = 1; +my ($interface, $a1, $a2, $a3, $a4, $fh, $output_route); + +# Create interface configuration for use case 0 and 1 +my $interface_config = "interface.txt"; +open($fh, '>', $interface_config) or die "Could not open file '$interface_config' $!"; +print $fh "# interface IP address/prefix\n"; +for ($interface = 0; $interface < $max_nb_interfaces; $interface++) { + print $fh ($interface+64).".0.0.240/24\n"; +} +close $fh; + +# Create interface configuration for use case 2 +my $interface_config = "interface_use_case_2.txt"; +open($fh, '>', $interface_config) or die "Could not open file '$interface_config' $!"; +print $fh "# interface IP address/prefix\n"; +for ($interface = 0; $interface < $max_nb_interfaces; $interface++) { + print $fh ($interface * 8 + 1).".0.0.240/5\n"; +} +close $fh; + +# Create routes configuration for use case 0 and 1 +while ($nb_next_hops <= $max_nb_next_hops) { + my $nb_routes_per_interface = $nb_next_hops; + while ($nb_routes_per_interface <= $max_nb_routes) { + $output_route = "route.".$nb_routes_per_interface.".".$nb_next_hops.".txt"; + open($fh, '>', $output_route) or die "Could not open file '$output_route' $!"; + print $fh "# destination/prefix;nex-hop\n"; + + for (my $route_nb = 0; $route_nb < $nb_routes_per_interface; $route_nb++) { + for ($interface = 0; $interface < $max_nb_interfaces; $interface++) { + $a1 = $interface * 8 + 1 + (($route_nb & 1) << 2) + ($route_nb & 2); + $a2 = (($route_nb & 4) << 5) + (($route_nb & 8) << 1) + (($route_nb & 0x10) >> 1) + (($route_nb & 0x20) >> 4) + (($route_nb & 0x40) >> 6); + $a3 = (($route_nb & 0x80)) + (($route_nb & 0x100) >> 2) + (($route_nb & 0x200) >> 5) + (($route_nb & 0x400) >> 7) + (($route_nb & 0x800) >> 10) + (($route_nb & 0x1000) >> 12); + $a4 = 0; + print $fh $a1.".".$a2.".".$a3.".".$a4."/24;"; + print $fh ($interface+64).".0.".(($route_nb % $nb_next_hops) >> 7).".".(1 + (($route_nb % $nb_next_hops) & 0x7f)) ."\n"; + } + } + $nb_routes_per_interface = $nb_routes_per_interface * 2; + } + $nb_next_hops = $nb_next_hops * 2; +} +close $fh; + +# Create routes configuration for use case 2 +$output_route = "route.1.1.use_case_2.txt"; +open($fh, '>', $output_route) or die "Could not open file '$output_route' $!"; +print $fh "# destination/prefix;nex-hop\n"; + +for ($interface = 0; $interface < $max_nb_interfaces; $interface++) { + $a1 = $interface + 64 ; + $a2 = 0; + $a3 = 0; + $a4 = 0; + print $fh $a1.".".$a2.".".$a3.".".$a4."/24;"; + print $fh ($interface * 8 + 1).".0.0.1\n"; +} +close $fh; diff --git a/VNFs/DPPD-PROX/helper-scripts/testvRouter/remote_system.py b/VNFs/DPPD-PROX/helper-scripts/testvRouter/remote_system.py new file mode 100755 index 00000000..f00ab77b --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/testvRouter/remote_system.py @@ -0,0 +1,57 @@ +#!/bin/env 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 os +import thread +import time +import socket + +def ssh(user, ip, cmd): + # print cmd; + ssh_options = "" + ssh_options += "-o StrictHostKeyChecking=no " + ssh_options += "-o UserKnownHostsFile=/dev/null " + ssh_options += "-o LogLevel=quiet " + running = os.popen("ssh " + ssh_options + " " + user + "@" + ip + " \"" + cmd + "\""); + ret = {}; + ret['out'] = running.read().strip(); + ret['ret'] = running.close(); + if (ret['ret'] == None): + ret['ret'] = 0; + + return ret; + +def ssh_check_quit(obj, user, ip, cmd): + ret = ssh(user, ip, cmd); + if (ret['ret'] != 0): + obj._err = True; + obj._err_str = ret['out']; + exit(-1); + +class remote_system: + def __init__(self, user, ip): + self._ip = ip; + self._user = user; + def run(self, cmd): + return ssh(self._user, self._ip, cmd); + def run_forked(self, cmd): + thread.start_new_thread(ssh, (self._user, self._ip, cmd)); + return 0; + def scp(self, src, dst): + running = os.popen("scp " + self._user + "@" + self._ip + ":" + src + " " + dst); + return running.close(); |