Beispiel #1
0
def launch():
    """
    core is able to register all the pox components
    core.openflow is the pox openflow component
    _handle_ConnectionUp subscribe to core.openflow's ConnectionUp event

    each Timer instance add a non-default parameter to show Timer
    capabilities.

    """

    TIME_TO_WAKE = 2
    args = ["ciao", "mare"]
    core.callDelayed(TIME_TO_WAKE, timeout_handler, args)

    t = Timer(
            TIME_TO_WAKE,
            timeout_handler,
            args='t1')

    t2 = Timer(
            TIME_TO_WAKE,
            timeout_handler,
            absoluteTime=True,  # use False
            args='t2')

    tr = Timer(
            TIME_TO_WAKE,
            timeout_handler,
            absoluteTime=False,
            recurring=True,  # recur infinitely overtime
            args='tr')

    tw = Timer(
            TIME_TO_WAKE,
            timeout_handler,
            absoluteTime=False,
            recurring=False,
            started=False,  # not start automatically
            args='tw')
    time.sleep(TIME_TO_WAKE)
    tw.start()

    tk = Timer(
            TIME_TO_WAKE,
            timeout_handler_kill,  # handler able to cancel the timer
            absoluteTime=False,
            recurring=True,
            started=False,
            selfStoppable=False,  # timer can be cancelled by the handler
            args='tw')
Beispiel #2
0
 def update(self):
   # let the controller start update the configuration
   log.warning("Updating Starts.")
   self.update_step = 0
   self.config.read_config( INPUT_CONFIG_FILENAME )
   # Initial update
   self.update_timer = Timer(self.config.next_time, self._update_step, started = False, recurring = True)
   self._update_step()
   self.update_timer.start()
def GetTopologyParams():
  Timer(10, find_latency1, recurring = True)
  timeout = min(max(PATH_SETUP_TIME, 5) * 2, 15)
  Timer(timeout, WaitingPath.expire_waiting_paths, recurring=True)
  Timer(15, find_HostPorts, recurring = False)
Beispiel #4
0
 def iniciarTimer(self):
     Timer(10, self.getflowstats, recurring=True)
  def _handle_openflow_PacketIn (self, event):
    dpid = event.connection.dpid
    inport = event.port
    packet = event.parsed
    global set_Timer
    global defendDDOS
    global blockPort
    timerSet =False
    global diction
    def preventing():
      global diction
      global set_Timer
      if not set_Timer:
        set_Timer =True
      #Timer(1, _timer_func(), recurring=True)


      #print"\n\n*********new packetIN************"
      if len(diction) == 0:
        print("Enpty diction ",str(event.connection.dpid), str(event.port))
        diction[event.connection.dpid] = {}
        diction[event.connection.dpid][event.port] = 1
      elif event.connection.dpid not in diction:
        diction[event.connection.dpid] = {}
        diction[event.connection.dpid][event.port] = 1
        #print "ERROR"
      else:
        if event.connection.dpid in diction:
      # temp = diction[event.connection.dpid]
      #print(temp)
      #print "error check " , str(diction[event.connection.dpid][event.port])
          if event.port in diction[event.connection.dpid]:
            temp_count=0
            temp_count =diction[event.connection.dpid][event.port]
            temp_count = temp_count+1
            diction[event.connection.dpid][event.port]=temp_count
            #print "printting dpid port number and its packet count: ",  str(event.connection.dpid), str(diction[event.connection.dpid]), str(diction[event.connection.dpid][event.port])
          else:
            diction[event.connection.dpid][event.port] = 1
   
      print "\n",datetime.datetime.now(), ": printing diction ",str(diction),"\n"
    
    
    def _timer_func ():
      global diction
      global set_Timer
      if set_Timer==True:
        #print datetime.datetime.now(),": calling timer fucntion now!!!!!" 
        for k,v in diction.iteritems():
          for i,j in v.iteritems():
            if j >=50:
              print "_____________________________________________________________________________________________"
              print "\n",datetime.datetime.now(),"*******    DDOS DETECTED   ********"
              print "\n",str(diction)
              print "\n",datetime.datetime.now(),": BLOCKED PORT NUMBER  : ", str(i), " OF SWITCH ID: ", str(k)
              print "\n_____________________________________________________________________________________________"

              #self.dropDDOS ()
              dpid = k
              msg = of.ofp_packet_out(in_port=i)
              #msg.priority=42
              #msg.in_port = event.port
              #po = of.ofp_packet_out(buffer_id = buffer_id, in_port = in_port)
              core.openflow.sendToDPID(dpid,msg)

              
                
      diction={}

    if not packet.parsed:
      log.warning("%i %i ignoring unparsed packet", dpid, inport)
      return

    if dpid not in self.arpTable:
      # New switch -- create an empty table
      self.arpTable[dpid] = {}
      for fake in self.fakeways:
        self.arpTable[dpid][IPAddr(fake)] = Entry(of.OFPP_NONE,
         dpid_to_mac(dpid))

    if packet.type == ethernet.LLDP_TYPE:
      # Ignore LLDP packets
      return

#-------------------------------------------editing--------------------------------------------------
    if isinstance(packet.next, ipv4):
      log.debug("%i %i IP %s => %s", dpid,inport,
                packet.next.srcip,packet.next.dstip)

      ent_obj.statcolect(event.parsed.next.dstip)
      print "\n***** Entropy Value = ",str(ent_obj.value),"*****\n"
      if ent_obj.value <0.5:
        preventing()
        if timerSet is not True:
          Timer(2, _timer_func, recurring=True)
          timerSet=False
      else:
        timerSet=False
          

            
      # Send any waiting packets...
      self._send_lost_buffers(dpid, packet.next.srcip, packet.src, inport)

      # Learn or update port/MAC info
      if packet.next.srcip in self.arpTable[dpid]:
        if self.arpTable[dpid][packet.next.srcip] != (inport, packet.src):
          log.info("%i %i RE-learned %s", dpid,inport,packet.next.srcip)
          if self.wide:
            # Make sure we don't have any entries with the old info...
            msg = of.ofp_flow_mod(command=of.OFPFC_DELETE)
            msg.match.nw_dst = packet.next.srcip
            msg.match.dl_type = ethernet.IP_TYPE
            event.connection.send(msg)
      else:
        log.debug("%i %i learned %s", dpid,inport,packet.next.srcip)
      self.arpTable[dpid][packet.next.srcip] = Entry(inport, packet.src)
      #nandan: getting source ip address from the packetIn
      #myPacketInSrcIP= packet.next.srcip
      #myPacketInSrcEth= packet.src
      #myPacketInDstIP= packet.next.dstip
      #myPacketInDstEth= packet.dst

      #print "switcID: "+str(dpid)+" ,Port: "+str(event.port)+" ,MAC address: "+str(myPacketInSrcEth)+" ,SrcIP: "+ str(myPacketInSrcIP)+", Dst Mac: "+str(myPacketInDstEth)+", Dst IP: "+str(myPacketInDstEth)
      # Try to forward
      dstaddr = packet.next.dstip
      if dstaddr in self.arpTable[dpid]:
        # We have info about what port to send it out on...

        prt = self.arpTable[dpid][dstaddr].port
        mac = self.arpTable[dpid][dstaddr].mac
        if prt == inport:
          log.warning("%i %i not sending packet for %s back out of the "
                      "input port" % (dpid, inport, dstaddr))
        else:
          log.debug("%i %i installing flow for %s => %s out port %i"
                    % (dpid, inport, packet.next.srcip, dstaddr, prt))

          actions = []
          actions.append(of.ofp_action_dl_addr.set_dst(mac))
          actions.append(of.ofp_action_output(port = prt))
          if self.wide:
            match = of.ofp_match(dl_type = packet.type, nw_dst = dstaddr)
          else:
            match = of.ofp_match.from_packet(packet, inport)

          msg = of.ofp_flow_mod(command=of.OFPFC_ADD,
                                idle_timeout=FLOW_IDLE_TIMEOUT,
                                hard_timeout=of.OFP_FLOW_PERMANENT,
                                buffer_id=event.ofp.buffer_id,
                                actions=actions,
                                match=match)
          event.connection.send(msg.pack())
      elif self.arp_for_unknowns:
        # We don't know this destination.
        # First, we track this buffer so that we can try to resend it later
        # if we learn the destination, second we ARP for the destination,
        # which should ultimately result in it responding and us learning
        # where it is

        # Add to tracked buffers
        if (dpid,dstaddr) not in self.lost_buffers:
          self.lost_buffers[(dpid,dstaddr)] = []
        bucket = self.lost_buffers[(dpid,dstaddr)]
        entry = (time.time() + MAX_BUFFER_TIME,event.ofp.buffer_id,inport)
        bucket.append(entry)
        while len(bucket) > MAX_BUFFERED_PER_IP: del bucket[0]

        # Expire things from our outstanding ARP list...
        self.outstanding_arps = {k:v for k,v in
         self.outstanding_arps.iteritems() if v > time.time()}

        # Check if we've already ARPed recently
        if (dpid,dstaddr) in self.outstanding_arps:
          # Oop, we've already done this one recently.
          return

        # And ARP...
        self.outstanding_arps[(dpid,dstaddr)] = time.time() + 4

        r = arp()
        r.hwtype = r.HW_TYPE_ETHERNET
        r.prototype = r.PROTO_TYPE_IP
        r.hwlen = 6
        r.protolen = r.protolen
        r.opcode = r.REQUEST
        r.hwdst = ETHER_BROADCAST
        r.protodst = dstaddr
        r.hwsrc = packet.src
        r.protosrc = packet.next.srcip
        e = ethernet(type=ethernet.ARP_TYPE, src=packet.src,
                     dst=ETHER_BROADCAST)
        e.set_payload(r)
        log.debug("%i %i ARPing for %s on behalf of %s" % (dpid, inport,
         r.protodst, r.protosrc))
        msg = of.ofp_packet_out()
        msg.data = e.pack()
        msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
        msg.in_port = inport
        event.connection.send(msg)

    elif isinstance(packet.next, arp):
      a = packet.next
      log.debug("%i %i ARP %s %s => %s", dpid, inport,
       {arp.REQUEST:"request",arp.REPLY:"reply"}.get(a.opcode,
       'op:%i' % (a.opcode,)), a.protosrc, a.protodst)

      if a.prototype == arp.PROTO_TYPE_IP:
        if a.hwtype == arp.HW_TYPE_ETHERNET:
          if a.protosrc != 0:

            # Learn or update port/MAC info
            if a.protosrc in self.arpTable[dpid]:
              if self.arpTable[dpid][a.protosrc] != (inport, packet.src):
                log.info("%i %i RE-learned %s", dpid,inport,a.protosrc)
                if self.wide:
                  # Make sure we don't have any entries with the old info...
                  msg = of.ofp_flow_mod(command=of.OFPFC_DELETE)
                  msg.match.dl_type = ethernet.IP_TYPE
                  msg.match.nw_dst = a.protosrc
                  event.connection.send(msg)
            else:
              log.debug("%i %i learned %s", dpid,inport,a.protosrc)
            self.arpTable[dpid][a.protosrc] = Entry(inport, packet.src)

            # Send any waiting packets...
            self._send_lost_buffers(dpid, a.protosrc, packet.src, inport)

            if a.opcode == arp.REQUEST:
              # Maybe we can answer

              if a.protodst in self.arpTable[dpid]:
                # We have an answer...

                if not self.arpTable[dpid][a.protodst].isExpired():
                  # .. and it's relatively current, so we'll reply ourselves

                  r = arp()
                  r.hwtype = a.hwtype
                  r.prototype = a.prototype
                  r.hwlen = a.hwlen
                  r.protolen = a.protolen
                  r.opcode = arp.REPLY
                  r.hwdst = a.hwsrc
                  r.protodst = a.protosrc
                  r.protosrc = a.protodst
                  r.hwsrc = self.arpTable[dpid][a.protodst].mac
                  e = ethernet(type=packet.type, src=dpid_to_mac(dpid),
                               dst=a.hwsrc)
                  e.set_payload(r)
                  log.debug("%i %i answering ARP for %s" % (dpid, inport,
                   r.protosrc))
                  msg = of.ofp_packet_out()
                  msg.data = e.pack()
                  msg.actions.append(of.ofp_action_output(port =
                                                          of.OFPP_IN_PORT))
                  msg.in_port = inport
                  event.connection.send(msg)
                  return

      # Didn't know how to answer or otherwise handle this ARP, so just flood it
      log.debug("%i %i flooding ARP %s %s => %s" % (dpid, inport,
       {arp.REQUEST:"request",arp.REPLY:"reply"}.get(a.opcode,
       'op:%i' % (a.opcode,)), a.protosrc, a.protodst))

      msg = of.ofp_packet_out(in_port = inport, data = event.ofp,
          action = of.ofp_action_output(port = of.OFPP_FLOOD))
      event.connection.send(msg)
