class Node(object): def __init__(self, id, env, gen): self.env = env self.id = id self.packet_generator = None self.gen = gen self.routes = {} self.routing_algorithm = None self.network = None self.env.process(self.run()) self.packet_sink = PacketSink(env=self.env, rec_arrivals=True) self.packets_to_send = simpy.Store(self.env, capacity=1) self.packets_forwarded = 0 self.packets_not_acknowledged = [] self.switch_port = SwitchPort(env=self.env, rate=20, qlimit=64, limit_bytes=False, id=self.id) self.switch_port.out = self.packets_to_send #self.port_monitor = PortMonitor(env, self.switch_port, dist=1) def set_network(self, network): """ Set the network in which the node is placed in :param network: network :return: None """ self.network = network return def set_routing_algorithm(self, controller="RL"): """Set routing algorithm for this node :param controller: :return: """ if controller == "random": self.routing_algorithm = RandomRouting(gen=self.gen, node=self, graph=self.network) elif controller == "dijkstra": self.routing_algorithm = Dijkstra(graph=self.network, node=self) elif controller == "RL": self.routing_algorithm = RLRouting(node=self, graph=self.network) else: pass def route(self, packet): """Query the rooting algorithm for a link to route the packet to :param packet: :return: """ return self.routing_algorithm.route_packet(packet) def set_packet_generator(self, lbd, possible_destinations): """ :param lbd: :param possible_destinations: :return: """ def dst_dist(gen, destinations): if destinations is None: return None else: return gen.choice(destinations) def next_packet_time(gen, lbd_): return gen.exponential(lbd_) packet_dst = partial(dst_dist, self.gen, possible_destinations) next_pkt_time = partial(next_packet_time, self.gen, lbd) self.packet_generator = PacketGenerator(env=self.env, id="{}_pg".format(self.id), adist=next_pkt_time, sdist=100, dstdist=packet_dst) ## LOOK AT THIS AGAIN - might want to consider putting it into a switch port self.packet_generator.out = self.packets_to_send def get_port_id(self, dst_node_id): return "{}_{}".format(self.id, dst_node_id) def get_link_id(self, dst_node): return "{}_{}".format(self.id, dst_node.id) def add_connection(self, dst_node, rate, qlimit, monitor_rate, propagation_delay, bidirectional=True): """Add a new connection to this node given the following set of parameters :param dst_node: :param rate: :param qlimit: :param monitor_rate: :param propagation_delay: :param bidirectional: :return: """ link_id = self.get_link_id(dst_node) new_link = Link(self.env, id=link_id, cost=propagation_delay, dst=dst_node, src=self) self.routes[link_id] = new_link if bidirectional: new_link_reverse = dst_node.add_connection(self, rate=rate, qlimit=qlimit, monitor_rate=monitor_rate, propagation_delay=propagation_delay, bidirectional=False) return [new_link, new_link_reverse[0]] return [new_link] def id_str_to_num(self): return int(self.id.strip("n")) def get_neighbours(self): """Get neighbours of this node :return: list of neighbouring nodes sorted by id """ neighbours = [] neighbour_debug = [] neighbour_id = self.get_neighbour_id() for name in neighbour_id: link_name = "{}_{}".format(self.id, name) neighbours.append(self.routes[link_name].dst) neighbour_debug.append(link_name) #print("debug " + str(neighbour_debug)) return neighbours def get_neighbour_id(self): """Get all id's of neighbours of this node :return: sorted list of of neighbour ids """ neighbour_id = [] for link in self.routes.values(): if link.src.id == self.id: neighbour = link.dst else: neighbour = link.src neighbour_id.append(neighbour.id) neighbour_id.sort() return neighbour_id def is_neighbour(self, node): """Check if a certain node is a neighbour of this node :param node: Node name (str) to be searched for among the neighbours :return: Boolean indicating if the node is found """ if node == self: return False for link in self.routes.values(): if link.dst == node or link.src == node: return True return False def get_link(self, node): return self.routes["{}_{}".format(self.id, node.id)] def clear_packets(self): """Clear all packets from the node's switch port :return: None """ while len(self.packets_to_send.items) is not 0: packet = self.packets_to_send.get() del packet self.switch_port.clear_packets() #del self.switch_port #self.switch_port = SwitchPort(env=self.env, rate=20, qlimit=64, limit_bytes=False, id=self.id) def send_acknowledgement(self, packet): pkt = AcknowledgementPacket(time=self.env.now, src=self.id, dst=packet.src, id=packet.id, size=1) print("creating ack packet with dst" + str(pkt.dst)) self.put(pkt) def put(self, packet): """Called by objects that wants to put a packet into this node :param packet: Packet object :return: None """ if not isinstance(packet, Packet): return previous_node = packet.current_node packet.set_current_node(self) if packet.dst == self.id: if isinstance(packet, AcknowledgementPacket): self.packets_not_acknowledged.remove("n{}".format(packet.acknowledgement_id.strip("ack"))) else: self.packet_sink.put(packet) # self.send_acknowledgement(packet) else: self.switch_port.put(packet) if packet.src == self.id: self.packets_not_acknowledged.append(packet.id) if previous_node is not None: print("Packet " + str(packet.id) + " put from node " + str(previous_node.id) + " into node " + str(self.id)) else: print("Packet " + str(packet.id) + " put into node " + str(self.id)) def run(self): """Simpy process: constantly runs and creates events that are put into the event queue :return: None """ while True: packet = yield (self.packets_to_send.get()) outgoing_port = self.route(packet) if outgoing_port is not None and self.routes[outgoing_port.id].state: packet.increment_hops() packet.incrementRouteWeight(self.routes[outgoing_port.id].cost) packet.total_traffic += self.routes[outgoing_port.id].traffic packet.decrement_ttl(self.env.now) packet.path.append([outgoing_port.dst.id, self.routes[outgoing_port.id].cost]) outgoing_port.put(packet) self.packets_forwarded += 1 elif outgoing_port is None: self.put(packet) else: pass
class Node(object): def __init__(self, id, env, gen): self.env = env self.id = id self.packet_generator = None self.gen = gen self.routes = {} self.routing_algorithm = None self.network = None self.env.process(self.run()) self.packet_sink = PacketSink(env=self.env, rec_arrivals=True) self.packets_to_send = simpy.Store(self.env, capacity=1) self.packets_sent = 0 self.switch_port = SwitchPort(env=env, rate=500, qlimit=64, limit_bytes=False, id=self.id) self.switch_port.out = self.packets_to_send #self.port_monitor = PortMonitor(env, self.switch_port, dist=1) def set_network(self, network): """ Set the network in which the node is placed in :param network: :return: """ self.network = network def set_routing_algo(self, controller): # put this router into the controller controller.setNode(self.id) if controller == "random": self.routing_algorithm = RandomRouting(gen=self.gen, node=self, graph=self.network) elif controller == "dijkstra": self.routing_algorithm = Dijkstra(graph=self.network, node=self) else: pass def route(self, packet): return self.routing_algorithm.route_packet(packet) def set_packet_generator(self, lbd, possible_destinations): def dst_dist(gen, destinations): if destinations is None: return None else: return gen.choice(destinations) def next_packet_time(gen, lbd_): return gen.exponential(lbd_) packet_dst = partial(dst_dist, self.gen, possible_destinations) next_pkt_time = partial(next_packet_time, self.gen, lbd) self.packet_generator = PacketGenerator(env=self.env, id="{}_pg".format(self.id), adist=next_pkt_time, sdist=100, dstdist=packet_dst) ## LOOK AT THIS AGAIN - might want to consider putting it into a switch port self.packet_generator.out = self.packets_to_send def get_port_id(self, dst_node_id): return "{}_{}".format(self.id, dst_node_id) def get_link_id(self, dst_node): return "{}_{}".format(self.id, dst_node.id) def add_connection(self, dst_node, rate, qlimit, monitor_rate, propagation_delay, bidirectional=True): """ Add a new connection to this node given the following set of parameters :param dst_node: :param rate: :param qlimit: :param monitor_rate: :param propagation_delay: :param bidirectional: :return: """ link_id = self.get_link_id(dst_node) new_link = Link(self.env, id=link_id, cost=propagation_delay, dst=dst_node, src=self.id) self.routes[link_id] = new_link if bidirectional: new_link_reverse = dst_node.add_connection(self, rate, qlimit, monitor_rate, propagation_delay, bidirectional=False) return [new_link, new_link_reverse[0]] return [new_link] def is_neighbour(self, node): """ Check if a certain node is a neighbour of this node :param node: Node name (str) to be searched for among the neighbours :return: Boolean indicating if the node is found """ if node == self: return False for link in self.routes.values(): if link.dst == node or link.src == node: return True return False def get_link_weight(self, node): pass def clear_packets(self): """ Clear all packets from the node's switch port :return: """ self.switch_port.clear_packets() def put(self, packet): if not isinstance(packet, Packet): return packet.set_current_node(self) if packet.dst == self.id: self.packet_sink.put(packet) else: self.switch_port.put(packet) print("Packet " + str(packet.id) + " put into node " + str(self.id)) def run(self): while True: packet = yield (self.packets_to_send.get()) outgoing_port = self.route(packet) if outgoing_port is not None and self.routes[ outgoing_port.id].state: # Increment counter in packet packet.increment_hops() packet.incrementRouteWeight(self.routes[outgoing_port.id].cost) packet.decrement_ttl() outgoing_port.put(packet) self.packets_sent += 1