def cli_summary_attributes(self): if self.dest_type == DEST_TYPE_NODE: destination_str = utils.system_id_str(self.system_id) if self.name: destination_str += " (" + self.name + ")" elif self.dest_type == DEST_TYPE_PREFIX: destination_str = packet_common.ip_prefix_str(self.prefix) elif self.dest_type == DEST_TYPE_POS_DISAGG_PREFIX or \ self.dest_type == DEST_TYPE_NEG_DISAGG_PREFIX: destination_str = packet_common.ip_prefix_str(self.prefix) + " (Disagg)" else: assert False if self.tags: tags_str = list(self.tags) else: tags_str = "" if self.positively_disaggregate: disaggregate_str = 'Positive' elif self.negatively_disaggregate: disaggregate_str = 'Negative' else: disaggregate_str = '' return [ destination_str, self.cost, sorted(self.predecessors), tags_str, disaggregate_str, [str(next_hop) for next_hop in sorted(self.ipv4_next_hops)], [str(next_hop) for next_hop in sorted(self.ipv6_next_hops)] ]
def put_route(self, rte): """ Add a RibRoute object to the Destination object associated to the prefix. :param rte: (RibRoute) the object to add to the Destination associated to the prefix :return: """ packet_common.assert_prefix_address_family(rte.prefix, self.address_family) rte.stale = False self.debug("Put %s", rte) # If there is no Destination object for the prefix, create a new Destination object # for the given prefix and insert it in the Trie prefix = packet_common.ip_prefix_str(rte.prefix) if not self.destinations.has_key(prefix): prefix_destination = _Destination(self, rte.prefix) self.destinations.insert(prefix, prefix_destination) else: prefix_destination = self.destinations.get(prefix) # Insert desired route in destination object best_changed = prefix_destination.put_route(rte) # Get children prefixes before performing actions on the prefix # (it can be deleted from the Trie) children_prefixes = self.destinations.children( packet_common.ip_prefix_str(prefix_destination.prefix)) # If best route changed in Destination object if best_changed: # Update prefix in the fib self.fib.put_route(prefix_destination.best_route) # Try to delete superfluous children if not self._delete_superfluous_children(prefix_destination, children_prefixes): # If children have not been deleted, update them self._update_prefix_children(children_prefixes)
def all_prefix_routes(self, prefix): assert_prefix_address_family(prefix, self.address_family) prefix_str = ip_prefix_str(prefix) if self.destinations.has_key(prefix_str): destination = self.destinations[prefix_str] for rib_route in destination.rib_routes: yield rib_route
def update_fib(self, prefix, child_prefix_strs): # The child_prefix_strs have to be passed as a parameter, because they need to be collected # before the parent is potentially deleted by the calling function. # Locate the best RIB route for the prefix (None if there is no RIB route for the prefix). prefix_str = ip_prefix_str(prefix) if self.destinations.has_key(prefix_str): destination = self.destinations.get(prefix_str) rib_route = destination.best_route() else: rib_route = None # Determine the next-hops for the corresponding FIB route. If the next-hops is an empty # list [] it means it is a discard route. If the next-hops is None it means there should not # be a FIB route. if rib_route: fib_next_hops = rib_route.compute_fib_next_hops() else: fib_next_hops = None # Update the FIB route accordingly. if fib_next_hops is not None: fib_route = FibRoute(prefix, fib_next_hops) self.fib.put_route(fib_route) else: self.fib.del_route(prefix) # Recursively update the FIB for all child routes: their negative next-hops, if any, may # have to be recomputed if a parent route changed. for child_prefix_str in child_prefix_strs: child_destination = self.destinations[child_prefix_str] child_rib_route = child_destination.best_route() child_prefix = child_rib_route.prefix grand_child_prefix_strs = self.destinations.children( child_prefix_str) self.update_fib(child_prefix, grand_child_prefix_strs)
def cli_summary_attributes(self): return [ packet_common.ip_prefix_str(self.prefix), constants.owner_str(self.owner), list(map(lambda x: str(x[0]) if x[1] else "~%s" % str(x[0]), self._get_nexthops_sorted())) ]
def __str__(self): all_next_hops = self._get_nexthops_sorted() return "%s: %s -> %s" % (constants.owner_str(self.owner), packet_common.ip_prefix_str(self.prefix), ", ".join( map(lambda x: str(x[0]) if x[1] else "~%s" % str(x[0]), all_next_hops)))
def get_route(self, rte_prefix, owner): packet_common.assert_prefix_address_family(rte_prefix, self.address_family) prefix = packet_common.ip_prefix_str(rte_prefix) if self.destinations.has_key(prefix): return self.destinations.get(prefix).get_route(owner) else: return None
def all_prefix_routes(self, rte_prefix): packet_common.assert_prefix_address_family(rte_prefix, self.address_family) prefix = packet_common.ip_prefix_str(rte_prefix) if self.destinations.has_key(prefix): destination = self.destinations[prefix] for rte in destination.routes: yield rte
def cli_summary_attributes(self): if self.is_discard_route(): return [ packet_common.ip_prefix_str(self.prefix), "Discard", "", "", "" ] nhops = sorted(self.next_hops) types = ["Positive" for _ in nhops] interfaces = [ nh.interface if nh.interface is not None else "" for nh in nhops ] addresses = [ nh.address if nh.address is not None else "" for nh in nhops ] weights = [nh.weight if nh.weight is not None else "" for nh in nhops] return [ packet_common.ip_prefix_str(self.prefix), types, interfaces, addresses, weights ]
def parent_prefix_dest(self): """ :return: the Destination object associated to the parent prefix of the current one """ parent_prefix = self.rib.destinations.parent(packet_common.ip_prefix_str(self.prefix)) if parent_prefix is None: return None return self.rib.destinations.get(parent_prefix)
def put_route(self, rib_route): assert_prefix_address_family(rib_route.prefix, self.address_family) rib_route.stale = False self.debug("Put %s", rib_route) prefix = rib_route.prefix prefix_str = ip_prefix_str(prefix) if not self.destinations.has_key(prefix_str): destination = Destination(self, prefix) self.destinations.insert(prefix_str, destination) else: destination = self.destinations.get(prefix_str) best_changed = destination.put_route(rib_route) if best_changed: child_prefix_strs = self.destinations.children(prefix_str) self.update_fib(prefix, child_prefix_strs)
def cli_summary_attributes(self): if self.dest_type == DEST_TYPE_NODE: destination_str = utils.system_id_str(self.system_id) if self.name: destination_str += " (" + self.name + ")" else: destination_str = packet_common.ip_prefix_str(self.prefix) if self.tags: tags_str = list(self.tags) else: tags_str = "" return [ destination_str, self.cost, sorted(self.predecessors), tags_str, [str(next_hop) for next_hop in sorted(self.next_hops)] ]
def cli_route_prefix_table(self, table_nr, prefix): prefix_str = packet_common.ip_prefix_str(prefix) route = None for rte in self.ipr.get_routes(): route_table_nr = rte.get_attr('RTA_TABLE') dst_prefix_str = self.kernel_route_dst_prefix_str(rte) if (table_nr == route_table_nr) and (dst_prefix_str == prefix_str): route = rte break if route is None: return None links = self.ipr.get_links() tab = table.Table(separators=False) next_hops = self.kernel_route_nhops(route, links) next_hops_cell = [] for nhop in next_hops: next_hop_str = str(nhop[0]) + " " + str(nhop[1]) + " " + str( nhop[2]) next_hops_cell.append(next_hop_str) tab.add_row(["Table", self.table_nr_to_name(table_nr)]) tab.add_row( ["Address Family", self.af_str(self.af_str(route["family"]))]) tab.add_row(["Destination", prefix_str]) tab.add_row(["Type", self.route_type_str(route["type"])]) tab.add_row(["Protocol", self.proto_str(route["proto"])]) tab.add_row(["Scope", self.scope_str(route["scope"])]) tab.add_row(["Next-hops", next_hops_cell]) tab.add_row(["Priority", self.to_str(route.get_attr('RTA_PRIORITY'))]) tab.add_row(["Preference", self.to_str(route.get_attr('RTA_PREF'))]) tab.add_row([ "Preferred Source Address", self.to_str(route.get_attr('RTA_PREFSRC')) ]) tab.add_row(["Source", self.kernel_route_src_prefix_str(route)]) tab.add_row(["Flow", self.to_str(route.get_attr('RTA_FLOW'))]) tab.add_row([ "Encapsulation Type", self.to_str(route.get_attr('RTA_ENCAP_TYPE')) ]) tab.add_row( ["Encapsulation", self.to_str(route.get_attr('RTA_ENCAP'))]) tab.add_row(["Metrics", self.to_str(route.get_attr('RTA_METRICS'))]) tab.add_row(["Type of Service", route["tos"]]) tab.add_row(["Flags", route["flags"]]) return tab
def del_route(self, prefix): if not self.platform_supported: return False if self._table_nr == -1: return False dst = packet_common.ip_prefix_str(prefix) try: self.ipr.route('del', table=self._table_nr, dst=dst, proto=RTPROT_RIFT) except pyroute2.netlink.exceptions.NetlinkError as err: if err.code != errno.ESRCH: # It is not an error to delete a non-existing route self.error("Netlink error \"%s\" deleting route to %s", err, dst) return False except OSError as err: self.error("OS error \"%s\" deleting route to %s", err, dst) return False else: self.debug("Delete route to %s", prefix) return True
def del_route(self, rte_prefix, owner): """ Delete given prefix and owner RibRoute object. If no more RibRoute objects are available, also delete Destination from trie and from the FIB. :param rte_prefix: (string) prefix to delete :param owner: (int) owner of the prefix :return: (boolean) if the route has been deleted or not """ packet_common.assert_prefix_address_family(rte_prefix, self.address_family) destination_deleted = False best_changed = False children_prefixes = None prefix = packet_common.ip_prefix_str(rte_prefix) # Check if the prefix is stored in the trie if self.destinations.has_key(prefix): # Get children prefixes before performing actions on the prefix # (it can be deleted from the Trie) children_prefixes = self.destinations.children(prefix) destination = self.destinations.get(prefix) # Delete route from the Destination object deleted, best_changed = destination.del_route(owner) # Route was not present in Destination object, nothing to do if deleted: self.debug("Delete %s", prefix) else: self.debug("Attempted delete %s (not present)", prefix) return deleted if not destination.routes: # No more routes available for current prefix, delete it from trie and FIB self.destinations.delete(prefix) self.fib.del_route(rte_prefix) destination_deleted = True elif best_changed: # Best route changed, push it in the FIB self.fib.put_route(destination.best_route) else: deleted = False if deleted and (best_changed or destination_deleted): # If route has been deleted and an event occurred # (best changed or destination deleted), update children self._update_prefix_children(children_prefixes) return deleted
def put_route(self, rte): if not self.platform_supported or self._simulated_interfaces: return False if self._table_nr == -1: return False dst = packet_common.ip_prefix_str(rte.prefix) # No next hops means that the route is unreachable. if not rte.next_hops: kernel_args = {"type": "unreachable"} elif len(rte.next_hops) == 1: nhop = rte.next_hops[0] kernel_args = self.nhop_to_kernel_args(nhop, dst) if kernel_args == {}: self.del_route(rte.prefix) return False else: kernel_args = {"multipath": []} for nhop in rte.next_hops: nhop_args = self.nhop_to_kernel_args(nhop, dst) if nhop_args: kernel_args["multipath"].append(nhop_args) if kernel_args["multipath"] == []: self.del_route(rte.prefix) return False try: self.ipr.route('replace', table=self._table_nr, dst=dst, proto=RTPROT_RIFT, priority=RTPRIORITY_RIFT, **kernel_args) except pyroute2.netlink.exceptions.NetlinkError as err: self.error("Netlink error %s replacing route to %s: %s", err, dst, kernel_args) return False except OSError as err: self.error("OS error \"%s\" replacing route to %s: %s", err, dst, kernel_args) return False else: self.debug("Replace route to \"%s\": %s", dst, kernel_args) return True
def del_route(self, prefix, owner): assert_prefix_address_family(prefix, self.address_family) prefix_str = ip_prefix_str(prefix) if self.destinations.has_key(prefix_str): destination = self.destinations.get(prefix_str) child_prefix_strs = self.destinations.children(prefix_str) deleted, best_changed = destination.del_route(owner) # If that was the last route for the destination, delete the destination itself if not destination.rib_routes: del self.destinations[prefix_str] else: deleted = False best_changed = False if deleted: self.debug("Delete %s", prefix) else: self.debug("Attempted delete %s (not present)", prefix) if best_changed: self.update_fib(prefix, child_prefix_strs) return deleted
def __str__(self): sorted_next_hops = sorted([str(next_hop) for next_hop in self.next_hops]) return "%s -> %s" % (packet_common.ip_prefix_str(self.prefix), ", ".join(sorted_next_hops))
def __repr__(self): next_hops_str = ", ".join( [str(next_hop) for next_hop in sorted(self.next_hops)]) return "%s -> %s" % (packet_common.ip_prefix_str( self.prefix), next_hops_str)
def get_route(self, prefix, owner): assert_prefix_address_family(prefix, self.address_family) prefix = ip_prefix_str(prefix) if self.destinations.has_key(prefix): return self.destinations.get(prefix).get_route(owner) return None
def cli_summary_attributes(self): return [ packet_common.ip_prefix_str(self.prefix), [str(next_hop) for next_hop in self.next_hops] ]
def __str__(self): return ("route to " + packet_common.ip_prefix_str(self.prefix) + " via " + ", ".join(str(nhop) for nhop in self.next_hops) + " owned by " + constants.owner_str(self.owner))
def parent_destination(self): parent_prefix = self.rib.destinations.parent( packet_common.ip_prefix_str(self.prefix)) if parent_prefix is None: return None return self.rib.destinations.get(parent_prefix)
def cli_summary_attributes(self): return [ packet_common.ip_prefix_str(self.prefix), constants.owner_str(self.owner), [str(next_hop) for next_hop in sorted(self.next_hops)] ]
def __repr__(self): next_hops_str = ", ".join( [str(next_hop) for next_hop in sorted(self.next_hops)]) return "%s: %s -> %s" % (owner_str( self.owner), ip_prefix_str(self.prefix), next_hops_str)