def expand(G_in): """ Expands out graph products. G is the source "backbone" graph. H_x is the "PoP template" graphs """ graph_unwrapped = ank_utils.unwrap_graph(G_in) G = graph_unwrapped.copy() ank.set_node_default(G_in, G_in) template_names = set(node.pop_template for node in G_in) template_names.discard("None") template_names.discard(None) if not len(template_names): log.debug("No PoP templates set") return # no templates set # Load these templates templates = {} for template in template_names: template_filename = os.path.join("pop_templates", "%s.graphml" % template) try: pop_graph = autonetkit.load.graphml.load_graphml(template_filename) #TODO: pass in properties eg edge type = physical except Exception, e: log.warning("Unable to load pop template %s: %s" % (template, e)) return pop_graph = pop_graph.to_undirected() # Undirected for now TODO: document this templates[template] = pop_graph
def expand(G_in): """ Expands out graph products. G is the source "backbone" graph. H_x is the "PoP template" graphs """ graph_unwrapped = ank_utils.unwrap_graph(G_in) G = graph_unwrapped.copy() ank.set_node_default(G_in, G_in) template_names = set(node.pop_template for node in G_in) template_names.discard("None") template_names.discard(None) if not len(template_names): log.debug("No PoP templates set") return # no templates set # Load these templates templates = {} for template in template_names: template_filename = os.path.join("pop_templates", "%s.graphml" % template) try: pop_graph = autonetkit.load.graphml.load_graphml( template_filename ) #TODO: pass in properties eg edge type = physical except Exception, e: log.warning("Unable to load pop template %s: %s" % (template, e)) return pop_graph = pop_graph.to_undirected( ) # Undirected for now TODO: document this templates[template] = pop_graph
def expand(G_in): """ Expands out graph products. G is the source "backbone" graph. H_x is the "PoP template" graphs """ graph_unwrapped = ank_utils.unwrap_graph(G_in) G = graph_unwrapped.copy() ank.set_node_default(G_in, G_in) template_names = set(node.pop_template for node in G_in) template_names.remove(None) if not len(template_names): return # no templates set # Load these templates templates = {} for template in template_names: print "TEMplate is", template template_filename = os.path.join("pop_templates", "%s.graphml" % template) pop_graph = ank.load_graphml(template_filename) #TODO: pass in properties eg edge type = physical pop_graph = pop_graph.to_undirected() # Undirected for now TODO: document this templates[template] = pop_graph # construct new graph G_out = nx.Graph() #TODO: what about bidirectional graphs? G_out.add_nodes_from(expand_nodes(G, templates)) G_out.add_edges_from(intra_pop_links(G, templates)) G_out.add_edges_from(inter_pop_links(G, templates)) for s, t in G_out.edges(): G_out[s][t]['type'] = 'physical' # ensure copied across # Update properties based on co-ordinates for node in G_out: u, v = node template = G.node[u]['pop_template'] u_properties = dict(G.node[u]) v_properties = dict(templates[template].node[v]) # create copy to append with x = float(u_properties.get('x')) + float(v_properties.get('x')) y = float(u_properties.get('y')) + float(v_properties.get('y')) asn = u_properties['asn'] u_properties.update(v_properties) u_properties['x'] = x u_properties['y'] = y u_properties['label'] = "%s_%s" % (v, u) u_properties['id'] = "%s_%s" % (v, u) u_properties['pop'] = u u_properties['asn'] = asn # restore, don't inherit from pop del u_properties['pop_template'] G_out.node[node] = u_properties nx.relabel_nodes(G_out, dict( ((u, v), "%s_%s" % (v, u)) for (u, v) in G_out), copy = False) #TODO: set edge_ids for s, t in G_out.edges(): G_out[s][t]['edge_id'] = "%s_%s" % (s, t) G_in._replace_graph(G_out) return
def igp_routes(anm, measured): # TODO: split up expected calculation and comparison so don't need to calculate SPF multiple times # TODO: allow choice of IGP - for now is just OSPF import networkx as nx g_ipv4 = anm['ipv4'] g_ospf = anm['ospf'] log.info("Verifying IGP routes") # extract source node from measured data try: src_node = measured[0][0] except IndexError: log.info("Unable to parse measured results, returning") return # calculate expected routes prefixes_by_router = {} prefix_reachability = defaultdict(list) for router in g_ospf: ipv4_node = g_ipv4.node(router) neighbors = ipv4_node.neighbors() neighbor_subnets = [n.subnet for n in neighbors] prefixes_by_router[router] = neighbor_subnets for subnet in neighbor_subnets: # use strings for faster matching from here on # (can convert back to overlay_nodes later) prefix_reachability[str(subnet)].append(str(router)) # print prefixes_by_router # print prefix_reachability graph = unwrap_graph(g_ospf) shortest_paths = nx.shortest_path(graph, source=src_node, weight='cost') shortest_path_lengths = nx.shortest_path_length( graph, source=src_node, weight='cost') # pprint.pprint(shortest_path_lengths) optimal_prefixes = {} for prefix, routers in prefix_reachability.items(): # decorate with cost try: routers_with_costs = [ (shortest_path_lengths[r], r) for r in routers] except KeyError: continue # no router, likely from eBGP min_cost = min(rwc[0] for rwc in routers_with_costs) shortest_routers = [rwc[1] for rwc in routers_with_costs if rwc[0] == min_cost] optimal_prefixes[str(prefix)] = shortest_routers # print optimal_prefixes verified_prefixes = {} for route in measured: dst_cd = route[-1] prefix = str(g_ipv4.node(dst_cd).subnet) try: optimal_routers = optimal_prefixes[prefix] except KeyError: continue # prefix not present if src_node in optimal_routers: continue # target is self optimal_routes = [shortest_paths[r] for r in optimal_routers] optimal_next_hop = [p[1] for p in optimal_routes] actual_next_hop = route[1] log.info("Match: %s, %s, optimal: %s, actual: %s" % ( actual_next_hop in optimal_next_hop, prefix, ", ".join(optimal_next_hop), actual_next_hop)) if actual_next_hop not in optimal_next_hop: log.info("Unverified prefix: %s on %s. Expected: %s. Received: %s" % (prefix, dst_cd, ", ".join(optimal_next_hop), actual_next_hop)) verified_prefixes[prefix] = actual_next_hop in optimal_next_hop verified_count = verified_prefixes.values().count(True) try: verified_fraction = round( 100 * verified_count / len(verified_prefixes), 2) except ZeroDivisionError: verified_fraction = 0 log.info("%s%% verification rate" % verified_fraction) return verified_prefixes
def igp_routes(anm, measured): #TODO: split up expected calculation and comparison so don't need to calculate SPF multiple times #TODO: allow choice of IGP - for now is just OSPF import networkx as nx g_ipv4 = anm['ipv4'] g_ospf = anm['ospf'] log.info("Verifying IGP routes") # extract source node from measured data try: src_node = measured[0][0] except IndexError: log.info("Unable to parse measured results, returning") return # calculate expected routes prefixes_by_router = {} prefix_reachability = defaultdict(list) for router in g_ospf: ipv4_node = g_ipv4.node(router) neighbors = ipv4_node.neighbors() neighbor_subnets = [n.subnet for n in neighbors] prefixes_by_router[router] = neighbor_subnets for subnet in neighbor_subnets: # use strings for faster matching from here on # (can convert back to overlay_nodes later) prefix_reachability[str(subnet)].append(str(router)) #print prefixes_by_router #print prefix_reachability graph = unwrap_graph(g_ospf) shortest_paths = nx.shortest_path(graph, source = src_node, weight = 'cost') shortest_path_lengths = nx.shortest_path_length(graph, source = src_node, weight = 'cost') #pprint.pprint(shortest_path_lengths) optimal_prefixes = {} for prefix, routers in prefix_reachability.items(): # decorate with cost routers_with_costs = [(shortest_path_lengths[r], r) for r in routers] min_cost = min(rwc[0] for rwc in routers_with_costs) shortest_routers = [rwc[1] for rwc in routers_with_costs if rwc[0] == min_cost] optimal_prefixes[str(prefix)] = shortest_routers #print optimal_prefixes verified_prefixes = {} for route in measured: dst_cd = route[-1] prefix = str(g_ipv4.node(dst_cd).subnet) optimal_routers = optimal_prefixes[prefix] if src_node in optimal_routers: continue # target is self optimal_routes = [shortest_paths[r] for r in optimal_routers] optimal_next_hop = [p[1] for p in optimal_routes] actual_next_hop = route[1] log.debug( "Match: %s, %s, optimal: %s, actual: %s" % ( actual_next_hop in optimal_next_hop, prefix, ", ".join(optimal_next_hop), actual_next_hop)) if actual_next_hop not in optimal_next_hop: log.info("Unverified prefix: %s on %s. Expected: %s. Received: %s" % (prefix, dst_cd, ", ".join(optimal_next_hop), actual_next_hop)) verified_prefixes[prefix] = actual_next_hop in optimal_next_hop verified_count = verified_prefixes.values().count(True) verified_fraction = round(100 * verified_count/len(verified_prefixes),2) log.info("%s%% verification rate" % verified_fraction) return verified_prefixes