def flow_timer(self, dpid): request['dpid'] = str("0x") + str(longlong_to_octstr(dpid)[6:].replace(':','')) addr_switch = str(longlong_to_octstr(dpid)[6:].replace(':','')) #print "\nRequisicao das Flows do DataPath: ", longlong_to_octstr(dpid)[6:].replace(':','') self.get_flows(request, addr_switch) self.post_callback(FLOW_COLLECTION_PERIOD, lambda : self.flow_timer(dpid))
def port_status_change(self, dp, reason, port): '''Update LLDP packets on port status changes Add to the list of LLDP packets if a port is added. Delete from the list of LLDP packets if a port is removed. Keyword arguments: dp -- Datapath ID of port reason -- what event occured port -- port ''' # Only process 'sane' ports if port[PORT_NO] <= openflow.OFPP_MAX: if reason == openflow.OFPPR_ADD: if port[STATE]== openflow.OFPPS_STP_BLOCK: lg.warn('Port '+ str(port[PORT_NO]) + ' on DPID ' + longlong_to_octstr(dp) +' is blocked') else: self.lldp_packets[dp][port[PORT_NO]] = create_discovery_packet(dp, port[HW_ADDR], port[PORT_NO], LLDP_TTL); elif reason == openflow.OFPPR_DELETE: del self.lldp_packets[dp][port[PORT_NO]] elif reason == openflow.OFPPR_MODIFY: if port[STATE] == openflow.OFPPS_STP_BLOCK: lg.warn('Port '+ str(port[PORT_NO]) + ' on DPID ' + longlong_to_octstr(dp) +' is blocked') try: del self.lldp_packets[dp][port[PORT_NO]] except KeyError,e: pass else: self.lldp_packets[dp][port[PORT_NO]] = create_discovery_packet(dp, port[HW_ADDR], port[PORT_NO], LLDP_TTL);
def port_status_change(self, dp, reason, port): '''Update LLDP packets on port status changes Add to the list of LLDP packets if a port is added. Delete from the list of LLDP packets if a port is removed. Keyword arguments: dp -- Datapath ID of port reason -- what event occured port -- port ''' # Only process 'sane' ports if port[PORT_NO] <= openflow.OFPP_MAX: if reason == openflow.OFPPR_ADD: if port[STATE] == openflow.OFPPS_STP_BLOCK: lg.warn('Port ' + str(port[PORT_NO]) + ' on DPID ' + longlong_to_octstr(dp) + ' is blocked') else: self.lldp_packets[dp][ port[PORT_NO]] = create_discovery_packet( dp, port[HW_ADDR], port[PORT_NO], LLDP_TTL) elif reason == openflow.OFPPR_DELETE: del self.lldp_packets[dp][port[PORT_NO]] elif reason == openflow.OFPPR_MODIFY: if port[STATE] == openflow.OFPPS_STP_BLOCK: lg.warn('Port ' + str(port[PORT_NO]) + ' on DPID ' + longlong_to_octstr(dp) + ' is blocked') try: del self.lldp_packets[dp][port[PORT_NO]] except KeyError, e: pass else: self.lldp_packets[dp][ port[PORT_NO]] = create_discovery_packet( dp, port[HW_ADDR], port[PORT_NO], LLDP_TTL)
def manage_lldp_packet_from_host(self, dp_id, inport, lldph, chassid): #lg.debug('New lldp packet from host arrived') for i in lldph.tlvs: if i.type == lldp.MANAGEMENT_ADDR: mng_addr = i.mng_addr_int if i.type == lldp.SYSTEM_NAME_TLV: sys_name = i.system_name #print sys_name #print mng_addr #print type(lldph) dl_addr = ethernetaddr(chassid) nw_addr = mng_addr hosttuple =(dp_id, inport, dl_addr, nw_addr, sys_name) if hosttuple not in self.adjacency_hosts: lg.debug('Recieved LLDP packet from unconnected host') self.post_host_event(hosttuple, 'ADD') lg.debug('New Host detected (' + longlong_to_octstr(hosttuple[0]) +' p: ' \ +str(hosttuple[1]) + ' -> ' + \ sys_name + ' p: ' + longlong_to_octstr(chassid)) # add to adjaceny list or update timestamp self.adjacency_hosts[(dp_id, inport, dl_addr, nw_addr, sys_name)] = time.time()
def flow_timer(self, dpid): request['dpid'] = str("0x") + str( longlong_to_octstr(dpid)[6:].replace(':', '')) addr_switch = str(longlong_to_octstr(dpid)[6:].replace(':', '')) #print "\nRequisicao das Flows do DataPath: ", longlong_to_octstr(dpid)[6:].replace(':','') self.get_flows(request, addr_switch) self.post_callback(FLOW_COLLECTION_PERIOD, lambda: self.flow_timer(dpid))
def timeout_links(self): curtime = time.time() self.post_callback(TIMEOUT_CHECK_PERIOD, lambda : discovery.timeout_links(self)) deleteme = [] for linktuple in self.adjacency_list: if (curtime - self.adjacency_list[linktuple]) > LINK_TIMEOUT: deleteme.append(linktuple) lg.warn('link timeout ('+longlong_to_octstr(linktuple[0])+" p:"\ +str(linktuple[1]) +' -> '+\ longlong_to_octstr(linktuple[2])+\ 'p:'+str(linktuple[3])+')') self.delete_links(deleteme)
def verify_bidir_links(self, links): '''Verify that all links are bi-directional Delete unidirectional links and disable ports ''' srcs_to_delete = [] for src_dpid in links.keys(): dsts_to_delete = [] for dst_dpid in links[src_dpid].keys(): # Work out which ports need deleting ports_to_delete = [] for (src_port, dst_port) in links[src_dpid][dst_dpid]: ok = True try: if (dst_port, src_port) not in links[dst_dpid][src_dpid]: ok = False except KeyError: ok = False if not ok: self.debugPrint("WARNING: Unidirectional link detected between %s -- %d <--> %s -- %d"% (longlong_to_octstr(src_dpid)[6:], src_port, longlong_to_octstr(dst_dpid)[6:], dst_port)) ports_to_delete.append((src_port, dst_port)) try: if (src_dpid <= dst_dpid): self.datapaths[dst_dpid][dst_port]['enable'] = False else: self.datapaths[src_dpid][src_port]['enable'] = False except KeyError: self.datapaths[src_dpid][src_port]['enable'] = False # Delete the ports and work out if we need to delete the dst_dpid for ports in ports_to_delete: links[src_dpid][dst_dpid].discard(ports) if len(links[src_dpid][dst_dpid]) == 0: dsts_to_delete.append(dst_dpid) # Delete the dst_dpids and identify whether to delete the src_dpid for dst_dpid in dsts_to_delete: del links[src_dpid][dst_dpid] if len(links[src_dpid]) == 0: srcs_to_delete.append(src_dpid) # Delete the src_dpids for src_dpid in srcs_to_delete: del links[src_dpid]
def dp_join(self, dp, stats): self.debugPrint("Datapath join: "+longlong_to_octstr(dp)[6:]) if (not self.datapaths.has_key(dp)): # Process the port information returned by the switch # Build a list of ports now = time.time() ports = {} for port in stats['ports']: ports[port[core.PORT_NO]] = port if port[core.PORT_NO] <= openflow.OFPP_MAX: port['enable_time'] = now + FLOOD_WAIT_TIME port['flood'] = False hw_addr = "\0\0" + port[core.HW_ADDR] hw_addr = struct.unpack("!q", hw_addr)[0] self.ctxt.send_port_mod(dp, port[core.PORT_NO], ethernetaddr(hw_addr), openflow.OFPPC_NO_FLOOD, openflow.OFPPC_NO_FLOOD) # Record the datapath self.datapaths[dp] = ports self.port_count += len(ports) # Update the LLDP send period self.update_lldp_send_period() return CONTINUE
def dp_leave(self, dp): self.debugPrint("Datapath leave, "+longlong_to_octstr(dp)[6:]) if (self.datapaths.has_key(dp)): # Decrement port count by # of ports in datapath that is leaving self.port_count -= len(self.datapaths[dp]) del self.datapaths[dp] return CONTINUE
def table_stats_in_handler(self, dpid, tables): # If RRD does't exist create rrd_file = '/home/'+USER+'/rrds/table_' + longlong_to_octstr(dpid)[6:] if os.path.exists(rrd_file): for item in tables: print '\t',item['name'],':',item['active_count'] else: for item in tables: print '\t',item['name'],':',item['active_count']
def dp_join(self, dp, stats): self.dps[dp] = stats self.lldp_packets[dp] = {} for port in stats[PORTS]: # ignore local port if port[PORT_NO] == OFPP_LOCAL: continue if port[STATE]== openflow.OFPPS_STP_BLOCK: lg.warn('Port '+ str(port[PORT_NO]) + ' on DPID ' + longlong_to_octstr(dp) +' is blocked') else: self.lldp_packets[dp][port[PORT_NO]] = create_discovery_packet(dp, port[HW_ADDR], port[PORT_NO], LLDP_TTL);
def dp_join(self, dp, stats): self.dps[dp] = stats self.lldp_packets[dp] = {} for port in stats[PORTS]: # ignore local port if port[PORT_NO] == OFPP_LOCAL: continue if port[STATE] == openflow.OFPPS_STP_BLOCK: lg.warn('Port ' + str(port[PORT_NO]) + ' on DPID ' + longlong_to_octstr(dp) + ' is blocked') else: self.lldp_packets[dp][port[PORT_NO]] = create_discovery_packet( dp, port[HW_ADDR], port[PORT_NO], LLDP_TTL)
def aggregate_stats_in_handler(self, dpid, stats): # If RRD does't exist create agg_rrd_file = '/home/'+USER+'/rrds/agg_' + longlong_to_octstr(dpid)[6:] + '.rrd' upd_time = int(time.time()) print "Agg stat from ",longlong_to_octstr(dpid)[6:] if os.path.exists(agg_rrd_file): packet_count = str(stats['packet_count']) byte_count = str(stats['byte_count']) flow_count = str(stats['flow_count']) # print 'agg stats:',packet_count,':',byte_count,':',flow_count print stats; rrdtool.update( agg_rrd_file, 'N:' + packet_count + ':' + byte_count + ':' + flow_count ) else: # in real life data_sources would be populated in loop or something similar rrdtool.create( agg_rrd_file, 'DS:packet_count:COUNTER:60:U:U', 'DS:byte_count:COUNTER:60:U:U', 'DS:flow_count:COUNTER:60:U:U', 'RRA:AVERAGE:0.5:1:525600', 'RRA:AVERAGE:0.5:60:8760' )
def port_stats_in_handler(self, dpid, ports): for item in ports: # If RRD does't exist create port_no = str(item['port_no']) port_rrd_file = '/home/'+USER+'/rrds/port_' + longlong_to_octstr(dpid)[6:] + '_' + port_no + '.rrd' if os.path.exists(port_rrd_file): tx_packets = str(item['tx_packets']) print 'port stats:',tx_packets if tx_packets != '-1' : rrdtool.update( port_rrd_file, 'N:' + tx_packets ) else: rrdtool.create( port_rrd_file, 'DS:tx_packets:COUNTER:60:U:U', 'RRA:AVERAGE:0.5:1:525600', 'RRA:AVERAGE:0.5:60:8760' )
def aggregate_stats_in_handler(self, dpid, stats): print "Aggregate stats in from datapath", longlong_to_octstr(dpid)[6:] print '\t', stats
def update_spanning_tree_callback(self, links): '''Callback called by get_all_links to process the set of links. Currently: - updates the flood ports to build a spanning tree Note: each link probably appears twice (once for each direction) As a temporary hack to deal with the fact that we don't have spanning tree support in NOX we build a set of "flood-ports". Each datapath id representing a switch has a set of ports associated which represent links that don't contain other OpenFlow switches. This set of paths can be used safely for flooding to ensure that we don't circulate broadcast packets. @param links list link tuples (src_dpid, src_port, dst_dpid, dst_port) ''' # Walk through the datapaths and mark all ports # that are potentially enableable now = time.time() for dp in self.datapaths.iterkeys(): for port_no, port in self.datapaths[dp].iteritems(): if port_no > openflow.OFPP_MAX or now > port['enable_time']: port['enable'] = True else: port['enable'] = False port['keep'] = False # Walk through the links and create a dict based on source port my_links = self.build_link_dict(links) self.verify_bidir_links(my_links) # Now try to build the spanning tree seen = set() roots = set() # Get all sources in reversed sorted order srcs = self.datapaths.keys() srcs.sort() srcs = srcs[::-1] #kyr if len(srcs): self.root = srcs[len(srcs)-1] # Process all sources while len(srcs) > 0: src_dpid = srcs.pop() # Add the dpid to the list of roots if we haven't yet seen it # (it must the be root of a tree) if src_dpid not in seen: roots.add(src_dpid) # Record that we've seen this node seen.add(src_dpid) # Make sure we know the src_dpid # This is necessary occasionally during start-up if not my_links.has_key(src_dpid): self.debugPrint("Warning: cannot find src_dpid %s in my_links"%longlong_to_octstr(src_dpid)[6:]) continue # Walk through all dests dsts = my_links[src_dpid].keys() dsts.sort() next_dpids = [] for dst_dpid in dsts: if dst_dpid not in seen: # Attempt to find the fastest link to the other switch best_speed = -1 best_pair = (-1, -1) for (src_port, dst_port) in my_links[src_dpid][dst_dpid]: try: speed = self.datapaths[src_dpid][src_port]['speed'] if speed > best_speed: best_speed = speed best_pair = (src_port, dst_port) except KeyError: pass # Disable all links but the fastest for (src_port, dst_port) in my_links[src_dpid][dst_dpid]: try: if (src_port, dst_port) != best_pair: self.datapaths[dst_dpid][dst_port]['enable'] = False else: self.datapaths[src_dpid][src_port]['keep'] = True self.datapaths[dst_dpid][dst_port]['keep'] = True except KeyError: pass # Record that we've seen the dpid seen.add(dst_dpid) next_dpids.append(dst_dpid) # Already-seen DPIDs else: # Disable the link to the already-seen DPIDs if src_dpid <= dst_dpid: (local_src_dpid, local_dst_dpid) = (src_dpid, dst_dpid) else: (local_src_dpid, local_dst_dpid) = (dst_dpid, src_dpid) for (src_port, dst_port) in my_links[local_src_dpid][local_dst_dpid]: # If the src/dst dpids are the same, sort the ports if local_src_dpid == local_dst_dpid: if (src_port > dst_port): (src_port, dst_port) = (dst_port, src_port) # Disable the ports try: if not self.datapaths[local_dst_dpid][dst_port]['keep']: self.datapaths[local_dst_dpid][dst_port]['enable'] = False if not self.datapaths[local_src_dpid][src_port]['keep']: self.datapaths[local_src_dpid][src_port]['enable'] = False except KeyError: pass # Once we've processed all links from this source, update the # list of sources so that the DPIDs we've just linked to will # be processed next. This is achieved by placing them at the # end of the list. next_dpids = next_dpids[::-1] for dpid in next_dpids: try: srcs.remove(dpid) except ValueError: pass srcs.extend(next_dpids) # Update the list of roots self.roots = roots # Build dictionary to send to gui # Format { dp: [stp_ports] } stp_ports = {} # Walk through links and enable/disable as appropriate for dp in self.datapaths.iterkeys(): floodports = [] nonfloodports = [] for port_no, port in self.datapaths[dp].iteritems(): if port_no <= openflow.OFPP_MAX: if port['enable'] != port['flood']: if port['flood']: port['flood'] = False msg = 'Disabling' config = openflow.OFPPC_NO_FLOOD else: port['flood'] = True msg = 'Enabling' config = 0 self.debugPrint("%s port: %s--%d"%(msg, longlong_to_octstr(dp)[6:], port_no)) hw_addr = "\0\0" + port[core.HW_ADDR] hw_addr = struct.unpack("!q", hw_addr)[0] self.ctxt.send_port_mod(dp, port[core.PORT_NO], ethernetaddr(hw_addr), openflow.OFPPC_NO_FLOOD, config) if port['flood']: floodports.append(port_no) else: nonfloodports.append(port_no) self.debugPrint("Ports for %s: Flood: %s Non-flood: %s"%(longlong_to_octstr(dp)[6:], floodports, nonfloodports)) dp = str(hex(dp)) dp = dp[2:len(dp)-1] while len(dp)<12: dp = "0"+dp stp_ports[dp] = floodports#, nonfloodports) # If ST has changed, update and send new enabled ports to GUI if cmp(self.current_stp_ports, stp_ports) != 0: self.current_stp_ports = stp_ports root = str(self.root) while len(root)<12: root = "0"+root stp_ports['root'] = root self.send_to_gui("stp_ports", self.current_stp_ports) else: self.debugPrint("SP has not changed")
def lldp_input_handler(self, dp_id, inport, ofp_reason, total_frame_len, buffer_id, packet): assert (packet.type == ethernet.LLDP_TYPE) if not packet.next: lg.error("lldp_input_handler lldp packet could not be parsed") return assert (isinstance(packet.next, lldp)) lldph = packet.next if (len(lldph.tlvs) < 4) or \ (lldph.tlvs[0].type != lldp.CHASSIS_ID_TLV) or\ (lldph.tlvs[1].type != lldp.PORT_ID_TLV) or\ (lldph.tlvs[2].type != lldp.TTL_TLV): lg.error("lldp_input_handler invalid lldp packet") return # parse out chassis id if lldph.tlvs[0].subtype == chassis_id.SUB_MAC: assert (len(lldph.tlvs[0].id) == 6) cid = lldph.tlvs[0].id # convert 48bit cid (in nbo) to longlong chassid = cid[5] | cid[4] << 8 | \ cid[3] << 16 | cid[2] << 24 | \ cid[1] << 32 | cid[0] << 40 elif lldph.tlvs[0].subtype == chassis_id.SUB_NETWORK: assert (len(lldph.tlvs[0].id) == 8) cid = lldph.tlvs[0].id # convert 48bit cid (in nbo) to longlong chassid = cid[7] | cid[6] << 8 | \ cid[5] << 16 | cid[4] << 24 | \ cid[3] << 32 | cid[2] << 40 | \ cid[1] << 48 | cid[0] << 56 else: lg.error("lldp chassis ID subtype is not recognized. ignoring") return # if chassid is from a switch we're not connected to, ignore if chassid not in self.dps: lg.debug('Recieved LLDP packet from unconnected switch'+\ longlong_to_octstr(chassid)) return # grab 16bit port ID from port tlv if lldph.tlvs[1].subtype != port_id.SUB_PORT: return # not one of ours if len(lldph.tlvs[1].id) != 2: lg.error("invalid lldph port_id format") return (portid, ) = struct.unpack("!H", lldph.tlvs[1].id) if (dp_id, inport) == (chassid, portid): lg.error('Loop detected, received our own LLDP event') return if inport not in self.lldp_packets[dp_id]: lg.warn('Received LLDP on unavailable or STP-blocked port ' + str(inport) + ' on DPID ' + longlong_to_octstr(dp_id)) return # print 'LLDP packet in from',longlong_to_octstr(chassid),' port',str(portid) linktuple = (dp_id, inport, chassid, portid) if linktuple not in self.adjacency_list: self.add_link(linktuple) lg.warn('new link detected ('+longlong_to_octstr(linktuple[0])+' p:'\ +str(linktuple[1]) +' -> '+\ longlong_to_octstr(linktuple[2])+\ ' p:'+str(linktuple[3])+')') # add to adjaceny list or update timestamp self.adjacency_list[(dp_id, inport, chassid, portid)] = time.time()
def port_stats_in_handler(self, dpid, ports): print "Port stats in from datapath", longlong_to_octstr(dpid)[6:] for item in ports: print '\t',item['port_no'],':',item['tx_packets']
def lldp_input_handler(self, dp_id, inport, ofp_reason, total_frame_len, buffer_id, packet): assert (packet.type == ethernet.LLDP_TYPE) if not packet.next: lg.error("lldp_input_handler lldp packet could not be parsed") return assert (isinstance(packet.next, lldp)) lldph = packet.next if (len(lldph.tlvs) < 4) or \ (lldph.tlvs[0].type != lldp.CHASSIS_ID_TLV) or\ (lldph.tlvs[1].type != lldp.PORT_ID_TLV) or\ (lldph.tlvs[2].type != lldp.TTL_TLV): lg.error("lldp_input_handler invalid lldp packet") return # parse out chassis id if lldph.tlvs[0].subtype == chassis_id.SUB_MAC: assert(len(lldph.tlvs[0].id) == 6) cid = lldph.tlvs[0].id # convert 48bit cid (in nbo) to longlong chassid = cid[5] | cid[4] << 8 | \ cid[3] << 16 | cid[2] << 24 | \ cid[1] << 32 | cid[0] << 40 elif lldph.tlvs[0].subtype == chassis_id.SUB_NETWORK: assert(len(lldph.tlvs[0].id) == 8) cid = lldph.tlvs[0].id # convert 48bit cid (in nbo) to longlong chassid = cid[7] | cid[6] << 8 | \ cid[5] << 16 | cid[4] << 24 | \ cid[3] << 32 | cid[2] << 40 | \ cid[1] << 48 | cid[0] << 56 else: lg.error("lldp chassis ID subtype is not recognized. ignoring") return # if chassid is from a switch we're not connected to, ignore if chassid not in self.dps: lg.debug('Recieved LLDP packet from unconnected switch'+\ longlong_to_octstr(chassid)) return # grab 16bit port ID from port tlv if lldph.tlvs[1].subtype != port_id.SUB_PORT: return # not one of ours if len(lldph.tlvs[1].id) != 2: lg.error("invalid lldph port_id format") return (portid,) = struct.unpack("!H", lldph.tlvs[1].id) if (dp_id, inport) == (chassid, portid): lg.error('Loop detected, received our own LLDP event') return if inport not in self.lldp_packets[dp_id]: lg.warn('Received LLDP on unavailable or STP-blocked port ' + str(inport) + ' on DPID ' + longlong_to_octstr(dp_id)) return # print 'LLDP packet in from',longlong_to_octstr(chassid),' port',str(portid) linktuple = (dp_id, inport, chassid, portid) if linktuple not in self.adjacency_list: self.add_link(linktuple) lg.warn('new link detected ('+longlong_to_octstr(linktuple[0])+' p:'\ +str(linktuple[1]) +' -> '+\ longlong_to_octstr(linktuple[2])+\ ' p:'+str(linktuple[3])+')') # add to adjaceny list or update timestamp self.adjacency_list[(dp_id, inport, chassid, portid)] = time.time()
def table_stats_in_handler(self, dpid, tables): print "Table stats in from datapath", longlong_to_octstr(dpid)[6:] for item in tables: print '\t',item['name'],':',item['active_count']
def aggregate_stats_in_handler(self, dpid, stats): print "Aggregate stats in from datapath", longlong_to_octstr(dpid)[6:] print '\t',stats
def lldp_input_handler(self, dp_id, inport, ofp_reason, total_frame_len, buffer_id, packet): assert (packet.type == ethernet.LLDP_TYPE) if not packet.next: lg.error("lldp_input_handler lldp packet could not be parsed") return assert (isinstance(packet.next, lldp)) lldph = packet.next if (len(lldph.tlvs) < 4) or \ (lldph.tlvs[0].type != lldp.CHASSIS_ID_TLV) or\ (lldph.tlvs[1].type != lldp.PORT_ID_TLV) or\ (lldph.tlvs[2].type != lldp.TTL_TLV): lg.error("lldp_input_handler invalid lldp packet") return # parse out chassis id if lldph.tlvs[0].subtype != chassis_id.SUB_LOCAL: lg.error("lldp chassis ID subtype is not 'local', ignoring") return if not lldph.tlvs[0].id.tostring().startswith('dpid:'): lg.error("lldp chassis ID is not a dpid, ignoring") return try: chassid = int(lldph.tlvs[0].id.tostring()[5:], 16) except: lg.error("lldp chassis ID is not numeric', ignoring") return # if chassid is from a switch we're not connected to, ignore if chassid not in self.dps: lg.debug('Recieved LLDP packet from unconnected switch') return # grab 16bit port ID from port tlv if lldph.tlvs[1].subtype != port_id.SUB_PORT: return # not one of ours if len(lldph.tlvs[1].id) != 2: lg.error("invalid lldph port_id format") return (portid, ) = struct.unpack("!H", lldph.tlvs[1].id) if (dp_id, inport) == (chassid, portid): lg.error('Loop detected, received our own LLDP event') return # print 'LLDP packet in from',longlong_to_octstr(chassid),' port',str(portid) linktuple = (dp_id, inport, chassid, portid) if linktuple not in self.adjacency_list: self.add_link(linktuple) lg.warn('new link detected ('+longlong_to_octstr(linktuple[0])+' p:'\ +str(linktuple[1]) +' -> '+\ longlong_to_octstr(linktuple[2])+\ ' p:'+str(linktuple[3])+')') # add to adjaceny list or update timestamp self.adjacency_list[(dp_id, inport, chassid, portid)] = time.time()
def lldp_input_handler(self, dp_id, inport, ofp_reason, total_frame_len, buffer_id, packet): assert (packet.type == ethernet.LLDP_TYPE) if not packet.next: lg.error("lldp_input_handler lldp packet could not be parsed") return assert (isinstance(packet.next, lldp)) lldph = packet.next if (len(lldph.tlvs) < 4) or \ (lldph.tlvs[0].type != lldp.CHASSIS_ID_TLV) or\ (lldph.tlvs[1].type != lldp.PORT_ID_TLV) or\ (lldph.tlvs[2].type != lldp.TTL_TLV): lg.error("lldp_input_handler invalid lldp packet") return # parse out chassis id if lldph.tlvs[0].subtype != chassis_id.SUB_LOCAL: lg.error("lldp chassis ID subtype is not 'local', ignoring") return if not lldph.tlvs[0].id.tostring().startswith('dpid:'): lg.error("lldp chassis ID is not a dpid, ignoring") return try: chassid = int(lldph.tlvs[0].id.tostring()[5:], 16) except: lg.error("lldp chassis ID is not numeric', ignoring") return # if chassid is from a switch we're not connected to, ignore if chassid not in self.dps: lg.debug('Recieved LLDP packet from unconnected switch') return # grab 16bit port ID from port tlv if lldph.tlvs[1].subtype != port_id.SUB_PORT: return # not one of ours if len(lldph.tlvs[1].id) != 2: lg.error("invalid lldph port_id format") return (portid,) = struct.unpack("!H", lldph.tlvs[1].id) if (dp_id, inport) == (chassid, portid): lg.error('Loop detected, received our own LLDP event') return # print 'LLDP packet in from',longlong_to_octstr(chassid),' port',str(portid) linktuple = (dp_id, inport, chassid, portid) if linktuple not in self.adjacency_list: self.add_link(linktuple) lg.warn('new link detected ('+longlong_to_octstr(linktuple[0])+' p:'\ +str(linktuple[1]) +' -> '+\ longlong_to_octstr(linktuple[2])+\ ' p:'+str(linktuple[3])+')') # add to adjaceny list or update timestamp self.adjacency_list[(dp_id, inport, chassid, portid)] = time.time()
def table_stats_in_handler(self, dpid, tables): print "Table stats in from datapath", longlong_to_octstr(dpid)[6:] for item in tables: print '\t', item['name'], ':', item['active_count']
def port_stats_in_handler(self, dpid, ports): print "Port stats in from datapath", longlong_to_octstr(dpid)[6:] for item in ports: print '\t', item['port_no'], ':', item['tx_packets']
def lldp_input_handler(self, dp_id, inport, ofp_reason, total_frame_len, buffer_id, packet): assert (packet.type == ethernet.LLDP_TYPE) if not packet.next: lg.error("lldp_input_handler lldp packet could not be parsed") return assert (isinstance(packet.next, lldp)) lldph = packet.next if (len(lldph.tlvs) < 4) or \ (lldph.tlvs[0].type != lldp.CHASSIS_ID_TLV) or\ (lldph.tlvs[1].type != lldp.PORT_ID_TLV) or\ (lldph.tlvs[2].type != lldp.TTL_TLV): lg.error("lldp_input_handler invalid lldp packet") return # parse out chassis id if lldph.tlvs[0].subtype != chassis_id.SUB_MAC: lg.error("lldp chassis ID subtype is not MAC, ignoring") return assert(len(lldph.tlvs[0].id) == 6) cid = lldph.tlvs[0].id # convert 48bit cid (in nbo) to longlong chassid = cid[5] | cid[4] << 8 | \ cid[3] << 16 | cid[2] << 24 | \ cid[1] << 32 | cid[0] << 40 # if chassid is from a switch we're not connected to, ignore dst_dpid_ = None for k_ in self.dps.keys(): if chassid == (k_ & 0x00ffffff): dst_dpid_ = k_ break else: for info in self.dps[k_]['ports']: chassid_mac = array_to_octstr(array.array('B',struct.pack('!Q',chassid))[2:]) if chassid_mac == mac_to_str(info['hw_addr']): dst_dpid_ = k_ break if dst_dpid_: break if not dst_dpid_: lg.debug('Received LLDP packet from unconnected switch') return chassid = dst_dpid_ # grab 16bit port ID from port tlv if lldph.tlvs[1].subtype != port_id.SUB_PORT: return # not one of ours if len(lldph.tlvs[1].id) != 2: lg.error("invalid lldph port_id format") return (portid,) = struct.unpack("!H", lldph.tlvs[1].id) if (dp_id, inport) == (chassid, portid): lg.error('Loop detected, received our own LLDP event') return # print 'LLDP packet in from',longlong_to_octstr(chassid),' port',str(portid) #linktuple = (longlong_to_octstr(dp_id), inport, longlong_to_octstr(chassid), portid) linktuple = (dp_id, inport, chassid, portid) if linktuple not in self.adjacency_list: self.add_link(linktuple) lg.warn('new link detected ('+longlong_to_octstr(linktuple[0])+' p:'\ +str(linktuple[1]) +' -> '+\ longlong_to_octstr(linktuple[2])+\ ' p:'+str(linktuple[3])+')') # add to adjaceny list or update timestamp self.adjacency_list[(dp_id, inport, chassid, portid)] = time.time()