#!/usr/bin/python # # Copyright (c) 2007 OLPC # Author: Ricardo Carrano # Version 0.2.0 # # this program is free software; you can redistribute it and/or modify # it under the terms of the gnu general public license as published by # the free software foundation; either version 2 of the license, or # (at your option) any later version. # # this program is distributed in the hope that it will be useful, # but without any warranty; without even the implied warranty of # merchantability or fitness for a particular purpose. see the # gnu general public license for more details. # # you should have received a copy of the gnu general public license # along with this program; if not, write to the free software # foundation, inc., 51 franklin st, fifth floor, boston, ma 02110-1301 usa import sys import commands from stats import mean,stdev from optparse import OptionParser arguments = OptionParser() arguments.add_option("-f","--pcap-file", dest="pcapfile", help="Capture dump") arguments.add_option("-t","--text-file", dest="textfile", help="Capture already converted/filtered") arguments.add_option("--no-fcs", action="store_false", dest="crc", default=True, help="don't check if frames have bad crc") (options, args) = arguments.parse_args() if not (options.pcapfile or options.textfile) : print "input file is mandatory" sys.exit(0) if options.pcapfile: pcapfile = options.pcapfile inputfile = pcapfile if options.textfile: textfile = options.textfile inputfile = textfile else: textfile = pcapfile+'.tmp' filter_exp = "wlan.fcs_good == 1 && wlan_mgt.fixed.action_type == 1" if not options.crc: filter_exp = "wlan_mgt.fixed.action_type == 1" filter_cmd='tshark -r %s -R "%s" -T fields -e frame.time_relative -e wlan.sa -e wlan.da -e wlan_mgt.fixed.sa -e wlan_mgt.fixed.da -e wlan_mgt.fixed.mesh_action -e wlan_mgt.fixed.metric -e wlan_mgt.fixed.hopcount -e wlan_mgt.fixed.ttl -e wlan.seq -e wlan_mgt.fixed.ssn -e wlan_mgt.fixed.dsn -e radiotap.datarate > %s' % (pcapfile, filter_exp, textfile) s, o = commands.getstatusoutput(filter_cmd) fd = open(textfile, 'r') maxttl = 5 datarates = ('108', '72', '22', '2', '0') groups={} rreqs={} rreps={} rerrs={} participants={} originators={} targets={} spread_times={} rreqs['count'] = 0 rreps['count'] = 0 rerrs['count'] = 0 rreqs['datarate']={} rreqs['hops']={} rreps['hops']={} for datarate in datarates: rreqs['datarate'][datarate]=0 for ttl in range(1, maxttl+1): rreqs['hops'][ttl]=0 rreps['hops'][ttl]=0 spread_times[ttl] = [] # Airtime costs # PREQ = 86 bytes # PREP = 80 bytes preq_airtime = {} preq_airtime['108'] = 0.0387 preq_airtime['72'] = 0.0457 preq_airtime['22'] = 0.2545 preq_airtime['2'] = 0.8800 preq_airtime['0'] = 0.0 prep_airtime = 0.8320 airtime = 0 starttime = 0 endtime = 0 multihop_percent = 0 def stdev2(serie): try: sd = stdev(serie) return sd except TypeError: return 0 def formattime(timetoformat): if timetoformat: return (mean(timetoformat)*1000, stdev2(timetoformat)*1000, min(timetoformat)*1000, max(timetoformat)*1000) else: return "no availabe data" # # PARSING THE INPUT FILE and POPULATING DICTS # for line in fd: time, transmitter, receiver, origin, target, action, metric, hops, meshttl, msn, ssn, dsn, datarate = line.split('\t') datarate = datarate.strip('\n') for xo in transmitter, receiver, origin, target: for array in participants, originators, targets: if not array.has_key(xo) and xo != 'ff:ff:ff:ff:ff:ff' and xo != '': array[xo] = {} array[xo]['counter'] = 0 array[xo]['sd'] = 0 # source or destination if not starttime: starttime = time endtime = time participants[transmitter]['counter'] += 1 if action != '0x0002': originators[origin]['counter'] += 1 targets[target]['counter'] += 1 if action == '0x0000': rreqs['count'] += 1 rreqs['datarate'][datarate] += 1 rreqs['hops'][int(maxttl)-int(meshttl)] += 1 group=origin+'-'+target+'-'+ssn if groups.has_key(group): groups[group]['count'] += 1 groups[group]['lasttime'] = time else: groups[group]={} groups[group]['count'] = 1 targets[target]['sd'] += 1 originators[origin]['sd'] += 1 if action == '0x0000' and transmitter == origin and datarate == '108': # The original 54Mbps RREQ groups[group]['starttime'] = time if action == '0x0000' and groups[group].has_key('starttime'): spread_times[maxttl-int(meshttl)].append(float(time)-float(groups[group]['starttime'])) if action == '0x0001': groups[group]['replied'] = True rreps['count'] += 1 rreps['hops'][int(hops)] += 1 if receiver == origin: # The last RREP groups[group]['endtime'] = time if transmitter == target: # The first RREP groups[group]['resptime'] = time else: rerrs['count'] += 1 # # ACCOUNTING (processing the DICTS) # disc_frames = int(rreqs['count']) + int(rreps['count']) + int(rerrs['count']) discovery_times = [] end_times = [] last_times = [] time_spread = {} counts = [] replied_counter = 0 for group in groups.keys(): if groups[group].has_key('starttime') and groups[group].has_key('resptime'): discovery_time = float(groups[group]['resptime']) - float(groups[group]['starttime']) discovery_times.append(discovery_time) if groups[group].has_key('starttime') and groups[group].has_key('endtime'): end_time = float(groups[group]['endtime']) - float(groups[group]['starttime']) end_times.append(end_time) if groups[group].has_key('starttime') and groups[group].has_key('lasttime'): last_time = float(groups[group]['lasttime']) - float(groups[group]['starttime']) last_times.append(last_time) if groups[group].has_key('replied'): replied_counter += 1 counts.append(groups[group]['count']) # # REPORT GENERATION # print "-----------------------------"+"-"*len(inputfile) print "ROUTE DISCOVERY REPORT (for %s)" % (inputfile) print "-----------------------------"+"-"*len(inputfile) print "Captured route discovery frames: %s [RREQs %s (%.2f%%) RREPs %s (%.2f%%) RERRs %s (%.2f%%)]" % (disc_frames, rreqs['count'], float(rreqs['count'])*100/float(disc_frames), rreps['count'], float(rreps['count'])*100/float(disc_frames), rerrs['count'], float(rerrs['count'])*100/float(disc_frames)) print "Route discovery clusters: %s" % (len(groups)) print "Average # of frames captured per cluster: %.2f (stdev = %.2f) [RREQs %.2f, RREPs %.2f, RERRs %.2f]" % (mean(counts), stdev2(counts), float(rreqs['count'])/float(len(groups)), float(rreps['count'])/float(len(groups)), float(rerrs['count'])/float(len(groups))) print "Replied requisitions (with any rrep captured): %s (%.2f%%)" % (replied_counter,replied_counter*100/len(groups)) print "Completed requisitions (with final rrep captured): %s (%.2f%%)" % (len(end_times),float(len(end_times)*100/len(groups))) print "\nRREQs:" print "By Hop Count:", for ttl in range(1, maxttl+1): print "%s: %s (%.2f%%)" % (ttl, rreqs['hops'][ttl], float(rreqs['hops'][ttl]*100)/float(rreqs['count'])), print "\nBy Datarate:", for datarate in datarates: txrate = int(datarate)/2 if datarate == '0': txrate = 'Unknown' print "%s: %s (%.2f%%)" % (txrate, rreqs['datarate'][datarate], float(rreqs['datarate'][datarate])*100/float(rreqs['count'])), airtime += int(rreqs['datarate'][datarate]) * preq_airtime[datarate] airtime += int(rreps['count']) * prep_airtime print "\n\nRREPs:" print "By Hop Count:", for ttl in range(1, maxttl+1): print "%s: %s (%.2f%%)" % (ttl, rreps['hops'][ttl], float(rreps['hops'][ttl]*100)/float(rreps['count'])), if ttl > 1: multihop_percent += float(rreps['hops'][ttl]*100)/float(rreps['count'])/int(ttl) print "\nEstimated %% of multihop paths: %.2f%%\n" % (multihop_percent) print "First RREP elapsed time (ms): %.2f (stdev = %.2f) MIN: %.2f MAX: %.2f" % (formattime(discovery_times)) print "Route acquisition time (ms): %.2f (stdev = %.2f) MIN %.2f MAX %.2f" % (formattime(end_times)) if last_times: print "Route discovery lifespan (ms): %.2f (stdev = %.2f) MAX %.2f" % (mean(last_times)*1000, stdev2(last_times)*1000, max(last_times)*1000) else: print "Route discovery lifespan (ms): no available data" for ttl in range(1, maxttl+1): if spread_times[ttl]: print "RREQ distribution for %s hop(s) (ms): mean = %.2f (stdev = %.2f) MIN: %.2f MAX: %.2f" % (ttl, mean(spread_times[ttl])*1000, stdev2(spread_times[ttl])*1000, min(spread_times[ttl])*1000, max(spread_times[ttl])*1000) print "\nPDM Airtime (ms):", airtime print "PDM Activity Interval (s): %.2f" % (float(endtime)-float(starttime)) print "PDM Airtime %%: %.2f" % (float(airtime)/(10*(float(endtime)-float(starttime)))) print "\nParticipants: %s\n" % (len(participants)) for xo in participants.keys(): print "%s: FWD %s\t\tORIGIN %s => %s\t\tTARGET %s => %s" % (xo, participants[xo]['counter'], originators[xo]['sd'], originators[xo]['counter'], targets[xo]['sd'], targets[xo]['counter'])