def _update(interface_info_dict, interface_info): interface_info_dict.update({ 'v4Addrs': [ipnetwork.sprint_addr(v4Addr.addr) for v4Addr in interface_info.v4Addrs], 'v6LinkLocalAddrs': [ipnetwork.sprint_addr(v6Addr.addr) for v6Addr in interface_info.v6LinkLocalAddrs] })
def sprint_adj_db_full(global_adj_db, adj_db, bidir): """ given serialized adjacency database, print neighbors. Use the global adj database to validate bi-dir adjacencies :param global_adj_db map(str, AdjacencyDatabase): map of node names to their adjacent node names :param adj_db lsdb_types.AdjacencyDatabase: latest from kv store :param bidir bool: only print bidir adjacencies :return [str]: list of string to be printed """ assert isinstance(adj_db, lsdb_types.AdjacencyDatabase) this_node_name = adj_db.thisNodeName node_label_str = "Node Label: {}".format(adj_db.nodeLabel) rows = [] column_labels = [ "Neighbor", "Local Intf", "Remote Intf", "Metric", "Label", "NextHop-v4", "NextHop-v6", "Uptime", ] for adj in adj_db.adjacencies: if bidir: other_node_db = global_adj_db.get(adj.otherNodeName, None) if other_node_db is None: continue other_node_neighbors = { a.otherNodeName for a in other_node_db.adjacencies } if this_node_name not in other_node_neighbors: continue nh_v6 = ipnetwork.sprint_addr(adj.nextHopV6.addr) nh_v4 = ipnetwork.sprint_addr(adj.nextHopV4.addr) overload_status = click.style("Overloaded", fg="red") metric = overload_status if adj.isOverloaded else adj.metric uptime = time_since(adj.timestamp) if adj.timestamp else "" rows.append([ adj.otherNodeName, adj.ifName, adj.otherIfName, metric, adj.adjLabel, nh_v4, nh_v6, uptime, ]) return node_label_str, printing.render_horizontal_table( rows, column_labels)
def _parse_intf_info(info): return bunch.Bunch(**{ 'isUp': info.isUp, 'ifIndex': info.ifIndex, 'v4Addrs': [ipnetwork.sprint_addr(v.addr) for v in info.v4Addrs], 'v6Addrs': [ipnetwork.sprint_addr(v.addr) for v in info.v6LinkLocalAddrs], })
def _parse(if2node, adj_db): nexthop_dict = if2node[adj_db.thisNodeName] for adj in adj_db.adjacencies: nh6_addr = ipnetwork.sprint_addr(adj.nextHopV6.addr) nh4_addr = ipnetwork.sprint_addr(adj.nextHopV4.addr) nexthop_dict[(adj.ifName, nh6_addr)] = adj.otherNodeName nexthop_dict[(adj.ifName, nh4_addr)] = adj.otherNodeName
def _update(adj_dict, adj): # Only addrs need string conversion so we udpate them adj_dict.update( { "nextHopV6": ipnetwork.sprint_addr(adj.nextHopV6.addr), "nextHopV4": ipnetwork.sprint_addr(adj.nextHopV4.addr), } )
def _update(next_hop_dict, nextHop): next_hop_dict.update( { "address": ipnetwork.sprint_addr(nextHop.address.addr), "nextHop": ipnetwork.sprint_addr(nextHop.address.addr), "ifName": nextHop.address.ifName, } ) if nextHop.mplsAction: next_hop_dict.update({"mplsAction": thrift_to_dict(nextHop.mplsAction)})
def _update(interface_info_dict, interface_info): interface_info_dict.update({ # TO BE DEPRECATED SOON 'v4Addrs': [ipnetwork.sprint_addr(v4Addr.addr) for v4Addr in interface_info.v4Addrs], # TO BE DEPRECATED SOON 'v6LinkLocalAddrs': [ipnetwork.sprint_addr(v6Addr.addr) for v6Addr in interface_info.v6LinkLocalAddrs], 'networks': [ipnetwork.sprint_prefix(prefix) for prefix in interface_info.networks], })
def _parse_intf_info(info): addrs = [] if info.networks is not None: addrs = [ipnetwork.sprint_addr(v.prefixAddress.addr) for v in info.networks] else: addrs = [ipnetwork.sprint_addr(v.addr) for v in info.v4Addrs] + [ ipnetwork.sprint_addr(v.addr) for v in info.v6LinkLocalAddrs ] return bunch.Bunch( **{"isUp": info.isUp, "ifIndex": info.ifIndex, "Addrs": addrs} )
def print_routes_table(route_db, prefixes=None): """ print the the routes from Decision/Fib module """ networks = None if prefixes: networks = [ipaddress.ip_network(p) for p in prefixes] route_strs = [] for route in sorted(route_db.routes, key=lambda x: x.prefix.prefixAddress.addr): prefix_str = ipnetwork.sprint_prefix(route.prefix) if not ipnetwork.contain_any_prefix(prefix_str, networks): continue paths_str = "\n".join([ "via {}%{} metric {}".format( ipnetwork.sprint_addr(path.nextHop.addr), path.ifName, path.metric) for path in route.paths ]) route_strs.append((prefix_str, paths_str)) caption = "Routes for {}".format(route_db.thisNodeName) if not route_strs: route_strs.append(["No routes found."]) print(printing.render_vertical_table(route_strs, caption=caption))
def print_links_table(interfaces, caption=None): ''' @param interfaces: dict<interface-name, InterfaceDetail> @param caption: Caption to show on table name ''' rows = [] columns = ['Interface', 'Status', 'Metric Override', 'Addresses'] for (k, v) in sorted(interfaces.items()): state = 'Up' if v.info.isUp else click.style('Down', fg='red') metric_override = v.metricOverride if v.metricOverride else '' if v.isOverloaded: metric_override = click.style('Overloaded', fg='red') rows.append([k, state, metric_override, '']) firstAddr = True for prefix in (v.info.networks): addrStr = ipnetwork.sprint_addr(prefix.prefixAddress.addr) if firstAddr: rows[-1][3] = addrStr firstAddr = False else: rows.append(['', '', '', addrStr]) print(printing.render_horizontal_table(rows, columns, caption)) print()
def adjacency_to_dict(adjacency): ''' convert adjacency from thrift instance into a dict in strings :param adjacency as a thrift instance: adjacency :return dict: dict with adjacency attributes as key, value in strings ''' # Only addrs need string conversion so we udpate them adj_dict = copy.copy(adjacency).__dict__ adj_dict.update({ 'nextHopV6': ipnetwork.sprint_addr(adjacency.nextHopV6.addr), 'nextHopV4': ipnetwork.sprint_addr(adjacency.nextHopV4.addr) }) return adj_dict
def _backtracking(cur, path, hop, visited, in_fib): """ Depth-first search (DFS) for traversing graph and getting paths from src to dst with lowest metric in total. Attributes: cur: current starting node path: a list of the nodes who form the path from src to the current node hop: how many hops from src node to the current node visited: a set of visited nodes in_fib: if current node is in fib path """ if hop > max_hop: return # get the longest prefix match for dst_addr from current node's advertising prefixes cur_lpm_len = self.get_lpm_len_from_node(cur, dst_addr) # get the next hop nodes next_hop_nodes = self.get_nexthop_nodes( client.getRouteDbComputed(cur), dst_addr, cur_lpm_len, if2node, fib_routes, in_fib, ) if len(next_hop_nodes) == 0: if hop != 1: paths.append((in_fib, path[:])) return for next_hop_node in next_hop_nodes: next_hop_node_name = next_hop_node[0] # prevent loops if next_hop_node_name in visited: return path.append([hop] + next_hop_node) visited.add(next_hop_node_name) # check if next hop node is in fib path is_nexthop_in_fib_path = False for nexthop in fib_routes[cur]: if ( next_hop_node[3] == ipnetwork.sprint_addr(nexthop.addr) and next_hop_node[1] == nexthop.ifName ): is_nexthop_in_fib_path = True # recursion - extend the path from next hop node _backtracking( next_hop_node_name, path, hop + 1, visited, is_nexthop_in_fib_path and in_fib, ) visited.remove(next_hop_node_name) path.pop()
def _parse_intf_info(info): addrs = [] if info.networks is not None: addrs = [ ipnetwork.sprint_addr(v.prefixAddress.addr) for v in info.networks ] else: addrs = [ ipnetwork.sprint_addr(v.addr) for v in info.v4Addrs] + [ ipnetwork.sprint_addr(v.addr) for v in info.v6LinkLocalAddrs] return bunch.Bunch(**{ 'isUp': info.isUp, 'ifIndex': info.ifIndex, 'Addrs': addrs, })
def _backtracking(cur, path, hop, visited, in_fib): if hop > max_hop: return cur_lpm_len = self.get_lpm_len_from_node(cur, dst_addr) next_hop_nodes = self.get_nexthop_nodes( self.client.get_route_db(cur), dst_addr, cur_lpm_len, if2node, fib_routes, in_fib) if len(next_hop_nodes) == 0: if hop != 1: paths.append((in_fib, path[:])) return for next_hop_node in next_hop_nodes: next_hop_node_name = next_hop_node[0] # prevent loops if next_hop_node_name in visited: return path.append([hop] + next_hop_node) visited.add(next_hop_node_name) # check if next hop node is in fib path is_nexthop_in_fib_path = False for nexthop in fib_routes[cur]: if next_hop_node[3] == ipnetwork.sprint_addr(nexthop.addr) and\ next_hop_node[1] == nexthop.ifName: is_nexthop_in_fib_path = True _backtracking(next_hop_node_name, path, hop + 1, visited, is_nexthop_in_fib_path and in_fib) visited.remove(next_hop_node_name) path.pop()
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, ipnetwork.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 = ipnetwork.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 print_links_table(interfaces, caption=None): ''' @param interfaces: dict<interface-name, InterfaceDetail> @param caption: Caption to show on table name ''' rows = [] columns = ['Interface', 'Status', 'Overloaded', 'Metric Override', 'ifIndex', 'Addresses'] for (k, v) in sorted(interfaces.items()): state = 'Up' if v.info.isUp else 'Down' overloaded = 'True' if v.isOverloaded else '' metric_override = v.metricOverride if v.metricOverride else '' index = v.info.ifIndex rows.append([k, state, overloaded, metric_override, index, '']) firstAddr = True for a in (v.info.v4Addrs + v.info.v6LinkLocalAddrs): addrStr = ipnetwork.sprint_addr(a.addr) if firstAddr: rows[-1][5] = addrStr firstAddr = False else: rows.append(['', '', '', '', '', addrStr]) print(printing.render_horizontal_table(rows, columns, caption)) print()
def print_links_table(interfaces, caption=None): """ @param interfaces: dict<interface-name, InterfaceDetail> @param caption: Caption to show on table name """ rows = [] columns = ["Interface", "Status", "Metric Override", "Addresses"] for (k, v) in sorted(interfaces.items()): metric_override = v.metricOverride if v.metricOverride else "" if v.info.isUp: backoff_sec = v.linkFlapBackOffMs / 1000 state = 'Up' if backoff_sec == 0 else click.style( 'Hold ({} s)'.format(backoff_sec), fg='yellow') else: state = click.style('Down', fg='red') if v.isOverloaded: metric_override = click.style("Overloaded", fg="red") rows.append([k, state, metric_override, ""]) firstAddr = True for prefix in v.info.networks: addrStr = ipnetwork.sprint_addr(prefix.prefixAddress.addr) if firstAddr: rows[-1][3] = addrStr firstAddr = False else: rows.append(["", "", "", addrStr]) print(printing.render_horizontal_table(rows, columns, caption)) print()
def build_table_row(k: str, v: object) -> List[Any]: metric_override = v.metricOverride if v.metricOverride else "" if v.info.isUp: backoff_sec = int( (v.linkFlapBackOffMs if v.linkFlapBackOffMs else 0) / 1000 ) if backoff_sec == 0: state = "Up" elif not utils.is_color_output_supported(): state = backoff_sec else: state = click.style("Hold ({} s)".format(backoff_sec), fg="yellow") else: state = ( click.style("Down", fg="red") if utils.is_color_output_supported() else "Down" ) if v.isOverloaded: metric_override = ( click.style("Overloaded", fg="red") if utils.is_color_output_supported() else "Overloaded" ) addrs = [] for prefix in v.info.networks: addrStr = ipnetwork.sprint_addr(prefix.prefixAddress.addr) addrs.append(addrStr) row = [k, state, metric_override, addrs] return row
def sprint_adj_db_full(global_adj_db, adj_db, bidir): ''' given serialized adjacency database, print neighbors. Use the global adj database to validate bi-dir adjacencies :param global_adj_db map(str, AdjacencyDatabase): map of node names to their adjacent node names :param adj_db lsdb_types.AdjacencyDatabase: latest from kv store :param bidir bool: only print bidir adjacencies :return [str]: list of string to be printed ''' assert (isinstance(adj_db, lsdb_types.AdjacencyDatabase)) this_node_name = adj_db.thisNodeName node_label_str = 'Node Label: {}'.format(adj_db.nodeLabel) rows = [] column_labels = [ 'Neighbor', 'Local Interface', 'Remote Interface', 'Metric', 'Adj Label', 'NextHop-v4', 'NextHop-v6', 'Uptime' ] for adj in adj_db.adjacencies: if bidir: other_node_db = global_adj_db.get(adj.otherNodeName, None) if other_node_db is None: continue other_node_neighbors = set(a.otherNodeName for a in other_node_db.adjacencies) if this_node_name not in other_node_neighbors: continue nh_v6 = ipnetwork.sprint_addr(adj.nextHopV6.addr) nh_v4 = ipnetwork.sprint_addr(adj.nextHopV4.addr) overload_status = click.style('Overloaded', fg='red') metric = overload_status if adj.isOverloaded else adj.metric uptime = time_since(adj.timestamp) if adj.timestamp else '' rows.append([ adj.otherNodeName, adj.ifName, adj.otherIfName, metric, adj.adjLabel, nh_v4, nh_v6, uptime ]) return node_label_str, printing.render_horizontal_table( rows, column_labels)
def ip_nexthop_to_str(nh, ignore_v4_iface=False): ''' Convert ttypes.BinaryAddress to string representation of a nexthop ''' ifName = '@{}'.format(nh.ifName) if nh.ifName else '' if len(nh.addr) == 4 and ignore_v4_iface: ifName = '' return "{}{}".format(ipnetwork.sprint_addr(nh.addr), ifName)
def alloc_prefix_to_loopback_ip_str(prefix): """ :param prefix: IpPrefix representing an allocation prefix (CIDR network) :returns: Loopback IP corresponding to allocation prefix :rtype: string """ ip_addr = prefix.prefixAddress.addr print(ip_addr) if prefix.prefixLength != 128: ip_addr = ip_addr[:-1] + chr(ord(ip_addr[-1]) | 1) print(ip_addr) return ipnetwork.sprint_addr(ip_addr)
def print_config(self, prefix_alloc): seed_prefix = prefix_alloc.seedPrefix seed_prefix_addr = ipnetwork.sprint_addr(seed_prefix.prefixAddress.addr) caption = 'Prefix Allocator parameters stored' rows = [] rows.append(['Seed prefix: {}/{}'.format(seed_prefix_addr, seed_prefix.prefixLength)]) rows.append(['Allocated prefix length: {}'.format( prefix_alloc.allocPrefixLen)]) rows.append(['Allocated prefix index: {}'.format( prefix_alloc.allocPrefixIndex)]) print(printing.render_vertical_table(rows, caption=caption))
def get_node_ip(self, prefix_db: lsdb_types.PrefixDatabase) -> Any: """get routable IP address of node from it's prefix database""" # First look for LOOPBACK prefix for prefix_entry in prefix_db.prefixEntries: if prefix_entry.type == network_types.PrefixType.LOOPBACK: return ipnetwork.sprint_addr(prefix_entry.prefix.prefixAddress.addr) # Next look for PREFIX_ALLOCATOR prefix if any for prefix_entry in prefix_db.prefixEntries: if prefix_entry.type == network_types.PrefixType.PREFIX_ALLOCATOR: return utils.alloc_prefix_to_loopback_ip_str(prefix_entry.prefix) # Else return None return None
def ip_nexthop_to_str(nextHop: network_types.NextHopThrift, ignore_v4_iface: bool = False) -> str: """ Convert Network.BinaryAddress to string representation of a nexthop """ nh = nextHop.address ifName = "%{}".format(nh.ifName) if nh.ifName else "" if len(nh.addr) == 4 and ignore_v4_iface: ifName = "" mpls_action_str = ("{} ".format(mpls_action_to_str(nextHop.mplsAction)) if nextHop.mplsAction is not None else "") return "{}{}{}".format(mpls_action_str, ipnetwork.sprint_addr(nh.addr), ifName)
def run(self): resp = self.client.peek() headers = [ 'Node', 'IP Address', 'Last Value Sent', 'Last Ack From Node', 'Last Ack To Node' ] rows = [] for name, node in resp.nodeInfo.items(): rows.append([ name, ipnetwork.sprint_addr(node.ipAddress.addr), node.lastValSent, node.lastAckFromNode, node.lastAckToNode ]) print() print(tabulate.tabulate(rows, headers=headers)) print()
def get_node_ip(self, prefix_db): """ get routable IP address of node from it's prefix database :return: string representation of Node's IP addresss. Returns None if no IP found. """ # First look for LOOPBACK prefix for prefix_entry in prefix_db.prefixEntries: if prefix_entry.type == network_types.PrefixType.LOOPBACK: return ipnetwork.sprint_addr(prefix_entry.prefix.prefixAddress.addr) # Next look for PREFIX_ALLOCATOR prefix if any for prefix_entry in prefix_db.prefixEntries: if prefix_entry.type == network_types.PrefixType.PREFIX_ALLOCATOR: return utils.alloc_prefix_to_loopback_ip_str(prefix_entry.prefix) # Else return None return None
def update_global_prefix_db(global_prefix_db, prefix_db): ''' update the global prefix map with a single publication :param global_prefix_map map(node, set([str])): map of all prefixes in the network :param prefix_db lsdb_types.PrefixDatabase: publication from single node ''' assert(isinstance(prefix_db, lsdb_types.PrefixDatabase)) this_node = prefix_db.thisNodeName prefix_set = set() for prefix_entry in prefix_db.prefixEntries: addr_str = ipnetwork.sprint_addr(prefix_entry.prefix.prefixAddress.addr) prefix_len = prefix_entry.prefix.prefixLength prefix_set.add("{}/{}".format(addr_str, prefix_len)) global_prefix_db[this_node] = prefix_set return
def _update(path_dict, path): path_dict.update({ 'nextHop': ipnetwork.sprint_addr(path.nextHop.addr), })
def _update(path_dict, path): path_dict.update({"nextHop": ipnetwork.sprint_addr(path.nextHop.addr)})