def get_path(self, from_dpid, to_dpid, packet): # TODO: Support IPv6 tcp_packet = packet.find("tcp") udp_packet = packet.find("udp") ip_packet = packet.find("ipv4") if tcp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, tcp_packet.srcport, ip_packet.dstip, tcp_packet.dstport) elif udp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, udp_packet.srcport, ip_packet.dstip, udp_packet.dstport) elif ip_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, PathPreferenceTable.WILDCARD, ip_packet.dstip, PathPreferenceTable.WILDCARD) else: path_identifier = PathPreferenceTable.create_path_identifier( PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD) preference = self.path_preference_table.match(path_identifier) if preference is PathPreferenceTable.MAXIMUM_BANDWIDTH: # Interim solution: use path on maximum spanning tree for max bw path # graph = maximum_spanning_tree(core.overseer_topology.graph, PathPreferenceTable.MAXIMUM_BANDWIDTH) # return nx.shortest_path(graph, from_dpid, to_dpid, preference) from weighted import dijkstra_path as maximin_path return maximin_path(core.overseer_topology.graph, from_dpid, to_dpid, preference) else: return nx.shortest_path(core.overseer_topology.graph, from_dpid, to_dpid, preference)
def get_path(self, from_dpid, to_dpid, packet): # TODO: Support IPv6 tcp_packet = packet.find("tcp") udp_packet = packet.find("udp") ip_packet = packet.find("ipv4") if tcp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, tcp_packet.srcport, ip_packet.dstip, tcp_packet.dstport ) elif udp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, udp_packet.srcport, ip_packet.dstip, udp_packet.dstport ) elif ip_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, PathPreferenceTable.WILDCARD, ip_packet.dstip, PathPreferenceTable.WILDCARD ) else: path_identifier = PathPreferenceTable.create_path_identifier( PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD ) preference = self.path_preference_table.match(path_identifier) if preference is PathPreferenceTable.MAXIMUM_BANDWIDTH: # Interim solution: use path on maximum spanning tree for max bw path # graph = maximum_spanning_tree(core.overseer_topology.graph, PathPreferenceTable.MAXIMUM_BANDWIDTH) # return nx.shortest_path(graph, from_dpid, to_dpid, preference) from weighted import dijkstra_path as maximin_path return maximin_path(core.overseer_topology.graph, from_dpid, to_dpid, preference) else: return nx.shortest_path(core.overseer_topology.graph, from_dpid, to_dpid, preference)
def __init__(self, flow_idle_timeout=30, flow_hard_timeout=60, default_latency=1, default_bandwidth=100): core.listen_to_dependencies(self) self.log = core.getLogger() # self.path_preference_table = PathPreferenceTable.Instance() self.path_preference_table = PathPreferenceTable() self.flow_idle_timeout = flow_idle_timeout self.flow_hard_timeout = flow_hard_timeout self.default_latency = default_latency # Milliseconds self.default_bandwidth = default_bandwidth # Megabits self.path_preferences = dict()
class Overseer(object): """ Overseer - POX Component Implementing Bandwith/Latency-aware OpenFlow Controller """ # LATENCY_WEIGHT_LABEL = "latency" # BANDWIDTH_WEIGHT_LABEL = "inversed_bandwidth" _core_name = "overseer" # We want to be core.overseer # def __init__(self, flow_idle_timeout=10, flow_hard_timeout=30, def __init__(self, flow_idle_timeout=30, flow_hard_timeout=60, default_latency=1, default_bandwidth=100): core.listen_to_dependencies(self) self.log = core.getLogger() # self.path_preference_table = PathPreferenceTable.Instance() self.path_preference_table = PathPreferenceTable() self.flow_idle_timeout = flow_idle_timeout self.flow_hard_timeout = flow_hard_timeout self.default_latency = default_latency # Milliseconds self.default_bandwidth = default_bandwidth # Megabits self.path_preferences = dict() def _handle_overseer_topology_LinkUp(self, event): graph = core.overseer_topology.graph # dpid1 -> dpid2 graph.edge[event.dpid1][event.dpid2][ PathPreferenceTable.MAXIMUM_BANDWIDTH] = self.default_bandwidth graph.edge[event.dpid1][event.dpid2][ PathPreferenceTable.MINIMUM_LATENCY] = self.default_latency graph.edge[event.dpid1][event.dpid2][PathPreferenceTable.DEFAULT] = 1 # dpid2 -> dpid1 graph.edge[event.dpid2][event.dpid1][ PathPreferenceTable.MAXIMUM_BANDWIDTH] = self.default_bandwidth graph.edge[event.dpid2][event.dpid1][ PathPreferenceTable.MINIMUM_LATENCY] = self.default_latency graph.edge[event.dpid2][event.dpid1][PathPreferenceTable.DEFAULT] = 1 def _handle_openflow_PacketIn(self, event): # TODO: Refactor this method packet = event.parsed source = packet.src destination = packet.dst # self.log.info("SRC: %s" % source) # self.log.info("DST: %s" % destination) if destination.is_multicast: # Note: pick between 2 flooding techniques here # Flood the packet # ** Manual flooding ** # TODO: Install new flow instead of crafting new packet (hold down?) for mac, entry in core.host_tracker.entryByMAC.iteritems(): if source == mac: continue message = of.ofp_packet_out() message.actions.append(of.ofp_action_output(port=entry.port)) message.data = event.data # message.data = event.ofp core.overseer_topology.graph.node[ entry.dpid]['connection'].send(message) self.log.debug( "FLOODING: MAC %s is connected to switch %s at port %s" % (mac, entry.dpid, entry.port)) # ** Use OFPP_FLOOD ** # message = of.ofp_packet_out() # message.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD)) # message.buffer_id = event.ofp.buffer_id # # message.data = event.ofp # message.in_port = event.port # event.connection.send(message) return entryByMAC = core.host_tracker.entryByMAC known_hosts = entryByMAC.keys() if (source not in known_hosts) or (destination not in known_hosts): # Ignore non-end-to-end packet self.log.info("There is no path from host %s to host %s" % (source, destination)) return self.log.info("Finding path from host %s to host %s" % (source, destination)) from_host = entryByMAC[source] to_host = entryByMAC[destination] path = self.get_path(from_host.dpid, to_host.dpid, packet) match = of.ofp_match.from_packet(packet) match.in_port = None # match.dl_src = None # match.dl_dst = None #match.dl_vlan = None #match.dl_vlan_pcp = None # match.nw_proto = None #match.nw_tos = None self.log.info("Installing path from host %s to host %s" % (source, destination)) # Install flows # TODO: Handle buffer_id properly # first = True for from_switch, to_switch in utils.pairwise(path): self.log.info("Installing flow from switch %x to switch %x" % (from_switch, to_switch)) portByDpid = core.overseer_topology.graph.get_edge_data( from_switch, to_switch)["portByDpid"] message = of.ofp_flow_mod() message.match = match message.idle_timeout = self.flow_idle_timeout message.hard_timeout = self.flow_hard_timeout message.actions.append( of.ofp_action_output(port=portByDpid[from_switch])) # self.log.info("DEBUG: %s %d" % (type(portByDpid[from_switch]), portByDpid[from_switch])) # if first: # message.buffer_id = event.ofp.buffer_id # first = False core.overseer_topology.graph.node[from_switch]['connection'].send( message) # Install final flow self.log.info("Installing final flow from switch %x to host %s" % (path[-1], destination)) message = of.ofp_flow_mod() message.match = match message.idle_timeout = self.flow_idle_timeout message.hard_timeout = self.flow_hard_timeout message.actions.append(of.ofp_action_output(port=to_host.port)) core.overseer_topology.graph.node[path[-1]]['connection'].send(message) def get_path(self, from_dpid, to_dpid, packet): # TODO: Support IPv6 tcp_packet = packet.find("tcp") udp_packet = packet.find("udp") ip_packet = packet.find("ipv4") if tcp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, tcp_packet.srcport, ip_packet.dstip, tcp_packet.dstport) elif udp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, udp_packet.srcport, ip_packet.dstip, udp_packet.dstport) elif ip_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, PathPreferenceTable.WILDCARD, ip_packet.dstip, PathPreferenceTable.WILDCARD) else: path_identifier = PathPreferenceTable.create_path_identifier( PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD) preference = self.path_preference_table.match(path_identifier) self.log.info("Path Identifier: %s %s %s %s" % path_identifier) self.log.info("Preference: %x" % preference) if preference is PathPreferenceTable.MAXIMUM_BANDWIDTH: # Interim solution: use path on maximum spanning tree for max bw path # graph = maximum_spanning_tree(core.overseer_topology.graph, PathPreferenceTable.MAXIMUM_BANDWIDTH) # return nx.shortest_path(graph, from_dpid, to_dpid, preference) from weighted import dijkstra_path as maximin_path return maximin_path(core.overseer_topology.graph, from_dpid, to_dpid, preference) else: return nx.shortest_path(core.overseer_topology.graph, from_dpid, to_dpid, preference) def _handle_openflow_ErrorIn(self, event): # Log all OpenFlow errors self.log.error("OF:%s" % event.asString()) def _handle_overseer_topology_Update(self, event): # TODO: Update all-pair shortest paths using Floyd-Warshall algorithm pass
class Overseer (object): """ Overseer - POX Component Implementing Bandwith/Latency-aware OpenFlow Controller """ # LATENCY_WEIGHT_LABEL = "latency" # BANDWIDTH_WEIGHT_LABEL = "inversed_bandwidth" _core_name = "overseer" # We want to be core.overseer # def __init__(self, flow_idle_timeout=10, flow_hard_timeout=30, def __init__(self, flow_idle_timeout=30, flow_hard_timeout=60, default_latency=1, default_bandwidth=100): core.listen_to_dependencies(self) self.log = core.getLogger() # self.path_preference_table = PathPreferenceTable.Instance() self.path_preference_table = PathPreferenceTable() self.flow_idle_timeout = flow_idle_timeout self.flow_hard_timeout = flow_hard_timeout self.default_latency = default_latency # Milliseconds self.default_bandwidth = default_bandwidth # Megabits self.path_preferences = dict() def _handle_overseer_topology_LinkUp(self, event): graph = core.overseer_topology.graph # dpid1 -> dpid2 graph.edge[event.dpid1][event.dpid2][PathPreferenceTable.MAXIMUM_BANDWIDTH] = self.default_bandwidth graph.edge[event.dpid1][event.dpid2][PathPreferenceTable.MINIMUM_LATENCY] = self.default_latency graph.edge[event.dpid1][event.dpid2][PathPreferenceTable.DEFAULT] = 1 # dpid2 -> dpid1 graph.edge[event.dpid2][event.dpid1][PathPreferenceTable.MAXIMUM_BANDWIDTH] = self.default_bandwidth graph.edge[event.dpid2][event.dpid1][PathPreferenceTable.MINIMUM_LATENCY] = self.default_latency graph.edge[event.dpid2][event.dpid1][PathPreferenceTable.DEFAULT] = 1 def _handle_openflow_PacketIn(self, event): # TODO: Refactor this method packet = event.parsed source = packet.src destination = packet.dst # self.log.info("SRC: %s" % source) # self.log.info("DST: %s" % destination) if destination.is_multicast: # Note: pick between 2 flooding techniques here # Flood the packet # ** Manual flooding ** # TODO: Install new flow instead of crafting new packet (hold down?) for mac, entry in core.host_tracker.entryByMAC.iteritems(): if source == mac: continue message = of.ofp_packet_out() message.actions.append(of.ofp_action_output(port=entry.port)) message.data = event.data # message.data = event.ofp core.overseer_topology.graph.node[entry.dpid]['connection'].send(message) self.log.debug("FLOODING: MAC %s is connected to switch %s at port %s" % (mac, entry.dpid, entry.port)) # ** Use OFPP_FLOOD ** # message = of.ofp_packet_out() # message.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD)) # message.buffer_id = event.ofp.buffer_id # # message.data = event.ofp # message.in_port = event.port # event.connection.send(message) return entryByMAC = core.host_tracker.entryByMAC known_hosts = entryByMAC.keys() if (source not in known_hosts) or (destination not in known_hosts): # Ignore non-end-to-end packet self.log.info("There is no path from host %s to host %s" % (source, destination)) return self.log.info("Finding path from host %s to host %s" % (source, destination)) from_host = entryByMAC[source] to_host = entryByMAC[destination] path = self.get_path(from_host.dpid, to_host.dpid, packet) match = of.ofp_match.from_packet(packet) match.in_port = None # match.dl_src = None # match.dl_dst = None #match.dl_vlan = None #match.dl_vlan_pcp = None # match.nw_proto = None #match.nw_tos = None self.log.info("Installing path from host %s to host %s" % (source, destination)) # Install flows # TODO: Handle buffer_id properly # first = True for from_switch, to_switch in utils.pairwise(path): self.log.info("Installing flow from switch %x to switch %x" % (from_switch, to_switch)) portByDpid = core.overseer_topology.graph.get_edge_data(from_switch, to_switch)["portByDpid"] message = of.ofp_flow_mod() message.match = match message.idle_timeout = self.flow_idle_timeout message.hard_timeout = self.flow_hard_timeout message.actions.append(of.ofp_action_output(port=portByDpid[from_switch])) # self.log.info("DEBUG: %s %d" % (type(portByDpid[from_switch]), portByDpid[from_switch])) # if first: # message.buffer_id = event.ofp.buffer_id # first = False core.overseer_topology.graph.node[from_switch]['connection'].send(message) # Install final flow self.log.info("Installing final flow from switch %x to host %s" % (path[-1], destination)) message = of.ofp_flow_mod() message.match = match message.idle_timeout = self.flow_idle_timeout message.hard_timeout = self.flow_hard_timeout message.actions.append(of.ofp_action_output(port=to_host.port)) core.overseer_topology.graph.node[path[-1]]['connection'].send(message) def get_path(self, from_dpid, to_dpid, packet): # TODO: Support IPv6 tcp_packet = packet.find("tcp") udp_packet = packet.find("udp") ip_packet = packet.find("ipv4") if tcp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, tcp_packet.srcport, ip_packet.dstip, tcp_packet.dstport ) elif udp_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, udp_packet.srcport, ip_packet.dstip, udp_packet.dstport ) elif ip_packet is not None: path_identifier = PathPreferenceTable.create_path_identifier( ip_packet.srcip, PathPreferenceTable.WILDCARD, ip_packet.dstip, PathPreferenceTable.WILDCARD ) else: path_identifier = PathPreferenceTable.create_path_identifier( PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD, PathPreferenceTable.WILDCARD ) preference = self.path_preference_table.match(path_identifier) self.log.info("Path Identifier: %s %s %s %s" % path_identifier) self.log.info("Preference: %x" % preference) if preference is PathPreferenceTable.MAXIMUM_BANDWIDTH: # Interim solution: use path on maximum spanning tree for max bw path # graph = maximum_spanning_tree(core.overseer_topology.graph, PathPreferenceTable.MAXIMUM_BANDWIDTH) # return nx.shortest_path(graph, from_dpid, to_dpid, preference) from weighted import dijkstra_path as maximin_path return maximin_path(core.overseer_topology.graph, from_dpid, to_dpid, preference) else: return nx.shortest_path(core.overseer_topology.graph, from_dpid, to_dpid, preference) def _handle_openflow_ErrorIn(self, event): # Log all OpenFlow errors self.log.error("OF:%s" % event.asString()) def _handle_overseer_topology_Update(self, event): # TODO: Update all-pair shortest paths using Floyd-Warshall algorithm pass