Beispiel #6
0
 def __init__ (self):
   # This timer handles expiring stuff
   self._expire_timer = Timer(5, _handle_expiration, recurring=True)
   core.listen_to_dependencies(self)
   core.addListeners(self, priority = 2)
Beispiel #7
0
# JRF:  Adding this for experimentation
from pox.lib.recoco import Timer

from pox.core import core
import pox.openflow.libopenflow_01 as of
from pox.lib.util import dpidToStr

log = core.getLogger()


def handle_timer_elapse(message):
    print "I was told to tell you:", message


Timer(10, handle_timer_elapse, args=["Hello"])


def _handle_ConnectionUp(event):
    """
  Be a proactive hub by telling every connected switch to flood all packets
  """
    msg = of.ofp_flow_mod()
    msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD))
    event.connection.send(msg)
    log.info("Hubifying %s", dpidToStr(event.dpid))


def _handle_PacketIn(event):
    """
  Be a reactive hub by flooding every incoming packet
Beispiel #8
0
    def _all_dependencies_met(self):
        self._startup("poxdesk_topo")

        # Periodically just send a topo
        self.timer = Timer(10, self.send_table, recurring=True)
        log.debug("Ready to rip.")
def launch():

    core.registerNew(Multi_switches_load_balancing)

    core.openflow.addListenerByName("FlowStatsReceived", handle_flow_stats)
    Timer(0.5, handle_timer_elapse, recurring=True)
Beispiel #10
0
  def _handle_PacketIn (self, event):
    dpid = event.connection.dpid
    inport = event.port
    packet = event.parsed
    
    #print "------------------------------------------------------------------------"
    #print "IPv4: ", event.parsed.find('ipv4')
    #print "ARP: ", event.parsed.find('arp')
    #print "Packet Type: " , packet.type
    
    #print datetime.datetime.now(), ":", packet
    #print "\n", packet.parsed
    #print "\n", event.ofp
    global call_Timer
    global set_Timer
    global diction
    timerSet =False
    
    def preventing():
      global diction
      global set_Timer
      if not set_Timer:
        set_Timer =True

      if len(diction) == 0:
        diction[event.connection.dpid] = {}
        diction[event.connection.dpid][event.port] = 1
      elif event.connection.dpid not in diction:
        diction[event.connection.dpid] = {}
        diction[event.connection.dpid][event.port] = 1
      else:
        if event.connection.dpid in diction:
          if event.port in diction[event.connection.dpid]:
            temp_count=0
            temp_count =diction[event.connection.dpid][event.port]
            temp_count = temp_count+1
            diction[event.connection.dpid][event.port]=temp_count
          else:
            diction[event.connection.dpid][event.port] = 1
   
      print "\n",datetime.datetime.now(), ": printing diction ",str(diction),"\n"
    
    
    def _timer_func ():
      global diction
      #print "Dictionary:", diction
      global set_Timer
      if not set_Timer:
        set_Timer =True

      if set_Timer==True:
        for k,v in diction.iteritems():
          for i,j in v.iteritems():
            if j >=20:
              print "\n",datetime.datetime.now(),"DDOS DETECTED"
              print "\n",str(diction)
              print "\n",datetime.datetime.now(),": BLOCKED PORT NUMBER : ", str(i), " OF SWITCH ID: ", str(k)
              #appending no actions to the out_msg the packets will be dropped from the current DPID-PORT pair  
              dpid = k									    		
              msg = of.ofp_packet_out(in_port=i)
              core.openflow.sendToDPID(dpid,msg)
      diction={}
    
    if not packet.parsed:
      log.warning("%i %i ignoring unparsed packet", dpid, inport)
      return

    if dpid not in self.arpTable:
      # New switch -- create an empty table
      self.arpTable[dpid] = {}
      for fake in self.fakeways:
        self.arpTable[dpid][IPAddr(fake)] = Entry(of.OFPP_NONE,
         dpid_to_mac(dpid))
    #print "Arp table: ", str(self.arpTable)
    if packet.type == ethernet.LLDP_TYPE:
      # Ignore LLDP packets
      return

    if isinstance(packet.next, ipv4):
      log.debug("%i %i IP %s => %s", dpid,inport,
                packet.next.srcip,packet.next.dstip)
      #print "\n"
      chi_obj.stats(packet.next.srcip)      #edit
      chi_obj.baseLine()		    #edit
      if chi_obj.y < 0.05 :
        print "DDoS might be there"
        preventing()
	      Timer(10, _timer_func)              

      # Send any waiting packets...
      self._send_lost_buffers(dpid, packet.next.srcip, packet.src, inport)
      #print "LOST BUFFERS: " , str(self.lost_buffers) #edited

      # Learn or update port/MAC info
      if packet.next.srcip in self.arpTable[dpid]:
        #print packet.next.srcip , "#editing"
        if self.arpTable[dpid][packet.next.srcip] != (inport, packet.src):
          log.info("%i %i RE-learned %s", dpid,inport,packet.next.srcip)
      else:
        log.debug("%i %i learned %s", dpid,inport,str(packet.next.srcip))
      self.arpTable[dpid][packet.next.srcip] = Entry(inport, packet.src)
      #print "Arp table: ", str(self.arpTable)
      # Try to forward
      dstaddr = packet.next.dstip
      if dstaddr in self.arpTable[dpid]:
        # We have info about what port to send it out on...

        prt = self.arpTable[dpid][dstaddr].port
        mac = self.arpTable[dpid][dstaddr].mac
        if prt == inport:
          log.warning("%i %i not sending packet for %s back out of the " +
                      "input port" % (dpid, inport, str(dstaddr)))
        else:
          log.debug("%i %i installing flow for %s => %s out port %i"
                    % (dpid, inport, packet.next.srcip, dstaddr, prt))

          actions = []
          actions.append(of.ofp_action_dl_addr.set_dst(mac))
          actions.append(of.ofp_action_output(port = prt))
          match = of.ofp_match.from_packet(packet, inport)
          match.dl_src = None # Wildcard source MAC

          msg = of.ofp_flow_mod(command=of.OFPFC_ADD,
                                idle_timeout=FLOW_IDLE_TIMEOUT,
                                hard_timeout=of.OFP_FLOW_PERMANENT,
                                buffer_id=event.ofp.buffer_id,
                                actions=actions,
                                match=of.ofp_match.from_packet(packet,
                                                               inport))
          event.connection.send(msg.pack())
      elif self.arp_for_unknowns:
        # We don't know this destination.
        # First, we track this buffer so that we can try to resend it later
        # if we learn the destination, second we ARP for the destination,
        # which should ultimately result in it responding and us learning
        # where it is

        # Add to tracked buffers
        if (dpid,dstaddr) not in self.lost_buffers:
          self.lost_buffers[(dpid,dstaddr)] = []
        bucket = self.lost_buffers[(dpid,dstaddr)]
        entry = (time.time() + MAX_BUFFER_TIME,event.ofp.buffer_id,inport)
        bucket.append(entry)
        while len(bucket) > MAX_BUFFERED_PER_IP: del bucket[0]

        # Expire things from our outstanding ARP list...
        self.outstanding_arps = {k:v for k,v in
         self.outstanding_arps.iteritems() if v > time.time()}

        # Check if we've already ARPed recently
        if (dpid,dstaddr) in self.outstanding_arps:
          # Oop, we've already done this one recently.
          return

        # And ARP...
        self.outstanding_arps[(dpid,dstaddr)] = time.time() + 4

        r = arp()
        r.hwtype = r.HW_TYPE_ETHERNET
        r.prototype = r.PROTO_TYPE_IP
        r.hwlen = 6
        r.protolen = r.protolen
        r.opcode = r.REQUEST
        r.hwdst = ETHER_BROADCAST
        r.protodst = dstaddr
        r.hwsrc = packet.src
        r.protosrc = packet.next.srcip
        e = ethernet(type=ethernet.ARP_TYPE, src=packet.src,
                     dst=ETHER_BROADCAST)
        e.set_payload(r)
        log.debug("%i %i ARPing for %s on behalf of %s" % (dpid, inport,
         str(r.protodst), str(r.protosrc)))
        msg = of.ofp_packet_out()
        msg.data = e.pack()
        msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
        msg.in_port = inport
        event.connection.send(msg)
Beispiel #11
0
 def __init__(self, timeout):
     self.debounce = {}
     self.timeout = int(timeout)
     core.listen_to_dependencies(self)
     Timer(self.timeout, self._handle_timer, recurring=True)
Beispiel #12
0
class MulticastPath(object):
    """Manages multicast route calculation and installation for a single pair of multicast group and multicast sender."""

    def __init__(self, src_ip, src_router_dpid, ingress_port, dst_mcast_address, groupflow_manager, groupflow_trace_event = None):
        self.src_ip = src_ip
        self.ingress_port = ingress_port
        self.src_router_dpid = src_router_dpid
        self.dst_mcast_address = dst_mcast_address
        self.path_tree_map = defaultdict(lambda : None)     # self.path_tree_map[router_dpid] = Complete path from receiver router_dpid to src
        self.weighted_topo_graph = []
        self.node_list = []                 # List of all managed router dpids
        self.installed_node_list = []       # List of all router dpids with rules currently installed
        self.receivers = []                 # Tuples of (router_dpid, port)
        self.groupflow_manager = groupflow_manager
        self.flow_cookie = self.groupflow_manager.get_new_mcast_group_cookie()
        self.calc_path_tree_dijkstras(groupflow_trace_event)
        self._last_flow_replacement_time = None
        self._flow_replacement_timer = None

    def calc_path_tree_dijkstras(self, groupflow_trace_event = None):
        """Calculates a shortest path tree from the group sender to all network switches, and caches the resulting tree.

        Note that this function does not install any flow modifications."""
        if not groupflow_trace_event is None:
            groupflow_trace_event.set_tree_calc_start_time(self.dst_mcast_address, self.src_ip)
        self._last_flow_replacement_time = time.time()
    
        self._calc_link_weights()
        
        nodes = set(self.node_list)
        edges = self.weighted_topo_graph
        graph = defaultdict(list)
        for src,dst,cost in edges:
            graph[src].append((cost, dst))
     
        path_tree_map = defaultdict(lambda : None)
        queue, seen = [(0,self.src_router_dpid,())], set()
        while queue:
            (cost,node1,path) = heappop(queue)
            if node1 not in seen:
                seen.add(node1)
                path = (node1, path)
                path_tree_map[node1] = path
     
                for next_cost, node2 in graph.get(node1, ()):
                    if node2 not in seen:
                        new_path_cost = cost + next_cost
                        heappush(queue, (new_path_cost, node2, path))
        
        self.path_tree_map = path_tree_map
        
        log.debug('Calculated shortest path tree for source at router_dpid: ' + dpid_to_str(self.src_router_dpid))
        for node in self.path_tree_map:
            log.debug('Path to Node ' + dpid_to_str(node) + ': ' + str(self.path_tree_map[node]))
        
        if not groupflow_trace_event is None:
            groupflow_trace_event.set_tree_calc_end_time()
    
    def _calc_link_weights(self):
        """Calculates link weights for all links in the network to be used by calc_path_tree_dijkstras().

        The cost assigned to each link is based on the link's current utilization (as determined by the FlowTracker
        module), and the exact manner in which utilization is converted to a link wieght is determined by
        groupflow_manager.link_weight_type. Valid options are LINK_WEIGHT_LINEAR and LINK_WEIGHT_EXPONENTIAL. Both options
        include a static weight which is always assigned to all links (determined by groupflow_manager.static_link_weight),
        and a dynamic weight which is based on the current utilization (determined by
        groupflow_manager.utilization_link_weight). Setting groupflow_manager.utilization_link_weight to 0 will always
        results in shortest hop routing.
        """
        curr_topo_graph = self.groupflow_manager.topology_graph
        self.node_list = list(self.groupflow_manager.node_set)
        
        weighted_topo_graph = []
        current_util = core.openflow_flow_tracker.get_max_flow_utilization(self.flow_cookie) / core.openflow_flow_tracker.link_max_bw
        log.info('Current utilization of flow ' + str(self.flow_cookie) + ': ' + str(current_util * core.openflow_flow_tracker.link_max_bw) + ' Mbps')
        
        for edge in curr_topo_graph:
            output_port = self.groupflow_manager.adjacency[edge[0]][edge[1]]
            raw_link_util = core.openflow_flow_tracker.get_link_utilization_normalized(edge[0], output_port);
            link_util_mcast_flow = core.openflow_flow_tracker.get_flow_utilization_normalized(edge[0], output_port, self.flow_cookie)
            
            link_util = max(0, (raw_link_util * (1 - link_util_mcast_flow)))
            
            # link_util = raw_link_util # Uncommenting this line will cause flows to reroute around their own traffic, good for testing
            
            # Current utilization here is doubled as a simple attempt to handle variability in flow rates
            if link_util + (current_util * 2) > 1:
                link_util = 1
            
            link_weight = 1
            
            if self.groupflow_manager.util_link_weight == 0:
                link_weight = self.groupflow_manager.static_link_weight
            else:
                if self.groupflow_manager.link_weight_type == LINK_WEIGHT_LINEAR:
                    if link_util >= 1:
                        link_weight = sys.float_info.max / core.openflow_flow_tracker.get_num_tracked_links()
                    else:
                        link_weight = min(self.groupflow_manager.static_link_weight + (self.groupflow_manager.util_link_weight * link_util),
                                sys.float_info.max / core.openflow_flow_tracker.get_num_tracked_links())
                elif self.groupflow_manager.link_weight_type == LINK_WEIGHT_EXPONENTIAL:
                    if link_util >= 1:
                        link_weight = sys.float_info.max / core.openflow_flow_tracker.get_num_tracked_links()
                    else:
                        link_weight = min(self.groupflow_manager.static_link_weight + (self.groupflow_manager.util_link_weight * ((1 / (1 - link_util)) - 1)),
                                sys.float_info.max / core.openflow_flow_tracker.get_num_tracked_links())
                
                log.debug('Router DPID: ' + dpid_to_str(edge[0]) + ' Port: ' + str(output_port) + 
                        ' TotalUtil: ' + str(raw_link_util) + ' FlowUtil: ' + str(link_util_mcast_flow) + ' OtherFlowUtil: ' + str(link_util) 
                        + ' Weight: ' + str(link_weight))

            weighted_topo_graph.append([edge[0], edge[1], link_weight])
        self.weighted_topo_graph = weighted_topo_graph
        
        log.debug('Calculated link weights for source at router_dpid: ' + dpid_to_str(self.src_router_dpid))
        for edge in self.weighted_topo_graph:
            log.debug(dpid_to_str(edge[0]) + ' -> ' + dpid_to_str(edge[1]) + ' W: ' + str(edge[2]))
    
    def install_openflow_rules(self, groupflow_trace_event = None):
        """Selects routes for active receivers from the cached shortest path tree, and installs/removes OpenFlow rules accordingly."""
        reception_state = self.groupflow_manager.get_reception_state(self.dst_mcast_address, self.src_ip)
        log.debug('Reception state for ' + str(self.dst_mcast_address) + ': ' + str(reception_state))
        outgoing_rules = defaultdict(lambda : None)
        
        if not groupflow_trace_event is None:
            groupflow_trace_event.set_route_processing_start_time(self.dst_mcast_address, self.src_ip)
            
        # Calculate the paths for the specific receivers that are currently active from the previously
        # calculated mst
        edges_to_install = []
        calculated_path_router_dpids = []
        for receiver in reception_state:
            if receiver[0] == self.src_router_dpid:
                continue
            if receiver[0] in calculated_path_router_dpids:
                continue
            
            # log.debug('Building path for receiver on router: ' + dpid_to_str(receiver[0]))
            receiver_path = self.path_tree_map[receiver[0]]
            log.debug('Receiver path for receiver ' + str(receiver[0]) + ': ' + str(receiver_path))
            if receiver_path is None:
                log.warn('Path could not be determined for receiver ' + dpid_to_str(receiver[0]) + ' (network is not fully connected)')
                continue
                
            while receiver_path[1]:
                edges_to_install.append((receiver_path[1][0], receiver_path[0]))
                receiver_path = receiver_path[1]
            calculated_path_router_dpids.append(receiver[0])
                    
        # Get rid of duplicates in the edge list (must be a more efficient way to do this, find it eventually)
        edges_to_install = list(Set(edges_to_install))
        if not edges_to_install is None:
            # log.info('Installing edges:')
            for edge in edges_to_install:
                log.debug('Installing: ' + str(edge[0]) + ' -> ' + str(edge[1]))
        
        if not groupflow_trace_event is None:
            groupflow_trace_event.set_route_processing_end_time()
            groupflow_trace_event.set_flow_installation_start_time()
        
        for edge in edges_to_install:
            if edge[0] in outgoing_rules:
                # Add the output action to an existing rule if it has already been generated
                output_port = self.groupflow_manager.adjacency[edge[0]][edge[1]]
                outgoing_rules[edge[0]].actions.append(of.ofp_action_output(port = output_port))
                #log.debug('ER: Configured router ' + dpid_to_str(edge[0]) + ' to forward group ' + \
                #    str(self.dst_mcast_address) + ' to next router ' + \
                #    dpid_to_str(edge[1]) + ' over port: ' + str(output_port))
            else:
                # Otherwise, generate a new flow mod
                msg = of.ofp_flow_mod()
                msg.hard_timeout = 0
                msg.idle_timeout = 0
                if edge[0] in self.installed_node_list:
                    msg.command = of.OFPFC_MODIFY
                else:
                    msg.command = of.OFPFC_ADD
                msg.match.dl_type = 0x800   # IPV4
                msg.match.nw_dst = self.dst_mcast_address
                msg.match.nw_src = self.src_ip
                msg.cookie = self.flow_cookie
                output_port = self.groupflow_manager.adjacency[edge[0]][edge[1]]
                msg.actions.append(of.ofp_action_output(port = output_port))
                outgoing_rules[edge[0]] = msg
                #log.debug('NR: Configured router ' + dpid_to_str(edge[0]) + ' to forward group ' + \
                #    str(self.dst_mcast_address) + ' to next router ' + \
                #    dpid_to_str(edge[1]) + ' over port: ' + str(output_port))
        
        for receiver in reception_state:
            if receiver[0] in outgoing_rules:
                # Add the output action to an existing rule if it has already been generated
                output_port = receiver[1]
                outgoing_rules[receiver[0]].actions.append(of.ofp_action_output(port = output_port))
                #log.debug('ER: Configured router ' + dpid_to_str(receiver[0]) + ' to forward group ' + \
                #        str(self.dst_mcast_address) + ' to network over port: ' + str(output_port))
            else:
                # Otherwise, generate a new flow mod
                msg = of.ofp_flow_mod()
                msg.hard_timeout = 0
                msg.idle_timeout = 0
                if receiver[0] in self.installed_node_list:
                    msg.command = of.OFPFC_MODIFY
                else:
                    msg.command = of.OFPFC_ADD
                msg.cookie = self.flow_cookie
                msg.match.dl_type = 0x800   # IPV4
                msg.match.nw_dst = self.dst_mcast_address
                msg.match.nw_src = self.src_ip
                output_port = receiver[1]
                msg.actions.append(of.ofp_action_output(port = output_port))
                outgoing_rules[receiver[0]] = msg
                #log.debug('NR: Configured router ' + dpid_to_str(receiver[0]) + ' to forward group ' + \
                #        str(self.dst_mcast_address) + ' to network over port: ' + str(output_port))
        
        # Setup empty rules for any router not involved in this path
        for router_dpid in self.node_list:
            if not router_dpid in outgoing_rules and router_dpid in self.installed_node_list:
                msg = of.ofp_flow_mod()
                msg.cookie = self.flow_cookie
                msg.match.dl_type = 0x800   # IPV4
                msg.match.nw_dst = self.dst_mcast_address
                msg.match.nw_src = self.src_ip
                msg.command = of.OFPFC_DELETE
                outgoing_rules[router_dpid] = msg
                #log.debug('Removed rule on router ' + dpid_to_str(router_dpid) + ' for group ' + str(self.dst_mcast_address))
        
        for router_dpid in outgoing_rules:
            connection = core.openflow.getConnection(router_dpid)
            if connection is not None:
                connection.send(outgoing_rules[router_dpid])
                if not outgoing_rules[router_dpid].command == of.OFPFC_DELETE:
                    self.installed_node_list.append(router_dpid)
                else:
                    self.installed_node_list.remove(router_dpid)
            else:
                log.warn('Could not get connection for router: ' + dpid_to_str(router_dpid))
        
        log.debug('New flows installed for Group: ' + str(self.dst_mcast_address) + ' Source: ' + str(self.src_ip) + ' FlowCookie: ' + str(self.flow_cookie))
        
        if self.groupflow_manager.flow_replacement_mode == PERIODIC_FLOW_REPLACEMENT and self._flow_replacement_timer is None:
            log.debug('Starting flow replacement timer for Group: ' + str(self.dst_mcast_address) + ' Source: ' + str(self.src_ip) + ' FlowCookie: ' + str(self.flow_cookie))
            self._flow_replacement_timer = Timer(self.groupflow_manager.flow_replacement_interval, self.update_flow_placement, recurring=True)
        
        if not groupflow_trace_event is None:
            groupflow_trace_event.set_flow_installation_end_time()
            core.groupflow_event_tracer.archive_trace_event(groupflow_trace_event)

                
    def remove_openflow_rules(self):
        """Removes all OpenFlow rules associated with this multicast group / sender pair.

        This should be used when the group has no active receivers."""
        log.info('Removing rules on all routers for Group: ' + str(self.dst_mcast_address) + ' Source: ' + str(self.src_ip))
        for router_dpid in self.node_list:
            msg = of.ofp_flow_mod()
            msg.cookie = self.flow_cookie
            msg.match.dl_type = 0x800   # IPV4
            msg.match.nw_dst = self.dst_mcast_address
            msg.match.nw_src = self.src_ip
            msg.match.in_port = None
            msg.command = of.OFPFC_DELETE
            connection = core.openflow.getConnection(router_dpid)
            if connection is not None:
                connection.send(msg)
            else:
                log.warn('Could not get connection for router: ' + dpid_to_str(router_dpid))
        self.installed_node_list = []
        
        if self._flow_replacement_timer is not None:
            self._flow_replacement_timer.cancel()
            self._flow_replacement_timer = None
        
    def update_flow_placement(self, groupflow_trace_event = None):
        """Replaces the existing flows by recalculating the cached shortest path tree, and installing new OpenFlow rules."""
        self.calc_path_tree_dijkstras(groupflow_trace_event)
        self.install_openflow_rules(groupflow_trace_event)
        log.info('Replaced flows for Group: ' + str(self.dst_mcast_address) + ' Source: ' + str(self.src_ip) + ' FlowCookie: ' + str(self.flow_cookie))
Beispiel #13
0
 def install_openflow_rules(self, groupflow_trace_event = None):
     """Selects routes for active receivers from the cached shortest path tree, and installs/removes OpenFlow rules accordingly."""
     reception_state = self.groupflow_manager.get_reception_state(self.dst_mcast_address, self.src_ip)
     log.debug('Reception state for ' + str(self.dst_mcast_address) + ': ' + str(reception_state))
     outgoing_rules = defaultdict(lambda : None)
     
     if not groupflow_trace_event is None:
         groupflow_trace_event.set_route_processing_start_time(self.dst_mcast_address, self.src_ip)
         
     # Calculate the paths for the specific receivers that are currently active from the previously
     # calculated mst
     edges_to_install = []
     calculated_path_router_dpids = []
     for receiver in reception_state:
         if receiver[0] == self.src_router_dpid:
             continue
         if receiver[0] in calculated_path_router_dpids:
             continue
         
         # log.debug('Building path for receiver on router: ' + dpid_to_str(receiver[0]))
         receiver_path = self.path_tree_map[receiver[0]]
         log.debug('Receiver path for receiver ' + str(receiver[0]) + ': ' + str(receiver_path))
         if receiver_path is None:
             log.warn('Path could not be determined for receiver ' + dpid_to_str(receiver[0]) + ' (network is not fully connected)')
             continue
             
         while receiver_path[1]:
             edges_to_install.append((receiver_path[1][0], receiver_path[0]))
             receiver_path = receiver_path[1]
         calculated_path_router_dpids.append(receiver[0])
                 
     # Get rid of duplicates in the edge list (must be a more efficient way to do this, find it eventually)
     edges_to_install = list(Set(edges_to_install))
     if not edges_to_install is None:
         # log.info('Installing edges:')
         for edge in edges_to_install:
             log.debug('Installing: ' + str(edge[0]) + ' -> ' + str(edge[1]))
     
     if not groupflow_trace_event is None:
         groupflow_trace_event.set_route_processing_end_time()
         groupflow_trace_event.set_flow_installation_start_time()
     
     for edge in edges_to_install:
         if edge[0] in outgoing_rules:
             # Add the output action to an existing rule if it has already been generated
             output_port = self.groupflow_manager.adjacency[edge[0]][edge[1]]
             outgoing_rules[edge[0]].actions.append(of.ofp_action_output(port = output_port))
             #log.debug('ER: Configured router ' + dpid_to_str(edge[0]) + ' to forward group ' + \
             #    str(self.dst_mcast_address) + ' to next router ' + \
             #    dpid_to_str(edge[1]) + ' over port: ' + str(output_port))
         else:
             # Otherwise, generate a new flow mod
             msg = of.ofp_flow_mod()
             msg.hard_timeout = 0
             msg.idle_timeout = 0
             if edge[0] in self.installed_node_list:
                 msg.command = of.OFPFC_MODIFY
             else:
                 msg.command = of.OFPFC_ADD
             msg.match.dl_type = 0x800   # IPV4
             msg.match.nw_dst = self.dst_mcast_address
             msg.match.nw_src = self.src_ip
             msg.cookie = self.flow_cookie
             output_port = self.groupflow_manager.adjacency[edge[0]][edge[1]]
             msg.actions.append(of.ofp_action_output(port = output_port))
             outgoing_rules[edge[0]] = msg
             #log.debug('NR: Configured router ' + dpid_to_str(edge[0]) + ' to forward group ' + \
             #    str(self.dst_mcast_address) + ' to next router ' + \
             #    dpid_to_str(edge[1]) + ' over port: ' + str(output_port))
     
     for receiver in reception_state:
         if receiver[0] in outgoing_rules:
             # Add the output action to an existing rule if it has already been generated
             output_port = receiver[1]
             outgoing_rules[receiver[0]].actions.append(of.ofp_action_output(port = output_port))
             #log.debug('ER: Configured router ' + dpid_to_str(receiver[0]) + ' to forward group ' + \
             #        str(self.dst_mcast_address) + ' to network over port: ' + str(output_port))
         else:
             # Otherwise, generate a new flow mod
             msg = of.ofp_flow_mod()
             msg.hard_timeout = 0
             msg.idle_timeout = 0
             if receiver[0] in self.installed_node_list:
                 msg.command = of.OFPFC_MODIFY
             else:
                 msg.command = of.OFPFC_ADD
             msg.cookie = self.flow_cookie
             msg.match.dl_type = 0x800   # IPV4
             msg.match.nw_dst = self.dst_mcast_address
             msg.match.nw_src = self.src_ip
             output_port = receiver[1]
             msg.actions.append(of.ofp_action_output(port = output_port))
             outgoing_rules[receiver[0]] = msg
             #log.debug('NR: Configured router ' + dpid_to_str(receiver[0]) + ' to forward group ' + \
             #        str(self.dst_mcast_address) + ' to network over port: ' + str(output_port))
     
     # Setup empty rules for any router not involved in this path
     for router_dpid in self.node_list:
         if not router_dpid in outgoing_rules and router_dpid in self.installed_node_list:
             msg = of.ofp_flow_mod()
             msg.cookie = self.flow_cookie
             msg.match.dl_type = 0x800   # IPV4
             msg.match.nw_dst = self.dst_mcast_address
             msg.match.nw_src = self.src_ip
             msg.command = of.OFPFC_DELETE
             outgoing_rules[router_dpid] = msg
             #log.debug('Removed rule on router ' + dpid_to_str(router_dpid) + ' for group ' + str(self.dst_mcast_address))
     
     for router_dpid in outgoing_rules:
         connection = core.openflow.getConnection(router_dpid)
         if connection is not None:
             connection.send(outgoing_rules[router_dpid])
             if not outgoing_rules[router_dpid].command == of.OFPFC_DELETE:
                 self.installed_node_list.append(router_dpid)
             else:
                 self.installed_node_list.remove(router_dpid)
         else:
             log.warn('Could not get connection for router: ' + dpid_to_str(router_dpid))
     
     log.debug('New flows installed for Group: ' + str(self.dst_mcast_address) + ' Source: ' + str(self.src_ip) + ' FlowCookie: ' + str(self.flow_cookie))
     
     if self.groupflow_manager.flow_replacement_mode == PERIODIC_FLOW_REPLACEMENT and self._flow_replacement_timer is None:
         log.debug('Starting flow replacement timer for Group: ' + str(self.dst_mcast_address) + ' Source: ' + str(self.src_ip) + ' FlowCookie: ' + str(self.flow_cookie))
         self._flow_replacement_timer = Timer(self.groupflow_manager.flow_replacement_interval, self.update_flow_placement, recurring=True)
     
     if not groupflow_trace_event is None:
         groupflow_trace_event.set_flow_installation_end_time()
         core.groupflow_event_tracer.archive_trace_event(groupflow_trace_event)
 def __init__(self, nexus=None):
     Transport.__init__(self, nexus)
     self._connections = {}
     self._t = Timer(SESSION_TIMEOUT, self._check_timeouts, recurring=True)
Beispiel #15
0
class AbstractRemoteDomainManager(AbstractDomainManager):
    """
  Abstract class for different remote domain managers.

  Implement polling mechanism for remote domains.
  """
    # Polling interval
    POLL_INTERVAL = 3
    """Polling interval"""
    # Request formats
    DEFAULT_DIFF_VALUE = False
    """Request formats"""
    def __init__(self, domain_name=None, adapters=None, **kwargs):
        """
    Init.

    :param domain_name: domain name
    :type domain_name: str
    :param adapters: config of adapters
    :type adapters: dict
    :param kwargs: optional params
    :type kwargs: dict
    :return: None
    """
        super(AbstractRemoteDomainManager,
              self).__init__(domain_name=domain_name,
                             adapters=adapters,
                             **kwargs)
        # Timer for polling function
        self.__timer = None
        if 'poll' in kwargs:
            self._poll = bool(kwargs['poll'])
        else:
            self._poll = False
        if 'diff' in kwargs:
            self._diff = bool(kwargs['diff'])
        else:
            self._diff = self.DEFAULT_DIFF_VALUE
        self.log.debug("Enforced configuration for %s: poll: %s, diff: %s" %
                       (self.__class__.__name__, self._poll, self._diff))

    @property
    def detected(self):
        """
    Return True if the Manager has detected the domain.

    :return: domain status
    :rtype: bool
    """
        return self._detected

    def get_domain_url(self):
        if isinstance(self.topoAdapter, AbstractRESTAdapter):
            return self.topoAdapter.URL

    ##############################################################################
    # Abstract functions for component control
    ##############################################################################

    def init(self, configurator, **kwargs):
        """
    Abstract function for component initialization.

    :param configurator: component configurator for configuring adapters
    :type configurator: :any:`ComponentConfigurator`
    :param kwargs: optional parameters
    :type kwargs: dict
    :return: None
    """
        # Load and initiate adapters using the initiate_adapters() template func
        self._load_adapters(configurator=configurator, **kwargs)
        # Skip to start polling if it's set
        if not self._poll:
            # Try to request/parse/update Mininet topology
            if not self._detect_topology():
                self.log.warning("%s domain not confirmed during init!" %
                                 self.domain_name)
            else:
                # Notify all components for topology change --> this event causes
                # the DoV updating
                self.raiseEventNoErrors(
                    DomainChangedEvent,
                    domain=self.domain_name,
                    data=self.internal_topo,
                    cause=DomainChangedEvent.TYPE.DOMAIN_UP)
        else:
            self.log.info("Start polling %s domain..." % self.domain_name)
            self.start_polling(self.POLL_INTERVAL)

    def initiate_adapters(self, configurator):
        """
    Initiate Adapters for DomainManager.

    Must override in inherited classes.
    Follows the Factory Method design pattern.

    :param configurator: component configurator for configuring adapters
    :type configurator: :any:`ComponentConfigurator`
    :return: None
    """
        raise NotImplementedError

    def finit(self):
        """
    Abstract function for starting component.

    :return: None
    """
        self.stop_polling()
        super(AbstractRemoteDomainManager, self).finit()

    ##############################################################################
    # Common functions for polling
    ##############################################################################

    def start_polling(self, interval=1):
        """
    Initialize and start a Timer co-op task for polling.

    :param interval: polling period (default: 1)
    :type interval: int
    :return: None
    """
        if self.__timer:
            # Already timing
            return
        self.__timer = Timer(interval,
                             self.poll,
                             recurring=True,
                             started=True,
                             selfStoppable=True)

    def restart_polling(self, interval=POLL_INTERVAL):
        """
    Reinitialize and start a Timer co-op task for polling.

    :param interval: polling period (default: 3)
    :type interval: int
    :return: None
    """
        if self.__timer:
            self.__timer.cancel()
        self.__timer = Timer(interval,
                             self.poll,
                             recurring=True,
                             started=True,
                             selfStoppable=True)

    def stop_polling(self):
        """
    Stop timer.

    :return: None
    """
        if self.__timer:
            self.__timer.cancel()
        self.__timer = None

    @property
    def polling(self):
        return self._poll

    def poll(self):
        """
    Poll the defined domain agent. Handle different connection errors and go
    to slow/rapid poll. When an agent is (re)detected update the current
    resource information.

    :return: None
    """
        # If domain is not detected
        if not self._detected:
            # Check the topology is reachable
            if self._detect_topology():
                # Domain is detected and topology is updated -> restart domain polling
                self.restart_polling()
                # Notify all components for topology change --> this event causes
                # the DoV updating
                self.raiseEventNoErrors(
                    DomainChangedEvent,
                    domain=self.domain_name,
                    data=self.internal_topo,
                    cause=DomainChangedEvent.TYPE.DOMAIN_UP)
                return
        # If domain has already detected
        else:
            # Check the domain is still reachable
            changed = self.topoAdapter.check_topology_changed()
            # No changes
            if changed is False:
                # Nothing to do
                self.log.log(
                    VERBOSE,
                    "Remote domain: %s has not changed!" % self.domain_name)
                return
            # Domain has changed
            elif isinstance(changed, NFFG):
                self.log.info("Remote domain: %s has changed! "
                              "Update global domain view..." %
                              self.domain_name)
                self.log.debug("Save changed topology: %s" % changed)
                # Update the received new topo
                self.internal_topo = changed
                # Notify all components for topology change --> this event causes
                # the DoV updating
                self.raiseEventNoErrors(
                    DomainChangedEvent,
                    domain=self.domain_name,
                    data=self.internal_topo,
                    cause=DomainChangedEvent.TYPE.DOMAIN_CHANGED)
                return
            # If changed is None something went wrong, probably remote domain is not
            # reachable. Step to the other half of the function
            elif changed is None:
                self.log.warning("Lost connection with %s agent! "
                                 "Going to slow poll..." % self.domain_name)
                # Clear internal topology
                self.log.debug("Clear topology from domain: %s" %
                               self.domain_name)
                self.internal_topo = None
                self.raiseEventNoErrors(
                    DomainChangedEvent,
                    domain=self.domain_name,
                    cause=DomainChangedEvent.TYPE.DOMAIN_DOWN)
            else:
                self.log.warning(
                    "Got unexpected return value from check_topology_changed(): %s"
                    % type(changed))
                return
        # If this is the first call of poll()
        if self._detected is None:
            self.log.warning("Local agent in domain: %s is not detected! "
                             "Keep trying..." % self.domain_name)
            self._detected = False
        elif self._detected:
            # Detected before -> lost connection = big Problem
            self._detected = False
            self.restart_polling()
        else:
            # No success but not for the first try -> keep trying silently
            pass

    ##############################################################################
    # ESCAPE specific functions
    ##############################################################################

    def install_nffg(self, nffg_part):
        """
    Install an :class:`NFFG` related to the specific domain.

    :raise: :any:`exceptions.NotImplementedError`
    :param nffg_part: NF-FG need to be deployed
    :type nffg_part: :class:`NFFG`
    :return: status if the install process was success
    :rtype: bool
    """
        raise NotImplementedError

    def clear_domain(self):
        """
    Clear the Domain according to the first received config.

    :raise: :any:`exceptions.NotImplementedError`
    :return: None
    """
        raise NotImplementedError
Beispiel #16
0
def _ready():
    if setup_time:
        #print '###############started coz of setup time'
        Timer(setup_time, _start)  #time before the topology discovery starts
Beispiel #17
0
def launch():
    core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp)
    core.openflow.addListenerByName("PacketIn", _handle_PacketIn)
    core.openflow.addListenerByName("PortStatsReceived",
                                    _handle_portstats_received)
    Timer(5, _timer_func, recurring=True)
Beispiel #18
0
def launch():
    from pox.lib.recoco import Timer
    core.registerNew(Phase1)

    global INTERVAL
    Timer(INTERVAL, _timer_func, recurring=True)
def launch():
	core.openflow.addListenerByName("ConnectionUp",_handle_ConnectionUp)
	core.openflow.addListenerByName("PacketIn",_handle_PacketIn)
	core.openflow.addListenerByName("FlowStatsReceived",_handle_flowstats_received) 
	# timer set to execute every five seconds
	Timer(5, _timer_func, recurring=True)
Beispiel #20
0
 def send_table(self):
     if self.pending: return
     self.pending = True
     Timer(.2, self._do_send_table, recurring=False)
Beispiel #21
0
        match.nw_dst = "100.100.100.0/24"  #to all hosts
        #L4 protocol
        match.tp_src = src_port
        match.tp_dst = 80

        msg.match = match
        msg.hard_timeout = 0
        msg.idle_timeout = 0
        connection.send(msg)


#Helper function to print out blocked IP address and TCP source ports
def print_blocked_ip():
    print("Blocked IPs and TCP ports:")
    for ip, port in blocked_ip.items():
        print("IP: %s   Blocked Port: %s" % (ip, port))
    #for i in range (len(blocked_ip)):
    #print blocked_ip[i],
    print("\n")


#--------------Auto run Functions---------------------------------
#attach handlers to listenrs
#Listens for the swithces' response to the flow_stats_request with the specific handler
core.openflow.addListenerByName("FlowStatsReceived",
                                _handle_flowstats_received)

#Run _timer_func very 0.01 sec and refresh screen_output every 1 sec
Timer(0.01, _timer_func, recurring=True)
Timer(1, _screen_output, recurring=True)
Beispiel #22
0
def launch ():
  Timer(120, prune_tainted_list, recurring = True)
  Timer(300, delete_flows_for_watermark_detection, recurring = True)
  core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp)
  core.openflow.addListenerByName("PacketIn",_handle_PacketIn)
 def _handle_timer (self):
   self.t = Timer(1, self._handle_timer)
   for sw in self.switches.values():
     sw._handle_timer()
 def __init__(self):
     #Check port stats every 30 seconds
     Timer(30, self.check_use_of_ports, recurring = True)
Beispiel #25
0
def launch():
	core.openflow.addListenerByName("PortStatsReceived", _handle_port_received)
	Timer(5,_timer_func, recurring=True)
Beispiel #26
0
    def __init__(self):
        # This timer handles expiring stuff
        self._expire_timer = Timer(5, _handle_expiration, recurring=True)

        core.addListeners(self)
Beispiel #27
0
class ARPTable(object):
    MAX_ENTRIES = 1024
    MAX_PENDING = 5

    MAX_PENDING_TIME = 2

    def __init__(self):
        self.by_ip = {}  # ip -> entry
        self.pending = []  # Packets waiting to be sent (ip,(send_args))
        self.timer = Timer(self.MAX_PENDING_TIME, self._timer_proc)

    def __str__(self):
        sending = set(x for x, y in self.pending)
        r = []
        for ip, e in sorted(self.by_ip.items()):
            m = "%-15s %16s" % (ip, e.mac)
            if ip in sending: m += " p"
            r.append(m)
        return "\n".join(r)

    def add_entry(self, ip, mac=None):
        """
    Add an entry

    The entry can't already exist.
    It will definitely exist after returning.
    """
        assert ip not in self.by_ip
        if len(self.by_ip) >= self.MAX_ENTRIES:
            # Sloppy, but simple.
            # Get ones with lowest age
            entries = sorted(self.by_ip.values(), key=lambda entry: entry.age)
            del entries[self.MAX_ENTRIES:]
            self.by_ip = {e.mac: e for e in entries}
        new_entry = ARPEntry(ip=ip, mac=mac)
        self.by_ip[ip] = new_entry
        return new_entry

    def send(self,
             eth_packet,
             router_ip=None,
             src_eth=None,
             src_ip=None,
             send_function=None):
        """
    Try to send a packet

    eth_packet is an ethernet object.
    src_eth is the source for any ARPs sent.
    src_ip is the source for any ARPs sent.
    If the above two are not specified, they are taken from eth_packet.
    send_function is a function which takes raw bytes to send.
    If send_function is unset, it is taken from a send_function attribute.
    """
        if send_function is None: send_function = self.send_function
        ipp = eth_packet.find("ipv4")

        if not ipp and eth_packet.type == eth_packet.IP_TYPE:
            if isinstance(eth_packet.payload, bytes):
                # Hm!  Try harder...
                ipp = pkt.ipv4(raw=eth_packet.payload)

        if not ipp or eth_packet.dst.is_multicast:
            send_function(eth_packet.pack())
            return
        if ipp.dstip == pkt.IPV4.IP_BROADCAST:
            #ipp.dstip = router_ip # Not sure what this was about
            eth_packet.dst = pkt.ETHERNET.ETHER_BROADCAST
            send_function(eth_packet.pack())
            return
        if ipp.dstip.is_multicast:
            eth_packet.dst = ipp.dstip.multicast_ethernet_address
            send_function(eth_packet.pack())
            return

        if src_ip is None: src_ip = ipp.srcip
        if src_eth is None: src_eth = eth_packet.src

        if router_ip is not None: dstip = router_ip
        else: dstip = ipp.dstip

        if dstip not in self.by_ip: self.add_entry(dstip)

        e = self.by_ip[dstip]
        if e.maybe_refresh():
            # Send ARP
            self._send_arp(dstip, src_eth, src_ip, send_function)

        if e.mac is not None:
            eth_packet.dst = e.mac
            send_function(eth_packet.pack())
        else:
            if len(self.pending) < self.MAX_PENDING:
                self.pending.append((dstip, (eth_packet, router_ip, src_eth,
                                             src_ip, send_function)))

    def _timer_proc(self):
        # We just blow away all the entries every interval, so on average, they
        # live for half the interval.
        del self.pending[:]

    def __del__(self):
        if self.timer:
            self.timer.cancel()
            self.timer = None

    def _send_arp(self, dstip, src_eth, src_ip, send_function):
        r = pkt.arp()
        r.opcode = r.REQUEST
        r.hwdst = pkt.ETHERNET.ETHER_BROADCAST
        r.protodst = dstip
        r.hwsrc = src_eth
        r.protosrc = src_ip
        e = pkt.ethernet(type=pkt.ethernet.ARP_TYPE, src=r.hwsrc, dst=r.hwdst)
        e.payload = r
        log.debug("Sending ARP for %s", dstip)
        send_function(e.pack())

    def rx_arp_reply(self, arp):
        assert arp.opcode == arp.REPLY
        self.rx_arp(arp)

    def rx_arp(self, arp):
        if arp.protosrc not in self.by_ip:
            self.add_entry(mac=arp.hwsrc, ip=arp.protosrc)
        else:
            self.by_ip[arp.protosrc].confirm(arp.hwsrc)

        # Send any pending packets
        for index, (ip, args) in reversed(list(enumerate(self.pending))):
            if ip == arp.protosrc:
                del self.pending[index]
                log.debug("ARP reply allows sending pending packet")
                self.send(*args)
Beispiel #28
0
 def moveRegras(self):
     if (self.nome != "Switch HW"):
         return
     regrasInseridas = 0
     Timer(1, self.moveRegras, recurring=False)
     global NUMPKTIN
     global LISTAEWMA
     LISTAEWMA.append(NUMPKTIN)
     NUMPKTIN = 0
     #EWMA da quantidade de regras instaladas nos x ultimos segundos
     lst = pd.Series(LISTAEWMA)
     limite = int(pd.Series.ewm(lst, alpha=0.9).mean().values[-1])
     log.info("%s: Movendo %d regra(s) para o switch SW.", self.nome,
              limite)
     for regra in self.tabela:
         #Movendo regra do switch HW para o switch SW
         if (regra.cookie == 55 or
             (regra.match.nw_proto != 6 and regra.match.nw_proto != 17)):
             continue  #Ignora as regras fixas e regras de arp
         if (regrasInseridas < limite):
             #Adiciona regra no SW
             reg = of.ofp_flow_mod()
             reg.match = regra.match
             #Alterando in_port
             if (regra.match.in_port == 3):
                 reg.match.in_port = 1
                 reg.actions.append(of.ofp_action_output(port=2))
             else:
                 reg.match.in_port = 2
                 reg.actions.append(of.ofp_action_output(port=1))
             reg.priority = regra.priority
             reg.idle_timeout = regra.idle_timeout
             reg.hard_timeout = regra.hard_timeout
             #Adiciona regra depois de um delay
             t = Delay(TEMPOADD, sSW.addRegra, [reg])
             t.start()
             if (regra.match.nw_dst == IPAddr('10.1.0.1')):
                 #Alterando regra no UL
                 regUL = of.ofp_match()
                 regUL.nw_proto = regra.match.nw_proto
                 regUL.dl_type = regra.match.dl_type
                 regUL.nw_src = IPAddr('10.1.0.2')
                 regUL.nw_dst = IPAddr('10.1.0.1')
                 regUL.tp_dst = regra.match.tp_dst
                 regUL.tp_src = regra.match.tp_src
                 regUL.in_port = 2
                 mod = of.ofp_flow_mod(
                     match=regUL,
                     command=of.OFPFC_MODIFY,
                     actions=[of.ofp_action_output(port=3)])
                 t1 = Delay(TEMPOMOD, sUL.addRegra, [mod])
                 t1.start()
             elif (regra.match.nw_dst == IPAddr('10.1.0.2')):
                 #Alterando regra no DL
                 regDL = of.ofp_match()
                 regDL.nw_proto = regra.match.nw_proto
                 regDL.dl_type = regra.match.dl_type
                 regDL.nw_dst = IPAddr('10.1.0.2')
                 regDL.nw_src = IPAddr('10.1.0.1')
                 regDL.tp_dst = regra.match.tp_dst
                 regDL.tp_src = regra.match.tp_src
                 regDL.in_port = 2
                 mod = of.ofp_flow_mod(
                     match=regDL,
                     command=of.OFPFC_MODIFY,
                     actions=[of.ofp_action_output(port=3)])
                 t2 = Delay(TEMPOMOD, sDL.addRegra, [mod])
                 t2.start()
             #Remove regra no HW
             dele = regra.match
             t3 = Delay(TEMPODEL, self.delRegra, [dele])
             t3.start()
             #Remove a regra da tabela na memoria
             self.tabela.pop(0)
             #Aumenta o contador
             regrasInseridas += 1
         else:
             log.info("%s: Regras movidas: %d", self.nome, regrasInseridas)
             return
Beispiel #29
0
 def __init__(self):
     self.by_ip = {}  # ip -> entry
     self.pending = []  # Packets waiting to be sent (ip,(send_args))
     self.timer = Timer(self.MAX_PENDING_TIME, self._timer_proc)
def launch():
    core.registerNew(GwSwOlsrdSwitch)
    Timer(5, _con_func, recurring=True)
    Timer(GW_FAILURE_CHECK_INTERVAL, gw_failure_monitoring, recurring=True)
Beispiel #31
0
 def __init__(self, nexus=None):
     Transport.__init__(self, nexus)
     self._connections = {}
     #self._t = Timer(5, self._check_timeouts, recurring=True)
     self._t = Timer(60 * 2, self._check_timeouts, recurring=True)
Beispiel #32
0
def launch ():
  core.registerNew(l2_multi)
 
  timeout = min(max(PATH_SETUP_TIME, 5) * 2, 15)
  Timer(timeout, WaitingPath.expire_waiting_paths, recurring=True)
        def handle_ip_complex():
            """ Maneja paquetes tipo ip """
            dst_mac_str = str(dst_mac)  # obtengo el string de mac destino
            log.info("SWITCH_%s: Mac destino es %s", self.switch_id,
                     dst_mac_str)

            # si el host destino es desconocido, entonces me falta conocer a mas hosts y manejo el paquete como un switch bobo
            if dst_mac_str not in hosts: return handle_all()

            host_switch_port = get_host_switch_port(dst_mac_str,
                                                    self.switch_id)
            # si la mac destino es de un host y este switch esta directamente conectado al mismo, entonces instalo un flujo inmediatamente
            if host_switch_port is not None:
                log.info(
                    'SWITCH_%s: La Mac destino %s corresponde a un host conectado a MI puerto %d!',
                    self.switch_id, dst_mac_str, host_switch_port)
                return install_flow(host_switch_port)

            # TODOOOOOOOOOO : VERIFICAR SI ACASO SE DEBE USAR install_flow EN VEZ DE install_path_flow

            # verifico si ya existe un path asignado a este flujo
            flow_key = build_flow_key()
            if flow_key in current_paths:
                path = current_paths[flow_key]
                log.info('SWITCH_%s: el path %s esta asignado al flow_key %s',
                         self.switch_id, str(path), flow_key)
                # instalo un flujo para forwardear el paquete
                switch_switch_link = get_switch_switch_link(
                    self.switch_id, path)
                if switch_switch_link is not None:
                    out_port = switch_switch_link.port1
                    log.info(
                        "SWITCH_%s: El paquete debe salir por mi puerto %d",
                        self.switch_id, out_port)
                    return install_flow(out_port)
                    #return install_path_flow(out_port)
                else:
                    log.warn(
                        'SWITCH_%s: encontre un path... pero yo no tengo enlace ALGO ESTA MAL',
                        self.switch_id)
                    return handle_all()

            # si llegue a este punto es porque no hay un path asignado al camino indicado... probablemente este switch es de borde
            # debo solicitar un camino libre y asignarlo
            host = get_host_by_mac(dst_mac)
            if host is not None:
                end_switch_id = host[
                    'switch_id']  # obtengo el id del switch al cual esta conectado el host destino
                # busco o bien un camino libre o cualquier camino en caso de no existir ninguno libre
                log.info("SWITCH_%s: Busco un path hacia switch %s",
                         self.switch_id, end_switch_id)
                path = find_non_taken_path(self.switch_id, end_switch_id)
                if path is None:
                    path = find_any_path(self.switch_id, end_switch_id)
                path_str = str(path)
                log.info(
                    "SWITCH_%s: Voy a usar el path %s y se lo asigno al flujo %s",
                    self.switch_id, path_str, flow_key)
                # guardo la asociacion entre la clave del flujo y el path encontrado
                current_paths[flow_key] = path
                # marco al path encontrado como TOMADO
                taken_paths.add(path_str)
                # incremento la cantidad de veces que el camino esta siendo usado
                current_paths_load[path_str] += 1
                # instalo un flujo para forwardear el paquete
                switch_switch_link = get_switch_switch_link(
                    self.switch_id, path)
                if switch_switch_link is not None:
                    out_port = switch_switch_link.port1
                    install_flow(out_port)

                    #return install_path_flow(out_port)
                    def remove_taken_path():
                        log.info("SWITCH_%s: ELIMINANDO PATH %s DE FLUJO %s",
                                 self.switch_id, path_str, flow_key)
                        if path_str in taken_paths:
                            taken_paths.remove(path_str)
                        if flow_key in current_paths:
                            current_paths.pop(flow_key)
                        current_paths_load[path_str] -= 1

                    # despues de un tiempo elimino el path de flujo instalado
                    Timer(FLOW_INSTALL_DURATION, remove_taken_path)
                    return True

                else:
                    log.warn(
                        'SWITCH_%s: encontre un path... pero yo no tengo enlace ALGO ESTA MAL',
                        self.switch_id)
                    return handle_all()

            # condicion fallback ... manejo el paquete como puedo
            handle_all()
Beispiel #34
0
def _check_handle_migration(event):
    '''returns 0 for no migration. returns 1 for migration'''
    eth_pkt = event.parsed
    arp_pkt = event.parsed.payload
    org_mac = eth_pkt.src.toStr(
    )  #actual mac of the current machine. same as old amac if vm mig. if vip, then diff.
    src_ip = arp_pkt.protosrc.toStr()
    old_pmac = arp_table[src_ip]
    old_amac = pmac_actual[old_pmac]  #
    sw, port = pmac_pos(old_pmac)
    #print 'In migration check. IP:{0}, old pos - {1}:{2} new pos - {3}:{4}'.format(src_ip, sw, port, event.dpid, event.port)
    if (sw != event.dpid) or (port != event.port):
        '''
        this host has migrated or virtual ip
        assign new pmac.
        add trans in new switch.
        add entry in old switch to frwrd to some agg switch replacing old pmac with new pmac
        remove prev trans tabbles from old switch.
        update our internal tables
        change the assigned mac string - not assign the old pmac for the timeout period of time
        '''
        if org_mac == old_amac:
            log.info(
                'VM migration detected. IP:{0}, old pos - {1}:{2} new pos - {3}:{4}'
                .format(src_ip, sw, port, event.dpid, event.port))
        else:
            log.info(
                'Virtual ip takeover detected. IP:{0}, old pos - {1}:{2} new pos - {3}:{4}'
                .format(src_ip, sw, port, event.dpid, event.port))

        return move_host(src_ip, event.dpid, event.port, org_mac, event)
        new_pmac = _handle_new_host(org_mac, src_ip, event.dpid, event.port)
        barrier = of.ofp_barrier_request()
        event.connection.send(barrier)

        old_switch_con = core.openflow.connections[sw]
        msg = nx.nx_flow_mod(table_id=0)
        msg.priority = 8000
        msg.hard_timeout = arp_cache_timeout
        msg.match.eth_dst = old_pmac
        rewrite_action = of.ofp_action_dl_addr.set_dst(adrs.EthAddr(new_pmac))
        msg.actions.append(rewrite_action)
        #choose one up link by hashing
        up_ports = g[event.dpid].keys()
        num_routes = len(up_ports)
        #msg.actions.append(of.ofp_action_output(port = up_ports[ random.randint(0, num_routes - 1) ] ))#simple hashing. edge switch x sends to agg switch x
        #old_switch_con.send(msg)

        #if more than 2 up ports are there, then hashing is req. if 1 up port, then no hashing. if 2, then the other port other than inp port
        if num_routes == 1:  #only one route
            msg.actions = [
                rewrite_action,
                of.ofp_action_output(port=of.OFPP_IN_PORT)
            ]
            old_switch_con.send(msg)
        elif num_routes == 2:
            msg.match.NXM_OF_IN_PORT = up_ports[0]
            msg.actions = [
                rewrite_action,
                of.ofp_action_output(port=up_ports[1])
            ]
            old_switch_con.send(msg)
            msg.match.NXM_OF_IN_PORT = up_ports[1]
            msg.actions = [
                rewrite_action,
                of.ofp_action_output(port=up_ports[0])
            ]
            old_switch_con.send(msg)
        else:  #3 or more ports. here need hahsing. based on src port num. also avoid the inp port. so match based on that also
            num_routes -= 1  #since we avoid each inp port
            num_bits = int(math.floor(math.log(num_routes, 2)))
            x = 2**num_bits  #Assumption:one edge switch doesn't have more than 255 direct connections to agg switches
            mask = '00:00:00:' + eth_addr_format(x - 1, 2) + ':00:00'
            prefix = '00:00:00:'
            suffix = ':00:00'
            for ii in range(num_routes + 1):
                cand_ports = list(up_ports)
                msg.match.NXM_OF_IN_PORT = cand_ports.pop(
                    ii)  #remove the inp port from the list of op ports
                for i in range(num_routes):
                    port = i % x
                    msg.match.eth_src_with_mask = (prefix +
                                                   eth_addr_format(port, 2) +
                                                   suffix, mask)
                    msg.actions = [
                        rewrite_action,
                        of.ofp_action_output(port=cand_ports[i])
                    ]
                    old_switch_con.send(msg)

        msg = nx.nx_flow_mod(table_id=0, command=of.OFPFC_DELETE)
        msg.priority = 5000
        msg.match.NXM_OF_IN_PORT = port
        msg.match.eth_src = old_amac
        old_switch_con.send(msg)
        msg = nx.nx_flow_mod(table_id=1, command=of.OFPFC_DELETE)
        msg.priority = 5000
        msg.match.eth_dst = old_pmac
        old_switch_con.send(msg)
        barrier = of.ofp_barrier_request()
        old_switch_con.send(barrier)

        arp_table[src_ip] = new_pmac
        actual_pmac.pop(
            pmac_actual.pop(old_pmac)
        )  #remove old pmac to actual and vice versa since they are not valid anymore
        actual_pmac[org_mac] = new_pmac
        pmac_actual[new_pmac] = org_mac

        #this nxt 2 lines should be in a fn called after the timeout. we dont want to assing old pmac to anyone until then
        def _remove_old_pmac():
            vmid = int(old_pmac[-5:].replace(':', ''), 16)
            assigned_pmac[sw][port] = assigned_pmac[sw][
                port][:vmid] + '0' + assigned_pmac[sw][port][vmid + 1:]

        Timer(arp_cache_timeout, _remove_old_pmac)
        return 1
    return 0
Beispiel #35
0
class MyExplorer(object):
  def __init__ (self):
    log.warning("MyExplorer Constructed.")
    core.listen_to_dependencies(self)
    # Adjacency map.  [sw1][sw2] -> port from sw1 to sw2
    self.adj = defaultdict(lambda:defaultdict(lambda:int))

    # Port map.  [sw1][sw2] -> the output port from sw1 to sw2
    self.ports = defaultdict(lambda:defaultdict(lambda:int))

    # Switches we know of.  [dpid] -> Switch
    self.switches = set()

    self.reset_hosts()
    # self.hosts: Hosts we know of. [macaddr (string)] -> Host
    # self.hadj: [h][sw] ->  the ports where switchs connect to the hosts
    # self.sd_pair: [h1][h2] -> source-destination pair id

    self.reset_path_tables()
    # self.path_id_table: Path ID -> Path table
    # self.sd_path_table: [Source][Destination] -> Path ID list

    self.reset_srcport_tables()
    # self.sd_srcport_table: [Source][Destination] -> Srcport list

    self.reset_flowdist_tables()
    # self.flow_dist_table: [sd_pair_id][path_id-1] -> Srcport distribution

    # Latency test function
    self.adj_test = []
    self.sw_test  = []
    self.sw_lat   = []
    self.lat_test_timer = []
    # Does latency test Start?
    self.lat_test = False

    # Update step
    self.update_step  = 0
    self.update_timer = []
    self.config = Configuration()

    random.seed(time.time())

  """
   Event Handlers
  """
  def _handle_core_ComponentRegistered (self, event):
    log.warning(event.name)
    if event.name == "host_tracker":
      event.component.addListenerByName("HostEvent",
        self.__handle_host_tracker_HostEvent)

  def _handle_openflow_ConnectionUp (self, event):
    dp = event.connection.dpid
    self.switches.add(dp)
    event.connection.addListenerByName("PacketIn",
        self.__handle_PacketIn)
    log.warning("Switch %s is discovered.", dpid_to_str(dp))

  def _handle_openflow_ConnectionDown (self, event):
    pass

  def _handle_openflow_discovery_LinkEvent (self, event):
    (dp1,p1),(dp2,p2) = event.link.end
    self.adj[dp1][dp2] = 1
    self.ports[dp1][dp2] = p1
    log.warning(
      "Link %s -> %s is discovered.",
      dpid_to_str(dp1),
      dpid_to_str(dp2)
    )

  def __handle_host_tracker_HostEvent (self, event):
    h = event.entry.macaddr.toStr()
    s = event.entry.dpid

    if h == "ff:ff:ff:ff:ff:ff":
      # The address for broadcasting and testing
      return

    if event.leave:
      if h in self.hosts:
        if s in self.hadj[h]:
          self.hosts.remove(h)
          del s
    else:
      # event.join, event.move, ...
      if h not in self.hosts:
        self.hosts.add(h)
      else:
        for s1 in self.hadj[h]:
          del s1
      self.hadj[h][s] = event.entry.port
      log.warning("Host %s is discovered.", h)

  def __handle_PacketIn(self, event):
    packet = event.parsed
    src = packet.src.toStr()
    dst = packet.dst.toStr()

    # Extract IP information
    ip   = packet.find('ipv4')
    udpp = packet.find('udp')
    if ip:
      # it is not a good way to define a variable, anyway
      srcip = ip.srcip
      dstip = ip.dstip
      self.srcip_table[src] = srcip
      self.dstip_table[dst] = dstip
      if udpp:
        srcport = udpp.srcport
        # Each src-dst pair has several ports
        if srcport not in self.sd_srcport_table[src][dst]:
          # New port discovered
          self.sd_srcport_table[src][dst].append(srcport)

    # Latency test packets handling
    if self.lat_test:
      if packet.type != 0x5566:
        # not test packet, drop it
        return

      src = self._MAC_to_int(src)
      dst = self._MAC_to_int(dst)

      timeinit, = struct.unpack('!I', packet.find('ethernet').payload)
      timediff = time.time()*1000 - self.system_time - timeinit

      if src in self.adj_test:
        if dst in self.adj_test[src]:
          self.adj[src][dst] = timediff
          del self.adj_test[src][dst]

      if dst in self.sw_test:
        self.sw_lat[dst] = timediff
        self.sw_test.remove(dst)

      return

    # assign path id
    pid = 0

    if src in self.hosts:
      for d in self.sd_path_table[src]:
        # FIXME: Pick one as default
        # Maybe we should apply flood function to broadcasting
        for sd_path_id in self.sd_path_table[src][d]:
          pid = sd_path_id
          # log.warning("Packet Vid = %i", pid)

      if dst in self.hosts:
        if self.config.config_set:
          if ip and udpp:
            # If the packet is an IP/UDP packet
            id_list = self.sd_path_table[src][dst]
            # last one, in case not found
            pid = self.get_pid_by_srcport(id_list, srcport)
            if pid is None:
              # Not existed port, choose the last one as default
              pid = id_list[len(id_list) - 1]
              for k in id_list:
                now_split = self.config.now_config
                real_split = self.config.real_config
                # log.warning("now %s real %s", now_split, real_split )
                if now_split[k-1] > real_split[k-1] or now_split[k-1] == 1:
                  pid = k
                  break
              # update flow_dist_table and real_config_table
              self.flow_dist_table[pid-1].append(srcport)
              self.config.compute_real_config(id_list, self.flow_dist_table)
          else:
            id_list = self.sd_path_table[src][dst]
            # last one, in case not found
            pid = id_list[len(id_list) - 1]
          
            sum_of_all = 0
            for x in id_list:
              sum_of_all += self.config.now_config[x-1]
            
            rand_num = sum_of_all * random.random()
            for x in id_list:
              rand_num -= self.config.now_config[x-1]  # Since the path ID starts from 1, which is different from the index
              if rand_num < 0:
                # path_id should start from 1
                pid = x
                break
          # log.warning("SD pair %i, pid %i", self.sd_pair[src][dst], pid) 
        else:
          # FIXME: path selection
          for sd_path_id in self.sd_path_table[src][dst]:
            # There exists a path
            pid = sd_path_id
            # log.warning("Packet Vid = %i", pid)        

      if ip and udpp:
        # FIXME: Do we need to modify the flow whenever the packet in?
        msg = of.ofp_flow_mod()
        msg.match.dl_type = 0x800
        msg.match.nw_src = IPAddr(srcip)
        msg.match.nw_dst = IPAddr(dstip)
        msg.match.nw_proto = 17
        msg.match.tp_src = srcport
        # slog.warning("Add rule for port %s", srcport)
      else:
        msg = of.ofp_packet_out(data = event.ofp)

      if pid != 0:
        # There exists a path
        path = self.path_id_table[pid]
        if len(path) > 3:
        # It is not the last sw, tag it and send into the network
          if USE_VLAN_TAG:
            msg.actions.append( of.ofp_action_vlan_vid( vlan_vid = pid ) )
          if USE_ETHERNET_SRC_TAG:
            msg.actions.append( of.ofp_action_dl_addr.set_src( EthAddr( self._int_to_MAC( pid ) ) ) )
          msg.actions.append( of.ofp_action_output( port = self.ports[path[1]][path[2]] ) )
        elif len(path) == 3:
          # last sw, forward to the host
          #msg.actions.append( of.ofp_action_output( port = of.OFPP_FLOOD ) )
          msg.actions.append( of.ofp_action_output( port = self.hadj[path[2]][path[1]] ) )

      event.connection.send(msg)

    """
      msg = of.ofp_packet_out( data = event.ofp )
      if pid != 0:
        # There exists a path
        path = self.path_id_table[pid]
        if len(path) > 3:
          # It is not the last sw, tag it and send into the network
          if USE_VLAN_TAG:
            msg.actions.append( of.ofp_action_vlan_vid( vlan_vid = pid ) )
          if USE_ETHERNET_SRC_TAG:
            msg.actions.append( of.ofp_action_dl_addr.set_src( EthAddr( self._int_to_MAC( pid ) ) ) )
          msg.actions.append( of.ofp_action_output( port = self.ports[path[1]][path[2]] ) )
        elif len(path) == 3:
          # last sw, forward to the host
          # msg.actions.append( of.ofp_action_output( port = of.OFPP_FLOOD ) )
          msg.actions.append( of.ofp_action_output( port = self.hadj[path[2]][path[1]] ) )
    """

  def _handle_openflow_FlowStatsReceived (self, event):
    log.warning("Flow stats received.")
    for x in flow_stats_to_list(event.stats):
      log.warning( x )

  def _handle_openflow_PortStatsReceived (self, event):
    log.warning("Port stats received.")
    log.warning(flow_stats_to_list(event.stats))

  """
   Tool Functions
  """
  def _clear_all_paths_for_all_switches (self):
    msg = of.ofp_flow_mod(command=of.OFPFC_DELETE)

    # iterate over all connected switches and delete all their flows
    for sw in self.switches:
      # _connections.values() before betta
      core.openflow.sendToDPID(sw, msg)
      log.warning("Clearing all flows from %s.", dpidToStr(sw))

  def _set_path_on_swtiches (self, pid, path):
    for k, sw in enumerate(path):
      msg = of.ofp_flow_mod()

      if USE_VLAN_TAG:
        msg.match.dl_vlan = pid
      if USE_ETHERNET_SRC_TAG:
        msg.match.dl_src = EthAddr( self._int_to_MAC( pid ) ) # match ethernet addr

      if k < 1:
        # First one, host
        continue
      if k > len(path)-2:
        # Last one, host
        continue

      if k == len(path) - 2:
        # sw -> host

        if USE_VLAN_TAG:
          # strip vlan tag then send to host
          msg.actions.append(
            of.ofp_action_strip_vlan()
          )
        if USE_ETHERNET_SRC_TAG:
          # add back the real src
          msg.actions.append(
            of.ofp_action_dl_addr.set_src( EthAddr(path[0]) )
          )

        msg.actions.append(
          of.ofp_action_output( port = self.hadj[path[k+1]][sw] )
        )
        core.openflow.sendToDPID(sw, msg)
        log.warning(
          "Set rule: %s -> %s via port %i",
          dpid_to_str(sw),
          path[k+1],
          self.hadj[path[k+1]][sw]
        )
      else:
        # sw -> sw
        msg.actions.append(
          of.ofp_action_output( port = self.ports[sw][path[k+1]] )
        )
        core.openflow.sendToDPID(sw, msg)
        log.warning(
          "Set rule: %s -> %s via port %i",
          dpid_to_str(sw),
          dpid_to_str(path[k+1]),
          self.ports[sw][path[k+1]]
        )

  def _int_to_MAC(self, pid):
    tmp_pid = pid
    ma=[]
    for x in range(0, 6):
      ma.append( "%X" % (tmp_pid % 256) )
      tmp_pid //= 256
    return ma[5] + ":" + ma[4] + ":" + ma[3] + ":" + ma[2] + ":" + ma[1] + ":" + ma[0]

  def _MAC_to_int(self, mac):
    return int( "0x" + mac.replace(':', ''), 16)

  def _latency_ready(self):
    # Check if it has TIMEOUT or all the link latencies have been detected
    if time.time()*1000 - self.system_time < SYSTEM_TIMEOUT:
      for x in self.adj_test:
        for y in self.adj_test[x]:
          # Not yet
          log.warning("Waiting ...")
          return
      for x in self.sw_test:
        # Not yet
        log.warning("Waiting ...")
        return

    for sw in self.sw_test:
      self.sw_lat[sw] = LATENCY_MAX
      log.warning("sw %i timeout!", sw)
    for s1 in self.adj_test:
      for s2 in self.adj_test[s1]:
        self.adj[s1][s2] = LATENCY_MAX
        log.warning("link %i -> %i timeout!", s1, s2)

    for s1 in self.adj:
      for s2 in self.adj[s1]:
        self.adj[s1][s2] -= (self.sw_lat[s1] + self.sw_lat[s2])/2

    self.lat_test_timer.cancel()
    self.lat_test = False
    log.warning("Latency test done.")

  def _update_step(self):
    if self.update_step > len(self.config.config) - 1:
      self.update_timer.cancel()
      log.warning("Updating Ends.")
      return
    self.config.change_step(self.update_step)
    self.update_timer._next = time.time() +  self.config.next_time

    # redistribute flows based on new configuration
    self.config.reset_real_config()
    self.reset_flowdist_tables()

    # Compute for each port in all source destination pair
    for src in self.sd_path_table:
      for dst in self.sd_path_table[src]:
        id_list = self.sd_path_table[src][dst]
        for srcport in self.sd_srcport_table[src][dst]:
          pid = self.get_pid_by_srcport(id_list, srcport)  # should be None
          if pid is None:
            # Not existed port, choose the last one as default
            pid = id_list[len(id_list) - 1]
            for k in id_list:
              now_split = self.config.now_config
              real_split = self.config.real_config
              if now_split[k-1] > real_split[k-1] or now_split[k-1] == 1:
                pid = k
                break
            # update flow_dist_table and real_config_table
            self.flow_dist_table[pid-1].append(srcport)
            self.config.compute_real_config(id_list, self.flow_dist_table)

          log.warning("pid %s", pid)

          srcip = self.srcip_table[src]
          dstip = self.dstip_table[dst]
          msg = of.ofp_flow_mod( command = of.OFPFC_MODIFY )
          msg.match.dl_type = 0x800
          msg.match.nw_src = IPAddr(srcip)
          msg.match.nw_dst = IPAddr(dstip)
          msg.match.nw_proto = 17
          msg.match.tp_src = srcport
          path = self.path_id_table[pid]
          if len(path) > 3:
            # It is not the last sw, tag it and send into the network
            if USE_VLAN_TAG:
              msg.actions.append( of.ofp_action_vlan_vid( vlan_vid = pid ) )
            if USE_ETHERNET_SRC_TAG:
              msg.actions.append( of.ofp_action_dl_addr.set_src( EthAddr( self._int_to_MAC( pid ) ) ) )
            msg.actions.append( of.ofp_action_output( port = self.ports[path[1]][path[2]] ) )
          elif len(path) == 3:
            # last sw, forward to the host
            # msg.actions.append( of.ofp_action_output( port = of.OFPP_FLOOD ) )
            msg.actions.append( of.ofp_action_output( port = self.hadj[path[2]][path[1]] ) )
          sw = path[1]
          core.openflow.sendToDPID(sw, msg)
          # print msg
          # log.warning("SD pair %i, pid %i", self.sd_pair[src][dst], pid)

    log.warning("Update Step %i ...", self.update_step)
    self.update_step += 1

  """
   The function starts with a small letter is for command line interface
  """
  def reset_hosts (self):
    # Hosts we know of. [macaddr] -> Host
    self.hosts = set()
    # The ports where switches connect to the hosts
    self.hadj = defaultdict(lambda:defaultdict(lambda:int))
    # self.sd_pair: [h1][h2] -> source-destination pair id
    self.sd_pair = defaultdict(lambda:defaultdict(lambda:int))

  def reset_path_tables (self):
    # Path ID -> Path table
    self.path_id_table = defaultdict(lambda:[])
    # [Source][Destination] -> Path ID list
    self.sd_path_table = defaultdict(lambda:defaultdict(lambda:[]))

  def reset_srcport_tables (self):
    # [Source][Destination] -> Srcport list
    self.sd_srcport_table = defaultdict(lambda:defaultdict(lambda:[]))
    # [Source] -> srcip
    self.srcip_table = defaultdict(lambda:[])
    # [Destination] -> dstip
    self.dstip_table = defaultdict(lambda:[])

  def reset_flowdist_tables (self):
    # [path_id-1] -> Srcports
    self.flow_dist_table = defaultdict(lambda:[])

  def get_pid_by_srcport (self, id_list, srcport):
    # Match the srcport from cadidate path_id in id_list
    for path_id in id_list:
      if srcport in self.flow_dist_table[path_id - 1]:
        return path_id
    return None

  def port_stat (self, dpid):
    core.openflow.sendToDPID(
      dpid,
      of.ofp_stats_request(body=of.ofp_port_stats_request())
    )

  def sw_stat (self, dpid):
    core.openflow.sendToDPID(
      dpid,
      of.ofp_stats_request(body=of.ofp_flow_stats_request())
    )

  def latency(self):
    # Find link latencies and write into self.adj
    log.warning("Start latency test, please wait ...")
    self.lat_test = True
    self._clear_all_paths_for_all_switches()

    self.adj_test    = copy.deepcopy(self.adj)
    self.sw_test     = copy.copy(self.switches)
    self.sw_lat      = defaultdict(lambda:int)
    # system reference
    self.system_time = time.time()*1000

    for sw in self.sw_test:
      proto = ProbeProto()
      proto.timestamp = int(time.time()*1000 - self.system_time)
      e = pkt.ethernet()
      e.type = 0x5566
      e.src = EthAddr( "ff:ff:ff:ff:ff:ff" )
      e.dst = EthAddr( self._int_to_MAC(sw) )
      e.payload = proto
      msg = of.ofp_packet_out()
      msg.data = e.pack()
      msg.actions.append( of.ofp_action_output( port = of.OFPP_CONTROLLER ) )
      core.openflow.sendToDPID(sw, msg)

    for src in self.adj_test:
      for dst in self.adj_test[src]:
        proto = ProbeProto()
        proto.timestamp = int(time.time()*1000 - self.system_time)
        e = pkt.ethernet()
        e.type = 0x5566
        e.src = EthAddr( self._int_to_MAC(src) )
        e.dst = EthAddr( self._int_to_MAC(dst) )
        e.payload = proto
        msg = of.ofp_packet_out()
        msg.data = e.pack()
        msg.actions.append( of.ofp_action_output( port = self.ports[src][dst] ) )
        core.openflow.sendToDPID(src, msg)

    self.lat_test_timer = Timer(1, self._latency_ready, started = True, recurring = True)

  def k_path (self, k):
    # Find k-shortest path based on self.adj and self.hadj
    log.warning("Find %u path",k)

    alladj = copy.deepcopy(self.adj)
    for h in self.hadj:
      for s in self.hadj[h]:
        alladj[h][s] = 1
        alladj[s][h] = 1
    G = y_gra.DiGraph(alladj)
    log.warning("Graph constructed")

    self._clear_all_paths_for_all_switches()
    self.reset_path_tables()
    self.reset_flowdist_tables()
    self.reset_srcport_tables()

    # sd_pair_id, h1, h2, path_id ...
    output_table_1 = ""
    # path_id, path_id_table[path_id]
    output_table_2 = ""
    sd_pair_id = 0
    path_id    = 1
    for h1 in self.hadj:
      for h2 in self.hadj:
        if h1 != h2:
          self.sd_pair[h1][h2] = sd_pair_id
          output_table_1 += str(sd_pair_id) + " ( " + h1 + " , " + h2 + " ) : "
          sd_pair_id += 1
          items = y_alg.ksp_yen(G,h1,h2,k)
          for path in items:
            #print "Cost:%s\t%s" % (path['cost'], "->".join(path['path']))
            self.path_id_table[path_id] = path['path']
            self.sd_path_table[h1][h2].append(path_id)
            output_table_1 += str(path_id) + " "
            output_table_2 += str(path_id) + " " + "%s" % self.path_id_table[path_id] + "\n"
            path_id += 1
          output_table_1 += "\n"

    for pid in self.path_id_table:
      self._set_path_on_swtiches (pid, self.path_id_table[pid])

    output_file = open(OUTPUT_PATH_FILENAME, "w")
    output_file.write("SD pairs:\n%s" % output_table_1)
    output_file.write("\nPath IDs:\n%s" % output_table_2)
    output_file.close()

  def update(self):
    # let the controller start update the configuration
    log.warning("Updating Starts.")
    self.update_step = 0
    self.config.read_config( INPUT_CONFIG_FILENAME )
    # Initial update
    self.update_timer = Timer(self.config.next_time, self._update_step, started = False, recurring = True)
    self._update_step()
    self.update_timer.start()