Support for ETSI GS NFV-TST 009
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / testvRouter / characterize_vRouter.py
1 #!/bin/env python
2
3 ##
4 ## Copyright (c) 2010-2017 Intel Corporation
5 ##
6 ## Licensed under the Apache License, Version 2.0 (the "License");
7 ## you may not use this file except in compliance with the License.
8 ## You may obtain a copy of the License at
9 ##
10 ##     http://www.apache.org/licenses/LICENSE-2.0
11 ##
12 ## Unless required by applicable law or agreed to in writing, software
13 ## distributed under the License is distributed on an "AS IS" BASIS,
14 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ## See the License for the specific language governing permissions and
16 ## limitations under the License.
17 ##
18
19 import socket
20 import sys
21 import os
22 from time import *
23 from datetime import  datetime
24 from optparse import OptionParser
25 import time
26 from remote_system import *
27 from math import log
28
29 # General parameters
30 accuracy = 0.1  # in percent of line rate
31 max_dropped = 0.001             # in percent
32 all_pkt_size = [64,128,256,512,1024,1280,1518]
33 #all_pkt_size = [64]
34
35 # vRouter parameters, in case commands must be sent
36 vRouter_host = "192.168.1.96" 
37
38 # Stear parameters
39 step_time = 0.01                # in seconds
40 step_delta = 0.025              # in percent of line rate
41
42 # Use case dependent parameters
43 ##### Use case 0: influence of number of routes and next hops #####
44 max_number_next_hops = 256                      # Maximum number of next-hops per interface
45 max_number_routes = 8192                        # Maximum number of routes per interface
46 max_number_addresses_local_network = 262144
47
48 ##### Use case 1: packet loss and latency #####
49 low_steps_delta_for_loss = 0.01                 # Use increment of 0.01% from 0 to low_steps
50 medium_steps_delta_for_loss = 0.1               # Use increment of 0.1% from low_steps to medium_steps
51 normal_steps_delta_for_loss = 1.0               # Use increment of 1% from medium_steps till 100%
52 low_steps = 0.1 
53 medium_steps = 1.0 
54
55 # Prox parameters
56 tx_port4 = [19,27,55,63]
57 tx_port5 = [20,28,56,64]
58 tx_port6 = [21,29,57,65]
59 tx_port7 = [22,30,58,66]
60 tx_port2 = [23,31,59,67]
61 tx_port3 = [24,32,60,68]
62 tx_port0 = [25,33,61,69]
63 tx_port1 = [26,34,62,70]
64 tx_task = 0
65
66 all_rx_cores = [1,2,3,4,5,6,7,10]
67 rx_lat_cores = [1,2,3,4,5,6,7,10]
68 rx_task = 1
69
70 # Some variables, do not change
71
72 # Program arguments
73 parser = OptionParser()
74 parser.add_option("-d", "--duration", dest="test_duration", help="Duration of each steps", metavar="integer", default=10)
75 parser.add_option("-s", "--speed", dest="init_speed", help="Initial speed", metavar="integer", default=100)
76 parser.add_option("-u", "--use-case", dest="use_case", help="Use Case Number", metavar="integer", default=0)
77 parser.add_option("-r", "--run", dest="run", help="Run test", metavar="integer", default=0)
78 parser.add_option("-c", "--configure", dest="configure", help="Configure Test", metavar="integer", default=0)
79 (options, args) = parser.parse_args()
80
81 init_speed = int(options.init_speed)
82 test_duration = int(options.test_duration)
83 use_case = int(options.use_case)
84 configure = int(options.configure)
85 run = int(options.run)
86
87 nb_cores_per_interface = len(tx_port0)
88 max_speed = (100.0/nb_cores_per_interface)
89 init_speed = (init_speed * 1.0/nb_cores_per_interface)
90 accuracy = (accuracy * 1.0/nb_cores_per_interface)
91 normal_steps_delta_for_loss = (normal_steps_delta_for_loss /nb_cores_per_interface)
92 medium_steps_delta_for_loss = (medium_steps_delta_for_loss /nb_cores_per_interface)
93 low_steps_delta_for_loss = (low_steps_delta_for_loss /nb_cores_per_interface)
94 medium_steps = (medium_steps /nb_cores_per_interface)
95 low_steps = (low_steps /nb_cores_per_interface)
96
97 max_dropped = max_dropped / 100
98
99 def to_str(arr):
100     ret = ""
101     first = 1;
102     for a in arr:
103         if (first == 0):
104             ret += ","
105
106         ret += str(a)
107         first = 0;
108     return ret;
109
110 tx_cores = tx_port0 + tx_port1 + tx_port2 + tx_port3 + tx_port4 + tx_port5 + tx_port6 + tx_port7
111
112 def send_all_pkt_size(cores, pkt_size):
113     for c in cores:
114         sock.sendall("pkt_size " + str(c) + " 0 " + str(pkt_size) + "\n");
115
116 def send_all_value(cores, offset, value, len):
117     for c in cores:
118         sock.sendall("set value " + str(c) + " 0 " + str(offset) + " " + str(value) + " " + str(len)+ "\n");
119
120 def send_all_random(cores, offset, rand_str, len):
121     for c in cores:
122         sock.sendall("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n");
123         #print("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n");
124
125 def send_all_speed(cores, speed_perc):
126     for c in cores:
127         sock.sendall("speed " + str(c) + " 0 " + str(speed_perc) + "\n");
128
129 def send_reset_random():
130         sock.sendall("reset randoms all" + "\n");
131
132 def send_reset_value():
133         sock.sendall("reset values all" + "\n");
134
135 def rx_stats(tx_cores, tx_task, rx_cores, rx_task):
136         rx = tx = drop = tsc = tsc_hs = ierrors = 0
137         for e in tx_cores:
138                 sock.sendall("core stats " + str(e) + " " + str(tx_task) +  "\n")
139                 recv = recv_once()
140                 rx += int(recv.split(",")[0])
141                 tx += int(recv.split(",")[1])
142                 drop += int(recv.split(",")[2])
143                 tsc = int(recv.split(",")[3])
144                 tsc_hz = int(recv.split(",")[4])
145         for e in rx_cores:
146                 sock.sendall("core stats " + str(e) + " " + str(rx_task) +  "\n")
147                 recv = recv_once()
148                 rx += int(recv.split(",")[0])
149                 tx += int(recv.split(",")[1])
150                 drop += int(recv.split(",")[2])
151                 tsc = int(recv.split(",")[3])
152                 tsc_hz = int(recv.split(",")[4])
153         # Also get the ierrors as generators might be the bottleneck...
154         sock.sendall("tot ierrors tot\n")
155         recv = recv_once()
156         ierrors += int(recv.split(",")[0])
157         rx+=ierrors
158         return rx,tx,drop,tsc,tsc_hz
159
160 def lat_stats(cores,task):
161         lat_min = [0 for e in range(127)]
162         lat_max = [0 for e in range(127)]
163         lat_avg = [0 for e in range(127)]
164         for e in cores:
165                 sock.sendall("lat stats " + str(e) + " " + str(task) + " " +  "\n")
166                 recv = recv_once()
167                 lat_min[e] = int(recv.split(",")[0])
168                 lat_max[e] = int(recv.split(",")[1])
169                 lat_avg[e] = int(recv.split(",")[2])
170         return lat_min, lat_max, lat_avg
171
172 def recv_once():
173     ret_str = "";
174     done = 0;
175     while done == 0:
176         dat = sock.recv(256);
177         i = 0;
178         while(i < len(dat)):
179             if (dat[i] == '\n'):
180                 done = 1
181             else:
182                 ret_str += dat[i];
183             i = i + 1;
184     return ret_str
185
186 def wait_vRouter_restarted(host):
187         while (1):
188                 ret = os.system("ping " + host + " -c 1 > /dev/null")
189                 if ret == 0:
190                         print "still up..."
191                 else:
192                         break;
193                 sleep(1)
194         
195         while (1):
196                 ret = os.system("ping " + host + " -c 1 > /dev/null")
197                 if (ret == 0):
198                         print "UP"
199                         break;
200                 else:
201                         print "still down..."
202                         sleep(1)
203
204 def reload_vRouter_config(config):
205         print "connecting to vRouter...and copying " + str(config)
206         sut = remote_system("root", vRouter_host)
207         cmd = "cp /config/prox/" + str(config) + " /config/config.boot"
208         sut.run(cmd)
209         print "Rebooting system at " + str(datetime.now().time())
210         sut.run_forked("reboot")
211         sleep(5)
212         wait_vRouter_restarted(vRouter_host)
213         print "Waiting for last startup scripts to start..."
214         last_script = "l2tp"
215         while(1):
216                 dmesg = str(sut.run("dmesg"))
217                 if last_script in dmesg:
218                         print "found l2tp - UP"
219                         break;
220                 sleep(1)
221         print "vRouter started - waiting 5 last seconds before starting test"
222         sleep(5)
223         print datetime.now().time()
224
225 def set_pkt_sizes(tx_cores, p):
226         send_all_pkt_size(tx_cores, p-4)
227         # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size
228         send_all_value(tx_cores, 16, p - 18, 2)         # 14 for MAC (12) EthType (2) 
229         send_all_value(tx_cores, 38, p - 38, 2)         # 34 for MAC (12) EthType (2) IP (20)
230
231 def run_measure_throughput(speed):
232         done = 0
233         # Intialize tests by stopping cores and resetting stats
234         step=0
235         steps_done = 0
236         sock.sendall("start " + to_str(all_rx_cores) + "\n")
237         sleep(2)
238         sock.sendall("stop " + to_str(all_rx_cores) + "\n")
239         sock.sendall("reset stats\n")
240         print "Speed    = " + str(speed * nb_cores_per_interface) 
241         sleep(1);
242         
243         send_all_speed(tx_cores, step);
244
245         # Now starting the steps. First go to the common speed, then increase steps for the faster one.
246         sock.sendall("start " + to_str(tx_cores) + "," + to_str(rx_lat_cores) + "\n")
247         while (steps_done == 0):
248                 sleep(step_time)
249                 if (step + step_delta <= speed):
250                         step+=step_delta
251                 else:
252                         steps_done = 1;
253                 send_all_speed(tx_cores, step)
254         
255         # Steps are now OK.  Set speed
256         send_all_speed(tx_cores, speed);
257         sleep(2);
258
259         # Getting statistics to calculate PPS at right speed....
260         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);
261         sleep(test_duration);
262
263         # Collect statistics before test stops...and stop the test. Important to get stats before stopping as stops take some time...
264         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);
265         lat_min,lat_max,lat_avg = lat_stats(rx_lat_cores, rx_task)
266         sock.sendall("stop " + "," + to_str(tx_cores) + "\n")
267         sock.sendall("start " + to_str(all_rx_cores) + "\n")
268         sleep(3);
269         sock.sendall("stop " + to_str(all_rx_cores) + "\n")
270         
271         rx_end, tx_end,drop_end,tsc_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task);
272         rx = rx_pps_end - rx_pps_beg
273         tsc = tsc_pps_end - tsc_pps_beg
274         mpps = rx / (tsc/float(tsc_hz)) / 1000000
275         tx = tx_pps_end - tx_pps_beg
276         tx_mpps = tx / (tsc/float(tsc_hz)) / 1000000
277         
278         #print "Runtime = " +  str((tsc)/float(tsc_hz));
279         if (tx_end == 0):
280                 dropped_tot = tx_end - rx_end
281                 dropped_pct = 0
282         else:
283                 dropped_tot = tx_end - rx_end
284                 dropped_pct = ((dropped_tot) * 1.0) / tx_end
285
286         if (dropped_tot > 0):
287                 if (dropped_pct >= max_dropped):
288                         print "** FAILED **: lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end)
289                 else:
290                         print "OK but lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end)
291         else:
292                 if (dropped_tot < 0):
293                         print "Something wrong happened - received more packets than transmitted"
294                 else:
295                         print "**   OK   **: RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) 
296         print "MPPS = " + str(mpps)
297         print "===================================================="
298         return dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg
299
300 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):
301         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) + "; ")
302         for e in rx_lat_cores:
303                 f.write(str(lat_min[e]) + "; " + str(lat_max[e]) + "; " + str(lat_avg[e]) + "; ")
304         f.write("\n");
305         f.flush()
306
307 def run_loss_graph(number_next_hops, number_routes, pkt_size, traffic):
308         speed = init_speed * 1.0
309         done = 0;
310         while done == 0:
311                 dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed)
312                 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);
313                 if (speed <= low_steps_delta_for_loss):
314                         done = 1
315                         return
316                 if (speed >= (medium_steps+normal_steps_delta_for_loss)):
317                         speed -= normal_steps_delta_for_loss
318                 else:
319                         if (speed >= (low_steps+medium_steps_delta_for_loss)):
320                                 speed -= medium_steps_delta_for_loss
321                         else:
322                                 speed -= low_steps_delta_for_loss
323
324 def run_dicho_search(number_next_hops, number_routes, pkt_size, traffic):
325         previous_success_speed = 0.0
326         previous_error_speed = max_speed
327         speed = init_speed * 1.0
328         done = 0;
329         good_tx_mpps = 0
330         good_mpps = 0
331         good_dropped_pct = 0
332         good_dropped_tot = 0
333         good_speed = 0
334         good_lat_min = [0 for e in range(127)]
335         good_lat_max = [0 for e in range(127)]
336         good_lat_avg = [0 for e in range(127)]
337
338         while done == 0:
339                 dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed)
340                 if ((dropped_tot >= 0) and (dropped_pct <= max_dropped)):
341                         good_tx_mpps = tx_mpps
342                         good_mpps = mpps
343                         good_dropped_pct = dropped_pct
344                         good_dropped_tot = dropped_tot
345                         good_speed = speed
346                         good_lat_min = lat_min
347                         good_lat_max = lat_max
348                         good_lat_avg = lat_avg
349                         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);
350                         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);
351                 else:
352                         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);
353
354                 if ((speed == max_speed) and (dropped_pct <= max_dropped)):
355                         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);
356                         done = 1
357                 if (dropped_pct <= max_dropped):
358                         previous_success_speed = speed
359                         if (speed > max_speed - accuracy):
360                                 speed = max_speed
361                         else:
362                                 if (previous_error_speed - speed < accuracy):
363                                         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);
364                                         done = 1
365                                 else:
366                                         speed = speed + (previous_error_speed - speed)/2;
367                 else:
368                         previous_error_speed = speed
369                         if (speed - previous_success_speed < accuracy):
370                                 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);
371                                 done = 1        
372                         else:
373                                 speed  = speed - (speed - previous_success_speed) / 2;
374
375         
376 def set_destination_ip(use_case, nb_destinations, traffic):
377         # minimmum 8 routes i.e. 1 per interface 
378         # Destination addressese: "00XXXYY1" "Z00ZZ0ZZ" "AA0AA0AA" "BBBBBB10"
379         # Where X = interface id. Starting with 00 to be in class A and skipping 0.x.y.z and 127.x.y.z
380         # Y, Z and A = additional routes
381         # B = IP in routes. 10 to avoid x.y.z.0 and x.y.z.255
382         # Gaps in A and B to void "too good" distributions e.g. using LPM and 
383         # First changing Y
384
385         mask = ""
386         for i in range (2):
387                 mask = str(mask)+"0"
388         end_mask = ""
389         if (use_case != 2):
390                 end_mask = "XXXXXX10"           # Last 8 bits
391
392                 if (nb_destinations == 1):
393                         end_mask = "0010000000000000000" + str(end_mask)
394                 if (nb_destinations == 2):
395                         end_mask = "X010000000000000000" + str(end_mask)
396                 if (nb_destinations == 4):
397                         end_mask = "XX10000000000000000" + str(end_mask)
398                 if (nb_destinations == 8):
399                         end_mask = "XX1X000000000000000" + str(end_mask)
400                 elif (nb_destinations == 16):
401                         end_mask = "XX1X00X000000000000" + str(end_mask)
402                 elif (nb_destinations == 32):
403                         end_mask = "XX1X00XX00000000000" + str(end_mask)
404                 elif (nb_destinations == 64):
405                         end_mask = "XX1X00XX0X000000000" + str(end_mask)
406                 elif (nb_destinations == 128):
407                         end_mask = "XX1X00XX0XX00000000" + str(end_mask)
408                 elif (nb_destinations == 256):
409                         end_mask = "XX1X00XX0XXX0000000" + str(end_mask)
410                 elif (nb_destinations == 512):
411                         end_mask = "XX1X00XX0XXXX000000" + str(end_mask)
412                 elif (nb_destinations == 1024):
413                         end_mask = "XX1X00XX0XXXX0X0000" + str(end_mask)
414                 elif (nb_destinations == 2048):
415                         end_mask = "XX1X00XX0XXXX0XX000" + str(end_mask)
416                 elif (nb_destinations == 4096):
417                         end_mask = "XX1X00XX0XXXX0XX0X0" + str(end_mask)
418                 elif (nb_destinations == 8192):
419                         end_mask = "XX1X00XX0XXXX0XX0XX" + str(end_mask)
420         else:
421                 if (nb_destinations <= 64 * 1):
422                         end_mask = "0010000000000000000"
423                         n_dest = int(log(nb_destinations, 2))
424                         for i in range (n_dest):
425                                 end_mask = str(end_mask) + "X"
426                         for i in range (6 - n_dest):
427                                 end_mask = str(end_mask) + "0"
428                         end_mask = str(end_mask) + "10"
429                 else:
430                         end_mask = "XXXXXX10"           # Last 8 bits
431
432                 if (nb_destinations == 64 * 2):
433                         end_mask = "001X000000000000000" + str(end_mask)
434                 elif (nb_destinations == 64 * 4):
435                         end_mask = "001X00X000000000000" + str(end_mask)
436                 elif (nb_destinations == 64 * 8):
437                         end_mask = "001X00XX00000000000" + str(end_mask)
438                 elif (nb_destinations == 64 * 16):
439                         end_mask = "001X00XX0X000000000" + str(end_mask)
440                 elif (nb_destinations == 64 * 32):
441                         end_mask = "001X00XX0XX00000000" + str(end_mask)
442                 elif (nb_destinations == 64 * 64):
443                         end_mask = "001X00XX0XXX0000000" + str(end_mask)
444                 elif (nb_destinations == 64 * 128):
445                         end_mask = "001X00XX0XXXX000000" + str(end_mask)
446                 elif (nb_destinations == 64 * 256):
447                         end_mask = "001X00XX0XXXX0X0000" + str(end_mask)
448                 elif (nb_destinations == 64 * 512):
449                         end_mask = "001X00XX0XXXX0XX000" + str(end_mask)
450                 elif (nb_destinations == 64 * 1024):
451                         end_mask = "001X00XX0XXXX0XX0X0" + str(end_mask)
452                 elif (nb_destinations == 64 * 2048):
453                         end_mask = "001X00XX0XXXX0XX0XX" + str(end_mask)
454                 elif (nb_destinations == 64 * 4096):
455                         end_mask = "001XX0XX0XXXX0XX0XX" + str(end_mask)
456                 elif (nb_destinations == 64 * 8192):
457                         end_mask = "001XXXXX0XXXX0XX0XX" + str(end_mask)
458                 elif (nb_destinations == 64 * 16384):
459                         end_mask = "001XXXXXXXXXX0XX0XX" + str(end_mask)
460                 elif (nb_destinations == 64 * 32768):
461                         end_mask = "001XXXXXXXXXXXXX0XX" + str(end_mask)
462                 elif (nb_destinations == 64 * 65536):
463                         end_mask = "001XXXXXXXXXXXXXXXX" + str(end_mask)
464         
465         if (traffic == 0):      # One-to-one. From odd interface to even interface and vice versa, no QPI cross
466                 mask1 = str(mask) + "001" + str(end_mask)
467                 mask2 = str(mask) + "000" + str(end_mask)
468                 mask3 = str(mask) + "011" + str(end_mask)
469                 mask4 = str(mask) + "010" + str(end_mask)
470                 mask5 = str(mask) + "101" + str(end_mask)
471                 mask6 = str(mask) + "100" + str(end_mask)
472                 mask7 = str(mask) + "111" + str(end_mask)
473                 mask8 = str(mask) + "110" + str(end_mask)
474
475         elif (traffic == 1):    # Full mesh within QPI (i.e. 1 to 4)
476                 mask1 = str(mask) + "0XX" + str(end_mask)
477                 mask2 = str(mask) + "0XX" + str(end_mask)
478                 mask3 = str(mask) + "0XX" + str(end_mask)
479                 mask4 = str(mask) + "0XX" + str(end_mask)
480                 mask5 = str(mask) + "1XX" + str(end_mask)
481                 mask6 = str(mask) + "1XX" + str(end_mask)
482                 mask7 = str(mask) + "1XX" + str(end_mask)
483                 mask8 = str(mask) + "1XX" + str(end_mask)
484         
485         elif (traffic == 2):    # One to one, crossing QPI (100% QPI)
486                 mask1 = str(mask) + "100" + str(end_mask)
487                 mask2 = str(mask) + "101" + str(end_mask)
488                 mask3 = str(mask) + "110" + str(end_mask)
489                 mask4 = str(mask) + "111" + str(end_mask)
490                 mask5 = str(mask) + "000" + str(end_mask)
491                 mask6 = str(mask) + "001" + str(end_mask)
492                 mask7 = str(mask) + "010" + str(end_mask)
493                 mask8 = str(mask) + "011" + str(end_mask)
494
495         elif (traffic == 3):    # 1 to 4 crossing QPI (100% QPI)
496                 mask1 = str(mask) + "1XX" + str(end_mask)
497                 mask2 = str(mask) + "1XX" + str(end_mask)
498                 mask3 = str(mask) + "1XX" + str(end_mask)
499                 mask4 = str(mask) + "1XX" + str(end_mask)
500                 mask5 = str(mask) + "0XX" + str(end_mask)
501                 mask6 = str(mask) + "0XX" + str(end_mask)
502                 mask7 = str(mask) + "0XX" + str(end_mask)
503                 mask8 = str(mask) + "0XX" + str(end_mask)
504
505         elif (traffic == 4):    # 1 to 4 (50% QPI)
506                 mask1 = str(mask) + "XX1" + str(end_mask)
507                 mask2 = str(mask) + "XX0" + str(end_mask)
508                 mask3 = str(mask) + "XX1" + str(end_mask)
509                 mask4 = str(mask) + "XX0" + str(end_mask)
510                 mask5 = str(mask) + "XX1" + str(end_mask)
511                 mask6 = str(mask) + "XX0" + str(end_mask)
512                 mask7 = str(mask) + "XX1" + str(end_mask)
513                 mask8 = str(mask) + "XX0" + str(end_mask)
514
515         elif (traffic == 5):    # Full mesh (50% QPI)
516                 mask1 = str(mask) + "XXX" + str(end_mask)
517                 mask2 = str(mask) + "XXX" + str(end_mask)
518                 mask3 = str(mask) + "XXX" + str(end_mask)
519                 mask4 = str(mask) + "XXX" + str(end_mask)
520                 mask5 = str(mask) + "XXX" + str(end_mask)
521                 mask6 = str(mask) + "XXX" + str(end_mask)
522                 mask7 = str(mask) + "XXX" + str(end_mask)
523                 mask8 = str(mask) + "XXX" + str(end_mask)
524
525         for c in tx_port0:
526                 send_all_random([c], 30, mask1, 4)
527         for c in tx_port1:
528                 send_all_random([c], 30, mask2, 4)
529         for c in tx_port2:
530                 send_all_random([c], 30, mask3, 4)
531         for c in tx_port3:
532                 send_all_random([c], 30, mask4, 4)
533         for c in tx_port4:
534                 send_all_random([c], 30, mask5, 4)
535         for c in tx_port5:
536                 send_all_random([c], 30, mask6, 4)
537         for c in tx_port6:
538                 send_all_random([c], 30, mask7, 4)
539         for c in tx_port7:
540                 send_all_random([c], 30, mask8, 4)
541         for c in tx_cores:
542                 send_all_random([c], 34, "0XXXXXXXXXXXXX10", 2)
543                 send_all_random([c], 36, "0XXXXXXXXXXXXX10", 2)
544                 
545 #========================================================================
546 class TestDefinition():
547     "Stores test parameters"
548     def __init__(self, use_case, next_hops, number_routes, pkt_size, traffic, reload):
549         self.use_case = use_case
550         self.next_hops = next_hops
551         self.number_routes = number_routes
552         self.pkt_size = pkt_size
553         self.traffic = traffic
554         self.reload = reload
555
556 #========================================================================
557 # Use case 0 increases input load and measure output load => show dropped packets at low loads, show overload behavior
558 # Use case 1 and use case 2 run dichotomic searches, searching for 0 packet loss (or whaever loss is configured)
559 # Use case 1 shows the effect of number of routes and next-hops
560 # Use case 2 shows the effect of the number of destination, using a fixed (low) number of routes and next-hops
561 #========================================================================
562 def run_use_case(use_case, number_next_hops, number_routes, pkt_size, traffic, reload):
563         if (reload):
564                 if (use_case == 2):
565                         config = "config.1_1" + "_" + str(use_case) + ".boot"
566                 else:
567                         config = "config." + str(number_routes) + "_" + str(number_next_hops) + ".boot"
568                 reload_vRouter_config(config)
569         send_reset_random()
570         send_reset_value()
571         set_destination_ip(use_case, number_routes, traffic)
572         set_pkt_sizes(tx_cores, pkt_size)
573         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"
574         if (use_case == 0):
575                 run_loss_graph(number_next_hops, number_routes, pkt_size, traffic)
576         else:
577                 run_dicho_search(number_next_hops, number_routes, pkt_size, traffic)
578         sleep(3)
579
580 #========================================================================
581 def run_all_use_cases():
582         use_case_nb = 1
583         # Connect to dppd 
584         file_path = '/tmp/prox.sock'
585         sock.connect(file_path)
586
587         f.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n")
588         f_all.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n")
589         f_minimal.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n")
590         f.flush();
591         f_all.flush();
592         f_minimal.flush();
593
594         # Starting tests
595         print "Stopping all cores and resetting all values and randoms before starting\n"
596         sock.sendall("stop all")
597         sock.sendall("reset stats\n")
598         sleep(3);
599         for line in file_tests:
600                 info = line.split(';')
601                 if (info[0][0] == '#'):
602                         continue
603                 if (info[0][0] == ''):
604                         break
605                 use_case = int(info[0])
606                 next_hops = int(info[1])
607                 number_routes = int(info[2])
608                 pkt_size = int(info[3])
609                 traffic = int(info[4])
610                 reload = int(info[5])
611                 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)
612                 run_use_case(use_case, next_hops, number_routes, pkt_size, traffic, reload)
613                 use_case_nb = use_case_nb + 1
614
615 #========================================================================
616 def configure_use_case(use_case):
617         Tests = []
618         if (use_case == 0):
619                 for pkt_size in all_pkt_size:
620                         Tests.append(TestDefinition("0", "1", "1", pkt_size, "0", "1"))
621                 for pkt_size in all_pkt_size:
622                         Tests.append(TestDefinition("0", "1", "1", pkt_size, "1", "1"))
623         if (use_case == 1):
624                 number_next_hops = 1
625                 reload = 0
626
627                 number_routes = number_next_hops        # At least same number of routes that number of next hops
628                 while number_routes <= max_number_routes:
629                         reload = 1
630                         for traffic in range(6):
631                                 for pkt_size in all_pkt_size:
632                                         Tests.append(TestDefinition(use_case, number_next_hops, number_routes, pkt_size, traffic, reload))
633                                         reload = 0
634                         if (number_routes < max_number_routes / 2):
635                                 number_routes = number_routes * 4
636                         else:
637                                 number_routes = number_routes * 2
638
639                 number_routes = max_number_next_hops
640                 while number_next_hops <= max_number_next_hops:
641                         reload = 1
642                         for traffic in range(6):
643                                 for pkt_size in all_pkt_size:
644                                         Tests.append(TestDefinition(use_case, number_next_hops, number_routes, pkt_size, traffic, reload))
645                                         reload = 0
646                         number_next_hops = number_next_hops * 2
647         if (use_case == 2):
648                 number_next_hops = 1
649                 reload = 1
650                 for traffic in range(6):
651                         nb_destinations = 1
652                         while nb_destinations <= max_number_addresses_local_network:
653                                 for pkt_size in all_pkt_size:
654                                         Tests.append(TestDefinition(use_case, number_next_hops, nb_destinations, pkt_size, traffic, reload))
655                                         reload = 0
656                                 nb_destinations = nb_destinations * 2
657                         reload = 1
658
659         file_tests = open('test_description.txt', 'w')
660         file_tests.write("# Use case; next_hops; routes; pkt_size; traffic; reload;\n")
661         for test in Tests:
662                 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")
663         file_tests.close()
664
665 #========================================================================
666 if ((configure == 0) and (run == 0)):
667         print "Nothing to do - please use -r 1 or -c 1"
668 if (configure == 1):
669         configure_use_case(use_case)
670 if (run == 1):
671         print "****************************************************************************************************************"
672         print "** Running vRouter Characterization with " + str(test_duration) + " seconds steps and starting at " + str(init_speed)   + " percent of line rate **"
673         print "****************************************************************************************************************"
674         sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
675         f_all = open('all_results.txt', 'w')
676         f = open('detailed_results.txt', 'w')
677         f_minimal = open('minimal_results.txt', 'w')
678         file_tests = open('test_description.txt', 'r')
679         run_all_use_cases()
680         f.close();
681         sock.close();