Esempio n. 1
0
    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

        #History data structure
        # {(port, destination), latency}
        self.history = {} 

        #Poisoned Routes
        self.poisoned_routes = set()
Esempio n. 2
0
    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

        self.history = {}

        self.removedHosts = []
        self.emptyFwdTableList = []
        self.poisonedHosts = []
        self.removedHostKeys = []
        self.removedFromPoisonedHosts = []
        self.trickledHosts = []
Esempio n. 3
0
    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

        # History data structure, dictionary within a dictionary. Maps ports to a dictionary, inner dictionary maps hosts/dst to advertisement packets
        self.history = {}
Esempio n. 4
0
    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Maps a port to the route most recently advertised
        self.routes_advertised = {}

        # A random index
        self.index = 0

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()
Esempio n. 5
0
class DVRouter(basics.DVRouterBase):
    # NO_LOG = True  # Set to True on an instance to disable its logging.
    # POISON_MODE = True  # Can override POISON_MODE here.
    # DEFAULT_TIMER_INTERVAL = 5  # Can override this yourself for testing.

    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

        self.history = {}

        self.port_table = set()

    def add_static_route(self, host, port):
        """
        Adds a static route to a host directly connected to this router.

        Called automatically by the framework whenever a host is connected
        to this router.

        :param host: the host.
        :param port: the port that the host is attached to.
        :returns: nothing.
        """
        # `port` should have been added to `peer_tables` by `handle_link_up`
        # when the link came up.
        assert port in self.peer_tables, "Link is not up?"

        # TODO: fill this in!
        self.peer_tables[port][host]=PeerTableEntry(host,0,PeerTableEntry.FOREVER)
        self.update_forwarding_table()
        self.send_routes(force=False)

    def handle_link_up(self, port, latency):
        """
        Called by the framework when a link attached to this router goes up.

        :param port: the port that the link is attached to.
        :param latency: the link latency.
        :returns: nothing.
        """
        self.link_latency[port] = latency
        self.peer_tables[port] = PeerTable()
        self.port_table.add(port)
        # TODO: fill in the rest!
        for neighbor in self.forwarding_table.keys():
            packet=basics.RoutePacket(self.forwarding_table[neighbor].dst,self.forwarding_table[neighbor].latency)
            self.history[(self.forwarding_table[neighbor].dst,port)]=latency
            self.send(packet,port,False)

    def handle_link_down(self, port):
        """
        Called by the framework when a link attached to this router does down.

        :param port: the port number used by the link.
        :returns: nothing.
        """
        # TODO: fill this in!
        if self.POISON_MODE:
            for host, entry in self.peer_tables[port].items():
                self.peer_tables[port][host]=PeerTableEntry(host,INFINITY,api.current_time()+ROUTE_TTL)
        else:
            for key in self.peer_tables.keys():
                if key == port:
                    self.peer_tables.pop(key)
        self.port_table.remove(port)
        self.update_forwarding_table()
        self.send_routes()

    def handle_route_advertisement(self, dst, port, route_latency):
        """
        Called when the router receives a route advertisement from a neighbor.

        :param dst: the destination of the advertised route.
        :param port: the port that the advertisement came from.
        :param route_latency: latency from the neighbor to the destination.
        :return: nothing.
        """
        # TODO: fill this in!
        self.peer_tables[port][dst]=PeerTableEntry(dst,route_latency,api.current_time()+ROUTE_TTL)
        self.update_forwarding_table()
        self.send_routes(force=False)


    def update_forwarding_table(self):
        """
        Computes and stores a new forwarding table merged from all peer tables.

        :returns: nothing.
        """
        self.forwarding_table.clear()  # First, clear the old forwarding table.

        # TODO: populate `self.forwarding_table` by combining peer tables.
        for peer in self.peer_tables.keys():
            for entry in self.peer_tables[peer].values():
                if entry.dst not in self.forwarding_table.keys():
                    latency = entry.latency + self.link_latency[peer] if entry.latency + self.link_latency[peer] < INFINITY else INFINITY
                    self.forwarding_table[entry.dst]=ForwardingTableEntry(entry.dst,peer,latency)
                else:
                    if(entry.latency + self.link_latency[peer] < self.forwarding_table[entry.dst].latency):
                        self.forwarding_table[entry.dst] = ForwardingTableEntry(entry.dst,peer,entry.latency + self.link_latency[peer])

    def handle_data_packet(self, packet, in_port):
        """
        Called when a data packet arrives at this router.

        You may want to forward the packet, drop the packet, etc. here.

        :param packet: the packet that arrived.
        :param in_port: the port from which the packet arrived.
        :return: nothing.
        """
        # TODO: fill this in!
        if packet.dst not in self.forwarding_table:
            return
        elif self.forwarding_table[packet.dst].latency >= INFINITY:
            return
        else:
            if self.forwarding_table[packet.dst].port == in_port:
                return
            self.send(packet,self.forwarding_table[packet.dst].port,False)


    def send_routes(self, force=False):
        """
        Send route advertisements for all routes in the forwarding table.

        :param force: if True, advertises ALL routes in the forwarding table;
                      otherwise, advertises only those routes that have
                      changed since the last advertisement.
        :return: nothing.
        """
        # TODO: fill this in!
        if(force==True):
            if(self.POISON_MODE==True):
                for neighbor in self.peer_tables:
                    for host, table in self.forwarding_table.items():
                        if neighbor in self.port_table:
                        #poison only 1 neighbor
                            if neighbor == table.port:
                                packet=basics.RoutePacket(table.dst,INFINITY)
                                self.history[(host,neighbor)]=INFINITY
                                self.send(packet,neighbor)
                            else:
                                packet1=basics.RoutePacket(table.dst,table.latency)
                                self.history[(host,neighbor)]=table.latency
                                self.send(packet1,neighbor)
            else:
                for neighbor in self.peer_tables:
                    for host, table in self.forwarding_table.items():
                        #advertise only to neighbors that are not the same port
                        if(neighbor != table.port):
                            packet1=basics.RoutePacket(table.dst,table.latency)
                            self.history[(host,neighbor)]=table.latency
                            self.send(packet1,neighbor)
        if(force==False):
            if(self.POISON_MODE==True):
                for neighbor in self.peer_tables:
                    for host, table in self.forwarding_table.items():
                        if neighbor in self.port_table:
                            if (host,neighbor) in self.history.keys() and table.latency != self.history[(host,neighbor)]:
                                if neighbor == table.port:
                                    if self.history[(host,neighbor)] != INFINITY:
                                        packet=basics.RoutePacket(table.dst,INFINITY)
                                        self.history[(host,neighbor)]=INFINITY
                                        self.send(packet,neighbor)
                                else:
                                    packet1=basics.RoutePacket(table.dst,table.latency)
                                    self.history[(host,neighbor)]=table.latency
                                    self.send(packet1,neighbor)
                            else:
                                if (host,neighbor) not in self.history.keys():
                                    if neighbor == table.port:
                                        packet=basics.RoutePacket(table.dst,INFINITY)
                                        self.history[(host,neighbor)]=INFINITY
                                        self.send(packet,neighbor)
                                    else:
                                        packet1=basics.RoutePacket(table.dst,table.latency)
                                        self.history[(host,neighbor)]=table.latency
                                        self.send(packet1,neighbor)
            else:
                for neighbor in self.peer_tables:
                    for host, table in self.forwarding_table.items():
                        if (host,neighbor) in self.history.keys() and self.forwarding_table[host].latency != self.history[(host,neighbor)]:
                            if neighbor != table.port:
                                if(table.latency >= INFINITY):
                                    packet_new = basics.RoutePacket(table.dst,INFINITY)
                                    self.history[(host,neighbor)]=INFINITY
                                    self.send(packet_new,neighbor)
                                else:
                                    packet1=basics.RoutePacket(table.dst,table.latency)
                                    self.history[(host,neighbor)]=table.latency
                                    self.send(packet1,neighbor)
                        else:
                            if (host,neighbor) not in self.history.keys():
                                if neighbor != table.port:
                                    if(table.latency >= INFINITY):
                                        packet_new = basics.RoutePacket(table.dst,INFINITY)
                                        self.history[(host,neighbor)]=INFINITY
                                        self.send(packet_new,neighbor)
                                    else:
                                        packet1=basics.RoutePacket(table.dst,table.latency)
                                        self.history[(host,neighbor)]=table.latency
                                        self.send(packet1,neighbor)
    def expire_routes(self):
        """
        Clears out expired routes from peer tables; updates forwarding table
        accordingly.
        """
        # TODO: fill this in!
        for table in self.peer_tables.values():
            for key, element in table.items():
                if (api.current_time() > element.expire_time):
                    if self.POISON_MODE:
                        table[key]=PeerTableEntry(key,INFINITY,api.current_time()+ROUTE_TTL)
                    else:
                        table.pop(key)
        self.update_forwarding_table()
    def handle_timer(self):
        """
        Called periodically.

        This function simply calls helpers to clear out expired routes and to
        send the forwarding table to neighbors.
        """
        self.expire_routes()
        self.send_routes(force=True)
