def initialise(input_graph): anm = autonetkit.anm.AbstractNetworkModel() input_undirected = nx.Graph(input_graph) g_in = anm.add_overlay("input", graph=input_undirected) anm.add_overlay("input_directed", graph=input_graph, directed=True) # set defaults if not g_in.data.specified_int_names: # if not specified then automatically assign interface names g_in.data.specified_int_names = False import autonetkit.plugins.graph_product as graph_product graph_product.expand(g_in) # apply graph products if relevant expand_fqdn = False # TODO: make this set from config and also in the input file if expand_fqdn and len(ank_utils.unique_attr(g_in, "asn")) > 1: # Multiple ASNs set, use label format device.asn anm.set_node_label(".", ['label', 'pop', 'asn']) g_in.update(g_in.nodes("is_router", platform="junosphere"), syntax="junos") g_in.update(g_in.nodes("is_router", platform="dynagen"), syntax="ios") g_in.update(g_in.nodes("is_router", platform="netkit"), syntax="quagga") g_in.update(g_in.nodes("is_server", platform="netkit"), syntax="quagga") g_graphics = anm.add_overlay("graphics") # plotting data g_graphics.add_nodes_from( g_in, retain=['x', 'y', 'device_type', 'device_subtype', 'pop', 'asn']) return anm
def initialise(input_graph): anm = autonetkit.anm.AbstractNetworkModel() input_undirected = nx.Graph(input_graph) g_in = anm.add_overlay("input", graph=input_undirected) anm.add_overlay("input_directed", graph=input_graph, directed=True) # set defaults if not g_in.data.specified_int_names: # if not specified then automatically assign interface names g_in.data.specified_int_names = False import autonetkit.plugins.graph_product as graph_product graph_product.expand(g_in) # apply graph products if relevant expand_fqdn = False # TODO: make this set from config and also in the input file if expand_fqdn and len(ank_utils.unique_attr(g_in, "asn")) > 1: # Multiple ASNs set, use label format device.asn anm.set_node_label(".", ['label', 'pop', 'asn']) g_in.update( g_in.nodes("is_router", platform="junosphere"), syntax="junos") g_in.update(g_in.nodes("is_router", platform="dynagen"), syntax="ios") g_in.update(g_in.nodes("is_router", platform="netkit"), syntax="quagga") g_in.update(g_in.nodes("is_server", platform="netkit"), syntax="quagga") g_graphics = anm.add_overlay("graphics") # plotting data g_graphics.add_nodes_from(g_in, retain=['x', 'y', 'device_type', 'device_subtype', 'pop', 'asn']) return anm
def initialise(input_graph): """Initialises the input graph with from a NetworkX graph""" all_multigraph = input_graph.is_multigraph() anm = autonetkit.anm.NetworkModel(all_multigraph=all_multigraph) g_in = anm.initialise_input(input_graph) # autonetkit.update_vis(anm) # set defaults if not g_in.data.specified_int_names: # if not specified then automatically assign interface names g_in.data.specified_int_names = False #import autonetkit.plugins.graph_product as graph_product # graph_product.expand(g_in) # apply graph products if relevant expand_fqdn = False # TODO: make this set from config and also in the input file if expand_fqdn and len(ank_utils.unique_attr(g_in, "asn")) > 1: # Multiple ASNs set, use label format device.asn anm.set_node_label(".", ['label', 'asn']) g_in.update(g_in.routers(platform="junosphere"), syntax="junos") g_in.update(g_in.routers(platform="dynagen"), syntax="ios") g_in.update(g_in.routers(platform="netkit"), syntax="quagga") # TODO: is this used? g_in.update(g_in.servers(platform="netkit"), syntax="quagga") autonetkit.ank.set_node_default(g_in, specified_int_names=None) g_graphics = anm.add_overlay("graphics") # plotting data g_graphics.add_nodes_from(g_in, retain=['x', 'y', 'device_type', 'label', 'device_subtype', 'asn']) return anm
def build_ip(anm): import autonetkit.plugins.ipv4 as ip G_ip = anm.add_overlay("ip") G_in = anm['input'] G_graphics = anm['graphics'] G_phy = anm['phy'] G_ip.add_nodes_from(G_in) G_ip.add_edges_from(G_in.edges(type="physical")) ank.aggregate_nodes(G_ip, G_ip.nodes("is_switch"), retain = "edge_id") edges_to_split = [edge for edge in G_ip.edges() if edge.attr_both("is_l3device")] split_created_nodes = list(ank.split(G_ip, edges_to_split, retain='edge_id')) for node in split_created_nodes: node['graphics'].x = ank.neigh_average(G_ip, node, "x", G_graphics) node['graphics'].y = ank.neigh_average(G_ip, node, "y", G_graphics) G_ip.update(split_created_nodes, collision_domain=True) for node in G_ip.nodes("collision_domain"): graphics_node = G_graphics.node(node) node.host = G_phy.node(node.neighbors().next()).host # Set host to be same as one of the neighbors (arbitrary choice) asn = ank.neigh_most_frequent(G_ip, node, "asn", G_phy) # arbitrary choice node.asn = asn graphics_node.asn = asn graphics_node.x = ank.neigh_average(G_ip, node, "x", G_graphics) graphics_node.device_type = "collision_domain" cd_label = "cd_" + "_".join(sorted(ank.neigh_attr(G_ip, node, "label", G_phy))) node.label = cd_label graphics_node.label = cd_label ip.allocate_ips(G_ip)
def build_ebgp(anm): g_in = anm['input'] g_phy = anm['phy'] g_ebgp = anm.add_overlay("ebgp", directed=True) g_ebgp.add_nodes_from(g_in.nodes("is_router")) ebgp_edges = [e for e in g_in.edges() if not e.attr_equal("asn")] g_ebgp.add_edges_from(ebgp_edges, bidirectional=True, type='ebgp') ebgp_switches = [ n for n in g_in.nodes("is_switch") if not ank_utils.neigh_equal(g_phy, n, "asn") ] g_ebgp.add_nodes_from(ebgp_switches, retain=['asn']) log.debug("eBGP switches are %s" % ebgp_switches) g_ebgp.add_edges_from( (e for e in g_in.edges() if e.src in ebgp_switches or e.dst in ebgp_switches), bidirectional=True, type='ebgp') ank_utils.aggregate_nodes(g_ebgp, ebgp_switches, retain="edge_id") ebgp_switches = list(g_ebgp.nodes( "is_switch")) # need to recalculate as may have aggregated log.debug("aggregated eBGP switches are %s" % ebgp_switches) exploded_edges = ank_utils.explode_nodes(g_ebgp, ebgp_switches, retain="edge_id") for edge in exploded_edges: edge.multipoint = True
def build_mpls_ldp(anm): """Builds MPLS LDP""" g_in = anm['input'] g_vrf = anm['vrf'] g_l3conn = anm['l3_conn'] g_mpls_ldp = anm.add_overlay("mpls_ldp") nodes_to_add = [n for n in g_in.nodes("is_router") if n['vrf'].vrf_role in ("PE", "P")] g_mpls_ldp.add_nodes_from(nodes_to_add, retain=["vrf_role", "vrf"]) # store as set for faster lookup pe_nodes = set(g_vrf.nodes(vrf_role = "PE")) p_nodes = set(g_vrf.nodes(vrf_role = "P")) pe_to_pe_edges = (e for e in g_l3conn.edges() if e.src in pe_nodes and e.dst in pe_nodes) g_mpls_ldp.add_edges_from(pe_to_pe_edges) pe_to_p_edges = (e for e in g_l3conn.edges() if e.src in pe_nodes and e.dst in p_nodes or e.src in p_nodes and e.dst in pe_nodes) g_mpls_ldp.add_edges_from(pe_to_p_edges) p_to_p_edges = (e for e in g_l3conn.edges() if e.src in p_nodes and e.dst in p_nodes) g_mpls_ldp.add_edges_from(p_to_p_edges)
def initialise(input_graph): """Initialises the input graph with from a NetworkX graph""" all_multigraph = input_graph.is_multigraph() anm = autonetkit.anm.NetworkModel(all_multigraph=all_multigraph) g_in = anm.initialise_input(input_graph) if g_in.data.igp: if g_in.data.profiles: node_profiles = g_in.data["profiles"] for node in g_in: for prof in node_profiles: if node.profile == prof["id"]: if "configs" in prof and "igp" in prof["configs"]: if ( "enabled" in prof["configs"]["igp"] and prof["configs"]["igp"]["enabled"] == 1 and prof["configs"]["igp"]["igp_prot"] ): node.igp = prof["configs"]["igp"]["igp_prot"] else: g_in.data.igp = None if g_in.data.vxlan_global_config: # sharad: right now enable multicast on all nodes by default if "multicast" in g_in.data.vxlan_global_config: for node in g_in: node.multicast = g_in.data.vxlan_global_config["multicast"] # autonetkit.update_vis(anm) # set defaults if not g_in.data.specified_int_names: # if not specified then automatically assign interface names g_in.data.specified_int_names = False # import autonetkit.plugins.graph_product as graph_product # graph_product.expand(g_in) # apply graph products if relevant expand_fqdn = False # TODO: make this set from config and also in the input file if expand_fqdn and len(ank_utils.unique_attr(g_in, "asn")) > 1: # Multiple ASNs set, use label format device.asn anm.set_node_label(".", ["label", "asn"]) g_in.update(g_in.routers(platform="junosphere"), syntax="junos") if autonetkit.config.settings["Graphml"]["Node Defaults"]["syntax"] == "ios": g_in.update(g_in.routers(platform="dynagen"), syntax="ios") elif autonetkit.config.settings["Graphml"]["Node Defaults"]["syntax"] == "nx_os": g_in.update(g_in.routers(platform="dynagen"), syntax="nx_os") g_in.update(g_in.routers(platform="netkit"), syntax="quagga") # TODO: is this used? g_in.update(g_in.servers(platform="netkit"), syntax="quagga") # TODO: check this is needed # autonetkit.ank.set_node_default(g_in, specified_int_names=None) g_graphics = anm.add_overlay("graphics") # plotting data g_graphics.add_nodes_from(g_in, retain=["x", "y", "device_type", "label", "device_subtype", "asn"]) return anm
def build_isis(anm): """Build isis overlay""" g_in = anm["input"] if not any(n.igp == "isis" for n in g_in): log.debug("No ISIS nodes") return g_ipv4 = anm["ipv4"] g_isis = anm.add_overlay("isis") g_isis.add_nodes_from(g_in.nodes("is_router", igp="isis"), retain=["asn"]) g_isis.add_nodes_from(g_in.nodes("is_switch"), retain=["asn"]) g_isis.add_edges_from(g_in.edges(), retain=["edge_id"]) # Merge and explode switches ank_utils.aggregate_nodes(g_isis, g_isis.nodes("is_switch"), retain="edge_id") exploded_edges = ank_utils.explode_nodes(g_isis, g_isis.nodes("is_switch"), retain="edge_id") for edge in exploded_edges: edge.multipoint = True g_isis.remove_edges_from([link for link in g_isis.edges() if link.src.asn != link.dst.asn]) for node in g_isis: ip_node = g_ipv4.node(node) node.net = ip_to_net_ent_title_ios(ip_node.loopback) node.process_id = 1 # default for link in g_isis.edges(): link.metric = 1 # default # link.hello = 5 # for debugging, TODO: read from graph for edge in g_isis.edges(): for interface in edge.interfaces(): interface.metric = edge.metric interface.multipoint = edge.multipoint
def build_l3_connectivity(anm): """ l3_connectivity graph: switch nodes aggregated and exploded""" g_in = anm["input"] g_l3conn = anm.add_overlay("layer3") g_l3conn.add_nodes_from( g_in, retain=[ "label", "update", "device_type", "asn", "specified_int_names", "device_subtype", "platform", "host", "syntax", ], ) g_l3conn.add_nodes_from(g_in.switches(), retain=["asn"]) g_l3conn.add_edges_from(g_in.edges()) ank_utils.aggregate_nodes(g_l3conn, g_l3conn.switches()) exploded_edges = ank_utils.explode_nodes(g_l3conn, g_l3conn.switches()) for edge in exploded_edges: edge.multipoint = True edge.src_int.multipoint = True edge.dst_int.multipoint = True
def apply_design_rules(anm): g_in = anm['input'] build_phy(anm) g_phy = anm['phy'] autonetkit.update_http(anm) build_l3_connectivity(anm) build_vrf(anm) # need to do before to add loopbacks before ip allocations build_ip(anm) # ip infrastructure topology #TODO: set defaults at the start, rather than inline, ie set g_in.data.address_family then use later address_family = g_in.data.address_family or "v4" # default is v4 #TODO: can remove the infrastructure now create g_ip seperately if address_family in ("v4", "dual_stack"): build_ipv4(anm, infrastructure = True) g_phy.update(g_phy, use_ipv4 = True) else: build_ipv4(anm, infrastructure = False) #TODO: Create a collision domain overlay for ip addressing - l2 overlay? if address_family in ("v6", "dual_stack"): build_ipv6(anm) g_phy.update(g_phy, use_ipv6 = True) else: anm.add_overlay("ipv6") # placeholder for compiler logic default_igp = g_in.data.igp or "ospf" non_igp_nodes = [n for n in g_in if not n.igp] #TODO: should this be modifying g_in? g_in.update(non_igp_nodes, igp=default_igp) # store igp onto each node ank_utils.copy_attr_from(g_in, g_phy, "include_csr") build_ospf(anm) build_isis(anm) build_bgp(anm) autonetkit.update_http(anm) # post-processing mark_ebgp_vrf(anm) build_ibgp_vpn_v4(anm) # build after bgp as is based on #autonetkit.update_http(anm) return anm
def build_conn(anm): #TODO: see if this is still required G_in = anm['input'] G_conn = anm.add_overlay("conn", directed = True) G_conn.add_nodes_from(G_in, retain=['label']) G_conn.add_edges_from(G_in.edges(type="physical")) return
def build_conn(anm): """Build connectivity overlay""" g_in = anm["input"] g_conn = anm.add_overlay("conn", directed=True) g_conn.add_nodes_from(g_in, retain=["label"]) g_conn.add_edges_from(g_in.edges(type="physical")) return
def build_conn(anm): """Build connectivity overlay""" g_in = anm['input'] g_conn = anm.add_overlay("conn", directed=True) g_conn.add_nodes_from(g_in, retain=['label']) g_conn.add_edges_from(g_in.edges(type="physical")) return
def initialise(input_graph): """Initialises the input graph with from a NetworkX graph""" all_multigraph = input_graph.is_multigraph() anm = autonetkit.anm.NetworkModel(all_multigraph=all_multigraph) g_in = anm.initialise_input(input_graph) if g_in.data.igp: if g_in.data.profiles: node_profiles = g_in.data['profiles'] for node in g_in: for prof in node_profiles: if node.profile == prof['id']: if 'configs' in prof and 'igp' in prof['configs']: if ('enabled' in prof['configs']['igp'] and prof['configs']['igp']['enabled'] == 1 and prof['configs']['igp']['igp_prot']): node.igp = prof['configs']['igp']['igp_prot'] else: g_in.data.igp = None if g_in.data.vxlan_global_config: #sharad: right now enable multicast on all nodes by default if 'multicast' in g_in.data.vxlan_global_config: for node in g_in: node.multicast = g_in.data.vxlan_global_config['multicast'] # autonetkit.update_vis(anm) # set defaults if not g_in.data.specified_int_names: # if not specified then automatically assign interface names g_in.data.specified_int_names = False #import autonetkit.plugins.graph_product as graph_product # graph_product.expand(g_in) # apply graph products if relevant expand_fqdn = False # TODO: make this set from config and also in the input file if expand_fqdn and len(ank_utils.unique_attr(g_in, "asn")) > 1: # Multiple ASNs set, use label format device.asn anm.set_node_label(".", ['label', 'asn']) g_in.update(g_in.routers(platform="junosphere"), syntax="junos") if autonetkit.config.settings['Graphml']['Node Defaults']['syntax'] == 'ios': g_in.update(g_in.routers(platform="dynagen"), syntax="ios") elif autonetkit.config.settings['Graphml']['Node Defaults']['syntax'] == 'nx_os': g_in.update(g_in.routers(platform="dynagen"), syntax="nx_os") g_in.update(g_in.routers(platform="netkit"), syntax="quagga") # TODO: is this used? g_in.update(g_in.servers(platform="netkit"), syntax="quagga") #TODO: check this is needed #autonetkit.ank.set_node_default(g_in, specified_int_names=None) g_graphics = anm.add_overlay("graphics") # plotting data g_graphics.add_nodes_from(g_in, retain=['x', 'y', 'device_type', 'label', 'device_subtype', 'asn']) return anm
def build_vrf(anm): """Build VRF Overlay""" g_in = anm['input'] g_vrf = anm.add_overlay("vrf") g_vrf.add_nodes_from(g_in.nodes("is_router"), retain=["vrf_role", "vrf"]) allocate_vrf_roles(g_vrf) vrf_pre_process(anm) def is_pe_ce_edge(edge): src_vrf_role = g_vrf.node(edge.src).vrf_role dst_vrf_role = g_vrf.node(edge.dst).vrf_role return (src_vrf_role, dst_vrf_role) in (("PE", "CE"), ("CE", "PE")) vrf_add_edges = (e for e in g_in.edges() if is_pe_ce_edge(e)) #TODO: should mark as being towards PE or CE g_vrf.add_edges_from(vrf_add_edges, retain=['edge_id']) def is_pe_p_edge(edge): src_vrf_role = g_vrf.node(edge.src).vrf_role dst_vrf_role = g_vrf.node(edge.dst).vrf_role return (src_vrf_role, dst_vrf_role) in (("PE", "P"), ("P", "PE")) vrf_add_edges = (e for e in g_in.edges() if is_pe_p_edge(e)) g_vrf.add_edges_from(vrf_add_edges, retain=['edge_id']) build_mpls_ldp(anm) # add PE to P edges add_vrf_loopbacks(g_vrf) # allocate route-targets per AS # This could later look at connected components for each ASN route_targets = {} for asn, devices in ank_utils.groupby("asn", g_vrf.nodes(vrf_role="PE")): asn_vrfs = [d.node_vrf_names for d in devices] # flatten list to unique set asn_vrfs = set(itertools.chain.from_iterable(asn_vrfs)) route_targets[asn] = { vrf: "%s:%s" % (asn, index) for index, vrf in enumerate(sorted(asn_vrfs), 1) } g_vrf.data.route_targets = route_targets for node in g_vrf: vrf_loopbacks = node.interfaces("is_loopback", "vrf_name") for index, interface in enumerate(vrf_loopbacks, start=101): interface.index = index for edge in g_vrf.edges(): # Set the vrf of the edge to be that of the CE device (either src or dst) edge.vrf = edge.src.vrf if edge.src.vrf_role is "CE" else edge.dst.vrf # map attributes to interfaces for edge in g_vrf.edges(): for interface in edge.interfaces(): interface.vrf_name = edge.vrf
def build_ebgp_v6(anm): #TODO: remove the bgp layer and have just ibgp and ebgp # TODO: build from design rules, currently just builds from ibgp links in bgp layer g_ebgp = anm['ebgp'] g_phy = anm['phy'] g_ebgpv6 = anm.add_overlay("ebgp_v6", directed=True) ipv6_nodes = set(g_phy.nodes("is_router", "use_ipv6")) g_ebgpv6.add_nodes_from(n for n in g_ebgp if n in ipv6_nodes) g_ebgpv6.add_edges_from(g_ebgp.edges(), retain="direction")
def build_vrf(anm): """Build VRF Overlay""" g_in = anm['input'] g_vrf = anm.add_overlay("vrf") g_vrf.add_nodes_from(g_in.nodes("is_router"), retain=["vrf_role", "vrf"]) allocate_vrf_roles(g_vrf) vrf_pre_process(anm) def is_pe_ce_edge(edge): src_vrf_role = g_vrf.node(edge.src).vrf_role dst_vrf_role = g_vrf.node(edge.dst).vrf_role return (src_vrf_role, dst_vrf_role) in (("PE", "CE"), ("CE", "PE")) vrf_add_edges = (e for e in g_in.edges() if is_pe_ce_edge(e)) #TODO: should mark as being towards PE or CE g_vrf.add_edges_from(vrf_add_edges, retain=['edge_id']) def is_pe_p_edge(edge): src_vrf_role = g_vrf.node(edge.src).vrf_role dst_vrf_role = g_vrf.node(edge.dst).vrf_role return (src_vrf_role, dst_vrf_role) in (("PE", "P"), ("P", "PE")) vrf_add_edges = (e for e in g_in.edges() if is_pe_p_edge(e)) g_vrf.add_edges_from(vrf_add_edges, retain=['edge_id']) build_mpls_ldp(anm) # add PE to P edges add_vrf_loopbacks(g_vrf) # allocate route-targets per AS # This could later look at connected components for each ASN route_targets = {} for asn, devices in ank_utils.groupby("asn", g_vrf.nodes(vrf_role = "PE")): asn_vrfs = [d.node_vrf_names for d in devices] # flatten list to unique set asn_vrfs = set(itertools.chain.from_iterable(asn_vrfs)) route_targets[asn] = {vrf: "%s:%s" % (asn, index) for index, vrf in enumerate(sorted(asn_vrfs), 1)} g_vrf.data.route_targets = route_targets for node in g_vrf: vrf_loopbacks = node.interfaces("is_loopback", "vrf_name") for index, interface in enumerate(vrf_loopbacks, start = 101): interface.index = index for edge in g_vrf.edges(): # Set the vrf of the edge to be that of the CE device (either src or dst) edge.vrf = edge.src.vrf if edge.src.vrf_role is "CE" else edge.dst.vrf # map attributes to interfaces for edge in g_vrf.edges(): for interface in edge.interfaces(): interface.vrf_name = edge.vrf
def build_ipv4(anm, infrastructure=True): """Builds IPv4 graph""" g_ipv4 = anm.add_overlay("ipv4") g_in = anm['input'] g_graphics = anm['graphics'] g_phy = anm['phy'] g_ipv4.add_nodes_from(g_in) g_ipv4.add_edges_from(g_in.edges(type="physical")) ank_utils.aggregate_nodes(g_ipv4, g_ipv4.nodes("is_switch"), retain="edge_id") edges_to_split = [edge for edge in g_ipv4.edges() if edge.attr_both( "is_l3device")] split_created_nodes = list( ank_utils.split(g_ipv4, edges_to_split, retain='edge_id')) for node in split_created_nodes: node['graphics'].x = ank_utils.neigh_average(g_ipv4, node, "x", g_graphics) + 0.1 # temporary fix for gh-90 node['graphics'].y = ank_utils.neigh_average(g_ipv4, node, "y", g_graphics) + 0.1 # temporary fix for gh-90 asn = ank_utils.neigh_most_frequent( g_ipv4, node, "asn", g_phy) # arbitrary choice node['graphics'].asn = asn node.asn = asn # need to use asn in IP overlay for aggregating subnets switch_nodes = g_ipv4.nodes("is_switch") # regenerate due to aggregated g_ipv4.update(switch_nodes, collision_domain=True) # switches are part of collision domain g_ipv4.update(split_created_nodes, collision_domain=True) # Assign collision domain to a host if all neighbours from same host for node in split_created_nodes: if ank_utils.neigh_equal(g_ipv4, node, "host", g_phy): node.host = ank_utils.neigh_attr( g_ipv4, node, "host", g_phy).next() # first attribute # set collision domain IPs for node in g_ipv4.nodes("collision_domain"): graphics_node = g_graphics.node(node) graphics_node.device_type = "collision_domain" if not node.is_switch: label = "_".join( sorted(ank_utils.neigh_attr(g_ipv4, node, "label", g_phy))) cd_label = "cd_%s" % label # switches keep their names node.label = cd_label node.cd_id = cd_label graphics_node.label = cd_label #TODO: need to set allocate_ipv4 by default in the readers if g_in.data.allocate_ipv4 is False: manual_ipv4_allocation(anm) else: import autonetkit.plugins.ipv4 as ipv4 ipv4.allocate_ips(g_ipv4, infrastructure) ank_utils.save(g_ipv4)
def apply_design_rules(anm): g_in = anm['input'] build_phy(anm) g_phy = anm['phy'] build_vrf(anm) # need to do before to add loopbacks before ip allocations build_ip(anm) # ip infrastructure topology #TODO: set defaults at the start, rather than inline, ie set g_in.data.address_family then use later address_family = g_in.data.address_family or "v4" # default is v4 #TODO: can remove the infrastructure now create g_ip seperately if address_family in ("v4", "dual_stack"): build_ipv4(anm, infrastructure=True) g_phy.update(g_phy, use_ipv4=True) else: build_ipv4(anm, infrastructure=False) #TODO: Create a collision domain overlay for ip addressing - l2 overlay? if address_family in ("v6", "dual_stack"): build_ipv6(anm) g_phy.update(g_phy, use_ipv6=True) else: anm.add_overlay("ipv6") # placeholder for compiler logic default_igp = g_in.data.igp or "ospf" non_igp_nodes = [n for n in g_in if not n.igp] #TODO: should this be modifying g_in? g_in.update(non_igp_nodes, igp=default_igp) # store igp onto each node ank_utils.copy_attr_from(g_in, g_phy, "include_csr") build_ospf(anm) build_isis(anm) build_bgp(anm) autonetkit.update_http(anm) # post-processing mark_ebgp_vrf(anm) build_ibgp_vpn_v4(anm) # build after bgp as is based on #autonetkit.update_http(anm) return anm
def build_ip6(anm): """Builds IPv6 graph, using nodes and edges from IPv4 graph""" import autonetkit.plugins.ipv6 as ipv6 # uses the nodes and edges from ipv4 g_ipv6 = anm.add_overlay("ipv6") g_ipv4 = anm['ipv4'] g_ipv6.add_nodes_from( g_ipv4, retain="collision_domain") # retain if collision domain or not g_ipv6.add_edges_from(g_ipv4.edges()) ipv6.allocate_ips(g_ipv6)
def build_ibgp_v6(anm): #TODO: remove the bgp layer and have just ibgp and ebgp # TODO: build from design rules, currently just builds from ibgp links in bgp layer #TODO: base on generic ibgp graph, rather than bgp graph g_bgp = anm['bgp'] g_phy = anm['phy'] g_ibgpv6 = anm.add_overlay("ibgp_v6", directed=True) ipv6_nodes = set(g_phy.nodes("is_router", "use_ipv6")) g_ibgpv6.add_nodes_from((n for n in g_bgp if n in ipv6_nodes), retain = ["ibgp_level", "ibgp_l2_cluster", "ibgp_l3_cluster"] ) g_ibgpv6.add_edges_from(g_bgp.edges(type="ibgp"), retain="direction")
def build_ip6(anm): import autonetkit.plugins.ip6 as ip6 # uses the nodes and edges from ipv4 #TODO: make the nodes/edges common for IP, and then allocate after these #TODO: globally replace ip with ip4 G_ip6 = anm.add_overlay("ip6") G_in = anm['input'] G_ip4 = anm['ip'] G_ip6.add_nodes_from(G_ip4, retain="collision_domain") # retain if collision domain or not G_ip6.add_edges_from(G_ip4.edges()) ip6.allocate_ips(G_ip6)
def build_ip(anm): g_ip = anm.add_overlay("ip") g_in = anm['input'] g_graphics = anm['graphics'] g_phy = anm['phy'] g_ip.add_nodes_from(g_in) g_ip.add_edges_from(g_in.edges(type="physical")) ank_utils.aggregate_nodes(g_ip, g_ip.nodes("is_switch"), retain="edge_id") edges_to_split = [ edge for edge in g_ip.edges() if edge.attr_both("is_l3device") ] for edge in edges_to_split: edge.split = True # mark as split for use in building nidb split_created_nodes = list( ank_utils.split(g_ip, edges_to_split, retain=['edge_id', 'split'], id_prepend="cd")) for node in split_created_nodes: node['graphics'].x = ank_utils.neigh_average( g_ip, node, "x", g_graphics) + 0.1 # temporary fix for gh-90 node['graphics'].y = ank_utils.neigh_average( g_ip, node, "y", g_graphics) + 0.1 # temporary fix for gh-90 asn = ank_utils.neigh_most_frequent(g_ip, node, "asn", g_phy) # arbitrary choice node['graphics'].asn = asn node.asn = asn # need to use asn in IP overlay for aggregating subnets switch_nodes = g_ip.nodes("is_switch") # regenerate due to aggregated g_ip.update(switch_nodes, collision_domain=True) # switches are part of collision domain g_ip.update(split_created_nodes, collision_domain=True) # Assign collision domain to a host if all neighbours from same host for node in split_created_nodes: if ank_utils.neigh_equal(g_ip, node, "host", g_phy): node.host = ank_utils.neigh_attr(g_ip, node, "host", g_phy).next() # first attribute # set collision domain IPs for node in g_ip.nodes("collision_domain"): graphics_node = g_graphics.node(node) graphics_node.device_type = "collision_domain" if not node.is_switch: # use node sorting, as accomodates for numeric/string names neighbors = sorted(neigh for neigh in node.neighbors()) label = "_".join(neigh.label for neigh in neighbors) cd_label = "cd_%s" % label # switches keep their names node.label = cd_label node.cd_id = cd_label graphics_node.label = cd_label
def initialise(input_graph): """Initialises the input graph with from a NetworkX graph""" anm = autonetkit.anm.AbstractNetworkModel() input_undirected = nx.Graph(input_graph) g_in = anm.add_overlay("input", graph=input_undirected) # set defaults if not g_in.data.specified_int_names: # if not specified then automatically assign interface names g_in.data.specified_int_names = False #import autonetkit.plugins.graph_product as graph_product #graph_product.expand(g_in) # apply graph products if relevant expand_fqdn = False # TODO: make this set from config and also in the input file if expand_fqdn and len(ank_utils.unique_attr(g_in, "asn")) > 1: # Multiple ASNs set, use label format device.asn anm.set_node_label(".", ['label', 'asn']) g_in.update(g_in.routers(platform="junosphere"), syntax="junos") g_in.update(g_in.routers(platform="dynagen"), syntax="ios") g_in.update(g_in.routers(platform="netkit"), syntax="quagga") #TODO: is this used? g_in.update(g_in.servers(platform="netkit"), syntax="quagga") autonetkit.ank.set_node_default(g_in, specified_int_names=None) g_graphics = anm.add_overlay("graphics") # plotting data g_graphics.add_nodes_from( g_in, retain=['x', 'y', 'device_type', 'label', 'device_subtype', 'asn']) if g_in.data.Creator == "VIRL": #TODO: move this to other module # Multiple ASNs set, use label format device.asn #anm.set_node_label(".", ['label_full']) pass return anm
def build_ibgp_v6(anm): #TODO: remove the bgp layer and have just ibgp and ebgp # TODO: build from design rules, currently just builds from ibgp links in bgp layer #TODO: base on generic ibgp graph, rather than bgp graph g_bgp = anm['bgp'] g_phy = anm['phy'] g_ibgpv6 = anm.add_overlay("ibgp_v6", directed=True) ipv6_nodes = set(g_phy.nodes("is_router", "use_ipv6")) g_ibgpv6.add_nodes_from( (n for n in g_bgp if n in ipv6_nodes), retain=["ibgp_level", "ibgp_l2_cluster", "ibgp_l3_cluster"]) g_ibgpv6.add_edges_from(g_bgp.edges(type="ibgp"), retain="direction")
def apply_design_rules(anm): """Applies appropriate design rules to ANM""" g_in = anm['input'] build_phy(anm) g_phy = anm['phy'] from autonetkit.design.osi_layers import (build_layer2, build_layer2_broadcast, build_layer3) build_layer2(anm) build_layer2_broadcast(anm) build_layer3(anm) build_l3_connectivity(anm) check_server_asns(anm) from autonetkit.design.mpls import build_vrf build_vrf(anm) # do before to add loopbacks before ip allocations from autonetkit.design.ip import build_ip, build_ipv4, build_ipv6 # TODO: replace this with layer2 overlay topology creation build_ip(anm) # ip infrastructure topology address_family = g_in.data.address_family or "v4" # default is v4 # TODO: can remove the infrastructure now create g_ip seperately if address_family == "None": log.info("IP addressing disabled, disabling routing protocol ", "configuration") anm['phy'].data.enable_routing = False if address_family == "None": log.info("IP addressing disabled, skipping IPv4") anm.add_overlay("ipv4") # create empty so rest of code follows g_phy.update(g_phy, use_ipv4=False) elif address_family in ("v4", "dual_stack"): build_ipv4(anm, infrastructure=True) g_phy.update(g_phy, use_ipv4=True) elif address_family == "v6": # Allocate v4 loopbacks for router ids build_ipv4(anm, infrastructure=False) g_phy.update(g_phy, use_ipv4=False) # TODO: Create collision domain overlay for ip addressing - l2 overlay? if address_family == "None": log.info("IP addressing disabled, not allocating IPv6") anm.add_overlay("ipv6") # create empty so rest of code follows g_phy.update(g_phy, use_ipv6=False) elif address_family in ("v6", "dual_stack"): build_ipv6(anm) g_phy.update(g_phy, use_ipv6=True) else: anm.add_overlay("ipv6") # placeholder for compiler logic default_igp = g_in.data.igp or "ospf" ank_utils.set_node_default(g_in, igp=default_igp) ank_utils.copy_attr_from(g_in, g_phy, "include_csr") try: from autonetkit_cisco import build_network as cisco_build_network except ImportError, e: log.debug("Unable to load autonetkit_cisco %s" % e)
def apply_design_rules(anm): """Applies appropriate design rules to ANM""" g_in = anm['input'] build_phy(anm) g_phy = anm['phy'] import autonetkit autonetkit.update_http(anm) build_l3_connectivity(anm) check_server_asns(anm) autonetkit.update_http(anm) build_vrf(anm) # need to do before to add loopbacks before ip allocations from autonetkit.design.ip import build_ip, build_ipv4,build_ipv6 build_ip(anm) # ip infrastructure topology #TODO: set defaults at the start, rather than inline, ie set g_in.data.address_family then use later address_family = g_in.data.address_family or "v4" # default is v4 #TODO: can remove the infrastructure now create g_ip seperately if address_family == "None": log.info("IP addressing disabled, disabling routing protocol configuration") anm['phy'].data.enable_routing = False if address_family == "None": log.info("IP addressing disabled, skipping IPv4") anm.add_overlay("ipv4") # create empty so rest of code follows through g_phy.update(g_phy, use_ipv4 = False) elif address_family in ("v4", "dual_stack"): build_ipv4(anm, infrastructure = True) g_phy.update(g_phy, use_ipv4 = True) elif address_family == "v6": # Allocate v4 loopbacks for router ids build_ipv4(anm, infrastructure = False) g_phy.update(g_phy, use_ipv4 = False) #TODO: Create a collision domain overlay for ip addressing - l2 overlay? if address_family == "None": log.info("IP addressing disabled, not allocating IPv6") anm.add_overlay("ipv6") # create empty so rest of code follows through g_phy.update(g_phy, use_ipv6 = False) elif address_family in ("v6", "dual_stack"): build_ipv6(anm) g_phy.update(g_phy, use_ipv6 = True) else: anm.add_overlay("ipv6") # placeholder for compiler logic default_igp = g_in.data.igp or "ospf" non_igp_nodes = [n for n in g_in if not n.igp] #TODO: should this be modifying g_in? g_in.update(non_igp_nodes, igp=default_igp) # store igp onto each node ank_utils.copy_attr_from(g_in, g_phy, "include_csr") try: from autonetkit_cisco import build_network as cisco_build_network except ImportError, e: log.debug("Unable to load autonetkit_cisco %s" % e)
def build_ip(anm): g_ip = anm.add_overlay("ip") g_in = anm['input'] g_graphics = anm['graphics'] g_phy = anm['phy'] g_ip.add_nodes_from(g_in) g_ip.add_edges_from(g_in.edges(type="physical")) ank_utils.aggregate_nodes(g_ip, g_ip.nodes("is_switch"), retain="edge_id") edges_to_split = [edge for edge in g_ip.edges() if edge.attr_both( "is_l3device")] for edge in edges_to_split: edge.split = True # mark as split for use in building nidb split_created_nodes = list( ank_utils.split(g_ip, edges_to_split, retain=['edge_id', 'split'], id_prepend = "cd")) for node in split_created_nodes: node['graphics'].x = ank_utils.neigh_average(g_ip, node, "x", g_graphics) + 0.1 # temporary fix for gh-90 node['graphics'].y = ank_utils.neigh_average(g_ip, node, "y", g_graphics) + 0.1 # temporary fix for gh-90 asn = ank_utils.neigh_most_frequent( g_ip, node, "asn", g_phy) # arbitrary choice node['graphics'].asn = asn node.asn = asn # need to use asn in IP overlay for aggregating subnets switch_nodes = g_ip.nodes("is_switch") # regenerate due to aggregated g_ip.update(switch_nodes, collision_domain=True) # switches are part of collision domain g_ip.update(split_created_nodes, collision_domain=True) # Assign collision domain to a host if all neighbours from same host for node in split_created_nodes: if ank_utils.neigh_equal(g_ip, node, "host", g_phy): node.host = ank_utils.neigh_attr( g_ip, node, "host", g_phy).next() # first attribute # set collision domain IPs for node in g_ip.nodes("collision_domain"): graphics_node = g_graphics.node(node) graphics_node.device_type = "collision_domain" if not node.is_switch: # use node sorting, as accomodates for numeric/string names neighbors = sorted(neigh for neigh in node.neighbors()) label = "_".join(neigh.label for neigh in neighbors) cd_label = "cd_%s" % label # switches keep their names node.label = cd_label node.cd_id = cd_label graphics_node.label = cd_label
def apply_design_rules(anm): """Applies appropriate design rules to ANM""" g_in = anm['input'] build_phy(anm) g_phy = anm['phy'] build_l3_connectivity(anm) check_server_asns(anm) from autonetkit.design.mpls import build_vrf build_vrf(anm) # need to do before to add loopbacks before ip allocations from autonetkit.design.ip import build_ip, build_ipv4, build_ipv6 #TODO: replace this with layer2 overlay topology creation build_ip(anm) # ip infrastructure topology #TODO: set defaults at the start, rather than inline, ie set g_in.data.address_family then use later address_family = g_in.data.address_family or "v4" # default is v4 #TODO: can remove the infrastructure now create g_ip seperately if address_family == "None": log.info( "IP addressing disabled, disabling routing protocol configuration") anm['phy'].data.enable_routing = False if address_family == "None": log.info("IP addressing disabled, skipping IPv4") anm.add_overlay("ipv4") # create empty so rest of code follows through g_phy.update(g_phy, use_ipv4=False) elif address_family in ("v4", "dual_stack"): build_ipv4(anm, infrastructure=True) g_phy.update(g_phy, use_ipv4=True) elif address_family == "v6": # Allocate v4 loopbacks for router ids build_ipv4(anm, infrastructure=False) g_phy.update(g_phy, use_ipv4=False) #TODO: Create a collision domain overlay for ip addressing - l2 overlay? if address_family == "None": log.info("IP addressing disabled, not allocating IPv6") anm.add_overlay("ipv6") # create empty so rest of code follows through g_phy.update(g_phy, use_ipv6=False) elif address_family in ("v6", "dual_stack"): build_ipv6(anm) g_phy.update(g_phy, use_ipv6=True) else: anm.add_overlay("ipv6") # placeholder for compiler logic default_igp = g_in.data.igp or "ospf" ank_utils.set_node_default(g_in, igp=default_igp) ank_utils.copy_attr_from(g_in, g_phy, "include_csr") try: from autonetkit_cisco import build_network as cisco_build_network except ImportError, e: log.debug("Unable to load autonetkit_cisco %s" % e)
def build_ipv4(anm, infrastructure=True): """Builds IPv4 graph""" import autonetkit.plugins.ipv4 as ipv4 g_ipv4 = anm.add_overlay("ipv4") g_ip = anm['ip'] g_in = anm['input'] g_ipv4.add_nodes_from( g_ip, retain="collision_domain") # retain if collision domain or not # Copy ASN attribute chosen for collision domains (used in alloc algorithm) ank_utils.copy_attr_from(g_ip, g_ipv4, "asn", nbunch = g_ipv4.nodes("collision_domain")) g_ipv4.add_edges_from(g_ip.edges()) # check if ip ranges have been specified on g_in infra_block, loopback_block, vrf_loopback_block = extract_ipv4_blocks(anm) # See if IP addresses specified on each interface l3_devices = [d for d in g_in if d.device_type in ("router", "server")] manual_alloc_devices = set() for device in l3_devices: physical_interfaces = list(device.physical_interfaces) if all(interface.ipv4_address for interface in physical_interfaces): manual_alloc_devices.add(device) # add as a manual allocated device if manual_alloc_devices == set(l3_devices): manual_alloc_ipv4_infrastructure = True else: manual_alloc_ipv4_infrastructure = False #TODO: need to set allocate_ipv4 by default in the readers if manual_alloc_ipv4_infrastructure: manual_ipv4_infrastructure_allocation(anm) else: ipv4.allocate_infra(g_ipv4, infra_block) if g_in.data.alloc_ipv4_loopbacks is False: manual_ipv4_loopback_allocation(anm) else: ipv4.allocate_loopbacks(g_ipv4, loopback_block) #TODO: need to also support secondary_loopbacks for IPv6 #TODO: only call if secondaries are set ipv4.allocate_vrf_loopbacks(g_ipv4, vrf_loopback_block) #TODO: replace this with direct allocation to interfaces in ip alloc plugin for node in g_ipv4.nodes("is_l3device"): node.loopback_zero.ip_address = node.loopback
def build_ipv4(anm, infrastructure=True): """Builds IPv4 graph""" g_ipv4 = anm.add_overlay("ipv4") g_ip = anm["ip"] g_in = anm["input"] g_ipv4.add_nodes_from(g_ip, retain="collision_domain") # retain if collision domain or not # Copy ASN attribute chosen for collision domains (used in alloc algorithm) ank_utils.copy_attr_from(g_ip, g_ipv4, "asn", nbunch=g_ipv4.nodes("collision_domain")) g_ipv4.add_edges_from(g_ip.edges()) autonetkit.update_http(anm) # TODO: need to set allocate_ipv4 by default in the readers if g_in.data.alloc_ipv4_infrastructure is False: manual_ipv4_infrastructure_allocation(anm) else: import autonetkit.plugins.ipv4 as ipv4 ipv4.allocate_ips(g_ipv4, infrastructure=True, loopbacks=False) # ank_utils.save(g_ipv4) if g_in.data.alloc_ipv4_loopbacks is False: manual_ipv4_loopback_allocation(anm) else: import autonetkit.plugins.ipv4 as ipv4 ipv4.allocate_ips(g_ipv4, infrastructure=False, loopbacks=True) # ank_utils.save(g_ipv4) # TODO: need to also support secondary_loopbacks for IPv6 ipv4.allocate_ips(g_ipv4, infrastructure=False, loopbacks=False, secondary_loopbacks=True) autonetkit.update_http(anm) # TODO: replace this with direct allocation to interfaces in ip alloc plugin for node in g_ipv4.nodes("is_l3device"): node.loopback_zero.ip_address = node.loopback for interface in node: edges = list(interface.edges()) if len(edges): edge = edges[0] # first (only) edge interface.ip_address = edge.ip_address interface.subnet = edge.dst.subnet # from collision domain # TODO: also map loopbacks to loopback interface 0 autonetkit.update_http(anm)
def build_l3_connectivity(anm): """ creates l3_connectivity graph, which is switch nodes aggregated and exploded""" #TODO: use this as base for ospf, ebgp, ip, etc rather than exploding in each g_in = anm['input'] g_l3conn = anm.add_overlay("l3_conn") g_l3conn.add_nodes_from(g_in, retain=['label', 'update', 'device_type', 'asn', 'specified_int_names', 'device_subtype', 'platform', 'host', 'syntax']) g_l3conn.add_nodes_from(g_in.nodes("is_switch"), retain=['asn']) #TODO: check if edge_id needs to be still retained g_l3conn.add_edges_from(g_in.edges(), retain=['edge_id']) ank_utils.aggregate_nodes(g_l3conn, g_l3conn.nodes("is_switch"), retain="edge_id") exploded_edges = ank_utils.explode_nodes(g_l3conn, g_l3conn.nodes("is_switch"), retain="edge_id") for edge in exploded_edges: edge.multipoint = True
def build_overlays(filename): anm = autonetkit.anm.AbstractNetworkModel() input_graph = graphml.load_graphml(filename) G_in = anm.add_overlay("input", graph=input_graph) G_graphics = anm.add_overlay("graphics") # plotting data G_graphics.add_nodes_from(G_in, retain=['x', 'y', 'device_type', 'asn']) G_phy = anm['phy'] G_phy.add_nodes_from( G_in, retain=['label', 'device_type', 'asn', 'platform', 'host', 'syntax']) G_phy.add_edges_from(G_in.edges(type="physical")) G_phy.update(G_phy, syntax="quagga") routers = list(G_in.routers()) G_ospf = anm.add_overlay("ospf", G_in.routers()) G_ospf.add_edges_from(e for e in G_in.edges() if e.src.asn == e.dst.asn) G_ospf.update(area=0) # set defaults G_ospf.update_edges(area=0) G_ebgp = anm.add_overlay("ebgp", G_in.routers(), directed=True) G_ebgp.add_edges_from((e for e in G_in.edges() if e.src.asn != e.dst.asn), bidirectional=True) G_ibgp = anm.add_overlay("ibgp", G_in.routers(), directed=True) G_ibgp.add_edges_from( ((s, t) for s in routers for t in routers if s.asn == t.asn), bidirectional=True) # hierarchical G_ibgp = anm.add_overlay("ibgp_rr", G_in.routers(), directed=True) graph_phy = ank_utils.unwrap_graph(G_phy) centrality = nx.degree_centrality(graph_phy) rrs = [n for n in centrality if centrality[n] > 0.13] for rr in rrs: G_ibgp.node(rr).route_reflector = True rrs = set(r for r in G_ibgp if r.route_reflector) clients = set(G_ibgp) - rrs G_ibgp.add_edges_from(((s, t) for s in clients for t in rrs), direction="up") G_ibgp.add_edges_from(((s, t) for s in rrs for t in clients), direction="down") G_ibgp.add_edges_from(((s, t) for s in rrs for t in rrs), direction="over") build_ip(anm) return anm
def build_l3_connectivity(anm): """ l3_connectivity graph: switch nodes aggregated and exploded""" g_in = anm['input'] g_l3conn = anm.add_overlay("l3_conn") g_l3conn.add_nodes_from( g_in, retain=['label', 'update', 'device_type', 'asn', 'specified_int_names', 'device_subtype', 'platform', 'host', 'syntax']) g_l3conn.add_nodes_from(g_in.switches(), retain=['asn']) g_l3conn.add_edges_from(g_in.edges()) ank_utils.aggregate_nodes(g_l3conn, g_l3conn.switches()) exploded_edges = ank_utils.explode_nodes(g_l3conn, g_l3conn.switches()) for edge in exploded_edges: edge.multipoint = True edge.src_int.multipoint = True edge.dst_int.multipoint = True
def build_speed(anm): g_in = anm['input'] g_speed = anm.add_overlay("speed") g_speed.add_nodes_from(g_in.nodes()) g_speed.add_edges_from(g_in.edges(), retain=['speed']) for edge in g_speed.edges(): if not edge.delay: delay = 0 else: delay = edge.delay if not edge.speed: speed = 0 else: speed = edge.speed edge.src_int.speed = speed edge.dst_int.speed = speed edge.src_int.delay = delay edge.dst_int.delay = delay
def build_l3_connectivity(anm): """ l3_connectivity graph: switch nodes aggregated and exploded""" g_in = anm['input'] g_l3conn = anm.add_overlay("layer3") g_l3conn.add_nodes_from(g_in, retain=[ 'label', 'update', 'device_type', 'asn', 'specified_int_names', 'device_subtype', 'platform', 'host', 'syntax' ]) g_l3conn.add_nodes_from(g_in.switches(), retain=['asn']) g_l3conn.add_edges_from(g_in.edges()) ank_utils.aggregate_nodes(g_l3conn, g_l3conn.switches()) exploded_edges = ank_utils.explode_nodes(g_l3conn, g_l3conn.switches()) for edge in exploded_edges: edge.multipoint = True edge.src_int.multipoint = True edge.dst_int.multipoint = True
def build_l3_connectivity(anm): """ creates l3_connectivity graph, which is switch nodes aggregated and exploded""" #TODO: use this as base for ospf, ebgp, ip, etc rather than exploding in each g_in = anm['input'] g_l3conn = anm.add_overlay("l3_conn") g_l3conn.add_nodes_from(g_in, retain=[ 'label', 'update', 'device_type', 'asn', 'specified_int_names', 'device_subtype', 'platform', 'host', 'syntax' ]) g_l3conn.add_nodes_from(g_in.switches(), retain=['asn']) g_l3conn.add_edges_from(g_in.edges()) ank_utils.aggregate_nodes(g_l3conn, g_l3conn.switches()) exploded_edges = ank_utils.explode_nodes(g_l3conn, g_l3conn.switches()) for edge in exploded_edges: edge.multipoint = True edge.src_int.multipoint = True edge.dst_int.multipoint = True
def build_ipv4(anm, infrastructure=True): """Builds IPv4 graph""" import autonetkit.plugins.ipv4 as ipv4 g_ipv4 = anm.add_overlay("ipv4") g_ip = anm['ip'] g_in = anm['input'] g_ipv4.add_nodes_from( g_ip, retain="collision_domain") # retain if collision domain or not # Copy ASN attribute chosen for collision domains (used in alloc algorithm) ank_utils.copy_attr_from(g_ip, g_ipv4, "asn", nbunch=g_ipv4.nodes("collision_domain")) g_ipv4.add_edges_from(g_ip.edges()) # check if ip ranges have been specified on g_in infra_block, loopback_block, vrf_loopback_block = extract_ipv4_blocks(anm) #TODO: need to set allocate_ipv4 by default in the readers if g_in.data.alloc_ipv4_infrastructure is False: manual_ipv4_infrastructure_allocation(anm) else: ipv4.allocate_infra(g_ipv4, infra_block) if g_in.data.alloc_ipv4_loopbacks is False: manual_ipv4_loopback_allocation(anm) else: ipv4.allocate_loopbacks(g_ipv4, loopback_block) #TODO: need to also support secondary_loopbacks for IPv6 ipv4.allocate_vrf_loopbacks(g_ipv4, vrf_loopback_block) #TODO: replace this with direct allocation to interfaces in ip alloc plugin for node in g_ipv4.nodes("is_l3device"): node.loopback_zero.ip_address = node.loopback for interface in node: edges = list(interface.edges()) if len(edges): edge = edges[0] # first (only) edge interface.ip_address = edge.ip_address interface.subnet = edge.dst.subnet # from collision domain
def build_ip(anm): import autonetkit.plugins.ipv4 as ip G_ip = anm.add_overlay("ip") G_in = anm['input'] G_graphics = anm['graphics'] G_phy = anm['phy'] G_ip.add_nodes_from(G_in) G_ip.add_edges_from(G_in.edges(type="physical")) ank.aggregate_nodes(G_ip, G_ip.nodes("is_switch"), retain="edge_id") edges_to_split = [ edge for edge in G_ip.edges() if edge.attr_both("is_l3device") ] split_created_nodes = list( ank.split(G_ip, edges_to_split, retain='edge_id')) for node in split_created_nodes: node['graphics'].x = ank.neigh_average(G_ip, node, "x", G_graphics) node['graphics'].y = ank.neigh_average(G_ip, node, "y", G_graphics) G_ip.update(split_created_nodes, collision_domain=True) for node in G_ip.nodes("collision_domain"): graphics_node = G_graphics.node(node) node.host = G_phy.node( node.neighbors().next() ).host # Set host to be same as one of the neighbors (arbitrary choice) asn = ank.neigh_most_frequent(G_ip, node, "asn", G_phy) # arbitrary choice node.asn = asn graphics_node.asn = asn graphics_node.x = ank.neigh_average(G_ip, node, "x", G_graphics) graphics_node.device_type = "collision_domain" cd_label = "cd_" + "_".join( sorted(ank.neigh_attr(G_ip, node, "label", G_phy))) node.label = cd_label graphics_node.label = cd_label ip.allocate_ips(G_ip)
def build_ipv6(anm): """Builds IPv6 graph, using nodes and edges from IPv4 graph""" import autonetkit.plugins.ipv6 as ipv6 # uses the nodes and edges from ipv4 g_ipv6 = anm.add_overlay("ipv6") g_ip = anm['ip'] g_ipv6.add_nodes_from( g_ip, retain="collision_domain") # retain if collision domain or not g_ipv6.add_edges_from(g_ip.edges()) ipv6.allocate_ips(g_ipv6) #TODO: replace this with direct allocation to interfaces in ip alloc plugin for node in g_ipv6.nodes("is_l3device"): node.loopback_zero.ip_address = node.loopback for interface in node: edges = list(interface.edges()) if len(edges): edge = edges[0] # first (only) edge interface.ip_address = edge.ip #TODO: make this consistent interface.subnet = edge.dst.subnet # from collision domain
def build_ebgp(anm): g_in = anm['input'] g_phy = anm['phy'] g_ebgp = anm.add_overlay("ebgp", directed=True) g_ebgp.add_nodes_from(g_in.nodes("is_router")) ebgp_edges = [e for e in g_in.edges() if not e.attr_equal("asn")] g_ebgp.add_edges_from(ebgp_edges, bidirectional=True, type='ebgp') ebgp_switches = [n for n in g_in.nodes("is_switch") if not ank_utils.neigh_equal(g_phy, n, "asn")] g_ebgp.add_nodes_from(ebgp_switches, retain=['asn']) log.debug("eBGP switches are %s" % ebgp_switches) g_ebgp.add_edges_from((e for e in g_in.edges() if e.src in ebgp_switches or e.dst in ebgp_switches), bidirectional=True, type='ebgp') ank_utils.aggregate_nodes(g_ebgp, ebgp_switches, retain="edge_id") ebgp_switches = list(g_ebgp.nodes("is_switch")) # need to recalculate as may have aggregated log.debug("aggregated eBGP switches are %s" % ebgp_switches) exploded_edges = ank_utils.explode_nodes(g_ebgp, ebgp_switches, retain="edge_id") for edge in exploded_edges: edge.multipoint = True
def build_mpls_ldp(anm): """Builds MPLS LDP""" g_in = anm['input'] g_vrf = anm['vrf'] g_mpls_ldp = anm.add_overlay("mpls_ldp") nodes_to_add = [ n for n in g_in.nodes("is_router") if n['vrf'].vrf_role in ("PE", "P") ] g_mpls_ldp.add_nodes_from(nodes_to_add, retain=["vrf_role", "vrf"]) # store as set for faster lookup pe_nodes = set(g_vrf.nodes(vrf_role="PE")) p_nodes = set(g_vrf.nodes(vrf_role="P")) pe_to_pe_edges = (e for e in g_in.edges() if e.src in pe_nodes and e.dst in pe_nodes) g_mpls_ldp.add_edges_from(pe_to_pe_edges) pe_to_p_edges = (e for e in g_in.edges() if e.src in pe_nodes and e.dst in p_nodes or e.src in p_nodes and e.dst in pe_nodes) g_mpls_ldp.add_edges_from(pe_to_p_edges)
def build_isis(anm): """Build isis overlay""" g_in = anm['input'] # add regardless, so allows quick check of node in anm['isis'] in compilers g_isis = anm.add_overlay("isis") if not any(n.igp == "isis" for n in g_in): log.debug("No ISIS nodes") return g_ipv4 = anm['ipv4'] g_isis.add_nodes_from(g_in.nodes("is_router", igp="isis"), retain=['asn']) g_isis.add_nodes_from(g_in.nodes("is_switch"), retain=['asn']) g_isis.add_edges_from(g_in.edges(), retain=['edge_id']) # Merge and explode switches ank_utils.aggregate_nodes(g_isis, g_isis.nodes("is_switch"), retain="edge_id") exploded_edges = ank_utils.explode_nodes(g_isis, g_isis.nodes("is_switch"), retain="edge_id") for edge in exploded_edges: edge.multipoint = True g_isis.remove_edges_from( [link for link in g_isis.edges() if link.src.asn != link.dst.asn]) for node in g_isis: ip_node = g_ipv4.node(node) node.net = ip_to_net_ent_title_ios(ip_node.loopback) node.process_id = 1 # default for link in g_isis.edges(): link.metric = 1 # default # link.hello = 5 # for debugging, TODO: read from graph for edge in g_isis.edges(): for interface in edge.interfaces(): interface.metric = edge.metric interface.multipoint = edge.multipoint
def build_isis(anm): G_in = anm['input'] G_ip = anm['ip'] G_isis = anm.add_overlay("isis") #G_isis.add_nodes_from(G_in.nodes("is_router", igp = "isis"), retain=['asn']) #TODO: filter only igp=isis nodes, set the igp as a default in build_network G_isis.add_nodes_from(G_in.nodes("is_router"), retain=['asn']) G_isis.add_nodes_from(G_in.nodes("is_switch"), retain=['asn']) G_isis.add_edges_from(G_in.edges(), retain = ['edge_id']) # Merge and explode switches ank.aggregate_nodes(G_isis, G_isis.nodes("is_switch"), retain = "edge_id") ank.explode_nodes(G_isis, G_isis.nodes("is_switch"), retain = "edge_id") G_isis.remove_edges_from([link for link in G_isis.edges() if link.src.asn != link.dst.asn]) for node in G_isis: ip_node = G_ip.node(node) node.net = ip_to_net_ent_title_ios(ip_node.loopback) node.process_id = 1 # default for link in G_isis.edges(): link.metric = 1 # default
def build_ipv4(anm, infrastructure=True): """Builds IPv4 graph""" import autonetkit.plugins.ipv4 as ipv4 g_ipv4 = anm.add_overlay("ipv4") g_ip = anm['ip'] g_in = anm['input'] g_ipv4.add_nodes_from( g_ip, retain="collision_domain") # retain if collision domain or not # Copy ASN attribute chosen for collision domains (used in alloc algorithm) ank_utils.copy_attr_from(g_ip, g_ipv4, "asn", nbunch = g_ipv4.nodes("collision_domain")) g_ipv4.add_edges_from(g_ip.edges()) # check if ip ranges have been specified on g_in infra_block, loopback_block, vrf_loopback_block = extract_ipv4_blocks(anm) #TODO: need to set allocate_ipv4 by default in the readers if g_in.data.alloc_ipv4_infrastructure is False: manual_ipv4_infrastructure_allocation(anm) else: ipv4.allocate_infra(g_ipv4, infra_block) if g_in.data.alloc_ipv4_loopbacks is False: manual_ipv4_loopback_allocation(anm) else: ipv4.allocate_loopbacks(g_ipv4, loopback_block) #TODO: need to also support secondary_loopbacks for IPv6 ipv4.allocate_vrf_loopbacks(g_ipv4, vrf_loopback_block) #TODO: replace this with direct allocation to interfaces in ip alloc plugin for node in g_ipv4.nodes("is_l3device"): node.loopback_zero.ip_address = node.loopback for interface in node: edges = list(interface.edges()) if len(edges): edge = edges[0] # first (only) edge interface.ip_address = edge.ip_address interface.subnet = edge.dst.subnet # from collision domain
def build_overlays(filename): anm = autonetkit.anm.AbstractNetworkModel() input_graph = graphml.load_graphml(filename) G_in = anm.add_overlay("input", graph = input_graph) G_graphics = anm.add_overlay("graphics") # plotting data G_graphics.add_nodes_from(G_in, retain=['x', 'y', 'device_type', 'asn']) G_phy = anm['phy'] G_phy.add_nodes_from(G_in, retain=['label', 'device_type', 'asn', 'platform', 'host', 'syntax']) G_phy.add_edges_from(G_in.edges(type="physical")) G_phy.update(G_phy, syntax="quagga") routers = list(G_in.routers()) G_ospf = anm.add_overlay("ospf", G_in.routers()) G_ospf.add_edges_from(e for e in G_in.edges() if e.src.asn == e.dst.asn) G_ospf.update(area=0) # set defaults G_ospf.update_edges(area=0) G_ebgp = anm.add_overlay("ebgp", G_in.routers(), directed = True) G_ebgp.add_edges_from((e for e in G_in.edges() if e.src.asn != e.dst.asn), bidirectional = True) G_ibgp = anm.add_overlay("ibgp", G_in.routers(), directed = True) G_ibgp.add_edges_from(((s, t) for s in routers for t in routers if s.asn == t.asn), bidirectional = True) # hierarchical G_ibgp = anm.add_overlay("ibgp_rr", G_in.routers(), directed = True) graph_phy = ank_utils.unwrap_graph(G_phy) centrality = nx.degree_centrality(graph_phy) rrs = [n for n in centrality if centrality[n] > 0.13] for rr in rrs: G_ibgp.node(rr).route_reflector = True rrs = set(r for r in G_ibgp if r.route_reflector) clients = set(G_ibgp) - rrs G_ibgp.add_edges_from(((s, t) for s in clients for t in rrs), direction = "up") G_ibgp.add_edges_from(((s, t) for s in rrs for t in clients), direction = "down") G_ibgp.add_edges_from(((s, t) for s in rrs for t in rrs), direction = "over") build_ip(anm) return anm
def build_isis(anm): """Build isis overlay""" g_in = anm['input'] # add regardless, so allows quick check of node in anm['isis'] in compilers g_isis = anm.add_overlay("isis") if not any(n.igp == "isis" for n in g_in): log.debug("No ISIS nodes") return g_ipv4 = anm['ipv4'] g_isis.add_nodes_from(g_in.nodes("is_router", igp = "isis"), retain=['asn']) g_isis.add_nodes_from(g_in.nodes("is_server", igp = "isis"), retain=['asn']) g_isis.add_nodes_from(g_in.nodes("is_switch"), retain=['asn']) g_isis.add_edges_from(g_in.edges(), retain=['edge_id']) # Merge and explode switches ank_utils.aggregate_nodes(g_isis, g_isis.nodes("is_switch"), retain="edge_id") exploded_edges = ank_utils.explode_nodes(g_isis, g_isis.nodes("is_switch"), retain="edge_id") for edge in exploded_edges: edge.multipoint = True g_isis.remove_edges_from( [link for link in g_isis.edges() if link.src.asn != link.dst.asn]) for node in g_isis: ip_node = g_ipv4.node(node) node.net = ip_to_net_ent_title_ios(ip_node.loopback) node.process_id = 1 # default for link in g_isis.edges(): link.metric = 1 # default for edge in g_isis.edges(): for interface in edge.interfaces(): interface.metric = edge.metric interface.multipoint = edge.multipoint
def initialise(input_graph): """Initialises the input graph with from a NetworkX graph""" all_multigraph = input_graph.is_multigraph() anm = autonetkit.anm.NetworkModel(all_multigraph=all_multigraph) g_in = anm.initialise_input(input_graph) # autonetkit.update_vis(anm) # set defaults if not g_in.data.specified_int_names: # if not specified then automatically assign interface names g_in.data.specified_int_names = False #import autonetkit.plugins.graph_product as graph_product # graph_product.expand(g_in) # apply graph products if relevant expand_fqdn = False # TODO: make this set from config and also in the input file if expand_fqdn and len(ank_utils.unique_attr(g_in, "asn")) > 1: # Multiple ASNs set, use label format device.asn anm.set_node_label(".", ['label', 'asn']) g_in.update(g_in.routers(platform="junosphere"), syntax="junos") g_in.update(g_in.routers(platform="dynagen"), syntax="ios") g_in.update(g_in.routers(platform="netkit"), syntax="quagga") # TODO: is this used? g_in.update(g_in.servers(platform="netkit"), syntax="quagga") #TODO: check this is needed #autonetkit.ank.set_node_default(g_in, specified_int_names=None) g_graphics = anm.add_overlay("graphics") # plotting data g_graphics.add_nodes_from( g_in, retain=['x', 'y', 'device_type', 'label', 'device_subtype', 'asn']) return anm
def build_ibgp_vpn_v4(anm): """Based on the ibgp_v4 hierarchy rules. Exceptions: 1. Remove links to (PE, RRC) nodes CE nodes are excluded from RR hierarchy ibgp creation through pre-process step """ #TODO: remove the bgp layer and have just ibgp and ebgp # TODO: build from design rules, currently just builds from ibgp links in bgp layer g_bgp = anm['bgp'] g_ibgp_v4 = anm['ibgp_v4'] g_vrf = anm['vrf'] g_phy = anm['phy'] g_ibgp_vpn_v4 = anm.add_overlay("ibgp_vpn_v4", directed=True) ibgp_v4_nodes = list(g_ibgp_v4.nodes()) pe_nodes = set(g_vrf.nodes(vrf_role="PE")) pe_rrc_nodes = { n for n in ibgp_v4_nodes if n in pe_nodes and n.ibgp_role == "RRC" } ce_nodes = set(g_vrf.nodes(vrf_role="CE")) ibgp_vpn_v4_nodes = (n for n in ibgp_v4_nodes if n not in pe_rrc_nodes and n not in ce_nodes) g_ibgp_vpn_v4.add_nodes_from(ibgp_vpn_v4_nodes, retain="ibgp_level") g_ibgp_vpn_v4.add_edges_from(g_ibgp_v4.edges(), retain="direction") for node in g_ibgp_vpn_v4: if node.ibgp_level in (2, 3): # HRR or RR node.retain_route_target = True ce_edges = [ e for e in g_ibgp_vpn_v4.edges() if e.src in ce_nodes or e.dst in ce_nodes ] """ #TODO: do we still need this? g_ibgp_vpn_v4.remove_edges_from(ce_edges) # add CE -> PE links based on physical connectivity #Note: this could later look at ce_to_pe_edges = [] ce_phy_nodes = {g_phy.node(n) for n in ce_nodes} pe_phy_nodes = {g_phy.node(n) for n in g_vrf.nodes(vrf_role = "PE")} ce_to_pe_edges += (e for e in g_phy.edges() if e.src.asn == e.dst.asn and ((e.src in ce_phy_nodes and e.dst in pe_phy_nodes) or (e.src in pe_phy_nodes and e.dst in ce_phy_nodes))) g_ibgp_vpn_v4.add_edges_from(ce_to_pe_edges, type="ibgp", bidirectional = True) """ # mark ibgp direction ce_pe_edges = [] pe_ce_edges = [] for edge in g_ibgp_vpn_v4.edges(): if (edge.src.vrf_role, edge.dst.vrf_role) == ("CE", "PE"): edge.direction = "up" edge.vrf = edge.src.vrf ce_pe_edges.append(edge) elif (edge.src.vrf_role, edge.dst.vrf_role) == ("PE", "CE"): edge.direction = "down" edge.vrf = edge.dst.vrf pe_ce_edges.append(edge) #TODO: Document this g_ibgpv4 = anm['ibgp_v4'] g_ibgpv6 = anm['ibgp_v6'] g_ibgpv4.remove_edges_from(ce_edges) g_ibgpv6.remove_edges_from(ce_edges) g_ibgpv4.add_edges_from(ce_pe_edges, retain=["direction", "vrf"]) g_ibgpv4.add_edges_from(pe_ce_edges, retain=["direction", "vrf"]) g_ibgpv6.add_edges_from(ce_pe_edges, retain=["direction", "vrf"]) g_ibgpv6.add_edges_from(pe_ce_edges, retain=["direction", "vrf"]) for edge in pe_ce_edges: # mark as exclude so don't include in standard ibgp config stanzas if g_ibgpv4.has_edge(edge): edge['ibgp_v4'].exclude = True if g_ibgpv6.has_edge(edge): edge['ibgp_v6'].exclude = True # legacy g_bgp = anm['bgp'] g_bgp.remove_edges_from(ce_edges) g_bgp.add_edges_from(ce_pe_edges, retain=["direction", "vrf", "type"]) g_bgp.add_edges_from(pe_ce_edges, retain=["direction", "vrf", "type"])
def build_bgp(anm): """Build iBGP end eBGP overlays""" # eBGP g_in = anm['input'] g_phy = anm['phy'] build_ebgp(anm) build_ebgp_v4(anm) build_ebgp_v6(anm) """TODO: remove from here once compiler updated""" g_bgp = anm.add_overlay("bgp", directed=True) g_bgp.add_nodes_from(g_in.nodes("is_router")) ebgp_edges = [edge for edge in g_in.edges() if not edge.attr_equal("asn")] g_bgp.add_edges_from(ebgp_edges, bidirectional=True, type='ebgp') #TODO: why don't we include edge_id here ebgp_switches = [ n for n in g_in.nodes("is_switch") if not ank_utils.neigh_equal(g_phy, n, "asn") ] g_bgp.add_nodes_from(ebgp_switches, retain=['asn']) log.debug("eBGP switches are %s" % ebgp_switches) g_bgp.add_edges_from((e for e in g_in.edges() if e.src in ebgp_switches or e.dst in ebgp_switches), bidirectional=True, type='ebgp') ank_utils.aggregate_nodes(g_bgp, ebgp_switches, retain="edge_id") ebgp_switches = list( g_bgp.nodes("is_switch")) # need to recalculate as may have aggregated log.debug("aggregated eBGP switches are %s" % ebgp_switches) exploded_edges = ank_utils.explode_nodes(g_bgp, ebgp_switches, retain="edge_id") for edge in exploded_edges: edge.multipoint = True """TODO: remove up to here once compiler updated""" # now iBGP ank_utils.copy_attr_from(g_in, g_bgp, "ibgp_level") ank_utils.copy_attr_from(g_in, g_bgp, "ibgp_l2_cluster") ank_utils.copy_attr_from(g_in, g_bgp, "ibgp_l3_cluster") for node in g_bgp: # set defaults if node.ibgp_level is None: node.ibgp_level = 1 if node.ibgp_level == "None": # if unicode string from yEd node.ibgp_level = 1 #TODO CHECK FOR IBGP NONE node.ibgp_level = int(node.ibgp_level) # ensure is numeric if not node.ibgp_l2_cluster or node.ibgp_l2_cluster == "None": # ibgp_l2_cluster defaults to region node.ibgp_l2_cluster = node.region or "default_l2_cluster" if not node.ibgp_l3_cluster or node.ibgp_l3_cluster == "None": # ibgp_l3_cluster defaults to ASN node.ibgp_l3_cluster = node.asn for asn, devices in ank_utils.groupby("asn", g_bgp): # group by nodes in phy graph routers = list(g_bgp.node(n) for n in devices if n.is_router) # list of nodes from bgp graph ibgp_levels = {int(r.ibgp_level) for r in routers} max_level = max(ibgp_levels) # all possible edge src/dst pairs ibgp_routers = [r for r in routers if r.ibgp_level > 0] all_pairs = [(s, t) for s in ibgp_routers for t in ibgp_routers if s != t] if max_level == 3: up_links, down_links, over_links = three_tier_ibgp_edges( ibgp_routers) elif max_level == 2: up_links, down_links, over_links = build_two_tier_ibgp( ibgp_routers) elif max_level == 1: up_links = [] down_links = [] over_links = [(s, t) for (s, t) in all_pairs if s.ibgp_l3_cluster == t.ibgp_l3_cluster and s.ibgp_l2_cluster == t.ibgp_l2_cluster] else: # no iBGP up_links = [] down_links = [] over_links = [] if max_level > 0: g_bgp.add_edges_from(up_links, type='ibgp', direction='up') g_bgp.add_edges_from(down_links, type='ibgp', direction='down') g_bgp.add_edges_from(over_links, type='ibgp', direction='over') else: log.debug("No iBGP routers in %s" % asn) # and set label back ibgp_label_to_level = { 0: "None", # Explicitly set role to "None" -> Not in iBGP 3: "RR", 1: "RRC", 2: "HRR", } for node in g_bgp: node.ibgp_role = ibgp_label_to_level[node.ibgp_level] ebgp_nodes = [ d for d in g_bgp if any(edge.type == 'ebgp' for edge in d.edges()) ] g_bgp.update(ebgp_nodes, ebgp=True) for ebgp_edge in g_bgp.edges(type="ebgp"): for interface in ebgp_edge.interfaces(): interface.ebgp = True for edge in g_bgp.edges(type='ibgp'): # TODO: need interface querying/selection. rather than hard-coded ids edge.bind_interface(edge.src, 0) #TODO: need to initialise interface zero to be a loopback rather than physical type for node in g_bgp: for interface in node.interfaces(): interface.multipoint = any(e.multipoint for e in interface.edges()) build_ibgp_v4(anm) build_ibgp_v6(anm)
def build_ospf(anm): """ Build OSPF graph. Allowable area combinations: 0 -> 0 0 -> x (x!= 0) x -> 0 (x!= 0) x -> x (x != 0) Not-allowed: x -> x (x != y != 0) #TODO: build check that verifies these rules """ import netaddr g_in = anm['input'] # add regardless, so allows quick check of node in anm['ospf'] in compilers g_ospf = anm.add_overlay("ospf") if not any(n.igp == "ospf" for n in g_in): log.debug("No OSPF nodes") return g_ospf.add_nodes_from(g_in.nodes("is_router", igp="ospf"), retain=['asn']) g_ospf.add_nodes_from(g_in.nodes("is_switch"), retain=['asn']) g_ospf.add_edges_from(g_in.edges(), retain=['edge_id']) ank_utils.copy_attr_from(g_in, g_ospf, "ospf_area", dst_attr="area") ank_utils.copy_edge_attr_from(g_in, g_ospf, "ospf_cost", dst_attr="cost", type=float) ank_utils.aggregate_nodes(g_ospf, g_ospf.nodes("is_switch"), retain="edge_id") exploded_edges = ank_utils.explode_nodes(g_ospf, g_ospf.nodes("is_switch"), retain="edge_id") for edge in exploded_edges: edge.multipoint = True g_ospf.remove_edges_from([ link for link in g_ospf.edges() if link.src.asn != link.dst.asn ]) # remove inter-AS links area_zero_ip = netaddr.IPAddress("0.0.0.0") area_zero_int = 0 area_zero_ids = {area_zero_ip, area_zero_int} default_area = area_zero_int if any(router.area == "0.0.0.0" for router in g_ospf): # string comparison as hasn't yet been cast to IPAddress default_area = area_zero_ip for router in g_ospf: if not router.area or router.area == "None": router.area = default_area # check if 0.0.0.0 used anywhere, if so then use 0.0.0.0 as format else: try: router.area = int(router.area) except ValueError: try: router.area = netaddr.IPAddress(router.area) except netaddr.core.AddrFormatError: log.warning("Invalid OSPF area %s for %s. Using default" " of %s" % (router.area, router, default_area)) router.area = default_area for router in g_ospf: # and set area on interface for edge in router.edges(): if edge.area: continue # allocated (from other "direction", as undirected) if router.area == edge.dst.area: edge.area = router.area # intra-area continue if router.area in area_zero_ids or edge.dst.area in area_zero_ids: # backbone to other area if router.area in area_zero_ids: # router in backbone, use other area edge.area = edge.dst.area else: # router not in backbone, use its area edge.area = router.area for router in g_ospf: areas = {edge.area for edge in router.edges()} router.areas = list(areas) # edges router participates in if len(areas) in area_zero_ids: router.type = "backbone" # no ospf edges (eg single node in AS) elif len(areas) == 1: # single area: either backbone (all 0) or internal (all nonzero) if len(areas & area_zero_ids): # intersection has at least one element -> router has area zero router.type = "backbone" else: router.type = "internal" else: # multiple areas if len(areas & area_zero_ids): # intersection has at least one element -> router has area zero router.type = "backbone ABR" else: log.warning( "%s spans multiple areas but is not a member of area 0" % router) router.type = "INVALID" if (any(area_zero_int in router.areas for router in g_ospf) and any(area_zero_ip in router.areas for router in g_ospf)): log.warning("Using both area 0 and area 0.0.0.0") for link in g_ospf.edges(): if not link.cost: link.cost = 1 # map areas and costs onto interfaces #TODO: later map them directly rather than with edges - this is part of the transition for edge in g_ospf.edges(): for interface in edge.interfaces(): interface.cost = edge.cost interface.area = edge.area interface.multipoint = edge.multipoint for router in g_ospf: router.loopback_zero.area = router.area router.loopback_zero.cost = 0
build_vrf(anm) # do before to add loopbacks before ip allocations from autonetkit.design.ip import build_ip, build_ipv4, build_ipv6 # TODO: replace this with layer2 overlay topology creation # log.info("Allocating IP addresses") build_ip(anm) # ip infrastructure topology address_family = g_in.data.address_family or "v4" # default is v4 # TODO: can remove the infrastructure now create g_ip seperately if address_family == "None": log.info("IP addressing disabled, disabling routing protocol ", "configuration") anm['phy'].data.enable_routing = False if address_family == "None": log.info("IP addressing disabled, skipping IPv4") anm.add_overlay("ipv4") # create empty so rest of code follows g_phy.update(g_phy, use_ipv4=False) elif address_family in ("v4", "dual_stack"): build_ipv4(anm, infrastructure=True) g_phy.update(g_phy, use_ipv4=True) elif address_family == "v6": # Allocate v4 loopbacks for router ids build_ipv4(anm, infrastructure=False) g_phy.update(g_phy, use_ipv4=False) # TODO: Create collision domain overlay for ip addressing - l2 overlay? if address_family == "None": log.info("IP addressing disabled, not allocating IPv6") anm.add_overlay("ipv6") # create empty so rest of code follows g_phy.update(g_phy, use_ipv6=False) elif address_family in ("v6", "dual_stack"):