nepatest_popbabel / scripts / multiprocessTimerouter.py @ 60ba786f
History | View | Annotate | Download (8.81 KB)
1 |
import glob |
---|---|
2 |
import json |
3 |
from pprint import pprint |
4 |
import sys |
5 |
import os |
6 |
import numpy as np |
7 |
import matplotlib |
8 |
matplotlib.use('Agg')
|
9 |
from matplotlib import pyplot as plt |
10 |
from pprint import pprint |
11 |
import code |
12 |
from multiprocessing import Process, Manager |
13 |
|
14 |
|
15 |
class MyTime: |
16 |
string = "0:0:0.0"
|
17 |
|
18 |
@classmethod
|
19 |
def vecToString(cls, vec): |
20 |
mus=vec[-1]
|
21 |
highORlow="high"
|
22 |
if (mus<0.5): |
23 |
highORlow="low"
|
24 |
return str(vec[0])+":"+str(vec[1])+":"+str(vec[2])+"-"+highORlow |
25 |
|
26 |
def __init__(self, timestring="0:0:0.0"): |
27 |
self.string=timestring
|
28 |
spl=self.string.split(':') |
29 |
self.mh=int(spl[-3]) |
30 |
self.mm=int(spl[-2]) |
31 |
self.ms=int(spl[-1].split('.')[0]) |
32 |
self.mus=int(spl[-1].split('.')[1]) * (10**-6) |
33 |
self.time=self.mh *60 * 60 + self.mm * 60 + self.ms + self.mus |
34 |
|
35 |
def asHMSUVector(self): |
36 |
if (self.mus<0.5): |
37 |
retmus=0
|
38 |
else:
|
39 |
retmus=5
|
40 |
#print "\t\tmus="+str(self.mus)+", retmus="+str(retmus)
|
41 |
return (self.mh,self.mm,self.ms,retmus) |
42 |
|
43 |
def asHMSVector(self): |
44 |
return (self.mh,self.mm,self.ms) |
45 |
|
46 |
def toString(self): |
47 |
return self.string |
48 |
|
49 |
def toFloat(self): |
50 |
return self.time |
51 |
|
52 |
#se self e' piu' tardi ritorna 1, -1 altrimenti
|
53 |
#si assume che i log siano stati fatti nella stessa ora!
|
54 |
def vecCompare(self,v2): |
55 |
h1,m1,s1,hl1=self.asHMSUVector()
|
56 |
h2,m2,s2,hl2=v2 |
57 |
if (h2 != h1):
|
58 |
if (h2>h1):
|
59 |
return -1 |
60 |
else:
|
61 |
return 1 |
62 |
if (m2 != m1):
|
63 |
if (m2>m1):
|
64 |
return -1 |
65 |
else:
|
66 |
return 1 |
67 |
if (s2 != s1):
|
68 |
if (s2>s1):
|
69 |
return -1 |
70 |
else:
|
71 |
return 1 |
72 |
if (hl2 != hl1):
|
73 |
if (hl2>hl1):
|
74 |
return -1 |
75 |
else:
|
76 |
return 1 |
77 |
return 0 |
78 |
|
79 |
def __cmp__(self,obj): |
80 |
return self.vecCompare(obj.asHMSUVector()) |
81 |
|
82 |
|
83 |
#return 1 if self older than other
|
84 |
|
85 |
class DestNotFound(Exception): |
86 |
def __init__(self, value): |
87 |
self.value = value
|
88 |
def __str__(self): |
89 |
return repr(self.value) |
90 |
|
91 |
#ok, let me call this function like this...
|
92 |
#currently works only because ALL routes are \32 addresses
|
93 |
def longestPrefixMatchNextHop(rt,dest): |
94 |
for entry in rt.keys(): |
95 |
if entry.startswith(dest):
|
96 |
return rt[entry]
|
97 |
raise DestNotFound("DEST 404: "+str(dest)) |
98 |
|
99 |
|
100 |
|
101 |
#time2N2RT: <secondo, N2RT>
|
102 |
time2N2RT={} |
103 |
#N2RT: <node_id, RT>
|
104 |
#N2RT = {}
|
105 |
#RT: <dest, next_hop>
|
106 |
#ip2node: <ip, node_id>
|
107 |
|
108 |
def navigateRoutingTable(node2rt,ip2node,node2ips,sec,failedNodesId): |
109 |
ips=ip2node.keys() |
110 |
|
111 |
#remove ips of failed_nodes, given we want to check how many routes among ips of active nodes pass trough the dead node
|
112 |
remIps=node2ips[failedNodesId] |
113 |
ips = list(set(ips) - set(remIps)) |
114 |
|
115 |
black_holes=0
|
116 |
loops=0
|
117 |
routes=[] |
118 |
for s in ips: |
119 |
for d in ips: |
120 |
#print "\t\tlooking for route from "+str(s)+"..->.."+str(d)
|
121 |
#r=route->list of IPs crossed
|
122 |
r = [] |
123 |
nr = [] |
124 |
r.append(s) |
125 |
source_node=ip2node[s] |
126 |
nr.append(source_node) |
127 |
target_node=ip2node[d] |
128 |
try:
|
129 |
nexthop=longestPrefixMatchNextHop(node2rt[source_node],d) |
130 |
except DestNotFound as dnf: |
131 |
print dnf, "probably alredy flushed" |
132 |
break;
|
133 |
except KeyError as e: |
134 |
print e
|
135 |
#print "Unexpected error:", sys.exc_info()[0], "\n\t Actually this concludes log analysis," \
|
136 |
# "when stop logging\n\tsome nodes terminates before others and some RT misses"
|
137 |
#pass
|
138 |
return ()
|
139 |
#break;
|
140 |
target=ip2node[nexthop] |
141 |
while(target!=target_node):
|
142 |
r.append(nexthop) |
143 |
source_node=ip2node[nexthop] |
144 |
if (source_node not in nr): |
145 |
nr.append(source_node) |
146 |
else:
|
147 |
#print "\t\t\t\tLoooooooop!!!!!"
|
148 |
loops+=1
|
149 |
break;
|
150 |
try:
|
151 |
nexthop=longestPrefixMatchNextHop(node2rt[source_node],d) |
152 |
except KeyError: |
153 |
black_holes+=1
|
154 |
'''print "\t\tNode "+str(ip2node[nexthop])+" owning "+str(nexthop)+" is dead"
|
155 |
sys.stdout.write("\t\t\t\t")
|
156 |
for i in range(len(r)):
|
157 |
if (i!=0):
|
158 |
sys.stdout.write("->")
|
159 |
sys.stdout.write("c"+str(r[i]))
|
160 |
print ""'''
|
161 |
break;
|
162 |
except:
|
163 |
print "IIIUnexpected error:", sys.exc_info()[0] |
164 |
break;
|
165 |
target=ip2node[nexthop] |
166 |
r.append(d) |
167 |
routes.append(r) |
168 |
print "\t#loops: "+str(loops)+", blackholes: "+str(black_holes) |
169 |
return (black_holes,loops,)
|
170 |
|
171 |
|
172 |
#the folder where to look for dumps and logs
|
173 |
folder=sys.argv[1]
|
174 |
print folder
|
175 |
|
176 |
'''t1=MyTime("12:00:01.200000")
|
177 |
t2=MyTime("12:00:01.700000")
|
178 |
|
179 |
print t1.vecCompare(t2.asHMSUVector())
|
180 |
|
181 |
print t2.vecCompare(t1.asHMSUVector())
|
182 |
|
183 |
print t1.vecCompare(t1.asHMSUVector())
|
184 |
|
185 |
code.interact(local=locals())'''
|
186 |
|
187 |
|
188 |
ip2node={} |
189 |
node2ips={} |
190 |
|
191 |
print "###########\n\n\n\n" |
192 |
#Ricostruzione RT indicizzate per tempo
|
193 |
#bisogna anche salvarsi il tempo di rottura del nodo che e' morto
|
194 |
minDumpsLength=sys.maxint |
195 |
failedNodesId=""
|
196 |
fail_time=MyTime() |
197 |
stopTimes=[] |
198 |
stopTimes2n={} |
199 |
|
200 |
|
201 |
for fname in glob.glob(folder+'topo*'): |
202 |
print "Loading json from " + fname |
203 |
f=open(fname, "r") |
204 |
jtimedroutes=json.load(f) |
205 |
del(jtimedroutes[0]) #the first dummy entry always put in Babel dumps |
206 |
|
207 |
#identifyinf failed node as the one with minimun number of dumps
|
208 |
'''if (len(jtimedroutes)<minDumpsLength):
|
209 |
minDumpsLength=len(jtimedroutes)
|
210 |
lastDump=jtimedroutes[-1]
|
211 |
failedNodesId=lastDump['router_id']
|
212 |
fail_time=MyTime(lastDump['topology_id'])
|
213 |
print "\tFAILURE NEWS: "+failedNodesId+" stopped working at "+fail_time.toString()'''
|
214 |
|
215 |
#put stopTime in a vector to see which is the first correct node that stopped logging
|
216 |
lastDump=jtimedroutes[-1]
|
217 |
router_id=lastDump['router_id']
|
218 |
stopTime=MyTime(lastDump['topology_id'])
|
219 |
stopTimes.append(stopTime) |
220 |
stopTimes2n[stopTime.asHMSUVector()]=router_id |
221 |
|
222 |
#pprint(time2N2RT)
|
223 |
#Retrieving RTs dumped by this node
|
224 |
slasttime=MyTime().toString |
225 |
for jtimedRT in jtimedroutes: |
226 |
router_id=jtimedRT['router_id']
|
227 |
stime=jtimedRT['topology_id']
|
228 |
routes=jtimedRT['routes']
|
229 |
#print "\tAt time: "+stime+" we have an RT for node: "+router_id
|
230 |
time=MyTime(stime) |
231 |
tk=time.asHMSUVector() |
232 |
#tk=tk[0]*60*60+tk[1]*60+tk[2]
|
233 |
|
234 |
if (not time2N2RT or tk not in time2N2RT): |
235 |
time2N2RT[tk]={} |
236 |
#print "New second",router_id,tk
|
237 |
if (not time2N2RT[tk] or router_id not in time2N2RT[tk]): |
238 |
time2N2RT[tk][router_id]={} |
239 |
#print "\tNew router for ",router_id,tk
|
240 |
|
241 |
thisnodeIPs=[] |
242 |
for r in routes: |
243 |
#RT=time2N2RT[tk][router_id]
|
244 |
dest=r['destination']
|
245 |
nexthop=r['next']
|
246 |
if(float(r['cost'])==0): |
247 |
nexthop=dest.split('/')[0] |
248 |
thisnodeIPs.append(nexthop) |
249 |
ip2node[nexthop]=router_id |
250 |
|
251 |
time2N2RT[tk][router_id][dest]=nexthop |
252 |
|
253 |
node2ips[router_id]=thisnodeIPs |
254 |
#N2RT[router_id]=RT
|
255 |
f.close() |
256 |
|
257 |
|
258 |
#code.interact(local=locals())
|
259 |
stopTimes=sorted(stopTimes)
|
260 |
fail_time=stopTimes[0]
|
261 |
failedNodesId=stopTimes2n[fail_time.asHMSUVector()] |
262 |
stopLogTime=stopTimes[1] #[0] -> fail node stop |
263 |
|
264 |
print "According to data read from json it seems that" |
265 |
print "Failure at: "+fail_time.toString() |
266 |
print "Stop log at: "+stopLogTime.toString() |
267 |
|
268 |
'''print "ip2node"
|
269 |
pprint(ip2node)
|
270 |
|
271 |
print "node2ips"
|
272 |
pprint(node2ips)
|
273 |
print "#################\n\n\n\n"
|
274 |
pprint(time2N2RT)'''
|
275 |
print "#################\n\n\n\n" |
276 |
srtsec=sorted(time2N2RT.keys())
|
277 |
#print "Times"
|
278 |
#pprint(srtsec)
|
279 |
#print "\n\n"
|
280 |
'''for sec in srtsec:
|
281 |
print "Al secondo: "+ MyTime.vecToString(sec)
|
282 |
for node in time2N2RT[sec]:
|
283 |
print "\t\tRT("+str(node)+")={"
|
284 |
for dest in time2N2RT[sec][node]:
|
285 |
print "\t\t\t\t"+str(dest)+" via "+str(time2N2RT[sec][node][dest])
|
286 |
print "\t\t}"
|
287 |
print "\n"'''
|
288 |
|
289 |
def broken_paths_discoverer(N2RT, ip2node, node2ips,sec, failedNodesId, res): |
290 |
print "\nProblems at time: "+MyTime.vecToString(sec)+"?" |
291 |
#da tenere conto di nodo_fallito e fail_time
|
292 |
#non analizziamo i log precedenti a fail_time
|
293 |
|
294 |
if (fail_time.vecCompare(sec)>0): |
295 |
print "\t"+MyTime.vecToString(sec) + " prior than fail_time: "+fail_time.toString() |
296 |
res[sec]=(-1,-1) |
297 |
|
298 |
elif (stopLogTime.vecCompare(sec)<0): |
299 |
print "\t"+MyTime.vecToString(sec) + " after than stopLogTime: "+stopLogTime.toString() |
300 |
res[sec]=(-1,-1) |
301 |
|
302 |
#"else" failTime < sec < StopLogTime ==> it is worth to navigate RTs
|
303 |
else:
|
304 |
res[sec]=navigateRoutingTable(time2N2RT[sec],ip2node,node2ips,sec,failedNodesId) |
305 |
|
306 |
|
307 |
|
308 |
print "#################\n\n\n\n" |
309 |
#Navigazione e conteggio disagi:
|
310 |
manager = Manager() |
311 |
results = manager.dict() |
312 |
#results={} #<time,vettore risultati>: disagi per secondo
|
313 |
|
314 |
print "Looking for problems in network for each period" |
315 |
jobs=[] |
316 |
for sec in srtsec: |
317 |
procs = len(srtsec)
|
318 |
for i in range(0, procs): |
319 |
process = Process(target=broken_paths_discoverer, |
320 |
args=(time2N2RT[sec],ip2node,node2ips,sec,failedNodesId,results)) |
321 |
jobs.append(process) |
322 |
|
323 |
for j in jobs: |
324 |
j.start() |
325 |
for j in jobs: |
326 |
j.join() |
327 |
|
328 |
print "#######\n\n\n" |
329 |
#code.interact(local=dict(globals(), **locals()))
|
330 |
|
331 |
#Visualiza data in pretty table
|
332 |
from prettytable import PrettyTable |
333 |
t = PrettyTable(['Time', '#loops','#blackholes']) |
334 |
|
335 |
#sava data in csv file
|
336 |
fldname=folder.strip("/")
|
337 |
f = open(folder+fldname+"-results.csv", "w") |
338 |
f.write("Time,loops,blackholes\n")
|
339 |
for sec in srtsec: |
340 |
if (sec in results): |
341 |
if (bool(results[sec])): |
342 |
#print "At sec: "+MyTime.vecToString(sec)+" #loops: "+str(results[sec][1]) + " #blackholes: "+str(results[sec][0])
|
343 |
t.add_row([ MyTime.vecToString(sec), str(results[sec][1]), str(results[sec][0])]) |
344 |
f.write(MyTime.vecToString(sec) +","+ str(results[sec][1])+","+ str(results[sec][0])+"\n") |
345 |
f.close() |
346 |
print t
|