Esempio n. 6
0
class DVRouter(basics.DVRouterBase):
    # NO_LOG = True  # Set to True on an instance to disable its logging.
    # POISON_MODE = True  # Can override POISON_MODE here.
    # DEFAULT_TIMER_INTERVAL = 5  # Can override this yourself for testing.

    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

        #History data structure
        # {(port, destination), latency}
        self.history = {} 

        #Poisoned Routes
        self.poisoned_routes = set()


        #different route available for a host, do not poison

    def add_static_route(self, host, port):
        """
        Adds a static route to a host directly connected to this router.

        Called automatically by the framework whenever a host is connected
        to this router.

        :param host: the host.
        :param port: the port that the host is attached to.
        :returns: nothing.
        """
        # `port` should have been added to `peer_tables` by `handle_link_up`
        # when the link came up.
        assert port in self.peer_tables, "Link is not up?"

        # TODO: fill this in!

        self.peer_tables[port] = PeerTable()

        self.peer_tables[port][host] = PeerTableEntry(host, 0, PeerTableEntry.FOREVER)

        self.update_forwarding_table()

    def handle_link_up(self, port, latency):
        """
        Called by the framework when a link attached to this router goes up.

        :param port: the port that the link is attached to.
        :param latency: the link latency.
        :returns: nothing.
        """

        self.link_latency[port] = latency
        self.peer_tables[port] = PeerTable()

        for key in self.forwarding_table:
            if (self.forwarding_table[key].latency) > INFINITY:
                self.send(basics.RoutePacket(self.forwarding_table[key].dst, INFINITY), port)   
            else:
                self.send(basics.RoutePacket(self.forwarding_table[key].dst, self.forwarding_table[key].latency), port)
 
    def handle_link_down(self, port):
        """
        Called by the framework when a link attached to this router does down.

        :param port: the port number used by the link.
        :returns: nothing.
        """
        # TODO: fill this in!


        if self.POISON_MODE:
            for p, peer_table in self.peer_tables.items():
                if p == port:
                    for pte in peer_table:
                        self.poisoned_routes.add(p)
                        peer_table[pte] = PeerTableEntry(peer_table[pte].dst, INFINITY, api.current_time() + ROUTE_TTL)
        else:
            del self.peer_tables[port]
            del self.link_latency[port]

        self.update_forwarding_table()
        self.send_routes(force=False)


    def handle_route_advertisement(self, dst, port, route_latency):
        """
        Called when the router receives a route advertisement from a neighbor.

        :param dst: the destination of the advertised route.
        :param port: the port that the advertisement came from.
        :param route_latency: latency from the neighbor to the destination.
        :return: nothing.
        """
        # TODO: fill this in!
        peer_table = self.peer_tables[port]
        peer_table[dst] = PeerTableEntry(dst, route_latency, (api.current_time() + ROUTE_TTL))             
        self.update_forwarding_table()
        self.send_routes(force=False)

    def update_forwarding_table(self):
        """
        Computes and stores a new forwarding table merged from all peer tables.

        :returns: nothing.
        """
        self.forwarding_table.clear()  # First, clear the old forwarding table.
        # TODO: populate `self.forwarding_table` by combining peer tables.
        # print(self.peer_tables)
        count = 0
        d = {}

        for port, peer_table in self.peer_tables.items():
            for pte in peer_table:
                if peer_table[pte].dst in d:
                    # print(peer_table)
                    if (peer_table[pte].latency + self.link_latency[port]) < self.forwarding_table[(peer_table[pte].dst)].latency:
                        d[(peer_table[pte].dst)] = peer_table[pte]
                        lat = peer_table[pte].latency + self.link_latency[port]
                        self.forwarding_table[(peer_table[pte].dst)] = ForwardingTableEntry((peer_table[pte].dst), port, lat)
                    else:
                        pass
                else:
                    d[peer_table[pte].dst] = peer_table[pte]
                    lat = peer_table[pte].latency + self.link_latency[port]
                    self.forwarding_table[peer_table[pte].dst] = ForwardingTableEntry((peer_table[pte].dst), port, lat)
        
        # for port, peer_table in self.peer_tables.items():
        #     if port == 1:
        #         for pte in peer_table:
        #             print(peer_table[pte])
            
        # print(self.forwarding_table)
        # for key in self.forwarding_table:
        #     print(key)

    def handle_data_packet(self, packet, in_port):
        """
        Called when a data packet arrives at this router.

        You may want to forward the packet, drop the packet, etc. here.

        :param packet: the packet that arrived.
        :param in_port: the port from which the packet arrived.
        :return: nothing.
        """
        # TODO: fill this in!
        for key in self.forwarding_table:
            if (self.forwarding_table[key].dst == packet.dst):
                if (self.forwarding_table[key].port != in_port):
                    if (self.forwarding_table[key].latency < INFINITY):
                        self.send(packet, self.forwarding_table[key].port)



    def send_routes(self, force=False):
        """
        Send route advertisements for all routes in the forwarding table.

        :param force: if True, advertises ALL routes in the forwarding table;
                      otherwise, advertises only those routes that have
                      changed since the last advertisement.
        :return: nothing.
        """

        # History data structure
        # { (port, destination), latency}
        # self.history = {} 


        # TODO: fill this in!
        if (force == False):
            for key in self.forwarding_table:
                for p in self.peer_tables:
                    # if self.POISON_MODE:
                    if p in self.poisoned_routes:
                    	continue
                    if p == self.forwarding_table[key].port:
                        if self.POISON_MODE:   
                            if (p, self.forwarding_table[key].dst) in self.history.keys():
                                if self.history[(p, self.forwarding_table[key].dst)] != self.forwarding_table[key].latency and self.history[(p, self.forwarding_table[key].dst)] != INFINITY:
                                    self.history[(p, self.forwarding_table[key].dst)] = INFINITY
                                    self.send(basics.RoutePacket(self.forwarding_table[key].dst, INFINITY), p)
                            else:
                                self.history[p, self.forwarding_table[key].dst] = INFINITY
                                self.send(basics.RoutePacket(self.forwarding_table[key].dst, INFINITY), p)
                        else:
                            pass
                    elif (self.forwarding_table[key].latency >= INFINITY):
                        if (p, self.forwarding_table[key].dst) in self.history.keys():
                            if self.history[(p, self.forwarding_table[key].dst)] != self.forwarding_table[key].latency and self.history[(p, self.forwarding_table[key].dst)] != INFINITY:
                                self.history[(p, self.forwarding_table[key].dst)] = INFINITY
                                self.send(basics.RoutePacket(self.forwarding_table[key].dst, INFINITY), p)
                        else:
                            self.history[(p, self.forwarding_table[key].dst)] = INFINITY
                            self.send(basics.RoutePacket(self.forwarding_table[key].dst, INFINITY), p)
                    else:
                        if (p, self.forwarding_table[key].dst) in self.history.keys():
                            if self.history[(p, self.forwarding_table[key].dst)] != self.forwarding_table[key].latency:
                                self.history[(p, self.forwarding_table[key].dst)] = self.forwarding_table[key].latency
                                self.send(basics.RoutePacket(self.forwarding_table[key].dst, self.forwarding_table[key].latency), p)
                        else:
                            self.history[(p, self.forwarding_table[key].dst)] = self.forwarding_table[key].latency
                            self.send(basics.RoutePacket(self.forwarding_table[key].dst, self.forwarding_table[key].latency), p)
        elif (force):
            for key in self.forwarding_table:
                for p in self.peer_tables:
                    if p in self.poisoned_routes:
                        continue
                    elif p == self.forwarding_table[key].port:
                        if (self.POISON_MODE):
                            self.history[p, self.forwarding_table[key].dst] = INFINITY
                            self.send(basics.RoutePacket(self.forwarding_table[key].dst, INFINITY), p)
                        else:
                            pass
                    else:
                        if (self.forwarding_table[key].latency) >= INFINITY:
                        	self.history[p, self.forwarding_table[key].dst] = INFINITY
                        	self.send(basics.RoutePacket(self.forwarding_table[key].dst, INFINITY), p)
                        else:
                            self.history[p, self.forwarding_table[key].dst] = self.forwarding_table[key].latency
                            self.send(basics.RoutePacket(self.forwarding_table[key].dst, self.forwarding_table[key].latency), p)


    def expire_routes(self):
        """
        Clears out expired routes from peer tables; updates forwarding table
        accordingly.
        """
        # TODO: fill this in!

        if self.POISON_MODE:
            for p, peer_table in self.peer_tables.items():
                for pte in peer_table:
                    if ((peer_table[pte].expire_time < api.current_time()) and (peer_table[pte].expire_time != PeerTableEntry.FOREVER)):
                        peer_table[pte] = PeerTableEntry(peer_table[pte].dst, INFINITY, api.current_time() + ROUTE_TTL)

        else:
            for port, peer_table in self.peer_tables.items():
                for pte in peer_table.keys():
                    if ((peer_table[pte].expire_time < api.current_time()) and (peer_table[pte].expire_time != PeerTableEntry.FOREVER)):
                        del peer_table[pte]

        self.update_forwarding_table()

    def handle_timer(self):
        """
        Called periodically.

        This function simply calls helpers to clear out expired routes and to
        send the forwarding table to neighbors.
        """
        self.expire_routes()
        self.send_routes(force=True)

    # Feel free to add any helper methods!
