class Rib: def __init__(self, fib): self._fib = fib # 1. The real production code for the RIB (but not the FIB) needs Destination objects and # Route objects to support multiple routes to the same destination (prefix): one per owner # (e.g. south-SPF and north-SPF). This prototype only supports a single route per # destination (prefix) to keep things simple and avoid distracting attention from the # negative disaggregation algorithm. # 2. The PyTricia code takes prefixes as strings. Not sure if this is the best choice # for production code. I suspect it is better to accept prefixes as Prefix objects that # have an internal binary representation. self._routes = PyTricia() def put_route(self, prefix, positive_nexthops, negative_nexthops=None): # Put the route in the RIB. if negative_nexthops is None: negative_nexthops = [] route = RibRoute(prefix, positive_nexthops, negative_nexthops) self._routes[prefix] = route # Gather the entire subtree of prefixes (children, grandchildren, ...) below the given # prefix (including the prefix itself). We rely on the fact that PyTricia.children always # returns parent aggregate routes before child more specific routes (although the PyTricia # documentation doesn't guarantee this). subtree_prefixes = [prefix] + self._routes.children(prefix) # Recompute the computed nexthops of child routes in the subtree and update the FIB # accordingly. self._recompute_subtree_nexthops(subtree_prefixes) def del_route(self, prefix): # If the route is not present in the RIB (this is legal), we have nothing to do. if not self._routes.has_key(prefix): return # Gather the entire subtree of prefixes (children, grandchildren, ...) below the given # prefix (excluding the prefix itself). We rely on the fact that PyTricia.children always # returns parent aggregate routes before child more specific routes (although the PyTricia # documentation doesn't guarantee this). subtree_prefixes = self._routes.children(prefix) # Delete the route from the RIB. del self._routes[prefix] # Delete corresponding route from the FIB. self._fib.del_route(prefix) # Recompute the computed nexthops of child routes in the subtree and update the FIB # accordingly. self._recompute_subtree_nexthops(subtree_prefixes) def get_route(self, prefix): if self._routes.has_key(prefix): return self._routes[prefix] return None def __str__(self): rep_str = "" for prefix in self._routes: rep_str += f"{self._routes[prefix]}\n" return rep_str def _recompute_subtree_nexthops(self, subtree_prefixes): for prefix in subtree_prefixes: route = self._routes[prefix] self._recompute_route_nexthops(route) self._fib.put_route(prefix, route.computed_nexthops) def _recompute_route_nexthops(self, route): # If the route does not have any negative nexthops, there is no disaggregation to be done. if not route.negative_nexthops: route.set_computed_nexthops(route.positive_nexthops) return # If the route does not have a parent route, there is no disaggregation to be done. parent_prefix = self._routes.parent(route.prefix) if parent_prefix is None: route.set_computed_nexthops(route.positive_nexthops) return # Compute the complementary nexthops of the negative nexthops. parent_route = self._routes[parent_prefix] complementary_nexthops = parent_route.computed_nexthops.difference( route.negative_nexthops) # Combine the complementary nexthops with the positive nexthops. computed_nexthops = route.positive_nexthops.union( complementary_nexthops) # Store the computed nexthops in the route route.set_computed_nexthops(computed_nexthops)