def ___reply_with_cached_path(self, path: List[int], dest_address: ILNPAddress, original_destination_id: int): """Replies to request with cached path""" reply = LocatorRouteReply(original_destination_id, LocatorHopList(path)) header = ControlHeader(reply.TYPE, reply.size_bytes()) message = ControlMessage(header, reply) reply_packet = ILNPPacket(self.my_address, dest_address, payload_length=message.size_bytes(), payload=message) # Next hop is either in my locator, neighbour locator , or hop before my locator if dest_address.loc == self.my_address.loc: logger.info("Next hop is in my locator") self.net_interface.send( bytes(reply_packet), self.forwarding_table.find_next_hop_for_local_node( dest_address.id)) else: logger.info("Next hop is in other locator") next_hop_locator = path[len(path) - 2] if len(path) > 1 else dest_address.loc logger.info("Next hop locator is {}".format(next_hop_locator)) self.net_interface.send( bytes(reply_packet), self.forwarding_table.find_next_hop_for_locator( next_hop_locator)) self.monitor.record_sent_packet(True, False)
def __handle_expired_link_list_message(self, packet: ILNPPacket): if packet.src.loc != self.my_address.loc: logger.info("Link failure in other network. None of my concern") return central_node_id: int = packet.src.id expired_message: ExpiredLinkList = packet.payload.body learned_something = False for expired_node_id in expired_message.lost_link_ids: learned_something |= self.network_graph.remove_link( central_node_id, expired_node_id) if learned_something: packet.decrement_hop_limit() if packet.hop_limit > 0: self.net_interface.broadcast(bytes(packet)) self.monitor.record_sent_packet(True, True) self.update_available = True
def extend_route_request(packet: ILNPPacket): """Appends empty locator to hop list and updates size of control and ILNP header payload lengths""" header: ControlHeader = packet.payload.header body: LocatorRouteRequest = packet.payload.body # Add empty locator to be overwritten body.locator_hop_list.append(0) # Refresh control header payload length header.payload_length = body.size_bytes() # Refresh ILNPPacket payload length packet.payload_length = packet.payload.size_bytes()
def __forward_locator_route_request(self, packet: ILNPPacket): """Forwards the route request to all neighbours it hasn't already visited""" packet.decrement_hop_limit() if len(self.forwarding_table.next_hop_to_locator) == 0: logger.info( "No neighbour locators to send destination request to.") logger.info("Discarding.") return elif packet.hop_limit == 0: logger.info("No more hops. Discarding.") return request_list: LocatorHopList = packet.payload.body.locator_hop_list path: List[int] = request_list.locator_hops if path[len(path) - 1] is not self.my_address.loc: self.net_interface.send( bytes(packet), self.forwarding_table.find_next_hop_for_locator( path[len(path) - 1])) self.monitor.record_sent_packet(True, True) else: # Get all neighbour locators not already in path and not the original source unvisited_neighbours = [ locator for locator in self.forwarding_table.next_hop_to_locator.keys() if locator not in path and locator != packet.src.loc ] # Forward packet to each neighbour locator if len(unvisited_neighbours) > 0: extend_route_request(packet) for locator in unvisited_neighbours: logger.info("Forwarding to {}".format(locator)) # Change last hop locator on each iteration request_list.locator_hops[len(request_list.locator_hops) - 1] = locator self.net_interface.send( bytes(packet), self.forwarding_table.find_next_hop_for_locator( locator)) self.monitor.record_sent_packet(True, True)
def __build_rreq(self, request_id: int, dest_id: int, first_hop_locator: int) -> ILNPPacket: logger.info("Building route request for {} via locator {}".format( dest_id, first_hop_locator)) initial_list = LocatorHopList([first_hop_locator]) rreq = LocatorRouteRequest(request_id, True, initial_list) header = ControlHeader(rreq.TYPE, rreq.size_bytes()) control = ControlMessage(header, rreq) return ILNPPacket(self.my_address, ILNPAddress(0, dest_id), payload=control, payload_length=control.size_bytes())
def handle_data_packet(self, packet: ILNPPacket, attempt_forward=True): """Attempt basic routing of packet using available resources""" logger.info("Handling data packet") if packet.dest.id == self.my_address.id: logger.info("Packet for me, adding to received queue <3") self.arrived_data_queue.put((packet.payload.body, packet.src.id)) return if not attempt_forward: return # Locator discovery might be necessary for packets coming from me is_from_me = packet.src.id == self.my_address.id if packet.dest.loc is None and is_from_me: logger.info("Don't know locator, need to find.") self.control_plane.find_route(packet) return destination_is_local = packet.dest.loc == self.my_address.loc next_hop = self.forwarding_table.get_next_hop(packet.dest, destination_is_local) if next_hop is not None: logger.info("Found next hop, forwarding to {}".format(next_hop)) packet.decrement_hop_limit() if packet.hop_limit > 0: self.net_interface.send(bytes(packet), next_hop) self.monitor.record_sent_packet(False, not is_from_me) else: logger.info("No more hops. Discarding packet") elif destination_is_local: logger.info("No node exists with that ID in this locator.") logger.info("Discarding packet") elif is_from_me: logger.info( "Finding route for packet destined for external locator") self.control_plane.find_route(packet) else: logger.info("No next hop found for packet. Dropping packet.")
def __broadcast_lsdb(self): """Broadcasts my LSDB to neighbouring nodes""" logger.info("Broadcasting my LSDB") lsdb = self.network_graph.to_lsdb_message( next(self.lsb_sequence_generator)) header = ControlHeader(LSDBMessage.TYPE, lsdb.size_bytes()) control_message = ControlMessage(header, lsdb) packet = ILNPPacket(self.my_address, ALL_LINK_LOCAL_NODES_ADDRESS, payload_length=control_message.size_bytes(), payload=control_message) self.net_interface.broadcast(bytes(packet)) self.monitor.record_sent_packet(True, False)
def __send_keepalive(self): """Broadcasts hello message containing this nodes current lambda""" keepalive = Hello(self.__calc_my_lambda()) header = ControlHeader(keepalive.TYPE, keepalive.size_bytes()) control_message = ControlMessage(header, keepalive) packet = ILNPPacket(self.my_address, ALL_LINK_LOCAL_NODES_ADDRESS, hop_limit=0, payload_length=control_message.size_bytes(), payload=bytes(control_message)) self.net_interface.broadcast(bytes(packet)) self.monitor.record_sent_packet(True, False)
def __handle_expired_links(self, expired: List[int]): """Broadcasts information about lost links and removes them from our network graph""" for expired_node_id in expired: self.network_graph.remove_link(self.my_address.id, expired_node_id) expired_message = ExpiredLinkList(expired) header = ControlHeader(expired_message.TYPE, expired_message.size_bytes()) control_message = ControlMessage(header, expired_message) packet = ILNPPacket(self.my_address, ALL_LINK_LOCAL_NODES_ADDRESS, payload_length=control_message.size_bytes(), payload=control_message) self.net_interface.broadcast(bytes(packet)) self.monitor.record_sent_packet(True, False)
def __reply_to_locator_route_request(self, packet: ILNPPacket): """Replies to request with reverse of their path""" request: LocatorRouteRequest = packet.payload.body path: List[int] = request.locator_hop_list.locator_hops reply = LocatorRouteReply(self.my_address.id, LocatorHopList(path)) header = ControlHeader(reply.TYPE, reply.size_bytes()) message = ControlMessage(header, reply) reply_packet = ILNPPacket(self.my_address, packet.src, payload_length=message.size_bytes(), payload=bytes(message)) # Next hop is either neighbour, or hop before my locator next_hop_locator = path[len(path) - 2] if len(path) > 1 else packet.src.loc self.net_interface.send( bytes(reply_packet), self.forwarding_table.find_next_hop_for_locator(next_hop_locator)) self.monitor.record_sent_packet(True, False)
def send(self, data, dest_id): """ Wraps the given data in an ILNPPacket for the given destination ID, and adds it to the queue to be processed :param data: data to be sent :param dest_id: id of node to be sent to """ if not self.monitor.running: raise IOError("Router is not running.") message = build_data_message(data) src_addr = self.my_address dest_loc = self.forwarding_table.get_locator_for_id(dest_id) dest_addr = ILNPAddress(dest_loc, dest_id) logger.info("Sending data from {} to {}".format( str(src_addr), str(dest_addr))) packet = ILNPPacket(src_addr, dest_addr, payload=message, payload_length=message.size_bytes()) self.packet_queue.put(packet)
def parse_packet(data) -> ILNPPacket: """Parses contents of packet""" packet = ILNPPacket.from_bytes(data) packet.payload = ControlMessage.from_bytes(packet.payload) return packet