class DVRouter(basics.DVRouterBase):
    # NO_LOG = True  # Set to True on an instance to disable its logging.
    # POISON_MODE = True  # Can override POISON_MODE here.
    # DEFAULT_TIMER_INTERVAL = 5  # Can override this yourself for testing.

    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

    def add_static_route(self, host, port):
        """
        Adds a static route to a host directly connected to this router.

        Called automatically by the framework whenever a host is connected
        to this router.

        :param host: the host.
        :param port: the port that the host is attached to.
        :returns: nothing.
        """
        # `port` should have been added to `peer_tables` by `handle_link_up`
        # when the link came up.
        assert port in self.peer_tables, "Link is not up?"

        # TODO: fill this in!

        self.update_forwarding_table()

    def handle_link_up(self, port, latency):
        """
        Called by the framework when a link attached to this router goes up.

        :param port: the port that the link is attached to.
        :param latency: the link latency.
        :returns: nothing.
        """
        self.link_latency[port] = latency
        self.peer_tables[port] = PeerTable()

        # TODO: fill in the rest!

    def handle_link_down(self, port):
        """
        Called by the framework when a link attached to this router does down.

        :param port: the port number used by the link.
        :returns: nothing.
        """
        # TODO: fill this in!

    def handle_route_advertisement(self, dst, port, route_latency):
        """
        Called when the router receives a route advertisement from a neighbor.

        :param dst: the destination of the advertised route.
        :param port: the port that the advertisement came from.
        :param route_latency: latency from the neighbor to the destination.
        :return: nothing.
        """
        # TODO: fill this in!

    def update_forwarding_table(self):
        """
        Computes and stores a new forwarding table merged from all peer tables.

        :returns: nothing.
        """
        self.forwarding_table.clear()  # First, clear the old forwarding table.

        # TODO: populate `self.forwarding_table` by combining peer tables.

    def handle_data_packet(self, packet, in_port):
        """
        Called when a data packet arrives at this router.

        You may want to forward the packet, drop the packet, etc. here.

        :param packet: the packet that arrived.
        :param in_port: the port from which the packet arrived.
        :return: nothing.
        """
        # TODO: fill this in!

    def send_routes(self, force=False):
        """
        Send route advertisements for all routes in the forwarding table.

        :param force: if True, advertises ALL routes in the forwarding table;
                      otherwise, advertises only those routes that have
                      changed since the last advertisement.
        :return: nothing.
        """
        # TODO: fill this in!

    def expire_routes(self):
        """
        Clears out expired routes from peer tables; updates forwarding table
        accordingly.
        """
        # TODO: fill this in!

    def handle_timer(self):
        """
        Called periodically.

        This function simply calls helpers to clear out expired routes and to
        send the forwarding table to neighbors.
        """
        self.expire_routes()
        self.send_routes(force=True)
