예제 #1
0
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
예제 #2
0
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