def _packet_in_handler(self, ev): """Handle packet_in events.""" if not self.link_discovery: return msg = ev.msg in_port = msg.match['in_port'] packet = Packet(msg.data) efm = packet.get_protocol(ethernet.ethernet) if efm.ethertype == ether.ETH_TYPE_ARP: self.send_event_to_observers(event.EventArpReceived(ev)) try: src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data) except LLDPPacket.LLDPUnknownFormat as e: # This handler can receive all the packtes which can be # not-LLDP packet. Ignore it silently return else: dst_dpid = msg.datapath.id dst_port_no = in_port src = self._get_port(src_dpid, src_port_no) if not src or src.dpid == dst_dpid: return dst = self._get_port(dst_dpid, dst_port_no) if not dst: return old_peer = self.links.get_peer(src) #LOG.debug("Packet-In") #LOG.debug(" src=%s", src) #LOG.debug(" dst=%s", dst) #LOG.debug(" old_peer=%s", old_peer) if old_peer and old_peer != dst: old_link = Link(src, old_peer) self.send_event_to_observers(event.EventLinkDelete(old_link)) link = Link(src, dst) if not link in self.links: self.send_event_to_observers(event.EventLinkAdd(link)) if not self.links.update_link(src, dst): # reverse link is not detected yet. # So schedule the check early because it's very likely it's up try: self.ports.lldp_received(dst) except KeyError as e: # There are races between EventOFPPacketIn and # EventDPPortAdd. So packet-in event can happend before # port add event. In that case key error can happend. # LOG.debug('lldp_received: KeyError %s', e) pass else: self.ports.move_front(dst) self.lldp_event.set()
def _link_down(self, port): try: dst, rev_link_dst = self.links.port_deleted(port) except KeyError: # LOG.debug('key error. src=%s, dst=%s', # port, self.links.get_peer(port)) return link = Link(port, dst) self.send_event_to_observers(event.EventLinkDelete(link)) if rev_link_dst: rev_link = Link(dst, rev_link_dst) self.send_event_to_observers(event.EventLinkDelete(rev_link)) self.ports.move_front(dst)
def dst_port_deleted(self, dst): src = self.get_peer(dst) if src is None: raise KeyError() link = Link(src, dst) rev_link = Link(dst, src) del self[link] del self._map[src] del self._rmap[dst] self.pop(rev_link, None) rev_link_dst = self._map.pop(dst, None) return src, rev_link_dst
def link_loop(self): while self.is_active: self.link_event.clear() now = time.time() deleted = [] for (link, timestamp) in self.links.items(): if timestamp + self.LINK_TIMEOUT < now: src = link.src if src in self.ports: port_data = self.ports.get_port(src) if port_data.lldp_dropped() > self.LINK_LLDP_DROP: deleted.append(link) for link in deleted: self.links.link_down(link) self.send_event_to_observers(event.EventLinkDelete(link)) dst = link.dst rev_link = Link(dst, link.src) if rev_link not in deleted: # It is very likely that the reverse link is also # disconnected. Check it early. expire = now - self.LINK_TIMEOUT self.links.rev_link_set_timestamp(rev_link, expire) if dst in self.ports: self.ports.move_front(dst) self.lldp_event.set() self.link_event.wait(timeout=self.TIMEOUT_CHECK_PERIOD)
def packet_in_handler(self, ev): self._logger.debug('Packet in') msg = ev.msg ofp = msg.datapath.ofproto pkt = packet.Packet(msg.data) headers = dict((p.protocol_name, p) for p in pkt.protocols if type(p) != str) src_mac = headers[ETHERNET].src try: src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data) except LLDPPacket.LLDPUnknownFormat as e: self._logger.debug('LLDPUnknownFormat %s', e) return dst_port_no = self.ofctl.get_packet_in_inport(msg) dst = self._get_port(dst_port_no) self._logger.debug('LLDP from %d.%d -> %d', src_dpid, src_port_no, dst_port_no) if not dst: self._logger.warning('Dst not found.') return self.ports.lldp_received(dst) src = Port(PortData(src_dpid, port_no=src_port_no, hw_addr=src_mac)) old_peer = self.links.get_peer(dst) need_update = False if old_peer and old_peer != src: self._logger.info('Peer changed.') self._report_link_deleted(Link(old_peer, dst)) need_update = True link = Link(src, dst) if link not in self.links: need_update = True self._report_link_added(Link(src, dst)) self.lldp_event.set() # Always return false, since we don't have the reverse link information if need_update: self.links.update_link(src, dst) self._logger.info('Update link %d.%d -> %d.%d', src.dpid, src.port_no, dst.dpid, dst.port_no)
def _link_down(self, port): try: src, rev_link_dst = self.links.dst_port_deleted(port) self._logger.info('Link down: %d.%d -> %d.%d', src.dpid, src.port_no, port.dpid, port.port_no) except KeyError: self._logger.info('Cannot find peer of %d.%d', port.dpid, port.port_no) return self._report_link_deleted(Link(src, port))
def link_deleted(self, src_port_data, dst_port_data): try: with self._switches_lock: src_port = self.switches[src_port_data.dpid].update_port( src_port_data) dst_port = self.switches[dst_port_data.dpid].update_port( dst_port_data) with self._links_lock: del self.links[src_port.dpid][dst_port.dpid] self._logger.info('Link %d.%d -> %d.%d down', src_port_data.dpid, src_port_data.port_no, dst_port_data.dpid, dst_port_data.port_no) self.send_event_to_observers( EventLinkDelete(Link(src_port, dst_port))) except KeyError: self._logger.error('Cannot find link %d.%d -> %d.%d', src_port_data.dpid, src_port_data.port_no, dst_port_data.dpid, dst_port_data.port_no)
def link_added(self, src_port_data, dst_port_data): try: with self._switches_lock: src_port = self.switches[src_port_data.dpid].update_port( src_port_data) dst_port = self.switches[dst_port_data.dpid].update_port( dst_port_data) link = Link(src_port, dst_port) with self._links_lock: if src_port.dpid not in self.links.keys(): self.links[src_port.dpid] = {} self.links[src_port.dpid][dst_port.dpid] = link self._logger.info('Link %d.%d -> %d.%d up', src_port_data.dpid, src_port_data.port_no, dst_port_data.dpid, dst_port_data.port_no) self.send_event_to_observers(EventLinkAdd(link)) except KeyError: self._logger.error('Cannot find dst port %d.%d', dst_port_data.dpid, dst_port_data.port_no)
def _createLink(self, src_dpid, src_port_no, dst_dpid, dst_port_no): port_src = self._createPort(src_dpid, src_port_no) port_dst = self._createPort(dst_dpid, dst_port_no) return Link(port_src, port_dst)
def _monitor(self): hub.sleep(200) # Wait for the topology discovery host_list = get_host(self, None) switch_list = get_switch(self, None) link_list = get_link(self, None).keys() # Add missing backward links link_pairs = set([(link.src.dpid, link.dst.dpid) for link in link_list]) missing_links = [ Link(link.dst, link.src) for link in link_list if not (link.dst.dpid, link.src.dpid) in link_pairs ] link_list.extend(missing_links) H, S = (len(host_list), len(switch_list)) # The number of nodes, the number of flows and the number of links respectively # +2*H is for the links connecting switches and hosts (bidrectional) N, H2, L = (H + S, H * (H - 1), len(link_list) + 2 * H) # Gather Flow Table Rules self.port_dst_to_rule = {} self.R, self.t = (0, None) for dp in self.datapaths.values(): self._request_stats(dp) hub.sleep(5) # self.port_to_link[switch_id][port_no] gives the corresponding link id # of the port of the switch self.port_to_link = {} # self.port_to_host[switch_id][port_no] gives the corresponding host of # the port of the switch self.port_to_host = {} # switch_to_links[switch_id] provides the id list of the links # connected to the switch switch_to_links = {} # switch_to_rules[switch_id] provides the id list of the rules # in the switch switch_to_rules = {} # Populate the dictionaries for link_id, link in enumerate(link_list): self.port_to_link.setdefault(link.src.dpid, {}) self.port_to_link[link.src.dpid][link.src.port_no] = link_id, link switch_to_links.setdefault(link.src.dpid, []) switch_to_links[link.src.dpid].append(link_id) switch_to_links.setdefault(link.dst.dpid, []) switch_to_links[link.dst.dpid].append(link_id) # Add hosts with the links for host_id, host in enumerate(host_list): rlink_id = len(link_list) + host_id # (Host -> Switch) tlink_id = rlink_id + H # (Switch -> Host) switch_to_links[host.port.dpid].extend([rlink_id, tlink_id]) self.port_to_host.setdefault(host.port.dpid, {}) self.port_to_host[host.port.dpid][ host.port.port_no] = rlink_id, tlink_id, host for switch_id in self.port_dst_to_rule: switch_to_rules[switch_id] = [ rule_id for rule_id, port_no in self.port_dst_to_rule[switch_id].values() ] # Create the routing matricess A = np.zeros((L, H2)) B = np.zeros((self.R, H2)) flow_id = 0 for src_id, src in enumerate(host_list): for dst_id, dst in enumerate(host_list): if src_id != dst_id: # Outgoing link id of src host (Host -> Switch) link_id = len(link_list) + src_id A[link_id, flow_id] = 1 # The first switch on the path switch_id = src.port.dpid # The corresponding rule and out port rule_id, port_no = self.port_dst_to_rule[switch_id][ src.port.port_no, dst.mac] B[rule_id, flow_id] = 1 # Populate through the switches on the path while port_no in self.port_to_link[switch_id]: # Next Link link_id, link = self.port_to_link[switch_id][port_no] A[link_id, flow_id] = 1 # Next Switch switch_id = link.dst.dpid rule_id, port_no = self.port_dst_to_rule[switch_id][ link.dst.port_no, dst.mac] B[rule_id, flow_id] = 1 # Incoming link id of the dst host (Switch -> Host) link_id = len(link_list) + H + dst_id A[link_id, flow_id] = 1 flow_id += 1 im = InferenceModule(A, links=switch_to_links) im2 = InferenceModule(B, links=switch_to_rules) # Start monitoring T = 1000 # The number of time steps self.trace = np.zeros((T, L)) # Time Step x Link ID self.trace2 = np.zeros((T, self.R)) # Time Step x Link ID for self.t in range(T): self.logger.info('Time Step: ' + str(self.t)) for dp in self.datapaths.values(): # Complete measurement self._request_stats(dp) # See SimpleMonitor13._request_stats hub.sleep(1) # Save with open( 'trace_' + datetime.now().strftime('%Y-%m-%d_%H:%M:%S') + '.pkl', 'w') as trace_file: pickle.dump( { 'im': im, 'im2': im2, 'A': A, 'B': B, 'trace': self.trace, 'trace2': self.trace2, 'port_dst_to_rule': self.port_dst_to_rule, 'switch_links': [(link.src.dpid, link.dst.dpid) for link in link_list], 'host_links': [(host.mac, host.port.dpid) for host in host_list], 'switch_to_links': switch_to_links, 'switch_to_rules': switch_to_rules, 'H': H, 'S': S, 'N': N, 'H2': H2, 'L': L, 'R': self.R, 'T': T }, trace_file)
def createLink(src_dpid, src_port_no, dst_dpid, dst_port_no): port_src = createPort(src_dpid, src_port_no) port_dst = createPort(dst_dpid, dst_port_no) return Link(port_src, port_dst)