Esempio n. 8
0
class DVRouter(basics.DVRouterBase):
    # NO_LOG = True  # Set to True on an instance to disable its logging.
    # POISON_MODE = True  # Can override POISON_MODE here.
    # DEFAULT_TIMER_INTERVAL = 5  # Can override this yourself for testing.

    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}
        self.route_hist = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

    def add_static_route(self, host, port):
        """
        Adds a static route to a host directly connected to this router.

        Called automatically by the framework whenever a host is connected
        to this router.

        :param host: the host.
        :param port: the port that the host is attached to.
        :returns: nothing.
        """
        # `port` should have been added to `peer_tables` by `handle_link_up`
        # when the link came up.
        assert port in self.peer_tables, "Link is not up?"
        pte = PeerTableEntry(host, 0, PeerTableEntry.FOREVER)
        self.peer_tables[port][host] = pte
        self.update_forwarding_table()

    def handle_link_up(self, port, latency):
        """
        Called by the framework when a link attached to this router goes up.

        :param port: the port that the link is attached to.
        :param latency: the link latency.
        :returns: nothing.
        """
        self.link_latency[port] = latency
        self.peer_tables[port] = PeerTable()
        for dst, fte in self.forwarding_table.items():
            packet = basics.RoutePacket(fte.dst, fte.latency)
            self.send(packet, port)

    def handle_link_down(self, port):
        """
        Called by the framework when a link attached to this router does down.

        :param port: the port number used by the link.
        :returns: nothing.
        """
        # TODO: fill this in!s
        self.link_latency[port] = INFINITY

        for dst, entry in self.peer_tables[port].items():
            self.peer_tables[port][dst] = PeerTableEntry(
                dst, INFINITY, entry.expire_time)
        self.update_forwarding_table()
        self.send_routes()

    def handle_route_advertisement(self, dst, port, route_latency):
        """
        Called when the router receives a route advertisement from a neighbor.

        :param dst: the destination of the advertised route.
        :param port: the port that the advertisement came from.
        :param route_latency: latency from the neighbor to the destination.
        :return: nothing.

        """
        pte = PeerTableEntry(dst, route_latency,
                             api.current_time() + ROUTE_TTL)
        self.peer_tables[port][dst] = pte
        self.update_forwarding_table()
        self.send_routes()

    def update_forwarding_table(self):
        """
         Computes and stores a new forwarding table merged from all peer tables.
         :returns: nothing.
        """
        self.forwarding_table.clear()  # First, clear the old forwarding table.
        # TODO: populate `self.forwarding_table` by combining peer tables.
        for port, peer_table in self.peer_tables.items():
            # if self.link_latency[port] < INFINITY:
            for host, entry in peer_table.items():
                if host not in self.forwarding_table:
                    self.forwarding_table[host] = ForwardingTableEntry(
                        host, port,
                        min(INFINITY, entry.latency + self.link_latency[port]))
                elif entry.latency + self.link_latency[
                        port] < self.forwarding_table[host].latency:
                    self.forwarding_table[host] = ForwardingTableEntry(
                        host, port,
                        min(INFINITY, entry.latency + self.link_latency[port]))

    def handle_data_packet(self, packet, in_port):
        """
        Called when a data packet arrives at this router.

        You may want to forward the packet, drop the packet, etc. here.

        :param packet: the packet that arrived.
        :param in_port: the port from which the packet arrived.
        :return: nothing.

        """
        packet_dst = packet.dst
        if packet_dst in self.forwarding_table and self.forwarding_table[packet_dst].latency < INFINITY and \
                in_port != self.forwarding_table[packet_dst].port:
            self.send(packet, self.forwarding_table[packet_dst].port)
        else:
            self.send(packet, None)

    def send_routes(self, force=False):
        """
        Send route advertisements for all routes in the forwarding table.

        :param force: if True, advertises ALL routes in the forwarding table;
                      otherwise, advertises only those routes that have
                      changed since the last advertisement.
        :return: nothing.
        """
        # TODO: fill this in!
        for dst, fte in self.forwarding_table.items():
            for prt in self.link_latency.keys():
                if self.link_latency[prt] < INFINITY:
                    packet_key = (prt, dst)
                    if not self.POISON_MODE and force:
                        if prt != fte.port:
                            packet = basics.RoutePacket(dst, fte.latency)
                            self.route_hist[packet_key] = packet
                            self.send(packet, prt)
                        # else:
                        #     packet = basics.RoutePacket(fte.port, INFINITY)
                        #     self.route_hist[packet_key] = packet
                        #     self.send(packet, prt)
                    elif self.POISON_MODE and force:
                        if prt != fte.port:
                            packet = basics.RoutePacket(dst, fte.latency)
                            self.route_hist[packet_key] = packet
                            self.send(packet, prt)
                        else:
                            self.send(basics.RoutePacket(dst, INFINITY), prt)
                            self.route_hist[packet_key] = basics.RoutePacket(
                                (dst, INFINITY), prt)

                    elif self.POISON_MODE and not force:
                        packet = basics.RoutePacket(dst, fte.latency)
                        if packet_key not in self.route_hist or packet.latency != self.route_hist[
                                packet_key].latency:
                            if prt != fte.port:
                                self.route_hist[packet_key] = packet
                                self.send(packet, prt)
                            else:
                                self.send(basics.RoutePacket(dst, INFINITY),
                                          prt)
                                self.route_hist[packet_key] = packet
                    elif not self.POISON_MODE and not force:
                        if prt != fte.port:
                            packet = basics.RoutePacket(dst, fte.latency)
                            if packet_key not in self.route_hist or packet.latency != self.route_hist.get(
                                    packet_key
                            ).latency or packet.destination != fte.dst:
                                packet = basics.RoutePacket(dst, fte.latency)

                                self.route_hist[packet_key] = packet
                                self.send(packet, prt)

    def expire_routes(self):
        """
        Clears out expired routes from peer tables; updates forwarding table
        accordingly.
        """
        # TODO: fill this in!
        for port, peer_table_entry in self.peer_tables.items():
            for host, entry in peer_table_entry.items():
                if entry.expire_time <= api.current_time():
                    if self.POISON_MODE:
                        peer_table_entry[host] = PeerTableEntry(
                            host, INFINITY,
                            api.current_time() + ROUTE_TTL)
                    else:
                        del peer_table_entry[host]

        self.update_forwarding_table()

    def handle_timer(self):
        """
        Called periodically.

        This function simply calls helpers to clear out expired routes and to
        send the forwarding table to neighbors.
        """
        self.expire_routes()
        self.send_routes(force=True)
Esempio n. 9
0
class DVRouter(basics.DVRouterBase):
    # NO_LOG = True  # Set to True on an instance to disable its logging.
    # POISON_MODE = True  # Can override POISON_MODE here.
    # DEFAULT_TIMER_INTERVAL = 5  # Can override this yourself for testing.

    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

        # History data structure, dictionary within a dictionary. Maps ports to a dictionary, inner dictionary maps hosts/dst to advertisement packets
        self.history = {}

    def add_static_route(self, host, port):
        """
        Adds a static route to a host directly connected to this router.

        Called automatically by the framework whenever a host is connected
        to this router.

        :param host: the host.
        :param port: the port that the host is attached to.
        :returns: nothing.
        """
        # `port` should have been added to `peer_tables` by `handle_link_up`
        # when the link came up.
        assert port in self.peer_tables, "Link is not up?"

        table = self.peer_tables[port]

        table[host] = PeerTableEntry(dst=host,
                                     latency=0,
                                     expire_time=PeerTableEntry.FOREVER)

        # TODO: fill this in!

        self.update_forwarding_table()
        self.send_routes(force=False)

    def handle_link_up(self, port, latency):
        """
        Called by the framework when a link attached to this router goes up.

        :param port: the port that the link is attached to.
        :param latency: the link latency.
        :returns: nothing.
        """
        self.link_latency[port] = latency
        self.peer_tables[port] = PeerTable()

        for host, entry in self.forwarding_table.items():

            packet = basics.RoutePacket(destination=entry.dst,
                                        latency=entry.latency)
            self.send(packet, port=port)

        # TODO: fill in the rest!

    def handle_link_down(self, port):
        """
        Called by the framework when a link attached to this router does down.

        :param port: the port number used by the link.
        :returns: nothing.
        """

        self.peer_tables.pop(port)
        self.update_forwarding_table()
        self.send_routes(force=False)

        # TODO: fill this in!

    def handle_route_advertisement(self, dst, port, route_latency):
        """
        Called when the router receives a route advertisement from a neighbor.

        :param dst: the destination of the advertised route.
        :param port: the port that the advertisement came from.
        :param route_latency: latency from the neighbor to the destination.
        :return: nothing.
        """

        pTable = self.peer_tables[port]

        pTable[dst] = PeerTableEntry(dst=dst,
                                     latency=route_latency,
                                     expire_time=api.current_time() + 15)

        self.update_forwarding_table()
        self.send_routes(force=False)

        # TODO: fill this in!

    def update_forwarding_table(self):
        """
        Computes and stores a new forwarding table merged from all peer tables.

        :returns: nothing.
        """
        self.forwarding_table.clear()  # First, clear the old forwarding table.

        newFT = self.forwarding_table
        for port, table in self.peer_tables.items():

            for host, entry in table.items():
                # print(host, entry)
                currLatency = float(entry.latency) + float(
                    self.link_latency[port])

                # print(currLatency, int(entry.latency))

                # Host exists, has a entry in it
                if (host in newFT):
                    # Get old latency
                    oldLatency = newFT[host].latency

                    # Compare with newLatency, if less, replace object in forwarding table
                    if (currLatency < oldLatency):
                        newEntry = ForwardingTableEntry(dst=host,
                                                        port=port,
                                                        latency=currLatency)
                        newFT[host] = newEntry
                else:
                    # forwarding entry doesn't exist for this host, add it
                    newEntry = ForwardingTableEntry(dst=host,
                                                    port=port,
                                                    latency=currLatency)
                    newFT[host] = newEntry

        self.forwarding_table = newFT

        # TODO: populate `self.forwarding_table` by combining peer tables.

    def handle_data_packet(self, packet, in_port):
        """
        Called when a data packet arrives at this router.

        You may want to forward the packet, drop the packet, etc. here.

        :param packet: the packet that arrived.
        :param in_port: the port from which the packet arrived.
        :return: nothing.
        """

        toDST = packet.dst

        # Check if destination is in the forwarding table, if not drop packet
        if (toDST in self.forwarding_table):
            forwardingEntry = self.forwarding_table[toDST]

            # Check if distance to destination is not long, if it is, drop packet (to prevent loops)
            if (forwardingEntry.latency < INFINITY):

                # Check if packet's in_port is different from out_port, if yes, send packet
                if (forwardingEntry.port is not in_port):
                    self.send(packet, port=forwardingEntry.port)

        # TODO: fill this in!

    def send_routes(self, force=False):
        """
        Send route advertisements for all routes in the forwarding table.

        :param force: if True, advertises ALL routes in the forwarding table;
                      otherwise, advertises only those routes that have
                      changed since the last advertisement.
        :return: nothing.
        """

        # print(self.history)
        # print(self.forwarding_table)

        if (self.POISON_MODE):
            # print(self.history)
            # print(self.forwarding_table)
            for port in self.history:
                pTable = self.history[port]

                for host in pTable:

                    if ((host not in self.forwarding_table)
                            and (port in self.peer_tables)):
                        packet = basics.RoutePacket(destination=host,
                                                    latency=INFINITY)
                        # self.send(packet, port=port)

                        # pTable[host] = packet
                        # self.history[port] = pTable
                        temp = self.peer_tables[port]
                        temp[host] = PeerTableEntry(
                            dst=host,
                            latency=INFINITY,
                            expire_time=api.current_time() + ROUTE_TTL)

                self.update_forwarding_table()

        for port, table in self.peer_tables.items():

            for host, entry in self.forwarding_table.items():

                tempLatency = None

                if (self.POISON_MODE):

                    if (entry.port == port):
                        tempLatency = INFINITY
                    else:
                        if (entry.latency > INFINITY):
                            tempLatency = INFINITY
                        else:
                            tempLatency = entry.latency

