def link_loop(self): while self.is_active: self.link_event.clear() now = time.time() deleted = [] inter_deleted = [] for (link, timestamp) in self.links.items(): # LOG.debug('%s timestamp %d (now %d)', link, timestamp, now) if timestamp + self.LINK_TIMEOUT < now: src = link.src if src in self.ports: port_data = self.ports.get_port(src) # LOG.debug('port_data %s', port_data) if port_data.lldp_dropped() > self.LINK_LLDP_DROP: deleted.append(link) for (link, timestamp) in self.inter_links.items(): # LOG.debug('%s timestamp %d (now %d)', link, timestamp, now) if timestamp + self.LINK_TIMEOUT < now: src = link.dst if src in self.ports: port_data = self.ports.get_port(src) # LOG.debug('port_data %s', port_data) if port_data.lldp_dropped() > self.LINK_LLDP_DROP: inter_deleted.append(link) #''' for host in self.hosts.values(): host_port = host.port dst_port = link.dst if host_port.dpid == dst_port.dpid and host_port.port_no == dst_port.port_no: del self.hosts[host.mac] ev = event.EventHostDelete(host) self.send_event_to_observers(ev) #''' for link in inter_deleted: self.inter_links.link_down(link) # LOG.debug('delete %s', link) self.send_event_to_observers(event.EventLinkDelete(link)) for link in deleted: self.links.link_down(link) # LOG.debug('delete %s', 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 host_check(self): # while self.is_active: # self.check_event.clear() for m in list(self.ip_pool.keys()): if time.perf_counter() - self.ip_pool[m][1] > 30: #print(time.perf_counter(), self.ip_pool[m][2]) id = int(self.ip_pool[m][0].split('.')[-1]) #print(m, str(self.mac_port[m][0])+":"+str(self.mac_port[m][1])) h = switches.Host( m, str(self.mac_port[m][0]) + ":" + str(self.mac_port[m][1])) h.ipv4.append(self.ip_pool[m][0]) self.send_event_to_observers(event.EventHostDelete(h)) del self.ip_pool[m] del self.mac_port[m] self.usable_id.append(id)
def lldp_packet_in_handler(self, ev): if not self.link_discovery: return msg = ev.msg try: src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data) except LLDPPacket.LLDPUnknownFormat as e: # This handler can receive all the packets which can be # not-LLDP packet. Ignore it silently return dst_dpid = msg.datapath.id if msg.datapath.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: dst_port_no = msg.in_port elif msg.datapath.ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION: dst_port_no = msg.match['in_port'] else: LOG.error('cannot accept LLDP. unsupported version. %x', msg.datapath.ofproto.OFP_VERSION) src = self._get_port(src_dpid, src_port_no) if not src or src.dpid == dst_dpid: return try: self.ports.lldp_received(src) except KeyError: # 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 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) del self.links[old_link] self.send_event_to_observers(event.EventLinkDelete(old_link)) link = Link(src, dst) if link not in self.links: self.send_event_to_observers(event.EventLinkAdd(link)) # remove hosts from edge port for host in self.hosts.values(): if not self._is_edge_port(host.port): ev = event.EventHostDelete(host) self.send_event_to_observers(ev) del self.hosts[host.mac] 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 self.ports.move_front(dst) self.lldp_event.set() if self.explicit_drop: self._drop_packet(msg)
def port_status_handler(self, ev): msg = ev.msg reason = msg.reason dp = msg.datapath ofpport = msg.desc if reason == dp.ofproto.OFPPR_ADD: # LOG.debug('A port was added.' + # '(datapath id = %s, port number = %s)', # dp.id, ofpport.port_no) self.port_state[dp.id].add(ofpport.port_no, ofpport) self.send_event_to_observers( event.EventPortAdd(Port(dp.id, dp.ofproto, ofpport))) if not self.link_discovery: return port = self._get_port(dp.id, ofpport.port_no) if port and not port.is_reserved(): self._port_added(port) self.lldp_event.set() elif reason == dp.ofproto.OFPPR_DELETE: # LOG.debug('A port was deleted.' + # '(datapath id = %s, port number = %s)', # dp.id, ofpport.port_no) self.port_state[dp.id].remove(ofpport.port_no) self.send_event_to_observers( event.EventPortDelete(Port(dp.id, dp.ofproto, ofpport))) if not self.link_discovery: return port = self._get_port(dp.id, ofpport.port_no) if port and not port.is_reserved(): # if port delete # then delete host on it for host in self.hosts.values(): if port.__eq__(host.port): ev = event.EventHostDelete(host) self.send_event_to_observers(ev) del self.hosts[host.mac] break self.ports.del_port(port) self._link_down(port) self.lldp_event.set() else: assert reason == dp.ofproto.OFPPR_MODIFY # LOG.debug('A port was modified.' + # '(datapath id = %s, port number = %s)', # dp.id, ofpport.port_no) self.port_state[dp.id].modify(ofpport.port_no, ofpport) self.send_event_to_observers( event.EventPortModify(Port(dp.id, dp.ofproto, ofpport))) if not self.link_discovery: return port = self._get_port(dp.id, ofpport.port_no) if port and not port.is_reserved(): if self.ports.set_down(port): # if port down # then delete host on it for host in self.hosts.values(): if port.__eq__(host.port): ev = event.EventHostDelete(host) self.send_event_to_observers(ev) del self.hosts[host.mac] break self._link_down(port) self.lldp_event.set()
def state_change_handler(self, ev): dp = ev.datapath assert dp is not None LOG.debug(dp) if ev.state == MAIN_DISPATCHER: dp_multiple_conns = False if dp.id in self.dps: LOG.warning('Multiple connections from %s', dpid_to_str(dp.id)) dp_multiple_conns = True (self.dps[dp.id]).close() self._register(dp) switch = self._get_switch(dp.id) LOG.debug('register %s', switch) if not dp_multiple_conns: self.send_event_to_observers(event.EventSwitchEnter(switch)) else: self.send_event_to_observers( event.EventSwitchReconnected(switch)) if not self.link_discovery: return if self.install_flow: ofproto = dp.ofproto ofproto_parser = dp.ofproto_parser # TODO:XXX need other versions if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: rule = nx_match.ClsRule() rule.set_dl_dst( addrconv.mac.text_to_bin(lldp.LLDP_MAC_NEAREST_BRIDGE)) rule.set_dl_type(ETH_TYPE_LLDP) actions = [ ofproto_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, self.LLDP_PACKET_LEN) ] dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions, priority=0xFFFF) elif ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION: match = ofproto_parser.OFPMatch( eth_type=ETH_TYPE_LLDP, eth_dst=lldp.LLDP_MAC_NEAREST_BRIDGE) # OFPCML_NO_BUFFER is set so that the LLDP is not # buffered on switch parser = ofproto_parser actions = [ parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER) ] inst = [ parser.OFPInstructionActions( ofproto.OFPIT_APPLY_ACTIONS, actions) ] mod = parser.OFPFlowMod(datapath=dp, match=match, idle_timeout=0, hard_timeout=0, instructions=inst, priority=0xFFFF) dp.send_msg(mod) else: LOG.error('cannot install flow. unsupported version. %x', dp.ofproto.OFP_VERSION) # Do not add ports while dp has multiple connections to controller. if not dp_multiple_conns: for port in switch.ports: if not port.is_reserved(): self._port_added(port) self.lldp_event.set() elif ev.state == DEAD_DISPATCHER: # dp.id is None when datapath dies before handshake if dp.id is None: return # if switch delete # then delete host on it hostlist = self.hosts.get_by_dpid(dp.id) for host in hostlist: ev = event.EventHostDelete(host) self.send_event_to_observers(ev) del self.hosts[host.mac] switch = self._get_switch(dp.id) if switch: if switch.dp is dp: self._unregister(dp) LOG.debug('unregister %s', switch) self.send_event_to_observers( event.EventSwitchLeave(switch)) if not self.link_discovery: return for port in switch.ports: if not port.is_reserved(): self.ports.del_port(port) self._link_down(port) self.lldp_event.set()
def lldp_packet_in_handler_for_interlink(self, ev): LOG.debug("lldp_packet_in_handler_for_interlink") if not self.link_discovery: LOG.debug( "lldp_packet_in_handler_for_interlink:link_discovert flag is false,return" ) return msg = ev.msg try: src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data) except LLDPPacket.LLDPUnknownFormat as e: # This handler can receive all the packets which can be # not-LLDP packet. Ignore it silently LOG.debug( "lldp_packet_in_handler_for_interlink: lldp_parse error:") LOG.debug(e) return dst_dpid = msg.datapath.id if msg.datapath.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: dst_port_no = msg.in_port elif msg.datapath.ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION: dst_port_no = msg.match['in_port'] else: LOG.error('cannot accept LLDP. unsupported version. %x', msg.datapath.ofproto.OFP_VERSION) LOG.debug("lldp_packet_in_handler_for_interlink:get dpid") src = self._get_port(src_dpid, src_port_no) #if src is local handle it in lldp_packet_in_handler if src: LOG.debug( "lldp_packet_in_handler_for_interlink: can find src port ,so its shouldn't be handled as interlink,return" ) return dst = self._get_port(dst_dpid, dst_port_no) if not dst: LOG.debug( "lldp_packet_in_handler_for_interlink: can find dst port ,so why cant find dst port in local,fail and return" ) return # so now ,src is None, create a src port instance #dst_json = json.dumps(dst, default=lambda obj: obj.__dict__) src = dst.copy() src.dpid = src_dpid src.port_no = src_port_no # change it to dst try: LOG.debug( "lldp_packet_in_handler_for_interlink: set dst port send count as zero" ) self.ports.lldp_received(dst) except KeyError: # 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 old_peer = self.inter_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) del self.inter_links[old_link] LOG.debug( "lldp_packet_in_handler_for_interlink:find a old peer, delete the old link" ) self.send_event_to_observers(event.EventLinkDelete(old_link)) # hanlde port form other domain,define port_no = dpid:port_no # TODO we assume that dpid is unique, if not we shuold extend LLDP to add with cid(controller id) LOG.debug("lldp_packet_in_handler_for_interlink:create interlink") inter_link = Link(src, dst) if inter_link not in self.inter_links: LOG.debug("discover inter_link:-----------------") LOG.debug(inter_link) LOG.debug( "lldp_packet_in_handler_for_interlink: send EventLinkAdd to observers" ) self.send_event_to_observers(event.EventLinkAdd(inter_link)) # remove hosts from edge port for host in self.hosts.values(): if self._is_domain_edge_port(host.port): del self.hosts[host.mac] print "delete host" print host ev = event.EventHostDelete(host) self.send_event_to_observers(ev) LOG.debug( "lldp_packet_in_handler_for_interlink: update link state time") self.inter_links.update_link(src, dst) if self.explicit_drop: self._drop_packet(msg)
def host_discovery_packet_in_handler(self, ev): msg = ev.msg pkt = packet.Packet(msg.data) eth = pkt.get_protocols(ethernet.ethernet)[0] # ignore lldp packet if eth.ethertype == ETH_TYPE_LLDP: return datapath = msg.datapath dpid = datapath.id port_no = -1 if msg.datapath.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: port_no = msg.in_port else: port_no = msg.match['in_port'] port = self._get_port(dpid, port_no) host_mac = eth.src # can't find this port(ex: logic port) if not port: return # ignore switch-to-switch port if not self._is_edge_port(port): #print "host in edge: <%d,%d>" % (dpid,port_no) local_host = self.hosts.get(host_mac) if local_host: del self.hosts[host_mac] ev = event.EventHostDelete(local_host) self.send_event_to_observers(ev) print "delete host" return if self._is_domain_edge_port(port): #print "host in domain edge: <%d,%d>" % (dpid,port_no) local_host = self.hosts.get(host_mac) if local_host: del self.hosts[host_mac] ev = event.EventHostDelete(local_host) self.send_event_to_observers(ev) print "delete host" return host = Host(host_mac, port) if host_mac not in self.hosts: self.hosts.add(host) ev = event.EventHostAdd(host) self.send_event_to_observers(ev) # arp packet, update ip address if eth.ethertype == ether_types.ETH_TYPE_ARP: arp_pkt = pkt.get_protocols(arp.arp)[0] self.hosts.update_ip(host, ip_v4=arp_pkt.src_ip) update_host = self.hosts[host.mac] uev = event.EventHostAdd(update_host) self.send_event_to_observers(uev) # ipv4 packet, update ipv4 address elif eth.ethertype == ether_types.ETH_TYPE_IP: ipv4_pkt = pkt.get_protocols(ipv4.ipv4)[0] self.hosts.update_ip(host, ip_v4=ipv4_pkt.src) update_host = self.hosts[host.mac] uev = event.EventHostAdd(update_host) self.send_event_to_observers(uev) # ipv6 packet, update ipv6 addressE elif eth.ethertype == ether_types.ETH_TYPE_IPV6: # TODO: need to handle NDP ipv6_pkt = pkt.get_protocols(ipv6.ipv6)[0] self.hosts.update_ip(host, ip_v6=ipv6_pkt.src) update_host = self.hosts[host.mac] uev = event.EventHostAdd(update_host) self.send_event_to_observers(uev)