class Node: def __init__(self, env, id, gen, routing_controller): self.env = env self.id = id self.in_packets = simpy.Store(self.env, capacity=1) self.outgoing_ports = {} self.port_monitors = {} self.links = {} self.env.process(self.run()) self.gen = gen self.packet_generator = None self.routing_controller = self._connect_to_controller( routing_controller) self.packet_sink = PacketSink(env=self.env, rec_arrivals=True, id="{}_ps".format(self.id)) self.packets_rec = 0 self.packets_sent_to_port = 0 #Packets sent to a port but still ave to go trough the queue self.route_time = 0 def _connect_to_controller(self, controller): controller.register_node(self.id) return controller def set_packet_generator(self, lbd, possible_destinations=None): self.packet_generator = self._create_packet_generator( lbd, possible_destinations) self.packet_generator.out = self return self.packet_generator def _create_packet_generator(self, lbd, possible_destinations): def dstdist(gen, possible_destinations): if possible_destinations is None: return None else: return gen.choice(possible_destinations) def next_packet_time(gen, lbd): return gen.exponential(lbd) def packet_size(): return 100 dstdist_partial = partial(dstdist, self.gen, possible_destinations) next_packet_time_partial = partial(next_packet_time, self.gen, lbd) return PacketGenerator(env=self.env, id="{}_pg".format(self.id), adist=next_packet_time_partial, sdist=packet_size, dstdist=dstdist_partial) def _get_port_id(self, dst_node_id): return "{}_{}".format(self.id, dst_node_id) def _get_link_id(self, dst_node_id): return "link_{}_{}".format(self.id, dst_node_id) def _add_outgoing_port(self, dst_node, rate, qlimit): outgoing_port_id = self._get_port_id(dst_node.id) port = self._create_switchport(rate, qlimit, outgoing_port_id=outgoing_port_id) self.outgoing_ports[outgoing_port_id] = port return port def _create_switchport(self, rate, qlimit, outgoing_port_id): return SwitchPort(self.env, rate=rate, qlimit=qlimit, limit_bytes=False, id=outgoing_port_id) def _create_link(self, dst_node, propagation_delay, linkid): link = Link(env=self.env, id=linkid, propagation_delay=propagation_delay, dst_node=dst_node) return link def _add_link(self, dst_node, propagation_delay): linkid = self._get_link_id(dst_node.id) link = self._create_link(dst_node, propagation_delay, linkid) self.links[linkid] = link return link def _add_connection(self, dst_node, rate, qlimit, propagation_delay): new_port = self._add_outgoing_port(dst_node, rate, qlimit) new_link = self._add_link(dst_node, propagation_delay) new_port.out = new_link self.routing_controller.register_connection(self.id, new_port.id) return new_port def add_connection(self, dst_node, rate, qlimit, monitor_rate, propagation_delay): new_port = self._add_connection(dst_node=dst_node, rate=rate, qlimit=qlimit, propagation_delay=propagation_delay) new_port_monitor = self._add_portmonitor(new_port, monitor_rate) return new_port def _add_portmonitor(self, port, monitor_rate): outgoing_port_id = port.id portmonitor = self._create_portmonitor(port, monitor_rate) self.port_monitors[outgoing_port_id] = portmonitor return portmonitor def _create_portmonitor(self, port, monitor_rate): pmdist = self._get_pmdist(monitor_rate) return PortMonitor(self.env, port, dist=pmdist) def _get_pmdist(self, monitor_rate): def dist(gen, lbd): return gen.exponential(lbd) dist_partial = partial(dist, self.gen, monitor_rate) return dist_partial def _route(self, packet): outgoing_port_id = self.routing_controller.route_packet( nodeid=self.id, outgoing_ports=list(self.outgoing_ports.keys()), stats=self._get_stats_to_controller(), packet=packet) outgoing_port = self.get_outgoing_port(outgoing_port_id) return outgoing_port def get_queue_port(self, portid): port = self.get_outgoing_port(portid) return len(port.store.items) def get_queues(self): queues_dict = {k: self.get_queue_port(k) for k in self.outgoing_ports} return queues_dict def get_portmonitor(self, portid): return self.port_monitors[portid] def get_outgoing_port(self, portid): return self.outgoing_ports[portid] def _get_stats_to_controller(self): stats = {} stats["queue_size"] = self.get_queues() return stats def run(self): while True: packet = (yield self.in_packets.get()) outgoing_port = self._route(packet) print("Sending packet from " + self.id + " to port " + outgoing_port.id) outgoing_port.put(packet) self.packets_sent_to_port += 1 def put(self, packet): self.packets_rec += 1 logger.debug( f"Packet received in {self.__class__.__name__} {self.id} at {self.env.now}: " + str(packet)) if packet.dst == self.id: return self.packet_sink.put(packet) else: return self.in_packets.put(packet)
class Node(object): def __init__(self, id, env, gen): self.env = env self.id = id self.packet_generator = None self.output_ports = {} self.port_monitors = {} self.routes = {} self.routing_algo = None self.env.process(self.run()) self.packet_sink = PacketSink(env=self.env, rec_arrivals=True, id="{}_ps".format(self.id)) self.gen = gen self.incoming_packets = simpy.Store(self.env, capacity=1) self.packets_received = 0 self.packets_sent = 0 def set_routing_algo(self): # put this router into the controller controller.setNode(self.id) self.routing_algo = RoutingAlgorithm(gen=self.gen, node=self) def set_packet_generator(self, lbd, possible_destinations): def dstdist(gen, possible_destinations): if possible_destinations is None: return None else: return gen.choice(possible_destinations) def next_packet_time(gen, lbd): return gen.exponential(lbd) packet_dst = partial(dstdist, 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 def get_port_id(self, dst_node_id): return "{}_{}".format(self.id, dst_node_id) def get_link_id(self, dst_node_id): return "{}_{}".format(self.id, dst_node_id) def add_connection(self, dst_node, rate, qlimit, monitor_rate, propagation_delay, bidirectional=False): port_id = self.get_port_id(dst_node.id) new_port = SwitchPort(self.env, rate=rate, qlimit=qlimit, limit_bytes=False, id=port_id) self.output_ports[port_id] = new_port link_id = self.get_link_id(dst_node.id) new_link = Link(self.env, id=link_id, delay=propagation_delay, dst=dst_node, src=self.id, switch_port=new_port) self.routes[link_id] = new_link new_port.out = new_link def dist(gen, lbd): return gen.exponential(lbd) port_monitor_id = new_port.id dist_partial = partial(dist, self.gen, monitor_rate) port_monitor = PortMonitor(self.env, port=new_port, dist=dist_partial) self.port_monitors[port_monitor_id] = port_monitor if bidirectional: dst_node.add_connection(self, rate, qlimit, monitor_rate, propagation_delay) def route(self, packet): return self.routing_algo.route_packet(packet) def put(self, packet): self.packets_received += 1 if packet.dst == self.id: self.packet_sink.put(packet) else: self.incoming_packets.put(packet) def run(self): while True: packet = yield (self.incoming_packets.get()) outgoing_port = self.route(packet) if self.routes[outgoing_port.id].up: # Increment counter in packet packet.incrementHops() packet.incrementRouteWeight(self.routes[outgoing_port.id].cost) packet.decrement_ttl() outgoing_port.put(packet) self.packets_sent += 1
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