def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ to_delete = [] for dest in self.routeTableLatency: if api.current_time() - self.routeTableTime[dest] <= 15: routePacket = basics.RoutePacket(dest, self.routeTableLatency[dest]) self.send(routePacket, self.routeTablePort[dest], True) else: if dest in self.neighborHosts and self.neighborHosts[dest][ 1] == self.routeTablePort[dest]: self.routeTableLatency[dest] = self.neighborHosts[dest][0] self.routeTablePort[dest] = self.neighborHosts[dest][1] self.routeTableTime[dest] = api.current_time() routePacket = basics.RoutePacket( dest, self.routeTableLatency[dest]) self.send(routePacket, self.routeTablePort[dest], True) else: to_delete.append(dest) routePacket = basics.RoutePacket(dest, INFINITY) self.send(routePacket, self.routeTablePort[dest], True) self.delete(to_delete)
def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ for route in self.routes: if (api.current_time() - self.route_time[route]) > self.ROUTE_TIMEOUT: self.log("%s (%s)", api.current_time() - self.route_time[route], api.current_time()) self.delete_route(route) self.update_state(route[0]) for destination in self.dst_port_lookup: self.update_neighbors(destination, self.dst_port_lookup[destination], self.dst_latency_lookup[destination]) for port in self.link: pack = basics.RoutePacket(self, 0) self.send(pack, port)
def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ # remove expired routes remove_dests = [] for dest, info in self.router_table.items(): time = api.current_time() - info[2] if time >= self.ROUTE_TIMEOUT: remove_dests.append(dest) for dest in remove_dests: # remove routes del self.router_table[dest] if self.POISON_MODE: self.poison.append(dest) self.host_route_default(dest, api.current_time()) # send to neighbors the router_table for port in self.port_latency.keys(): for dest, info in self.router_table.items(): if (info[0] != port): self.send(basics.RoutePacket(dest, info[1]), port) elif (info[0] == port and self.POISON_MODE): self.send(basics.RoutePacket(dest, INFINITY), port) if self.POISON_MODE: for dest in self.poison: if dest not in self.host_port: self.send(basics.RoutePacket(dest, INFINITY), port) self.poison = []
def expire_routes(self): """ Clears out expired routes from table. accordingly. """ # TODO: fill this in! hosts = list(self.table.keys()) for host in hosts: table_entry = self.table[host] if table_entry.expire_time == FOREVER: return # route is poison and expired if self.POISON_EXPIRED and api.current_time( ) > table_entry.expire_time: current_route = self.table[host] poison_route = TableEntry(host, current_route.port, latency=INFINITY, expire_time=self.ROUTE_TTL) self.table[host] = poison_route # route is expired elif api.current_time() > table_entry.expire_time: del self.table[host]
def handle_route_advertisement(self, route_dst, route_latency, port): """ Called when the router receives a route advertisement from a neighbor. :param route_dst: the destination of the advertised route. :param route_latency: latency from the neighbor to the destination. :param port: the port that the advertisement arrived on. :return: nothing. """ # TODO: fill this in! # if its not in the table entry then I need to add it since it is a new destination if route_dst not in self.table.keys(): self.table[route_dst] = TableEntry( route_dst, port, self.ports.get_latency(port) + route_latency, api.current_time() + self.ROUTE_TTL) else: for host, entry in self.table.items(): if route_dst == host: # if my destination is in my table entry then maybe I have found a better path and must update my existing path if port == entry.port and route_latency >= INFINITY: self.table[host] = TableEntry(route_dst, port, INFINITY, api.current_time()) self.send_routes(False) elif port == entry.port or entry.latency > route_latency + self.ports.get_latency( port): self.table[host] = TableEntry( route_dst, port, route_latency + self.ports.get_latency(port), api.current_time() + self.ROUTE_TTL) self.send_routes(False)
def route_update(self, destination, port, latency): if (latency + self.port_latency[port] < INFINITY): total_distance = latency + self.port_latency[port] else: total_distance = INFINITY if destination in self.router_table: # Destination in routing table if port == self.router_table[destination][0]: if total_distance != INFINITY: # trust most recent route self.router_table[destination] = [ port, total_distance, api.current_time() ] else: if destination in self.router_table: del self.router_table[destination] if self.POISON_MODE: self.poison.append(destination) elif (port != self.router_table[destination][0] and total_distance <= self.router_table[destination][1]): self.router_table[destination] = [ port, total_distance, api.current_time() ] else: if total_distance != INFINITY: self.router_table[destination] = [ port, total_distance, api.current_time() ] # add default host route self.host_route_default(destination, api.current_time())
def bellman_ford_update(self, packet, port): packet_distance = self.neighbors_distance[port] + packet.latency # If we don't have our own distance, then packet_distance is the shortest one! if packet.destination not in self.distance_vectors.keys(): self.distance_vectors[packet.destination] = RoutingTable( packet_distance, port, api.current_time()) else: table = self.distance_vectors[packet.destination] our_distance = table.latency # If packet distance is different despite using that port, that means something has changed on their end, so have to update the distance. if (port == table.port): if packet.destination in self.neighbors: direct_table = self.neighbors[packet.destination] if packet_distance > direct_table.latency: table.update_table(direct_table.latency, direct_table.port, api.current_time()) else: table.update_table(packet_distance, table.port, api.current_time()) #If our distance is greater than through this packet, then we update our distance and change the port we go through. elif our_distance >= packet_distance: table.update_table(packet_distance, port, api.current_time())
def handle_rx (self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ self.log("RX %s on %s (%s)", packet, port, api.current_time()) if isinstance(packet, basics.RoutePacket): new_latency = packet.latency + self.weights[port] if new_latency >= INFINITY: if packet.destination in self.DP and self.DP[packet.destination][0] == port: del self.DP[packet.destination] if self.POISON_MODE: self.send(basics.RoutePacket(packet.destination, INFINITY), port, flood=True) elif packet.destination not in self.DP or self.DP[packet.destination][1] >= new_latency or self.DP[packet.destination][0] == port: self.DP[packet.destination] = (port, new_latency) self.timer[packet.destination] = api.current_time() self.send(basics.RoutePacket(packet.destination, new_latency), port, flood=True) elif isinstance(packet, basics.HostDiscoveryPacket): self.DP[packet.src] = (port, self.weights[port]) self.timer[packet.src] = api.current_time() elif packet.dst in self.DP: self.send(packet, self.DP[packet.dst][0])
def handle_route_advertisement(self, route_dst, route_latency, port): """ Called when the router receives a route advertisement from a neighbor. :param route_dst: the destination of the advertised route. :param route_latency: latency from the neighbor to the destination. :param port: the port that the advertisement arrived on. :return: nothing. """ # TODO: fill this in! if route_dst in self.table: current_route = self.table.get(route_dst) if (route_latency + self.ports.get_latency(port) < current_route.latency) or (port == self.table[route_dst].port): if route_latency >= INFINITY: self.table[route_dst] = TableEntry(route_dst, port, route_latency, api.current_time()) else: self.table[route_dst] = TableEntry( route_dst, port, route_latency + self.ports.get_latency(port), api.current_time() + self.ROUTE_TTL) else: if (route_latency < INFINITY): self.table[route_dst] = TableEntry( route_dst, port, route_latency + self.ports.get_latency(port), api.current_time() + self.ROUTE_TTL)
def valid_packet(self, packet, port): new_dist = packet.latency + self.port_to_latency[port]; if self.POISON_MODE: if packet.destination in self.poison_state: self.poison_state.pop(packet.destination) self.send(basics.RoutePacket(packet.destination, INFINITY), port) if packet.destination not in self.host_to_route.keys() \ or self.host_to_route[packet.destination] is None \ or self.host_to_route[packet.destination][0] > new_dist: self.host_to_route[packet.destination] = \ [self.port_to_latency[port] + packet.latency, port, api.current_time()] self.send(basics.RoutePacket(packet.destination, new_dist), port, flood=True) else: if new_dist == self.host_to_route[packet.destination][0]: if self.host_to_route[packet.destination][2] < api.current_time(): self.host_to_route[packet.destination] = \ [new_dist, port, api.current_time()] self.send(basics.RoutePacket( packet.destination, new_dist), port, flood=True) if self.host_to_route[packet.destination][1] == port: # ??? if new_dist > self.host_to_route[packet.destination][0]: self.host_to_route[packet.destination][0] = new_dist self.send(basics.RoutePacket( packet.destination, new_dist), port, flood=True) self.host_to_route[packet.destination][2] = api.current_time()
def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ # check through the routes and see if 15 seconds have passed -> remove route for dest in self.destination_map.keys(): if dest == self: self.destination_map.get(dest)[2] = api.current_time() if self.destination_map.get(dest)[3] == True: self.destination_map.get(dest)[2] = api.current_time() if api.current_time() - self.destination_map.get( dest)[2] >= self.ROUTE_TIMEOUT: del self.destination_map[dest] #send updated routes to neighbors/ poison stuff for port in self.port_latency: for dest in self.destination_map: #if dest is itself, send with latency 0 if self.destination_map.get(dest)[0] == 0: latency = 0 destination = dest rPacket = basics.RoutePacket(destination, latency) self.send(rPacket, port) continue #poison mode if self.POISON_MODE: #same port that the route uses, advertise dist of INFINITY if port == self.destination_map.get(dest)[1]: destination = dest latency = INFINITY rPacket = basics.RoutePacket(destination, latency) self.send(rPacket, port) #different port than the one route uses elif port != self.destination_map.get(dest)[1]: latency = self.destination_map.get(dest)[0] destination = dest rPacket = basics.RoutePacket(destination, latency) self.send(rPacket, port) #not poison mode else: #same port that the route uses, don't advertise route if port == dest[1]: continue #different port than the one route uses elif port != dest[1]: latency = self.destination_map.get(dest)[0] destination = dest rPacket = basics.RoutePacket(destination, latency) self.send(rPacket, port)
def handle_rx(self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ #self.log("RX %s on %s (%s)", packet, port, api.current_time()) if isinstance(packet, basics.RoutePacket): #if host is not in table if packet.destination not in self.table: #add host to table with (link latency + this latency) and current time newLatency = packet.latency + self.portLatency[port] self.table[packet.destination] = (newLatency, port, api.current_time(), port) #flood new host to other switches/routers self.send(basics.RoutePacket(packet.destination, newLatency), port, flood=True) #else try to update vector else: hostVector = self.table[packet.destination] originalLatency = hostVector[0] newLatency = packet.latency + self.portLatency[port] if self.directRoute.has_key(packet.destination) and self.directRoute[packet.destination][0] < originalLatency: #update to direct route if possible self.table[packet.destination] = self.directRoute[packet.destination] elif hostVector[1] == port: #update time if newLatency > originalLatency: #update latency self.table[packet.destination] = (newLatency, hostVector[1], api.current_time(), hostVector[3]) self.send(basics.RoutePacket(packet.destination, newLatency), port, flood=True) else: self.table[packet.destination] = (originalLatency, hostVector[1], api.current_time(), hostVector[3]) elif newLatency <= originalLatency: #update vector with lower latency self.table[packet.destination] = (newLatency, port, api.current_time(), originalLatency) elif isinstance(packet, basics.HostDiscoveryPacket): #add host to table hostVector = (self.portLatency[port], port, None, port) self.table[packet.src] = hostVector self.directRoute[packet.src] = hostVector #send host to other links self.send(basics.RoutePacket(packet.src, hostVector[0]), port, flood=True) else: #forward regular packet isHairpin = packet.src != packet.dst #need to better implement isIntable = packet.dst in self.table if isinstance(packet.dst, api.HostEntity) and isHairpin and isIntable: hostPort = self.table[packet.dst][1] hostLatency = self.table[packet.dst][0] if not hostLatency >= INFINITY: self.send(packet, hostPort)
def handle_rx (self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ #self.log("RX %s on %s (%s)", packet, port, api.current_time()) if isinstance(packet, basics.RoutePacket): dest = packet.destination newLatency = self.neighbours[port] + packet.latency oldLatency = INFINITY if dest in self.routesToDest: oldLatency = self.routesToDest[dest][1] if dest not in self.routesToDest or newLatency <= oldLatency or (dest in self.routesToDest and self.routesToDest[dest][0] == port): self.routesToDest[dest] = (port, newLatency, api.current_time(), False) if dest in self.hosts and self.hosts[dest][1] <= self.routesToDest[dest][1]: self.routesToDest[dest] = self.hosts[dest] if oldLatency != self.routesToDest[dest][1]: newPacket = basics.RoutePacket(dest, self.routesToDest[dest][1]) self.send(newPacket, port, True) elif isinstance(packet, basics.HostDiscoveryPacket): self.routesToDest[packet.src] = (port, self.neighbours[port], api.current_time(), True) self.send(basics.RoutePacket(packet.src, self.neighbours[port]), port, True) self.hosts[packet.src] = (port, self.neighbours[port], api.current_time(), True) else: # Totally wrong behavior for the sake of demonstration only: send # the packet back to where it came from! reciever = packet.dst if reciever in self.routesToDest: latency = self.routesToDest[reciever][1] if latency < INFINITY and self.routesToDest[reciever][0] != port: self.send(packet, self.routesToDest[reciever][0], False) return if reciever in self.hosts: self.routesToDest[reciever] = self.hosts[reciever] latency = self.routesToDest[reciever][1] if latency < INFINITY and self.routesToDest[reciever][0] != port: self.send(packet, self.hosts[reciever][0], False)
def check_times(self): """ Expires all ports whose time last updated is 15 seconds between then and now. """ for destination in self.distanceVectors: distanceVector = self.distanceVectors[destination] for viaEntity in distanceVector: # Don't expire host links or distances to yourself (who cares about that) print(api.current_time()) if not isinstance(viaEntity, basics.BasicHost) and api.current_time() - distanceVector[viaEntity][1] >= 15 and destination != viaEntity: self.set_distance_vectors(destination, viaEntity, INFINITY)
def handle_route_packet(self, packet, port): self.port_table[port][packet.destination] = packet.latency special_send = False if packet.destination in self.forward_table.keys(): if self.output_port_table[packet.destination] == port: starting_latency = self.latency_table[packet.destination] starting_port = self.output_port_table[packet.destination] update_latency = self.links[port] + packet.latency update_port = port for packet_source in self.port_table.keys(): if packet_source != port and packet.destination in self.port_table[packet_source] and self.port_table[packet_source][packet.destination] < INFINITY: if self.links[packet_source] + self.port_table[packet_source][packet.destination] < update_latency: update_latency = self.links[packet_source] + self.port_table[packet_source][packet.destination] update_port = packet_source if update_latency > INFINITY: special_send = True update_latency = INFINITY if not (update_latency == starting_latency and update_port == starting_port): if (update_latency == INFINITY and (self.POISON_MODE or special_send)) or update_latency != INFINITY: #print "send infinity update_latency" self.send(basics.RoutePacket(packet.destination, update_latency), update_port, True) self.forward_table[packet.destination] = True self.latency_table[packet.destination] = update_latency self.output_port_table[packet.destination] = update_port self.time_table[packet.destination] = api.current_time() else: if self.links[port] + packet.latency < self.output_port_table[packet.destination]: self.forward_table[packet.destination] = True self.latency_table[packet.destination] = self.links[port] + packet.latency self.output_port_table[packet.destination] = port self.time_table[packet.destination] = api.current_time() # print "send handle_route packet for no equal ports" self.send(basics.RoutePacket(packet.destination, self.latency_table[packet.destination]), self.output_port_table[packet.destination], True) if self.links[port] + self.latency_table[packet.destination] < packet.latency: del self.port_table[port][packet.destination] else: self.forward_table[packet.destination] = True self.latency_table[packet.destination] = min(INFINITY, self.links[port] + packet.latency) self.output_port_table[packet.destination] = port self.time_table[packet.destination] = api.current_time() #print "send handle_route packet for no in keys" self.send(basics.RoutePacket(packet.destination, self.latency_table[packet.destination]), port, True)
def calc_send(self, cost, port, host): self.routing_tb[host] = self.b_ford(cost, port, host) if cost == INFINITY: if self.POISON_MODE: self.routing_tb[host] = [INFINITY, port, api.current_time()] self.send(basics.RoutePacket(host, cost), port, flood=True) elif host in self.routing_tb: del self.routing_tb[host] else: self.routing_tb[host] = [cost, port, api.current_time()] self.send(basics.RoutePacket(host, cost), port, flood=True)
def check_times(self): """ Expires all ports whose time last updated is 15 seconds between then and now. """ for destination in self.distanceVectors: distanceVector = self.distanceVectors[destination] for viaEntity in distanceVector: # Don't expire host links or distances to yourself (who cares about that) print(api.current_time()) if not isinstance( viaEntity, basics.BasicHost ) and api.current_time() - distanceVector[viaEntity][ 1] >= 15 and destination != viaEntity: self.set_distance_vectors(destination, viaEntity, INFINITY)
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_rx(self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ #self.log("RX %s on %s (%s)", packet, port, api.current_time()) if isinstance(packet, basics.RoutePacket): router = packet.src dst = packet.destination latency = packet.latency self.neighbors[port] = router if not self.dv.has_key(router): self.dv[router] = self.ports_latency[port] self.paths[router] = (port, api.current_time()) if dst == self: return if latency == INFINITY: if self.paths.has_key(dst) and (self.paths[dst][0] == port): del self.paths[dst] self.dv[dst] = INFINITY if (not self.dv.has_key(dst)) or (self.dv[router] + latency <= self.dv[dst]): self.dv[dst] = self.dv[router] + latency self.paths[dst] = (port, api.current_time()) elif isinstance(packet, basics.HostDiscoveryPacket): host = packet.src if self.dv.has_key(host): self.dv[host] = min(self.dv[host], self.ports_latency[port]) else: self.dv[host] = self.ports_latency[port] self.direct_paths[host] = port else: # Totally wrong behavior for the sake of demonstration only: send # the packet back to where it came from! dst = packet.dst if not self.dv.has_key(dst) or self.dv[dst] == INFINITY: return if self.paths.has_key(dst): if port != self.paths[dst][0]: self.send(packet, self.paths[dst][0]) return if self.direct_paths.has_key(dst): if port != self.direct_paths[dst]: self.send(packet, self.direct_paths[dst])
def handle_rx (self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ #self.log("RX %s on %s (self: %s) (src: %s)", packet, port, self, packet.src) if isinstance(packet, basics.RoutePacket): if(packet.latency + self.links[port] < INFINITY): if ((self.DV.get(packet.destination) == None) or (self.DV[packet.destination][0] > packet.latency + self.links[port])): newPacket = basics.RoutePacket(packet.destination, self.links[port] + packet.latency) self.DV[packet.destination] = [newPacket.latency, api.current_time(), port] self.send(newPacket, port, flood=True) if self.POISON_MODE: poison = basics.RoutePacket(packet.destination, INFINITY) self.send(poison, port, flood=False) else: if self.DV[packet.destination][2] == port: self.DV[packet.destination][1] = api.current_time() if packet.latency + self.links[port] > self.DV[packet.destination][0]: self.DV[packet.destination][0] = packet.latency + self.links[port] newPacket = basics.RoutePacket(packet.destination, self.links[port] + packet.latency) self.send(newPacket, port, flood=True) if self.POISON_MODE: poison = basics.RoutePacket(packet.destination, INFINITY) self.send(poison, port, flood=False) if self.poisoned.get(packet.destination) != None and self.POISON_MODE: del self.poisoned[packet.destination] elif packet.latency >= INFINITY and self.POISON_MODE: for x in self.DV.keys(): if (x == packet.destination) and (self.DV[x][2] == port): poison = basics.RoutePacket(packet.destination, INFINITY) self.send(poison, port, flood=True) self.poisoned[x] = self.DV[x] del self.DV[x] elif isinstance(packet, basics.HostDiscoveryPacket): self.DV[packet.src] = [self.links[port], -1, port] route = basics.RoutePacket(packet.src, self.links[port]) self.send(route, port, flood=True) else: # Totally wrong behavior for the sake of demonstration only: send # the packet back to where it came from! if (self.DV.get(packet.dst) != None and self.DV[packet.dst][2] != port): if self.DV[packet.dst][0] <= INFINITY: self.send(packet, self.DV[packet.dst][2], flood=False)
def handle_link_down (self, port): """ Called by the framework when a link attached to this Entity does down. The port number used by the link is passed in. """ del self.links[port] del self.port_table[port] for destination_host in self.host_table.keys(): if self.host_table[destination_host] == port: del self.host_table[destination_host] for destination_host in self.forward_table: if self.output_port_table[destination_host] == port: update_latency = INFINITY update_port = port for packet_source in self.port_table.keys(): if (destination_host in self.port_table[packet_source] and self.port_table[packet_source][destination_host] < INFINITY) and (self.links[packet_source] + self.port_table[packet_source][destination_host] < update_latency and self.links[packet_source] + self.port_table[packet_source][destination_host] < INFINITY): update_latency = self.links[packet_source] + self.port_table[packet_source][destination_host] update_port = packet_source self.forward_table[destination_host] = True self.latency_table[destination_host] = update_latency self.time_table[destination_host] = api.current_time() self.output_port_table = update_port if self.POISON_MODE: #print "sent poison mode link down" self.send(basics.RoutePacket(destination_host, update_latency), update_port, True)
def handle_rx(self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ if isinstance(packet, basics.RoutePacket): self.handle_route_packet(packet, port) return elif isinstance(packet, basics.HostDiscoveryPacket): self.handle_host_discover_packet(packet, port) return else: if not self.NO_LOG: self.log("RX UNKNOWN %s on %s (%s)", packet, port, api.current_time()) host = packet.dst mapping = self.route_map.next_hop(host) if mapping == DESTINATION_NOT_FOUND: self.send(packet, port, flood=True) return next_hop = m_next_hop(mapping) if next_hop != port: self.send(packet, next_hop) elif self.POISON_MODE: # The correct route is sending the packet back to the port # we received it on. We need to poison this route poison_packet = basics.RoutePacket(host, INFINITY) self.send(poison_packet, port)
def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ if self.POISON_MODE: for p_route in self.routing_data.get_poisoned_route_map(): self.send(basics.RoutePacket(p_route, INFINITY), flood=True) for host in self.routing_data.get_host_route_map(): route = self.routing_data.get_route(host) if route: time_diff = api.current_time() - route.get_time() if route.get_time() == -1 or time_diff <= self.ROUTE_TIMEOUT: if self.POISON_MODE: self.send(basics.RoutePacket(host, INFINITY), route.get_port()) self.send(basics.RoutePacket(host, route.get_distance()), route.get_port(), flood=True) else: if self.POISON_MODE: self.send(basics.RoutePacket(host, INFINITY), route.get_port()) self.routing_data.set_poisoned_route(host, route) self.routing_data.null_route(host)
def handle_route_packet(self, packet, port): if not self.NO_LOG: self.log("RX RoutePacket %s on %s (%s)", packet, port, api.current_time()) host = packet.destination latency = packet.latency # Notify the route map of the new route self.route_map.received_route(port, host, latency)
def handle_timer(self): for i in self.routeTable.keys(): if (((api.current_time() - self.routeTable[i][2]) <= self.ROUTE_TIMEOUT) or (self.routeTable[i][2] == -1)): #Checks if a route is expired or not self.send( basics.RoutePacket(i, self.routeTable[i][0]), flood=True) #updates neighbours with distance vector table if self.POISON_MODE == True: self.send(basics.RoutePacket(i, INFINITY), self.routeTable[i][1], flood=False) else: if self.POISON_MODE == True: self.p_reverse[i] = self.routeTable[ i] #populates poisoned reverse dictionary self.send(basics.RoutePacket(i, INFINITY), self.routeTable[i][1], flood=False) del self.routeTable[ i] #deletes route from dictionary if it is expired. if self.POISON_MODE == True: for i in self.p_reverse.keys(): self.send(basics.RoutePacket(i, INFINITY), port=None, flood=True)
def handle_rx (self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ if isinstance(packet, basics.RoutePacket): self.handle_route_packet(packet, port) return elif isinstance(packet, basics.HostDiscoveryPacket): self.handle_host_discover_packet(packet, port) return else: if not self.NO_LOG: self.log("RX UNKNOWN %s on %s (%s)", packet, port, api.current_time()) host = packet.dst mapping = self.route_map.next_hop(host) if mapping == DESTINATION_NOT_FOUND: self.send(packet, port, flood=True) return next_hop = m_next_hop(mapping) if next_hop != port: self.send(packet, next_hop) elif self.POISON_MODE: # The correct route is sending the packet back to the port # we received it on. We need to poison this route poison_packet = basics.RoutePacket(host, INFINITY) self.send(poison_packet, port)
def process_route(self, dest, latency, port, next_hop, time_expires=None): """ Add a new RouteEntry to memory, updating self.table and the cache as necessary. """ latency = min(latency, INFINITY) time_expires = time_expires or api.current_time() + 15 old_D = self.get_D(dest) if old_D != INFINITY: old_next_hop = self.table[dest].next_hop old_port = self.table[dest].port if dest not in self.cache: self.cache[dest] = [ENTRY_UNREACHABLE] # remove entries from same router self.cache[dest] = filter(lambda entry: entry.next_hop != next_hop, self.cache[dest]) self.cache[dest].append(RouteEntry(latency, port, next_hop, time_expires)) self.table[dest] = sorted(self.cache[dest], key=BY_LATENCY)[0] if old_D != self.get_D(dest): self.broadcast_route(dest) elif old_D != INFINITY and old_next_hop != self.table[dest].next_hop: # D is unchanged, but the next_hop has changed. if self.POISON_MODE: poisoned = basics.RoutePacket(dest, INFINITY) self.send(poisoned, self.table[dest].port) unpoison = basics.RoutePacket(dest, latency) self.send(unpoison, old_port)
def handle_host_discover_packet(self, packet, port): if not self.NO_LOG: self.log("RX HostDiscoveryPacket %s on %s (%s)", packet, port, api.current_time()) host = packet.src # Notify the route map of the new host self.route_map.host_discover(host, port)
def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ #will make expire_routes pass. #If time has expired, you remove the entry from the routing table. for key, val in self.routing_table.items(): if val[2] != None: if api.current_time() - val[2] > self.ROUTE_TIMEOUT: if self.POISON_MODE: self.routing_table[key][1] = INFINITY else: del self.routing_table[key] for port in self.link_up: for dest, val_list in self.routing_table.items(): if self.POISON_MODE == True: latency = val_list[1] if val_list[0] == port: latency = INFINITY new_packet = basics.RoutePacket(dest, latency) self.send(new_packet, port, flood=False) else: latency = val_list[1] if val_list[0] != port: new_packet = basics.RoutePacket(dest, latency) self.send(new_packet, port, flood=False)
def update_state(self, root): changed = False best_port = None shortest_latency = INFINITY for route in self.route_destination[root]: if route[2] < shortest_latency: shortest_latency = route[2] best_port = route[1] if best_port == None: return if root not in self.dst_port_lookup or self.dst_port_lookup[ root] != best_port or self.dst_latency_lookup[ root] != shortest_latency: changed = True if changed: if root in self.dst_port_lookup: self.port_list_dst_lookup[self.dst_port_lookup[root]].remove( root) if best_port in self.port_list_dst_lookup: self.port_list_dst_lookup[best_port].append(root) else: self.port_list_dst_lookup[best_port] = [root] self.dst_port_lookup[root] = best_port self.dst_latency_lookup[root] = shortest_latency if changed: self.log( "I am %s and i think the shorest path to %s is on port %s with latency %s (%s)", self.name, root, best_port, shortest_latency, api.current_time()) self.update_neighbors(root, best_port, shortest_latency)
def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ #self.log("handle_timer " + str(len(self.routesToDest))) deleteDests = set() for dest in self.routesToDest: recievedTime = self.routesToDest[dest][2] if api.current_time( ) - recievedTime <= TimeDiff or self.routesToDest[dest][3]: latency = self.routesToDest[dest][1] packet = basics.RoutePacket(dest, latency) port = self.routesToDest[dest][0] self.send(packet, port, True) else: if dest in self.hosts: packet = basics.RoutePacket(dest, self.hosts[dest][1]) self.send(packet, self.hosts[dest][0], True) self.routesToDest[dest] = self.hosts[dest] else: deleteDests.add(dest) self.sendPoison(dest) for dest in deleteDests: del self.routesToDest[dest]
def handle_timer(self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ dead_table = True current_time = api.current_time() for destination in self.table: to_expire = [] for port in self.table[destination]: if current_time - self.table[destination][port][1] > 15: to_expire.append(port) if destination not in self.hosts: for port in to_expire: del (self.table[destination][port]) self.poison(destination, port) for destination in self.table: port = self.best_path(destination) if not (port == None): dead_table = False update_packet = basics.RoutePacket( destination, self.table[destination][port][0]) self.send(update_packet, [port] + self.hosts.values(), flood=True)
def handle_timer (self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ for x in self.DV.keys(): #print x, self.DV[x][2], self.DV[x][0], self if (api.current_time() - self.DV[x][1] ) <= 15 or self.DV[x][1] == -1: route = basics.RoutePacket(x, self.DV[x][0]) self.send(route, self.DV[x][2], flood=True) if self.POISON_MODE: routePoison = basics.RoutePacket(x, INFINITY) self.send(routePoison, self.DV[x][2], flood=False) else: if self.POISON_MODE: routePoison = basics.RoutePacket(x, INFINITY) self.send(routePoison, self.DV[x][2], flood=False) self.poisoned[x] = self.DV[x] del self.DV[x] if self.POISON_MODE: for x in self.poisoned.keys(): poison = basics.RoutePacket(x, INFINITY) self.send(poison, port=None, flood=True)
def handle_link_down(self, port): """ Called by the framework when a link attached to this Entity does down. The port number used by the link is passed in. """ # self.log(" %s (%s)", port, api.current_time()) to_delete = [] del self.portLatency[port] for d in self.neighborHosts.keys(): if self.neighborHosts[d][1] == port: del self.neighborHosts[d] for d in self.routeTablePort: if self.routeTablePort[d] == port: if d in self.neighborHosts: self.routeTableLatency[d] = self.neighborHosts[d][0] self.routeTablePort[d] = self.neighborHosts[d][1] self.routeTableTime[d] = api.current_time() self.send(basics.RoutePacket(d, self.routeTableLatency[d]), port, True) else: to_delete.append(d) self.sendPoison(port, d) self.delete(to_delete)
def handle_link_down(self, port): """ Called by the framework when a link attached to this Entity does down. The port number used by the link is passed in. """ remove_hosts = [] remove_dests = [] for host in self.host_port: if (self.host_port[host] == port): remove_hosts.append(host) for host in remove_hosts: del self.host_port[host] for dest, info in self.router_table.items(): if (port == info[0]): remove_dests.append(dest) # remove routes for dest in remove_dests: del self.router_table[dest] if self.POISON_MODE: self.poison.append(dest) # add default host route self.host_route_default(dest, api.current_time()) del self.port_latency[port]
def handleHostDiscoveryPacket(self, packet, port): # print(self.name , packet.src , self.portLatency[port]) self.neighborHosts[packet.src] = (self.portLatency[port], port) if packet.src not in self.routeTableLatency or self.portLatency[ port] < self.routeTableLatency[packet.src]: self.routeTableLatency[packet.src] = self.portLatency[port] self.routeTablePort[packet.src] = port self.routeTableTime[packet.src] = api.current_time()
def current_time (): """ Returns the current time Appears bananas, but works. """ import sim.api as api return api.current_time()
def handle_link_down (self, port): """ Called by the framework when a link attached to this Entity does down. The port number used by the link is passed in. """ if not self.NO_LOG: self.log("handle_link_down on %s (%s)" % (port, api.current_time())) self.route_map.remove_link(port)
def handle_link_up (self, port, latency): """ Called by the framework when a link attached to this Entity goes up. The port attached to the link and the link latency are passed in. """ if not self.NO_LOG: self.log("handle_link_up on %s (%s)" % (port, api.current_time())) self.route_map.add_link(port, latency)
def _handle_route_packet(self, packet, port): # if api.get_name(self) == "s3": pdb.set_trace() if port not in self.neighbors.keys(): self.neighbors[port] = {} self.neighbors[port][packet.destination] = (packet.latency, port, api.current_time() + 15) if packet.destination in self.vector.keys(): self.recalculate_dest(packet.destination, send_update=True) else: self.set_dest(packet.destination, min(packet.latency + self.ports[port],INFINITY), port, api.current_time() + 15)
def handle_discovery_packet(self, packet, port): self.forward_table[packet.src] = True self.latency_table[packet.destination] = self.links[port] self.output_port_table[packet.destination] = port self.time_table[packet.destination] = api.current_time() self.host_table[packet.src] = port #print "send discovery packet discovery" self.send(basics.RoutePacket(packet.src, self.latency_table[packet.destination]), self.output_port_table[packet.destination], True)
def _get_min_latency(self, latencies): current_time = api.current_time() m_port = None m_latency = INFINITY for port, (latency, timer) in latencies.items(): if timer is not None and current_time - timer > TIMEOUT: del latencies[port] continue if latency < m_latency: m_port = port m_latency = latency return m_port, m_latency
def update(self, dst, port, cost): """ Called by self.handle_rx() when a entry in the table need to be updated. arguments dst - destination port - from which neighbour cost - latency to destination """ self.table[dst] = [port, cost, api.current_time()] p = basics.RoutePacket(dst, cost) self.send(p, port=port, flood=True) if self.POISON_MODE: p = basics.RoutePacket(dst, INFINITY) self.send(p, port=port)
def handle_timer (self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ # weed expired packets for dest in self.cache: old_D = self.get_D(dest) self.cache[dest] = filter(lambda entry: api.current_time() < entry.time_expires, self.cache[dest]) self.table[dest] = sorted(self.cache[dest], key=BY_LATENCY)[0] self.broadcast_all_routes() self.sanity_check() if self.SHOW_TICK: self.log('tick')
def set_distance_vectors(self, destination, viaEntity, distance): """ Sets distanceVector[destination][viaEntity] = distance if the table exists. Creates the table if it doesn't. Also sends out updates where necessary. """ if destination not in self.distanceVectors: self.distanceVectors[destination] = {} previousMinDistance = self.min_distance_to(destination) self.distanceVectors[destination][viaEntity] = [distance, api.current_time()] # print("Setting distance vector from " + str(destination) + " via " + str(viaEntity)) newMinDistance = self.min_distance_to(destination) # If the routing table changes, we want to send out the corresponding updates if previousMinDistance != newMinDistance: # print("Self: " + str(self) + "Destination: " + str(destination) + "; viaEntity: " + str(viaEntity) + str(previousMinDistance) + " is now " + str(newMinDistance)) if self.POISON_MODE or not self.is_infinity(newMinDistance): self.send_packet_to_all_valid_neighbors(basics.RoutePacket(destination, newMinDistance))
def check_expiration(self): time = api.current_time() for n in self.neighbors.keys(): for dest in self.neighbors[n].keys(): l, p, t = self.neighbors[n][dest] if t < time: if self.POISON_MODE: self.neighbors[n][dest] = (INFINITY, p, t) else: del self.neighbors[n][dest] for dest in self.vector.keys(): l, p, t = self.vector[dest] if t < time: # print api.get_name(self) + ' said that rout to '+ api.get_name(dest) + str(self.vector[dest]) +'is expired' if self.POISON_MODE: self.vector[dest] = (INFINITY, p, t) else: del self.vector[dest]
def handle_timer (self): """ Called periodically. When called, your router should send tables to port_table. It also might not be a bad place to check for whether any entries have expired. """ current_time = api.current_time() for destination_host in self.forward_table.keys(): if not destination_host in self.host_table: if current_time - self.time_table[packet.destination] >= EXPIRED or self.latency_table[packet.destination] >= INFINITY: if self.output_port_table[packet.destination] in self.port_table: del self.port_table[self.output_port_table[packet.destination]][destination_host] del self.forward_table[destination_host] del self.latency_table[destination_host] del self.output_port_table[destination_host] del self.time_table[desitnation_host] for destination_host in self.forward_table.keys(): if (self.latency_table[destination_host] == INFINITY and self.POISON_MODE) or self.latency_table[destination_host] != INFINITY: self.send(basics.RoutePacket(item, self.latency_table[destination_host]), self.output_port_table[destination_host], True)
def handle_timer (self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ # check if any entry expire. expiredEntries = [] for dst in self.table: # leave the entry of host unchanged if self.table[dst][0] not in self.hosts and api.current_time() - self.table[dst][2] >= 15: expiredEntries.append(dst) for dst in expiredEntries: del self.table[dst] if self.POISON_MODE: p = basics.RoutePacket(dst, INFINITY) self.send(p, flood=True) # send table to neighbours. for dst in self.table: p = basics.RoutePacket(dst, self.table[dst][1]) self.send(p, port=self.table[dst][0], flood=True)
def handle_rx(self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ #self.log("RX %s on %s (%s)", packet, port, api.current_time()) if isinstance(packet, basics.RoutePacket): if self.route_table.get(packet.destination) is None: self.route_table[packet.destination] = {} latency = self.port_latency[port] + packet.latency if latency >= INFINITY: if port in self.route_table[packet.destination]: del self.route_table[packet.destination][port] self._forward_route(packet.destination) else: self.route_table[packet.destination][port] =\ (latency, api.current_time()) self._forward_route(packet.destination) elif isinstance(packet, basics.HostDiscoveryPacket): if self.route_table.get(packet.src) is None: self.route_table[packet.src] = {} self.route_table[packet.src][ port] = (self.port_latency[port], None) self._forward_route(packet.src) else: # Totally wrong behavior for the sake of demonstration only: send # the packet back to where it came from! out_port, _ = self._get_min_latency( self.route_table.get(packet.dst, {})) if out_port is None: self.send(packet, port, flood=True) else: self.send(packet, out_port)
def handle_timer (self): """ Called periodically. When called, your router should send tables to neighbors. It also might not be a bad place to check for whether any entries have expired. """ dead_table = True; current_time = api.current_time() for destination in self.table: to_expire = [] for port in self.table[destination]: if current_time - self.table[destination][port][1] > 15: to_expire.append(port) if destination not in self.hosts: for port in to_expire: del(self.table[destination][port]) self.poison(destination,port) for destination in self.table: port = self.best_path(destination); if not(port == None): dead_table = False; update_packet = basics.RoutePacket(destination, self.table[destination][port][0]) self.send(update_packet, [port] + self.hosts.values(), flood=True)
def handle_rx (self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ #self.log("RX %s on %s (%s)", packet, port, api.current_time()) if isinstance(packet, basics.RoutePacket): dst = packet.destination cost = packet.latency + self.neighbour[port] if packet.latency == INFINITY and self.POISON_MODE: if dst in self.table and self.table[dst][0] == port: del self.table[dst] p = basics.RoutePacket(dst, INFINITY) self.send(p, flood=True) elif dst not in self.table or cost < self.table[dst][1]: self.update(dst, port, cost) # trust neighbour elif port == self.table[dst][0] and cost > self.table[dst][1]: self.update(dst, port, cost) elif port == self.table[dst][0] and cost == self.table[dst][1]: self.table[dst][2] = api.current_time() elif isinstance(packet, basics.HostDiscoveryPacket): self.hosts.append(port) dst = packet.src cost = self.neighbour[port] self.update(dst, port, cost) else: dst = packet.dst if dst in self.table and not self.table[dst][1] == INFINITY and self.table[dst][0] != port: self.send(packet, self.table[packet.dst][0])
def handle_rx (self, packet, port): """ Called by the framework when this Entity receives a packet. packet is a Packet (or subclass). port is the port number it arrived on. You definitely want to fill this in. """ self.log("RX %s on %s (%s)", packet, port, api.current_time()) if isinstance(packet, basics.RoutePacket): if packet.destination in self.table: #either too big or poisoned. #possibly no port created. if self.infinity(packet.latency, port): if port not in self.table[packet.destination]: return self.poison(packet.destination,port) del(self.table[packet.destination][port]) best_port = self.best_path(packet.destination); if(best_port != None): actual_latency = self.get_latency(packet.destination,best_port) update_packet = basics.RoutePacket(packet.destination, actual_latency) self.send(update_packet,[best_port] + self.hosts.values(), flood = True) else: #poison reverse if no proper backup update_packet = basics.RoutePacket(packet.destination, INFINITY) self.send(update_packet, port, flood = False) return same_port = False old_best_port = self.best_path(packet.destination) if( port in self.table[packet.destination]): old_latency = self.table[packet.destination][port][0] new_latency = packet.latency + self.neighbors[port]; self.table[packet.destination][port][0] = new_latency; self.table[packet.destination][port][1] = api.current_time() best_port = self.best_path(packet.destination); #replace if New optimal port or latency change on own port where it either stays the best option or becomes it. if((best_port != old_best_port) or (port == best_port and old_latency!=new_latency)): actual_latency = self.get_latency(packet.destination,best_port) update_packet = basics.RoutePacket(packet.destination, actual_latency) self.send(update_packet,[best_port] + self.hosts.values(), flood = True) else: new_latency = packet.latency + self.neighbors[port]; self.table[packet.destination][port] = [new_latency] + [api.current_time()]; best_port = self.best_path(packet.destination); actual_latency = self.table[packet.destination][best_port][0] update_packet = basics.RoutePacket(packet.destination, actual_latency) self.send(update_packet,[best_port] + self.hosts.values(), flood = True) else: # if not in the table, update a dictionary mapping time_rx = api.current_time() actual_latency = packet.latency + self.neighbors[port] if not self.infinity(packet.latency,port): self.table[packet.destination] = {port: [actual_latency,time_rx]} update_packet = basics.RoutePacket(packet.destination,actual_latency); self.send(update_packet,[port] + self.hosts.values(),flood=True); elif isinstance(packet, basics.HostDiscoveryPacket): if(packet.src in self.table): self.table[packet.src][port] = [self.neighbors[port]] + [api.current_time()] else: self.table[packet.src] = {port: [self.neighbors[port]] + [api.current_time()]} self.hosts[packet.src] = port if(self.neighbors[port]>=INFINITY): pass update_packet = basics.RoutePacket(packet.src, self.neighbors[port]); self.send(update_packet, [port] + self.hosts.values(), flood = True); else: if packet.dst in self.table: best_port = self.best_path(packet.dst) #If hairpinning if port == best_port: return self.send(packet, best_port) else: pass
def m_expired(mapping): time = m_time(mapping) return api.current_time() - time > TIME_TO_REMEMBER_ROUTE
def m_update_time(mapping): mapping[kTime] = api.current_time()
def m_mapping(distance, next_hop): return { kDistance : distance, kNextHop : next_hop, kTime : api.current_time(), }