# pTable = self.peer_tables[port]
# pTable[host] = PeerTableEntry(dst=host, latency=INFINITY, expire_time=api.current_time()+ROUTE_TTL)
# self.update_forwarding_table()

                elif (entry.port != port):

                    if (entry.latency > INFINITY):
                        tempLatency = INFINITY
                    else:
                        tempLatency = entry.latency

                if (tempLatency):
                    packet = basics.RoutePacket(destination=entry.dst,
                                                latency=tempLatency)

                    if (force):
                        self.send(packet, port=port)

                        pTable = {}

                        # if port already in history, get the table
                        if (port in self.history):
                            pTable = self.history[port]

# port not in history, create new dictionary entry
                        else:
                            self.history[port] = {}
                            pTable = self.history[port]

                        pTable[host] = packet
                        self.history[port] = pTable

                    # -------------------- Stage 8 --------------------
                    else:
                        send = False
                        pTable = {}

                        # if port already in history, get the table
                        if (port in self.history):
                            pTable = self.history[port]

                        # port not in history, create new dictionary entry
                        else:
                            self.history[port] = {}
                            pTable = self.history[port]

                    # Host in history
                        if (host in pTable):
                            prevEntry = pTable[host]

                            # Packet is not the same, update history and send
                            if ((prevEntry.latency != tempLatency)
                                    or (host != entry.dst)):
                                pTable[host] = packet
                                send = True

                    # Host not in history, add to history and send
                        else:
                            pTable[host] = packet
                            send = True
                            self.history[port] = pTable

                        if (send):
                            self.send(packet, port=port)

# for host, entry in self.forwarding_table.items():

#       	tempLatency = None
#       	if (entry.latency > INFINITY):
#       		tempLatency = INFINITY
#       	else:
#       		tempLatency = entry.latency

#       	packet = basics.RoutePacket(destination=entry.dst, latency=tempLatency)
#       	self.send(packet, port=entry.port, flood=force)

# TODO: fill this in!

    def expire_routes(self):
        """
        Clears out expired routes from peer tables; updates forwarding table
        accordingly.
        """

        for port, table in self.peer_tables.items():

            for host, entry in table.items():

                if (entry.expire_time == PeerTableEntry.FOREVER):
                    continue

                if (entry.expire_time < api.current_time()):
                    table.pop(host)

        self.update_forwarding_table()

        # TODO: fill this in!

    def handle_timer(self):
        """
        Called periodically.

        This function simply calls helpers to clear out expired routes and to
        send the forwarding table to neighbors.
        """
        self.expire_routes()
        self.send_routes(force=True)
