def checkVNFLoad(vnfSwitches, offLoad): swDict = {} for sw in vnfSwitches: # loop through all switches if type(sw) == type({}): sw = sw['dstHost'] #print "checkvnfLoad SW %s" % (sw) switchObj = switchFinder.findSwitch(sw) switchLoad = int(pktMon.getSwitchLoad(s_name=switchObj.name)) newLoad = int( float(switchLoad) + (float(abs(offLoad)) * float(1 + float(migrateMargin)))) #print "checkvnfLoad SW %s has load %i and will get load %i with new NF" % (sw, int(switchLoad), newLoad) if float(float(1 - migrateMargin) * switchObj.queueRate) > float( newLoad): # if switch will not be overloading: swDict[sw] = { 'curload': int(switchLoad), 'newLoad': int(newLoad), 'maxLoad': int(switchObj.queueRate), 'newloadNum': float(float(newLoad) / float(switchObj.queueRate)) } # order the dict: res = OrderedDict( sorted(swDict.items(), key=lambda x: getitem(x[1], 'newloadNum'))) return res
def startPacketCounter(dstSwName='s3'): # this service needs to: # - enable code on the switch # - write some behaviour to switch that indicates which things to do tStart = time.time() sw = switchFinder.findSwitch(dstSwName) # add vnf to object sw.vnfList.append('packetCounter') dbConnect.addVNF(vnfName='packetCounter', prio=-10) appServices.addService('packetCounter', None) # this function only does this if it doesn't exist res = appServices.addServiceSwitch('packetCounter', sw.name) if res != True: raise Exception("something went wrong for adding a VNF") tPacketSetupService = time.time() - tStart print "Service proxy started. The whole process took %f seconds" % (tPacketSetupService)
def startProxyService(dstSwName='s1'): # this service needs to: # - enable code on a switch # - write some rules to the switch to have some behaviour # this is the network address translation service that tracks the connections that have to go through the proxy service. tStart = time.time() sw = switchFinder.findSwitch(dstSwName) ruleList = [] # add any original service rules to the dict. not used now because this is the initializing function, but this may be used in the future ruleList.append({ 'origDstIP' : '10.0.1.2', 'origSrcIP' : '10.0.1.10', 'newDstIP' : '10.0.1.20', 'newMAC' : '02:00:00:00:02:22' } ) ruleList.append({ 'origDstIP' : '10.0.1.2', 'origSrcIP' : '10.0.1.20', 'newDstIP' : '10.0.1.10', 'newMAC' : '02:00:00:00:01:11' } ) for rule in ruleList: oldDstIP = rule['origDstIP'] oldSrcIP = rule['origSrcIP'] newDstIP = rule['newDstIP'] newMAC = rule['newMAC'] dbConnect.addProxyStateless(srcIP=oldSrcIP, dstIP=oldDstIP, newDstIP=newDstIP, newDstMAC=newMAC) dbConnect.addVNF(vnfName='proxyStateless', srcIP=oldSrcIP, dstIP=oldDstIP) # initialize one instance on switch s3: appServices.addService('proxyStateless', None) appServices.addServiceSwitch('proxyStateless', sw.name) # add vnf to object sw.vnfList.append('proxyStateless') tProxySetupService = time.time() - tStart print "Service proxy started. The whole process took %f seconds" % (tProxySetupService) return
def checkSwitches(srcSw, migrate=False): # the flow volume that has to be offloaded to stop overloading the switch swLoad = float(pktMon.getSwitchLoad(s_name=srcSw.name)) offLoad = abs( int(swLoad - int(float(srcSw.queueRate) * float(1 - float(migrateMargin))))) # absolute... print("We will need to offload %s from the current load of %s" % (int(offLoad), int(swLoad))) # check all VNFS that run on the switch: If one solution has been found, redistributing load is feasible and that particular VNF for vnf in srcSw.vnfList: if migrate == False: vnfSwitches = getRebalanceOptions(str(vnf)) else: vnfSwitches = getMigrationOptions(str(vnf)) #print ("vnfswitches: %s" % (str(vnfSwitches))) if str(srcSw.name) in vnfSwitches: vnfSwitches.remove(srcSw.name) if len(vnfSwitches) < 1: # only one VNF running... definately no migration continue #orders the switches that could handle the load, from low load to high load. swDict = checkVNFLoad(vnfSwitches=vnfSwitches, offLoad=offLoad) #print swDict for swName, swDict in swDict.items(): if swName == srcSw.name: # not much use for this... continue #print "Checking to offload NF %s from %s to switch %s" %(vnf, srcSw.name, swName) dstSw = switchFinder.findSwitch(swName) flowIDList = checkRedistributeSwitchLoad(srcSw=srcSw, dstSw=dstSw, offLoad=offLoad, vnf=vnf) print "flowIDlist = %s" % str(flowIDList) if len(flowIDList) > 0: return (flowIDList, dstSw, flowIDList, vnf) return False, False, False, False
def installLabelPath(path, pkt, firstSwitch, lastSwitch, sequence): if path == None: # find out if source and destination are hosts: # TODO this only works for host<=> host communications. raise Exception("Path None can't have a shortes route") if pkt.flowID == None: raise Exception( "Flowid with id None can't be processed by installLabelPathFunction" ) # find services for flowID i = path.index(lastSwitch) while i >= 0: if netGraph.getHostAttr(path[i], "type") == "switch": s = switchFinder.findSwitch(path[i]) installRules = [] if s is not None: # do routing only if the path doesn't end with a switch. Do this until the last switch. # This packet will send a new packetin when it has finished processing the packet. # doe als: if s.name != lastSwitch or path[-1] != str(lastSwitch): #if s.name is not lastSwitch: #print "installing route_flowID rule on switch %s" % s.name installRule = {} installRule["default_action"] = False installRule["table_name"] = "route_flowID_tbl" installRule["match_fields"] = { "flowID.flowID": int(pkt.flowID), } installRule["action_name"] = "route_flowID" installRule["action_params"] = { "outPort": int( netGraph.getLinkProperties(path[i], path[i + 1])["port"]) } installRules.append(installRule) # only install this last rule when switching to a real destination host. Otherwise packetins don't work if (s.name == str(firstSwitch)) and ( sequence == 0 ): # lastswitch bit added for single length paths. Is shouldn't set the flowID again. #print "installing set_flowID rule on switch %s" % s.name installRule = {} installRule["default_action"] = False installRule["table_name"] = "set_flowID_tbl" installRule["match_fields"] = { "ipv4.srcAddr": pkt.srcIP, "ipv4.dstAddr": pkt.dstIP, "ipv4.protocol": pkt.ip.p, "port_metadata.srcPort": pkt.srcPort, "port_metadata.dstPort": pkt.dstPort } installRule["action_name"] = "set_flowID" installRule["action_params"] = {"flowid": pkt.flowID} installRules.append(installRule) # if the last step in the path is the last switch, do not install the last forwarding rule. if (s.name == str(lastSwitch)) and (path[-1] != str(lastSwitch)): #print "installing remove_flowID rule on switch %s" % s.name installRule = {} installRule["default_action"] = False installRule["table_name"] = "remove_flowID_tbl" installRule["match_fields"] = { "flowID.flowID": int(pkt.flowID) } installRule["action_name"] = "remove_flowID" installRule["action_params"] = {} installRules.append(installRule) # at the end of this, install all rules to the switch s.installRulesOnSwitch(installRules) i -= 1 return True
def processMigPkt(self, msg): sleep(self.controlPlaneDelay) ts = time() #print "Pkt received from %s %s" % (self.name, msg.packet.payload.encode('hex')) try: idHdr = str(msg.packet.payload.encode('hex')[0:4]) migFlowID = int(msg.packet.payload.encode('hex')[4:12], 16) subProtocol = str(msg.packet.payload.encode('hex')[12:14]) sequenceID = int(msg.packet.payload.encode('hex')[14:18], 16) intVNFID = int(msg.packet.payload.encode('hex')[18:20], 16) sessionID = int(msg.packet.payload.encode('hex')[20:22], 16) flowID = int(msg.packet.payload.encode('hex')[22:30], 16) except: print 'error in packetpayload:' print msg.packet.payload.encode('hex') if subProtocol == 'aa' or subProtocol == '55': print "pkt is: %s" % msg.packet.payload.encode('hex') ts_u = int(msg.packet.payload.encode('hex')[-12], 16) pktMon.addMigPktReading(s_name=self.name, sequenceID=sequenceID, VNFID=intVNFID, sessionID=sessionID, flowID=flowID, ts_u=ts_u) # add logging rule to logDB #dbConnect.addFlowLog(flowID=flowID, ts=ts_u, recvSw=self.name, sequenceID=sequenceID, VNFID=intVNFID, subProtocol=subProtocol) print "Timingrommel ontvangen (%s), ts: %s!" % (subProtocol, str(ts_u)) # get the flowStatus. If the '3c' packet has been missed, elif subProtocol == '3c': # acceptflow packet from migration destination print """ Initial sync completed. Sync process is in update phase, where the migration destination is updated. Now change to 'forward' state. This will cause the secondary switch to process the packets. State updates will not be accepted anymore for this flow. """ # This is an initial sync packet # Now signal the migration destination switch that we can switch to the forward phase. # put the corresponding transmission algorithm into the next phase result = dbConnect.getMigSrcSw(flowID=flowID, VNFID=intVNFID) if result == None: print 'error getting dstSw, nothing returned from query %s' % str( result) return if 'dstHost' not in result: print 'Error getting dstSw!' print result return srcSw = switchFinder.findSwitch(result['dstHost']) pktMon.addNewMigrationLine(srcSw=srcSw.name, dstSw=self.name, ts=ts, phase=15, flowID=flowID) # spawn a new thread that # 1. waits for the rule installation to be complete # 2. kicks the process to the flowhandler state # immediately go to new state. t = threading.Thread(target=flowHandler.flowMigratetoForwardPhase, args=(srcSw, self, flowID, intVNFID)) t.start() elif subProtocol == 'ff' or subProtocol == '3f': # this is an ack for the forwardflow state. print """ Update phase completed (ack received from srcSrcSw). Now install the remaining path to divert traffic from migsrc to migdst immediately, and therefore releaving migsrc. Keep hanging 1 second after the process to prevent excessive migrations """ dstSwName = dbConnect.searchFlowMigrateDstHost(flowID=flowID, srcSw=self.name) if dstSwName == None: return srcSw = switchFinder.findSwitch(dstSwName) pktMon.addNewMigrationLine(srcSw=srcSw.name, dstSw=dstSwName, ts=ts, phase=30, flowID=flowID) t = threading.Thread(target=flowHandler.flowMigrateFinish, args=(self, dstSwName, flowID, intVNFID)) t.start()
def processpacketIn(self, pkt): # print "Packetin received from switch %s" % self.name # print "packet: %s" % (str(pkt.payload.encode('hex'))) h, flowID = getHash(srcIP=pkt.srcIP, dstIP=pkt.dstIP, srcPort=pkt.srcPort, dstPort=pkt.dstPort, ipProto=pkt.ip.p, srcHost=self.name) if h[-1] == True or str(h[-1]) == str(self.name): # packet does not yet exist, do everything doServices = False if pkt.flowID == None: pkt.flowID = int(random.getrandbits(30)) # if applicable, add hosts to the graph pkt.addLinktoGraph() # check whether this flow should go through a VNF. VNF = flowHandler.getService(srcMAC=pkt.srcMAC, dstMAC=pkt.dstMAC, srcIP=pkt.srcIP, srcPort=pkt.srcPort, dstIP=pkt.dstIP, dstPort=pkt.dstPort, protocol=pkt.ip.p) VNFList = dbConnect.getFlowVNFS(srcIP=pkt.srcIP, dstIP=pkt.dstIP, srcPort=pkt.srcPort, dstPort=pkt.dstPort, ipProtocol=pkt.ip.p) processedVNFList = dbConnect.searchVNFSbyFlow(flowID=pkt.flowID) VNF = None # search the first NF that has to be processed now: for vnf in VNFList: if vnf['vnfName'] not in processedVNFList: VNF = vnf['vnfName'] break # check which actions already are assigned to flow (and which are already processed): # change destination and install service to switch if VNF == 'proxyStateless': print 'we have a proxystateless machine!!!' # We have a packet that has to be processed by the proxy before it goes to its destination. dstSw = flowHandler.assignService(VNF) # install service on dstSw # TODO switchFinder.findSwitch(dstSw).installVNF(pkt=pkt, VNF=VNF) # calculate a new path for the packet to the assigned switch: do not remove flowID at the last switch pkt.realDstHost = dstSw elif VNF == 'packetCounter': # do packetcounter #print 'do packetcounter' dstSw = flowHandler.assignService(VNF) switchFinder.findSwitch(dstSw).installVNF(pkt=pkt, VNF=VNF) pkt.realDstHost = dstSw elif VNF == None: pkt.realDstHost = pkt.dstMAC # calculate the path from the current location of the packet (the receiving switch) to the destination path = findRoute(pkt.recv_sw, pkt.realDstHost) if path == []: print "iets foutgegaan in berekenen route" removeHash(srcIP=pkt.srcIP, dstIP=pkt.dstIP, srcPort=pkt.srcPort, dstPort=pkt.dstPort, ipProto=pkt.ip.p, srcHost=self.name) return # path has been found. firstSwitch = pathFindFirstSwitch(path) lastSwitch = pathFindLastSwitch(path) #print 'lastswitch is: %s' % str(lastSwitch) if lastSwitch != None and str(lastSwitch) != 'None': updateHash(srcIP=pkt.srcIP, dstIP=pkt.dstIP, srcPort=pkt.srcPort, dstPort=pkt.dstPort, ipProto=pkt.ip.p, srcHost=self.name, dstHost=lastSwitch, flowID=int(pkt.flowID)) # get flow infromation. If no result is shown, generate a new flowID and add it to the database # flow is distinguished based on following fields # srcHost # srcPort # ipv4 protocol # dstHost # dstPort if pkt.flowID is not None: flowInfo = dbConnect.searchFlowTable(flowID=pkt.flowID, srcIP=pkt.srcIP, srcPort=pkt.srcPort, ipProtocol=pkt.ip.p, dstIP=pkt.dstIP, dstPort=pkt.dstPort, vnf=VNF) if len(flowInfo) == 0: # add new entry. this one is not correct: print "Packet with new flowID %s" % (pkt.flowID) # add the new flow to the table: sequence = dbConnect.addFlowTableEntry(flowID=str(pkt.flowID), srcHost=str(path[0]), dstHost=str(path[-1]), vnf=str(VNF), srcIP=pkt.srcIP, srcPort=pkt.srcPort, ipProtocol=pkt.ip.p, dstIP=pkt.dstIP, dstPort=pkt.dstPort) else: sequence = flowInfo[0]['sequence'] # install path #print path installStatus = flowHandler.installLabelPath( path=path, pkt=pkt, firstSwitch=str(firstSwitch), lastSwitch=str(lastSwitch), sequence=sequence) if installStatus == False: print "installing path failed somewhere." removeHash(srcIP=pkt.srcIP, dstIP=pkt.dstIP, srcPort=pkt.srcPort, dstPort=pkt.dstPort, ipProto=pkt.ip.p, srcHost=self.name) return if lastSwitch != None: lastSw = switchFinder.findSwitch(lastSwitch) flowID = int(pkt.flowID) elif h != False: # packet already exists. send the packet to the destination. lastSw = switchFinder.findSwitch(h[-1]) flowID = flowID else: h = [False] #beunbeunbeun while (h[-1] == False or str(h[-1]) == str(self.name)): # buffer this packet until h != false anymore print 'Packet buffered!%s' % (str(h)) h, flowID = getHash(srcIP=pkt.srcIP, dstIP=pkt.dstIP, srcPort=pkt.srcPort, dstPort=pkt.dstPort, ipProto=pkt.ip.p, srcHost=self.name) if type(h) == type(None): h = [False] lastSw = switchFinder.findSwitch(h) flowID = flowID # print("poblempaket!") # print('h: %s' % str(h)) # print('flowID: %s' % str(flowID)) # print pkt.payload.encode('hex') # lastSw = None # send packetOut if lastSw != None and flowID != False: lastSw.sendPacketOutLabel(pkt.payload[:14] + pkt.payload[16:], int(flowID))