def process_request(self): req = self._prefix_mgr_server_socket.recv_thrift_obj( prefix_mgr_types.PrefixManagerRequest) if req.cmd == prefix_mgr_types.PrefixManagerCommand.ADD_PREFIXES: for prefix_entry in req.prefixes: self._prefix_map[sprint_prefix( prefix_entry.prefix)] = prefix_entry self._prefix_mgr_server_socket.send_thrift_obj( prefix_mgr_types.PrefixManagerResponse(success=True)) if req.cmd == prefix_mgr_types.PrefixManagerCommand.WITHDRAW_PREFIXES: success = False for prefix_entry in req.prefixes: prefix_str = sprint_prefix(prefix_entry.prefix) if prefix_str in self._prefix_map: del self._prefix_map[prefix_str] success = True self._prefix_mgr_server_socket.send_thrift_obj( prefix_mgr_types.PrefixManagerResponse(success=success)) if req.cmd == prefix_mgr_types.PrefixManagerCommand.GET_ALL_PREFIXES: resp = prefix_mgr_types.PrefixManagerResponse() resp.prefixes = self._prefix_map.values() resp.success = True self._prefix_mgr_server_socket.send_thrift_obj(resp)
def _parse(loopback_set, prefix_db): for prefix_entry in prefix_db.prefixEntries: # Only consider v6 address if len(prefix_entry.prefix.prefixAddress.addr) != 16: continue # Parse PrefixAllocator address if prefix_entry.type == lsdb_types.PrefixType.PREFIX_ALLOCATOR: prefix = utils.sprint_prefix(prefix_entry.prefix) if prefix_entry.prefix.prefixLength == 128: prefix = prefix.split('/')[0] else: # TODO: we should ideally get address with last bit # set to 1. `python3.6 ipaddress` libraries does this # in one line. Alas no easy options with ipaddr # NOTE: In our current usecase we are just assuming # that allocated prefix has last 16 bits set to 0 prefix = prefix.split('/')[0] + '1' loopback_set.add(prefix) continue # Parse LOOPBACK address if prefix_entry.type == lsdb_types.PrefixType.LOOPBACK: prefix = utils.sprint_prefix(prefix_entry.prefix) loopback_set.add(prefix.split('/')[0]) continue
def __init__(self, zmq_ctx, url): self._prefix_mgr_server_socket = socket.Socket(zmq_ctx, zmq.REP) self._prefix_mgr_server_socket.bind(url) self._prefix_map = { sprint_prefix(prefix_entry1.prefix): prefix_entry1, sprint_prefix(prefix_entry2.prefix): prefix_entry2, sprint_prefix(prefix_entry3.prefix): prefix_entry3 }
def get_nexthop_nodes(self, route_db, dst_addr, cur_lpm_len, if2node, fib_routes, in_fib): ''' get the next hop nodes. if the longest prefix is coming from the current node, return an empty list to terminate the path searching. ''' next_hop_nodes = [] is_initialized = fib_routes[route_db.thisNodeName] lpm_route = self.get_lpm_route(route_db, dst_addr) if lpm_route and lpm_route.prefix.prefixLength >= cur_lpm_len: if in_fib and not is_initialized: fib_routes[route_db.thisNodeName].extend( self.get_fib_path( route_db.thisNodeName, utils.sprint_prefix(lpm_route.prefix), self.fib_agent_port, self.timeout)) min_cost = min([p.metric for p in lpm_route.paths]) for path in [p for p in lpm_route.paths if p.metric == min_cost]: if len(path.nextHop.addr) == 16: nh_addr = utils.sprint_addr(path.nextHop.addr) next_hop_node_name = \ if2node[route_db.thisNodeName][(path.ifName, nh_addr)] next_hop_nodes.append([ next_hop_node_name, path.ifName, path.metric, nh_addr, ]) return next_hop_nodes
def get_nexthop_nodes(self, route_db, dst_addr, cur_lpm_len, if2node, fib_routes, in_fib): ''' get the next hop nodes. if the longest prefix is coming from the current node, return an empty list to terminate the path searching. ''' next_hop_nodes = [] is_initialized = fib_routes[route_db.thisNodeName] for lpm_route in self.get_lpm_routes(route_db, dst_addr): if lpm_route.prefix.prefixLength <= cur_lpm_len: continue if in_fib and not is_initialized: fib_routes[route_db.thisNodeName].extend( self.get_fib_path(route_db.thisNodeName, utils.sprint_prefix(lpm_route.prefix), self.fib_agent_port, self.timeout)) for path in lpm_route.paths: if len(path.nextHop.addr) == 16: next_hop_node_name = if2node[route_db.thisNodeName][ path.ifName] next_hop_nodes.append([ next_hop_node_name, path.ifName, path.metric, utils.sprint_addr(path.nextHop.addr) ]) return next_hop_nodes
def get_lpm_route(self, route_db, dst_addr): ''' find the routes to the longest prefix matches of dst. ''' max_prefix_len = -1 lpm_route = None for route in route_db.routes: if IPNetwork(utils.sprint_prefix(route.prefix)).Contains( IPAddress(dst_addr)): next_hop_prefix_len = route.prefix.prefixLength if next_hop_prefix_len == max_prefix_len: raise Exception('Duplicate prefix found in routing table {}' .format(utils.sprint_prefix(route.prefix))) elif next_hop_prefix_len > max_prefix_len: lpm_route = route max_prefix_len = next_hop_prefix_len return lpm_route
def run(self): resp = self.client.view_prefix() rows = [] for prefix_entry in resp.prefixes: prefix_str = utils.sprint_prefix(prefix_entry.prefix) prefix_type = utils.sprint_prefix_type(prefix_entry.type) rows.append((prefix_type, prefix_str)) print('\n', printing.render_horizontal_table(rows, ['Type', 'Prefix'])) print()
def _parse_nodes(rows, value): prefix_db = deserialize_thrift_object(value.value, lsdb_types.PrefixDatabase) marker = '* ' if prefix_db.thisNodeName == host_id else '> ' row = ["{}{}".format(marker, prefix_db.thisNodeName)] loopback_prefixes = [p.prefix for p in prefix_db.prefixEntries \ if p.type == lsdb_types.PrefixType.LOOPBACK] row.extend([utils.sprint_prefix(p) for p in loopback_prefixes]) rows.append(row)
def print_routes(caption, routes): route_strs = [] for route in routes: dest = utils.sprint_prefix(route.dest) paths_str = '\n'.join( ["via {}".format(ip_nexthop_to_str(nh)) for nh in route.nexthops]) route_strs.append((dest, paths_str)) print(printing.render_vertical_table(route_strs, caption=caption))
def _parse_nodes(rows, value): prefix_db = serializer.deserialize_thrift_object( value.value, lsdb_types.PrefixDatabase) marker = '* ' if prefix_db.thisNodeName == host_id else '> ' row = ["{}{}".format(marker, prefix_db.thisNodeName)] loopback_prefixes = [ p.prefix for p in prefix_db.prefixEntries if p.type == lsdb_types.PrefixType.LOOPBACK ] loopback_prefixes.sort(key=lambda x: len(x.prefixAddress.addr), reverse=True) row.extend([utils.sprint_prefix(p) for p in loopback_prefixes]) rows.append(row)
def get_fib_path(self, src, dst_prefix, fib_agent_port, timeout): src_addr = self.get_loopback_addr(src) if src_addr is None: return [] try: client = utils.get_fib_agent_client( src_addr, fib_agent_port, timeout) routes = client.getRouteTableByClient(client.client_id) except Exception: return [] for route in routes: if utils.sprint_prefix(route.dest) == dst_prefix: return route.nexthops return []
def get_fib_path(self, src, dst_prefix, fib_agent_port, timeout): try: client = utils.get_fib_agent_client(src, fib_agent_port, timeout) routes = client.getRouteTableByClient(client.client_id) except Exception: try: client = utils.get_fib_agent_client(src, fib_agent_port, timeout) routes = client.getRouteTableByClient(client.client_id) except Exception: return [] for route in routes: if utils.sprint_prefix(route.dest) == dst_prefix: return route.nexthops return []
def get_lpm_routes(self, route_db, dst_addr): ''' find the routes to the longest prefix matches of dst. ''' max_prefix_len = 0 lpm_routes = [] for route in route_db.routes: if IPNetwork(utils.sprint_prefix(route.prefix)).Contains( IPAddress(dst_addr)): next_hop_prefix_len = route.prefix.prefixLength if next_hop_prefix_len == max_prefix_len: lpm_routes.append(route) elif next_hop_prefix_len > max_prefix_len: lpm_routes = [route] max_prefix_len = next_hop_prefix_len return lpm_routes
def print_routes(caption, routes, prefixes=None): networks = None if prefixes: networks = [ipaddr.IPNetwork(p) for p in prefixes] route_strs = [] for route in routes: dest = utils.sprint_prefix(route.dest) if not utils.contain_any_prefix(dest, networks): continue paths_str = '\n'.join( ["via {}".format(ip_nexthop_to_str(nh)) for nh in route.nexthops]) route_strs.append((dest, paths_str)) print(printing.render_vertical_table(route_strs, caption=caption))
def get_route_as_dict(routes): ''' Convert a routeDb into a dict representing routes in str format :param routes: list ip_types.UnicastRoute (structured routes) :returns: dict of routes (prefix : [nexthops] :rtype: dict ''' # Thrift object instances do not have hash support # Make custom stringified object so we can hash and diff # dict of prefixes(str) : nexthops(str) routes_dict = { utils.sprint_prefix(route.dest): sorted([ip_nexthop_to_str(nh) for nh in route.nexthops]) for route in routes } return routes_dict
def _parse(prefix_set, prefix_db): for prefix_entry in prefix_db.prefixEntries: if len(prefix_entry.prefix.prefixAddress.addr) == 16: prefix_set.add(utils.sprint_prefix(prefix_entry.prefix))
def _parse(loopback_set, prefix_db): for prefix_entry in prefix_db.prefixEntries: if (prefix_entry.type == lsdb_types.PrefixType.LOOPBACK and len(prefix_entry.prefix.prefixAddress.addr) == 16): loopback_set.add(utils.sprint_prefix(prefix_entry.prefix))