class feedbackThread(threading.Thread): """ """ def __init__(self, requestQueue, responseQueue): super(feedbackThread, self).__init__() # Create queue attributes self.requestQueue = requestQueue self.responseQueue = responseQueue # Read network database self.db = DatabaseHandler() # Fill router cap files self.capFilesDict = self.pickCapFiles() # Data structure that maintains a set of current flows passing # through each router in the last second self.router_flowsets = {} self.updateRouterFlowSets() def run(self): """ A dictionary of flow -> possible path list is read from the requestQueue. A dictionary indexed by flow -> allocated path is returned """ queueLookupPeriod = 2 #seconds while True: try: requestFlowsDict = self.requestQueue.get(timeout=queueLookupPeriod) # Blocking read except: # Update flow sets for each router self.updateRouterFlowSets() else: #log.info("*** FEEDBACK REQUEST RECEIVED:\n") #log.info(" %s\n"%str(requestFlowsDict)) self.updateRouterFlowSets() responsePathDict = self.dealWithRequest(requestFlowsDict) if responsePathDict != {}: self.responseQueue.put(responsePathDict) def updateRouterFlowSets(self): for rid, capfile in self.capFilesDict.iteritems(): lines = capfile.readlines() # Create new empty set ridSet = set() for line in lines: try: # Parse ip's src_tmp = line.split(' ')[2] src_ip_tmp = src_tmp.split('.')[:4] src_ip = ipaddress.ip_address('.'.join(map(str, src_ip_tmp))) dst_tmp = line.split(' ')[4].strip(':') dst_ip_tmp = dst_tmp.split('.')[:4] dport = dst_tmp.split('.')[4] dst_ip = ipaddress.ip_address('.'.join(map(str, dst_ip_tmp))) ridSet.update({((src_ip, 's'), (dst_ip, 'd'), dport)}) except: pass # Add set into dictionary self.router_flowsets[rid] = ridSet def dealWithRequest(self, requestFlowsDict): """ """ # Results are saved here responsePathDict = {} start_time = time.time() for f, pl in requestFlowsDict.iteritems(): #flowsSet.update({(f.src, f.sport, f.dst, f.dport)}) # We can't fix the source port from iperf client, so it # will never match. This implies that same host can't same # two UDP flows to the same destination host. flowSet = set() flowSet.update({((f.src.ip, 's'), (f.dst.ip, 'd'), str(f.dport))}) # Set of routers containing flow routers_containing_flow = {self.db.getIpFromHostName(rid) for rid, rset in self.router_flowsets.iteritems() if rset.intersection(flowSet) != set()} #log.info("*** SEARCHING:\n") #log.info(" - %s\n"%f) #log.info(" - %s\n"%str(list(routers_containing_flow))) # Iterate path list and choose which of them is the one in # which the flow is allocated pathSetList = [(p, set(p)) for p in pl] # Retrieve path that matches chosen_path = [(p, pset) for (p, pset) in pathSetList if pset == routers_containing_flow] if len(chosen_path) == 1: responsePathDict[f] = chosen_path[0][0] elif len(chosen_path) == 0: pass else: log.info("*** FEEDBACK THREAD ERROR\n") return responsePathDict def pickCapFiles(self): """ Returns a dictionary indexed by router id -> corresponding .cap file """ return {rid: open(dconf.CAP_Path+rid+'.cap', 'r') for rid in self.db.routers_to_ip.keys()}
class TrafficGenerator(Base): """Object that creates a Traffic Generator in the network. """ def __init__(self, *args, **kwargs): super(TrafficGenerator, self).__init__(*args, **kwargs) self.scheduler = sched.scheduler(time.time, time.sleep) self.db = DatabaseHandler() self.thread_handlers = [] # IP of the Load Balancer Controller host. try: self._lbc_ip = ipaddress.ip_interface(self.db.getIpFromHostName(dconf.LBC_Hostname)).ip.compressed except: log.info("WARNING: Load balancer controller could not be found in the network\n") self._lbc_ip = None def _signal_handler(self, signal, frame): """ Terminates trafficgenerator thread gracefully. """ log.info("Signal caught... shuting down!\n") # collect all open _createFlow threads for t in self.thread_handlers: # t.join() log.info("_createFlow thread terminated\n") # exit sys.exit(0) def informLBController(self, flow): """Part of the code that deals with the JSON interface to inform to LBController a new flow created in the network. """ url = "http://%s:%s/newflowstarted" % (self._lbc_ip, dconf.LBC_JsonPort) log.info("\t Informing LBController\n") log.info("\t * Flow: %s\n" % self.toLogFlowNames(flow)) log.info("\t * Url: %s\n" % url) try: requests.post(url, json=flow.toJSON()) except Exception: log.info("ERROR: LBC could not be informed!\n") log.info("LOG: Exception in user code:\n") log.info("-" * 60 + "\n") log.info(traceback.print_exc()) log.info("-" * 60 + "\n") def toLogFlowNames(self, flow): a = "(%s -> %s): %s, t_o: %s, duration: %s" return a % ( self.db.getNameFromIP(flow.src.compressed), self.db.getNameFromIP(flow.dst.compressed), flow.setSizeToStr(flow.size), flow.setTimeToStr(flow.start_time), flow.setTimeToStr(flow.duration), ) def createFlow(self, flow): """Calls _createFlow in a different Thread (for efficiency) """ # Start thread that will send the Flask request t = Thread(target=self._createFlow, name="_createFlow", args=(flow,)).start() # Append thread handler to list self.thread_handlers.append(t) def _createFlow(self, flow): """Creates the corresponding iperf command to actually install the given flow in the network. This function has to call self.informLBController! """ # Sleep after it is your time to start time.sleep(flow["start_time"]) # Call to informLBController if it is active if self._lbc_ip: self.informLBController(flow) # time.sleep(0.2) # Create new flow with hosts ip's instead of interfaces # Iperf only understands ip's flow2 = Flow( src=flow["src"].ip.compressed, dst=flow["dst"].ip.compressed, sport=flow["sport"], dport=flow["dport"], size=flow["size"], start_time=flow["start_time"], duration=flow["duration"], ) url = "http://%s:%s/startflow" % (flow2["src"], dconf.Hosts_JsonPort) t = time.strftime("%H:%M:%S", time.gmtime()) log.info("%s - Starting Flow\n" % t) log.info("\t Sending request to host %s\n" % str(flow["src"])) log.info("\t * Flow: %s\n" % self.toLogFlowNames(flow)) log.info("\t * Url: %s\n" % url) # Send request to host to start new iperf client session try: requests.post(url, json=flow2.toJSON()) except Exception: log.info("ERROR: Request could not be sent to Host!\n") log.info("LOG: Exception in user code:\n") log.info("-" * 60 + "\n") log.info(traceback.print_exc()) log.info("-" * 60 + "\n") def stopFlow(self, flow): """Instructs host to stop iperf client session (flow). """ flow2 = Flow( src=flow["src"].ip.compressed, dst=flow["dst"].ip.compressed, sport=flow["sport"], dport=flow["dport"], size=flow["size"], start_time=flow["start_time"], duration=flow["duration"], ) url = "http://%s:%s/stopflow" % (flow2["src"], dconf.Hosts_JsonPort) t = time.strftime("%H:%M:%S", time.gmtime()) log.info("%s - Stopping Flow\n" % t) log.info("\t Sending request to host to stop flow %s\n" % str(flow["src"])) log.info("\t * Flow: %s\n" % self.toLogFlowNames(flow)) log.info("\t * Url: %s\n" % url) # Send request to host to start new iperf client session try: requests.post(url, json=flow2.toJSON()) except Exception: log.info("ERROR: Stop flow request could not be sent to Host!\n") def createRandomFlow(self): """Creates a random flow in the network """ pass def scheduleRandomFlows(self, ex_time=60, max_size="40M"): """Creates a random schedule of random flows in the network. This will be useful later to evaluate the performance of the LBController. """ pass def scheduleFileFlows(self, flowfile): """Schedules the flows specified in the flowfile """ f = open(flowfile, "r") flows = f.readlines() if flows: for flowline in flows: flowline = flowline.replace(" ", "").replace("\n", "") if flowline != "" and flowline[0] != "#": try: [s, d, sp, dp, size, s_t, dur] = flowline.strip("\n").split(",") # Get hosts IPs src_iface = self.db.getIpFromHostName(s) dst_iface = self.db.getIpFromHostName(d) except Exception: log.info("EP, SOMETHING HAPPENS HERE\n") src_iface = None dst_iface = None if src_iface != None and dst_iface != None: flow = Flow( src=src_iface, dst=dst_iface, sport=sp, dport=dp, size=size, start_time=s_t, duration=dur ) # Schedule flow creation self.scheduler.enter(0, 1, self.createFlow, ([flow])) else: log.info("ERROR! Hosts %s and/or %s do not exist in the network!\n" % (s, d)) # Make the scheduler run after file has been parsed self.scheduler.run() else: log.info("\t No flows to schedule in file\n")