def create_discovery_packet(self, dpid, port_num, port_addr): """ Build discovery packet """ chassis_id = pkt.chassis_id(subtype=pkt.chassis_id.SUB_LOCAL) chassis_id.id = bytes('dpid:' + hex(long(dpid))[2:-1]) # Maybe this should be a MAC. But a MAC of what? Local port, maybe? port_id = pkt.port_id(subtype=pkt.port_id.SUB_PORT, id=str(port_num)) ttl = pkt.ttl(ttl=self._ttl) sysdesc = pkt.system_description() sysdesc.payload = bytes('dpid:' + hex(long(dpid))[2:-1]) discovery_packet = pkt.lldp() discovery_packet.tlvs.append(chassis_id) discovery_packet.tlvs.append(port_id) discovery_packet.tlvs.append(ttl) discovery_packet.tlvs.append(sysdesc) discovery_packet.tlvs.append(pkt.end_tlv()) eth = pkt.ethernet(type=pkt.ethernet.LLDP_TYPE) eth.src = port_addr eth.dst = pkt.ETHERNET.NDP_MULTICAST eth.payload = discovery_packet po = of.ofp_packet_out(action=of.ofp_action_output(port=port_num)) po.data = eth.pack() return po.pack()
def create_discovery_packet (self, dpid, port_num, port_addr): """ Build discovery packet """ chassis_id = pkt.chassis_id(subtype=pkt.chassis_id.SUB_LOCAL) chassis_id.id = bytes('dpid:' + hex(long(dpid))[2:-1]) # Maybe this should be a MAC. But a MAC of what? Local port, maybe? port_id = pkt.port_id(subtype=pkt.port_id.SUB_PORT, id=str(port_num)) ttl = pkt.ttl(ttl = self._ttl) sysdesc = pkt.system_description() sysdesc.payload = bytes('dpid:' + hex(long(dpid))[2:-1]) discovery_packet = pkt.lldp() discovery_packet.tlvs.append(chassis_id) discovery_packet.tlvs.append(port_id) discovery_packet.tlvs.append(ttl) discovery_packet.tlvs.append(sysdesc) discovery_packet.tlvs.append(pkt.end_tlv()) eth = pkt.ethernet(type=pkt.ethernet.LLDP_TYPE) eth.src = port_addr eth.dst = pkt.ETHERNET.NDP_MULTICAST eth.payload = discovery_packet po = of.ofp_packet_out(action = of.ofp_action_output(port=port_num)) po.data = eth.pack() return po.pack()
def _handle_openflow_PacketIn(self, event): """ Receive and process LLDP packets """ packet = event.parsed if (packet.effective_ethertype != pkt.ethernet.LLDP_TYPE or packet.dst != pkt.ETHERNET.NDP_MULTICAST): if not self._eat_early_packets: return if not event.connection.connect_time: return enable_time = time.time() - self.send_cycle_time - 1 if event.connection.connect_time > enable_time: return EventHalt return if self._explicit_drop: if event.ofp.buffer_id is not None: log.debug("Dropping LLDP packet %i", event.ofp.buffer_id) msg = of.ofp_packet_out() msg.buffer_id = event.ofp.buffer_id msg.in_port = event.port event.connection.send(msg) lldph = packet.find(pkt.lldp) if lldph is None or not lldph.parsed: log.error("LLDP packet could not be parsed") return EventHalt if len(lldph.tlvs) < 3: log.error("LLDP packet without required three TLVs") return EventHalt if lldph.tlvs[0].tlv_type != pkt.lldp.CHASSIS_ID_TLV: log.error("LLDP packet TLV 1 not CHASSIS_ID") return EventHalt if lldph.tlvs[1].tlv_type != pkt.lldp.PORT_ID_TLV: log.error("LLDP packet TLV 2 not PORT_ID") return EventHalt if lldph.tlvs[2].tlv_type != pkt.lldp.TTL_TLV: log.error("LLDP packet TLV 3 not TTL") return EventHalt def lookInSysDesc(): r = None for t in lldph.tlvs[3:]: if t.tlv_type == pkt.lldp.SYSTEM_DESC_TLV: # This is our favored way... for line in t.payload.split('\n'): if line.startswith('dpid:'): try: return int(line[5:], 16) except: pass if len(t.payload) == 8: # Maybe it's a FlowVisor LLDP... # Do these still exist? try: return struct.unpack("!Q", t.payload)[0] except: pass return None originatorDPID = lookInSysDesc() if originatorDPID == None: # We'll look in the CHASSIS ID if lldph.tlvs[0].subtype == pkt.chassis_id.SUB_LOCAL: if lldph.tlvs[0].id.startswith('dpid:'): # This is how NOX does it at the time of writing try: originatorDPID = int(lldph.tlvs[0].id[5:], 16) except: pass if originatorDPID == None: if lldph.tlvs[0].subtype == pkt.chassis_id.SUB_MAC: # Last ditch effort -- we'll hope the DPID was small enough # to fit into an ethernet address if len(lldph.tlvs[0].id) == 6: try: s = lldph.tlvs[0].id originatorDPID = struct.unpack( "!Q", '\x00\x00' + s)[0] except: pass if originatorDPID == None: log.warning("Couldn't find a DPID in the LLDP packet") return EventHalt if originatorDPID not in core.openflow.connections: log.info('Received LLDP packet from unknown switch') return EventHalt # Get port number from port TLV if lldph.tlvs[1].subtype != pkt.port_id.SUB_PORT: log.warning( "Thought we found a DPID, but packet didn't have a port") return EventHalt originatorPort = None if lldph.tlvs[1].id.isdigit(): # We expect it to be a decimal value originatorPort = int(lldph.tlvs[1].id) elif len(lldph.tlvs[1].id) == 2: # Maybe it's a 16 bit port number... try: originatorPort = struct.unpack("!H", lldph.tlvs[1].id)[0] except: pass if originatorPort is None: log.warning("Thought we found a DPID, but port number didn't " + "make sense") return EventHalt if (event.dpid, event.port) == (originatorDPID, originatorPort): log.warning("Port received its own LLDP packet; ignoring") return EventHalt link = Discovery.Link(originatorDPID, originatorPort, event.dpid, event.port) if link not in self.adjacency: self.adjacency[link] = time.time() log.info('link detected: %s', link) self.raiseEventNoErrors(LinkEvent, True, link) else: # Just update timestamp self.adjacency[link] = time.time() return EventHalt # Probably nobody else needs this event
def _handle_openflow_PacketIn (self, event): """ Receive and process LLDP packets """ packet = event.parsed if (packet.effective_ethertype != pkt.ethernet.LLDP_TYPE or packet.dst != pkt.ETHERNET.NDP_MULTICAST): if not self._eat_early_packets: return if not event.connection.connect_time: return enable_time = time.time() - self.send_cycle_time - 1 if event.connection.connect_time > enable_time: return EventHalt return if self._explicit_drop: if event.ofp.buffer_id is not None: log.debug("Dropping LLDP packet %i", event.ofp.buffer_id) msg = of.ofp_packet_out() msg.buffer_id = event.ofp.buffer_id msg.in_port = event.port event.connection.send(msg) lldph = packet.find(pkt.lldp) if lldph is None or not lldph.parsed: log.error("LLDP packet could not be parsed") return EventHalt if len(lldph.tlvs) < 3: log.error("LLDP packet without required three TLVs") return EventHalt if lldph.tlvs[0].tlv_type != pkt.lldp.CHASSIS_ID_TLV: log.error("LLDP packet TLV 1 not CHASSIS_ID") return EventHalt if lldph.tlvs[1].tlv_type != pkt.lldp.PORT_ID_TLV: log.error("LLDP packet TLV 2 not PORT_ID") return EventHalt if lldph.tlvs[2].tlv_type != pkt.lldp.TTL_TLV: log.error("LLDP packet TLV 3 not TTL") return EventHalt def lookInSysDesc (): r = None for t in lldph.tlvs[3:]: if t.tlv_type == pkt.lldp.SYSTEM_DESC_TLV: # This is our favored way... for line in t.payload.split('\n'): if line.startswith('dpid:'): try: return int(line[5:], 16) except: pass if len(t.payload) == 8: # Maybe it's a FlowVisor LLDP... # Do these still exist? try: return struct.unpack("!Q", t.payload)[0] except: pass return None originatorDPID = lookInSysDesc() if originatorDPID == None: # We'll look in the CHASSIS ID if lldph.tlvs[0].subtype == pkt.chassis_id.SUB_LOCAL: if lldph.tlvs[0].id.startswith('dpid:'): # This is how NOX does it at the time of writing try: originatorDPID = int(lldph.tlvs[0].id[5:], 16) except: pass if originatorDPID == None: if lldph.tlvs[0].subtype == pkt.chassis_id.SUB_MAC: # Last ditch effort -- we'll hope the DPID was small enough # to fit into an ethernet address if len(lldph.tlvs[0].id) == 6: try: s = lldph.tlvs[0].id originatorDPID = struct.unpack("!Q",'\x00\x00' + s)[0] except: pass if originatorDPID == None: log.warning("Couldn't find a DPID in the LLDP packet") return EventHalt if originatorDPID not in core.openflow.connections: log.info('Received LLDP packet from unknown switch') return EventHalt # Get port number from port TLV if lldph.tlvs[1].subtype != pkt.port_id.SUB_PORT: log.warning("Thought we found a DPID, but packet didn't have a port") return EventHalt originatorPort = None if lldph.tlvs[1].id.isdigit(): # We expect it to be a decimal value originatorPort = int(lldph.tlvs[1].id) elif len(lldph.tlvs[1].id) == 2: # Maybe it's a 16 bit port number... try: originatorPort = struct.unpack("!H", lldph.tlvs[1].id)[0] except: pass if originatorPort is None: log.warning("Thought we found a DPID, but port number didn't " + "make sense") return EventHalt if (event.dpid, event.port) == (originatorDPID, originatorPort): log.warning("Port received its own LLDP packet; ignoring") return EventHalt link = Discovery.Link(originatorDPID, originatorPort, event.dpid, event.port) if link not in self.adjacency: self.adjacency[link] = time.time() log.info('link detected: %s', link) self.raiseEventNoErrors(LinkEvent, True, link) else: # Just update timestamp self.adjacency[link] = time.time() return EventHalt # Probably nobody else needs this event