Esempio n. 10
0
class DVRouter(basics.DVRouterBase):
    # NO_LOG = True  # Set to True on an instance to disable its logging.
    # POISON_MODE = True  # Can override POISON_MODE here.
    # DEFAULT_TIMER_INTERVAL = 5  # Can override this yourself for testing.

    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

        self.history = {}

        self.removedHosts = []
        self.emptyFwdTableList = []
        self.poisonedHosts = []
        self.removedHostKeys = []
        self.removedFromPoisonedHosts = []
        self.trickledHosts = []

    def add_static_route(self, host, port):
        """
        Adds a static route to a host directly connected to this router.

        Called automatically by the framework whenever a host is connected
        to this router.

        :param host: the host.
        :param port: the port that the host is attached to.
        :returns: nothing.
        """
        # `port` should have been added to `peer_tables` by `handle_link_up`
        # when the link came up.
        assert port in self.peer_tables, "Link is not up?"
        dst = host
        latency = 0
        expire_time = PeerTableEntry.FOREVER
        pte = PeerTableEntry(dst, latency, expire_time)
        self.peer_tables[port][host] = pte
        self.update_forwarding_table()
        self.send_routes(force=False)

    def handle_link_up(self, port, latency):
        """
        Called by the framework when a link attached to this router goes up.

        :param port: the port that the link is attached to.
        :param latency: the link latency.
        :returns: nothing.
        """
        self.link_latency[port] = latency
        self.peer_tables[port] = PeerTable()

        for key in self.forwarding_table.keys():
            adPacket = basics.RoutePacket(
                key,
                self.forwarding_table.get(key).latency)
            self.send(adPacket, port, flood=False)
            fte = ForwardingTableEntry(key, port,
                                       self.forwarding_table.get(key).latency)
            self.history[(port, key)] = fte

    def handle_link_down(self, port):
        """
        Called by the framework when a link attached to this router does down.

        :param port: the port number used by the link.
        :returns: nothing.
        """
        for x in self.forwarding_table.keys():
            if self.forwarding_table[x][1] == port:
                if ([self.forwarding_table[x][0],
                     port]) not in self.removedHosts:
                    self.removedHosts += [[self.forwarding_table[x][0], port]]
                    self.poisonedHosts += [[self.forwarding_table[x][0], port]]
                    del self.forwarding_table[x]

        if (port in self.peer_tables.keys()):
            del self.peer_tables[port]

        for elem in self.removedHosts:
            for item in self.history.keys():
                if elem[1] != item[0] and elem[0] == item[1]:
                    del self.history[item]

        self.update_forwarding_table()
        self.send_routes(force=False)

    def handle_route_advertisement(self, dst, port, route_latency):
        """
        Called when the router receives a route advertisement from a neighbor.

        :param dst: the destination of the advertised route.
        :param port: the port that the advertisement came from.
        :param route_latency: latency from the neighbor to the destination.
        :return: nothing.
        """
        currentPTE = PeerTableEntry(dst, route_latency,
                                    api.current_time() + ROUTE_TTL)
        self.peer_tables[port][dst] = currentPTE

        self.update_forwarding_table()
        self.send_routes(force=False)

    def update_forwarding_table(self):
        """
        Computes and stores a new forwarding table merged from all peer tables.

        :returns: nothing.
        """
        self.forwarding_table.clear()  # First, clear the old forwarding table.

        for port, peer_table in self.peer_tables.items():
            currCost = 0
            key = None
            for host, value in peer_table.items():
                key = host
                if (self.peer_tables.get(port)):
                    currCost = self.link_latency[port] + value.latency
                else:
                    currCost = self.link_latency[port]

                if (
                        currCost > INFINITY
                ):  #Stage 3: Cap route latency at INFINITY when you create a ForwardingTableEntry
                    currCost = INFINITY

                if (self.forwarding_table.get(key)):
                    prevCost = self.forwarding_table.get(key).latency
                    if (currCost < prevCost):
                        prevCost = currCost
                        fwdTableEntry = ForwardingTableEntry(
                            key, port, prevCost)
                        self.forwarding_table[key] = fwdTableEntry

                else:
                    fwdTableEntry = ForwardingTableEntry(key, port, currCost)
                    self.forwarding_table[key] = fwdTableEntry

    def handle_data_packet(self, packet, in_port):
        """
        Called when a data packet arrives at this router.

        You may want to forward the packet, drop the packet, etc. here.

        :param packet: the packet that arrived.
        :param in_port: the port from which the packet arrived.
        :return: nothing.
        """
        destination = packet.dst
        if (not self.forwarding_table.get(destination)):
            return
        dist = self.forwarding_table.get(destination).latency
        if (dist >= INFINITY):
            return
        out_port = self.forwarding_table.get(destination).port
        if (out_port == in_port):
            return
        self.send(packet, out_port, flood=False)

    def send_routes(self, force=False):
        """
        Send route advertisements for all routes in the forwarding table.

        :param force: if True, advertises ALL routes in the forwarding table;
                      otherwise, advertises only those routes that have
                      changed since the last advertisement.
        :return: nothing.
        """
        for port, peer_table in self.peer_tables.items():
            for key, item in self.forwarding_table.items():
                fwdPorts = item.port

                if (self.POISON_MODE):
                    if (port == fwdPorts):
                        if force == False:
                            if (port, key) not in self.history.keys() or (
                                    self.history[(port, key)][0] != key or
                                    self.history[(port, key)][2] != INFINITY):
                                adPacket = basics.RoutePacket(key, INFINITY)
                                self.send(adPacket, port, flood=False)
                                fte = ForwardingTableEntry(key, port, INFINITY)
                                self.history[(port, key)] = fte
                        else:
                            adPacket = basics.RoutePacket(key, INFINITY)
                            self.send(adPacket, port, flood=False)
                            fte = ForwardingTableEntry(key, port, INFINITY)
                            self.history[(port, key)] = fte

                    else:
                        if force == False:
                            if (port, key) not in self.history.keys() or (
                                    self.history[(port, key)][0] != key
                                    or self.history[
                                        (port, key)][2] != item.latency):
                                adPacket = basics.RoutePacket(
                                    key, item.latency)
                                self.send(adPacket, port, flood=False)
                                fte = ForwardingTableEntry(
                                    key, port, item.latency)
                                self.history[(port, key)] = fte

                        else:
                            adPacket = basics.RoutePacket(key, item.latency)
                            self.send(adPacket, port, flood=False)
                            fte = ForwardingTableEntry(key, port, item.latency)
                            self.history[(port, key)] = fte

                elif (not self.POISON_MODE and port != fwdPorts):
                    adPacket = basics.RoutePacket(key, item.latency)
                    if force == False:
                        if (port, key) not in self.history.keys() or (
                                self.history[(port, key)][0] != key or
                                self.history[(port, key)][2] != item.latency):
                            self.send(adPacket, port, flood=False)
                            fte = ForwardingTableEntry(key, port, item.latency)
                            self.history[(port, key)] = fte
                    else:
                        self.send(adPacket, port, flood=False)
                        fte = ForwardingTableEntry(key, port, item.latency)
                        self.history[(port, key)] = fte

        tempList = []
        if (self.POISON_MODE):
            for rem in self.removedHosts:
                for port in self.peer_tables.keys():
                    host = rem[0]

                    if (force == False):
                        if rem not in self.poisonedHosts:
                            break

                    if (force == True):
                        if (port, host) in self.history.keys():
                            val = self.history[(port, host)]
                            if val[2] != INFINITY:

                                if (len(self.forwarding_table) == 0):
                                    if (port, host) in self.history.keys(
                                    ) and (port,
                                           host) not in self.emptyFwdTableList:
                                        self.emptyFwdTableList += [(port, host)
                                                                   ]
                                    elif (port,
                                          host) in self.emptyFwdTableList:
                                        break

                                for key, value in self.forwarding_table.items(
                                ):
                                    if host != key and (
                                            port, host) in self.history.keys():
                                        del self.history[(port, host)]
                                    elif (host == key):
                                        tempList += [(port, key)]

                            else:

                                if (len(self.forwarding_table) == 0):
                                    if (port, host) in self.history.keys(
                                    ) and (port,
                                           host) not in self.emptyFwdTableList:
                                        self.emptyFwdTableList += [(port, host)
                                                                   ]
                                    elif (port,
                                          host) in self.emptyFwdTableList:
                                        break

                                for key, value in self.forwarding_table.items(
                                ):
                                    if (key == host and value[1] == port):
                                        tempList += [(port, key)]
                                    else:
                                        if ((port, host)
                                                in self.history.keys()):
                                            if [
                                                    host, port
                                            ] in self.removedFromPoisonedHosts:
                                                pass
                                            else:
                                                del self.history[(port, host)]

                    if ((port, host) not in self.history.keys()
                            or self.emptyFwdTableList):
                        if (port, host) in tempList:
                            continue

                        if [host, port] in self.removedFromPoisonedHosts:
                            continue

                        if [host, port] in self.trickledHosts:
                            continue

                        adPacket = basics.RoutePacket(host, INFINITY)
                        self.send(adPacket, port, flood=False)
                        fte = ForwardingTableEntry(host, port, INFINITY)
                        self.history[(port, host)] = fte

        if (self.POISON_MODE):
            if (force == False):
                for elem in self.poisonedHosts:
                    if elem in self.removedHosts:
                        self.poisonedHosts.remove(elem)
                        self.removedFromPoisonedHosts += [elem]

    def expire_routes(self):
        """
        Clears out expired routes from peer tables; updates forwarding table
        accordingly.
        """
        for port, peer_table in self.peer_tables.items():
            for host, value in peer_table.items():
                if (value.expire_time == PeerTableEntry.FOREVER):
                    return
                if (api.current_time() > value.expire_time):

                    for dest, fwdEntry in self.forwarding_table.items():
                        if (dest == host):
                            if [dest, port] not in self.removedHosts:
                                self.removedHosts += [[dest, port]]
                                self.poisonedHosts += [[dest, port]]

                            del self.peer_tables[port][dest]

                    self.update_forwarding_table()

    def handle_timer(self):
        """
        Called periodically.

        This function simply calls helpers to clear out expired routes and to
        send the forwarding table to neighbors.
        """
        self.expire_routes()
        self.send_routes(force=True)
Esempio n. 11
0
class DVRouter(basics.DVRouterBase):
    # NO_LOG = True  # Set to True on an instance to disable its logging.
    POISON_MODE = True  # Can override POISON_MODE here.

    # DEFAULT_TIMER_INTERVAL = 5  # Can override this yourself for testing.

    def __init__(self):
        """
        Called when the instance is initialized.

        DO NOT remove any existing code from this method.
        """
        self.start_timer()  # Starts calling handle_timer() at correct rate.

        # Maps a port to the latency of the link coming out of that port.
        self.link_latency = {}

        # Maps a port to the PeerTable for that port.
        # Contains an entry for each port whose link is up, and no entries
        # for any other ports.
        self.peer_tables = {}

        # Maps a port to the route most recently advertised
        self.routes_advertised = {}

        # A random index
        self.index = 0

        # Forwarding table for this router (constructed from peer tables).
        self.forwarding_table = ForwardingTable()

    def add_static_route(self, host, port):
        """
        Adds a static route to a host directly connected to this router.

        Called automatically by the framework whenever a host is connected
        to this router.

        :param host: the host.
        :param port: the port that the host is attached to.
        :returns: nothing.
        """
        # `port` should have been added to `peer_tables` by `handle_link_up`
        # when the link came up.
        assert port in self.peer_tables, "Link is not up?"

        staticRoute = PeerTableEntry(host, 0, PeerTableEntry.FOREVER)
        self.peer_tables.get(port).update({host: staticRoute})
        self.update_forwarding_table()
        self.send_routes(force=False)

    def handle_link_up(self, port, latency):
        """
        Called by the framework when a link attached to this router goes up.

        :param port: the port that the link is attached to.
        :param latency: the link latency.
        :returns: nothing.
        """
        self.link_latency[port] = latency
        self.peer_tables[port] = PeerTable()

        for host, ftEntry in self.forwarding_table.items():
            tempPacket = basics.RoutePacket(host, ftEntry.latency)
            self.send(tempPacket, port, flood=False)

    def handle_link_down(self, port):
        """
        Called by the framework when a link attached to this router does down.

        :param port: the port number used by the link.
        :returns: nothing.
        """
        self.peer_tables = {
            tempPort: tempTable
            for tempPort, tempTable in self.peer_tables.items()
            if tempPort != port
        }
        self.update_forwarding_table()
        self.send_routes(force=False)

    def handle_route_advertisement(self, dst, port, route_latency):
        """
        Called when the router receives a route advertisement from a neighbor.

        :param dst: the destination of the advertised route.
        :param port: the port that the advertisement came from.
        :param route_latency: latency from the neighbor to the destination.
        :return: nothing.
        """
        neighborPeerTable = self.peer_tables.get(port)
        ptEntry = PeerTableEntry(dst, route_latency,
                                 api.current_time() + ROUTE_TTL)
        neighborPeerTable.update({dst: ptEntry})
        self.peer_tables.update({port: neighborPeerTable})

        self.update_forwarding_table()
        self.send_routes(force=False)

    def update_forwarding_table(self):
        """
        Computes and stores a new forwarding table merged from all peer tables.

        :returns: nothing.
        """
        oldForwardingTable = dict(self.forwarding_table)

        self.forwarding_table.clear()  # First, clear the old forwarding table.

        for port, tempPeerTable in self.peer_tables.items():
            for host, entry in tempPeerTable.items():
                if ((self.forwarding_table.get(host, 110010100) == 110010100)
                        or ((entry.latency + self.link_latency.get(port)) <
                            self.forwarding_table.get(host).latency)):
                    tempFTE = ForwardingTableEntry(
                        host, port,
                        self.link_latency.get(port) + entry.latency)
                    self.forwarding_table.update({host: tempFTE})

        # if (self.POISON_MODE):
        #     balogneList = []
        #     self.index = 50
        #     for oldKey, oldValue in oldForwardingTable.items():
        #         marker = True
        #         for key, value in self.forwarding_table.items():
        #             if (oldKey == key) and (oldValue == value):
        #                 marker = False
        #         if (marker):
        #             balogneList.append((oldKey, oldValue))

        #     loopTimer = api.current_time() + 15

        # while (self.index > 0):
        #     for port in self.peer_tables.keys():
        #         # Maybe not same port endless loop
        #         for tempRoute in balogneList:
        #             self.send(basics.RoutePacket(tempRoute[0], tempRoute[1].latency), port, flood=False)
        #     self.index = self.index - 1

    def handle_data_packet(self, packet, in_port):
        """
        Called when a data packet arrives at this router.

        You may want to forward the packet, drop the packet, etc. here.

        :param packet: the packet that arrived.
        :param in_port: the port from which the packet arrived.
        :return: nothing.
        """
        forwardingTableEntry = self.forwarding_table.get(packet.dst, 110010100)
        if not (forwardingTableEntry == 110010100):
            if (in_port != forwardingTableEntry.port) and (
                    forwardingTableEntry.latency < INFINITY):
                self.send(packet, forwardingTableEntry.port, flood=False)

    def send_routes(self, force=False):
        """
        Send route advertisements for all routes in the forwarding table.

        :param force: if True, advertises ALL routes in the forwarding table;
                      otherwise, advertises only those routes that have
                      changed since the last advertisement.
        :return: nothing.
        """
        listOfPorts = self.peer_tables.keys()
        ftEntries = self.forwarding_table.values()
        routes_advertised_toUpdate = []
        if (force):
            for ftEntry in ftEntries:
                for port in listOfPorts:
                    if (port != ftEntry.port):
                        tempPacket = basics.RoutePacket(
                            ftEntry.dst, ftEntry.latency
                            if ftEntry.latency < INFINITY else INFINITY)
                        self.send(tempPacket, port, flood=False)
                        # self.routes_advertised.update({(ftEntry.dst, port): ftEntry.latency})
                        routes_advertised_toUpdate.append({
                            (ftEntry.dst, port):
                            ftEntry.latency
                        })
                    elif ((self.POISON_MODE) and (port == ftEntry.port) and
                          (ftEntry.latency != self.link_latency.get(port))):
                        tempPacket = basics.RoutePacket(ftEntry.dst, INFINITY)
                        self.send(tempPacket, port, flood=False)
                        # self.routes_advertised.update({(ftEntry.dst, port): ftEntry.latency})
                        routes_advertised_toUpdate.append({
                            (ftEntry.dst, port):
                            ftEntry.latency
                        })
                self.routes_advertised.update({
                    (ftEntry.dst, port):
                    ftEntry.latency
                })

        else:
            # for host, entry in self.forwarding_table.items():
            # for port in listOfPorts:
            #             toSend = None
            # if (port != entry.port):
            # toSend = basics.RoutePacket(entry.dst, entry.latency if entry.latency < INFINITY else INFINITY)
            # elif (self.POISON_MODE and port == entry.port and entry.latency != self.link_latency.get(port)):
            #                 toSend = basics.RoutePacket(entry.dst, entry.latency if entry.latency < INFINITY else INFINITY)

            #             if (toSend != None):
            #                 if ((self.routes_advertised.get((entry.dst, port)) != (entry.latency)) or ((entry.dst, port) not in self.routes_advertised.keys())):
            #                     self.send(toSend, port, flood=False)
            #                     self.routes_advertised.update({(toSend.dst, port): toSend.latency})

            # make packet -> compare packet latency history

            # key = (destination, port (advertised out of)) -> (latency)
            # if (self.routes_advertised.get(port) == )
            # for ftEntry in ftEntries:
            #     for port in listOfPorts:
            #         if (self.POISON_MODE):
            #             if (port == ftEntry.port):
            #                 tempPacket = basics.RoutePacket(ftEntry.dst, INFINITY)
            #                 if ((not self.packet_in_list(tempPacket, self.routes_advertised.values()))
            #                 or (not self.compare_packets(tempPacket, self.routes_advertised.get(ftEntry.port)))):
            #                     self.send(tempPacket, port, flood=False)
            #                     self.routes_advertised.update({port: tempPacket})
            #         if (port != ftEntry.port):
            #             tempPacket = basics.RoutePacket(ftEntry.dst, ftEntry.latency if ftEntry.latency < INFINITY else INFINITY)
            #             if ((not self.packet_in_list(tempPacket, self.routes_advertised.values()))
            #             or (not self.compare_packets(tempPacket, self.routes_advertised.get(ftEntry.port)))):
            #                 self.send(tempPacket, port, flood=False)
            #                 self.routes_advertised.update({port: tempPacket})

            #     if ((not self.POISON_MODE) and (port != ftEntry.port)):
            #         self.send(tempPacket, port, flood=False)
            #         self.routes_advertised.update({port: tempPacket})
            # elif ((self.POISON_MODE) and (port == ftEntry.port) and (ftEntry.latency != self.link_latency.get(port))):
            #     tempPacket = basics.RoutePacket(ftEntry.dst, INFINITY)
            #     if ((not self.packet_in_list(tempPacket, self.routes_advertised.values()))
            #     or (not self.compare_packets(tempPacket, self.routes_advertised.get(ftEntry.port)))):
            #         self.send(tempPacket, port, flood=False)
            #         self.routes_advertised.update({port: tempPacket})

            # for entry in ftEntries:
            #     for port in listOfPorts:
            #         if (port != entry.port):
            #             # self.send(tempPacket, port, flood=False)
            #             # routes_advertised_toUpdate.append({(entry.dst, port): entry.latency})
            #             packetToSend = basics.RoutePacket(entry.dst, entry.latency if entry.latency < INFINITY else INFINITY)

            #         elif (self.POISON_MODE):
            #             if ((port == entry.port) and (entry.latency != self.link_latency.get(port))):
            #                 packetToSend = basics.RoutePacket(entry.dst, INFINITY)

            #         else:
            #             packetToSend = basics.RoutePacket(entry.dst, -1)

            #         if ((self.routes_advertised.get((entry.dst, port)) != entry.latency)
            #         or (self.history_checker(entry, port))):
            #             if (packetToSend.latency != -1):
            #                 self.send(packetToSend, port, flood=False)
            #                 self.routes_advertised.update({(entry.dst, port): packetToSend.latency})
            #         else:
            #             continue

            #         routes_advertised_toUpdate.append({(entry.dst, port): entry.latency})
            # [self.routes_advertised.update(tempRoute) for tempRoute in routes_advertised_toUpdate]

            # 25/29 IMPLEMENTATION COPY
            for entry in ftEntries:
                tempPacket = basics.RoutePacket(
                    entry.dst,
                    entry.latency if entry.latency < INFINITY else INFINITY)
                for port in listOfPorts:
                    if ((self.routes_advertised.get(
                        (entry.dst, port)) != entry.latency)
                            or (self.history_checker(entry, port))):
                        if (port != entry.port):
                            self.send(tempPacket, port, flood=False)
                            # self.send_helper(tempPacket, port)
                            routes_advertised_toUpdate.append({
                                (entry.dst, port):
                                entry.latency
                            })
                        if (self.POISON_MODE):

                            if ((port == entry.port)
                                    and (entry.latency !=
                                         self.link_latency.get(port))):
                                tempPacket = basics.RoutePacket(
                                    entry.dst, INFINITY)
                                if ((self.routes_advertised.get(
                                    (entry.dst, port)) != (entry.latency)) or
                                    ((entry.dst, port)
                                     not in self.routes_advertised.keys())):
                                    self.send(tempPacket,
                                              entry.port,
                                              flood=False)
                                    # self.send_helper(tempPacket, port)
                                    routes_advertised_toUpdate.append({
                                        (entry.dst, port):
                                        entry.latency
                                    })
                                tempPacket = basics.RoutePacket(
                                    entry.dst, entry.latency
                                    if entry.latency < INFINITY else INFINITY)

                    routes_advertised_toUpdate.append({
                        (entry.dst, port):
                        entry.latency
                    })
            [
                self.routes_advertised.update(tempRoute)
                for tempRoute in routes_advertised_toUpdate
            ]

            # # 23/29 IMPLEMENTATION
            # for ftEntry in ftEntries:
            #     tempPacket = basics.RoutePacket(ftEntry.dst, ftEntry.latency if ftEntry.latency < INFINITY else INFINITY)
            #     if ((not self.packet_in_list(tempPacket, self.routes_advertised.values()))
            #     or (not self.compare_packets(tempPacket, self.routes_advertised.get(ftEntry.port)))):
            #         for port in listOfPorts:
            #             if (port != ftEntry.port):
            #                 self.send(tempPacket, port, flood=False)
            #                 routes_advertised_toUpdate.append({ftEntry.port: tempPacket})
            #             if ((self.POISON_MODE) and (port == ftEntry.port) and (ftEntry.latency != self.link_latency.get(port))):
            #                 tempPacket = basics.RoutePacket(ftEntry.dst, INFINITY)
            #                 if ((not self.packet_in_list(tempPacket, self.routes_advertised.values()))
            #                 or (not self.compare_packets(self.routes_advertised.get(ftEntry.port), tempPacket))):
            #                     self.send(tempPacket, ftEntry.port, flood=False)
            #                     routes_advertised_toUpdate.append({ftEntry.port: tempPacket})
            #                 tempPacket = basics.RoutePacket(ftEntry.dst, ftEntry.latency if ftEntry.latency < INFINITY else INFINITY)

            #         # routes_advertised_toUpdate.append({ftEntry.port: tempPacket})
            # [self.routes_advertised.update(tempRoute) for tempRoute in routes_advertised_toUpdate]

            # FIRST PART OF SEND
            # if (self.POISON_MODE):
            #     for ftEntry in ftEntries:
            #         for port in listOfPorts:
            #             if ((port == ftEntry.port) and (ftEntry.latency != self.link_latency.get(port))):
            #                 tempPacket = basics.RoutePacket(ftEntry.dst, INFINITY)
            #                 self.send(tempPacket, port, flood=False)
            #                 self.routes_advertised.update({port: tempPacket})
            #             else:
            #                 tempPacket = basics.RoutePacket(ftEntry.dst, ftEntry.latency if ftEntry.latency < INFINITY else INFINITY)
            #                 self.send(tempPacket, port, flood=False)
            #                 self.routes_advertised.update({port: tempPacket})

            # else:
            #     for ftEntry in ftEntries:
            #         tempPacket = basics.RoutePacket(ftEntry.dst, ftEntry.latency if ftEntry.latency < INFINITY else INFINITY)
            #         for port in listOfPorts:
            #             if (port != ftEntry.port):
            #                 self.send(tempPacket, port, flood=False)
            #                 self.routes_advertised.update({port: tempPacket})

    # def send_helper(self, packet, port):
    #     packetsAdvertisedList = self.routes_advertised.values()
    #     marker = True
    #     for tempRoute in packetsAdvertisedList:
    #         if ((tempRoute.latency == packet.latency) and (tempRoute.dst == packet.dst)):
    #             marker = False
    #     if (self.routes_advertised.get(port) == packet):
    #         marker = False

    #     if (marker):
    #         self.send(packet, port, flood=False)
    #         self.routes_advertised.update({port: packet})

    def compare_packets(self, packetA, packetB):
        """
        Compares the the destinations and latency of two packets to see if
        they equate to the same route. 
        """
        if (type(packetB) == type(None)):
            return False
        if ((packetA.latency == packetB.latency)
                and (packetA.dst == packetB.dst)):
            return True
        return False

    def packet_in_list(self, packet, packetList):
        for tempPacket in packetList:
            if ((packet.latency == tempPacket.latency)
                    and (packet.dst == tempPacket.dst)):
                return True
        return False

    def history_checker(self, entry, port):
        routeLatency = entry.latency
        destination = entry.dst

        for key, value in self.routes_advertised.items():
            # pdb.set_trace()
            if ((key[0] == destination) and (value == routeLatency)):
                return False
        return True

    def expire_routes(self):
        """
        Clears out expired routes from peer tables; updates forwarding table
        accordingly.
        """
        for port, peerTable in self.peer_tables.items():
            peerTable = {
                host: ptEntry
                for host, ptEntry in peerTable.items()
                if ptEntry.expire_time > api.current_time()
            }
            self.peer_tables.update({port: peerTable})

        self.update_forwarding_table()

    def handle_timer(self):
        """
        Called periodically.

        This function simply calls helpers to clear out expired routes and to
        send the forwarding table to neighbors.
        """
        self.expire_routes()
        self.send_routes(force=True)