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_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") # need to recalculate as may have aggregated ebgp_switches = list(g_ebgp.nodes("is_switch")) log.debug("aggregated eBGP switches are %s" % ebgp_switches) exploded_edges = ank_utils.explode_nodes(g_ebgp, ebgp_switches, retain="edge_id") same_asn_edges = [] for edge in exploded_edges: if edge.src.asn == edge.dst.asn: same_asn_edges.append(edge) else: edge.multipoint = True """TODO: remove up to here once compiler updated""" g_ebgp.remove_edges_from(same_asn_edges)
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.routers()) 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.switches() if not ank_utils.neigh_equal(g_phy, n, "asn")] g_ebgp.add_nodes_from(ebgp_switches, retain=['asn']) g_ebgp.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) # need to recalculate as may have aggregated ebgp_switches = list(g_ebgp.switches()) g_ebgp.log.debug("aggregated eBGP switches are %s" % ebgp_switches) exploded_edges = ank_utils.explode_nodes(g_ebgp, ebgp_switches) same_asn_edges = [] for edge in exploded_edges: if edge.src.asn == edge.dst.asn: same_asn_edges.append(edge) else: edge.multipoint = True """TODO: remove up to here once compiler updated""" g_ebgp.remove_edges_from(same_asn_edges)
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 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 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 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_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_ip(anm): #TODO: use the l3_conn graph g_ip = anm.add_overlay('ip') g_in = anm['input'] g_graphics = anm['graphics'] g_phy = anm['phy'] #TODO: add these from layer2 graph - and scrap g_ip: clone g_layer2 to g_ipv4 and g_ipv6 g_ip.add_nodes_from(g_phy) g_ip.add_edges_from(g_phy.edges()) ank_utils.aggregate_nodes(g_ip, g_ip.switches()) edges_to_split = [ edge for edge in g_ip.edges() if edge.src.is_l3device() and edge.dst.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=['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.switches() # regenerate due to aggregated g_ip.update(switch_nodes, broadcast_domain=True) # switches are part of collision domain g_ip.update(split_created_nodes, broadcast_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 #TODO; work out why this throws a json exception #autonetkit.ank.set_node_default(g_ip, broadcast_domain=False) for node in g_ip.nodes('broadcast_domain'): graphics_node = g_graphics.node(node) #graphics_node.device_type = 'broadcast_domain' if node.is_switch(): node['phy'].broadcast_domain = True if not node.is_switch(): # use node sorting, as accomodates for numeric/string names graphics_node.device_type = 'broadcast_domain' 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 node.device_type = "broadcast_domain"
def build_ip(anm): import autonetkit.plugins.ip 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")) #TODO: need to look at if allocate_v6 is specified: ie manually set ank.aggregate_nodes(G_ip, G_ip.nodes("is_switch"), retain = "edge_id") #TODO: add function to update edge properties: can overload node update? 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) asn = ank.neigh_most_frequent(G_ip, node, "asn", G_phy) # arbitrary choice node['graphics'].asn = asn # need to use asn in IP overlay for aggregating subnets node.asn = asn #TODO: could choose largest ASN if tie break #TODO: see if need G_phy - should auto fall through to phy for ASN 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.neigh_equal(G_ip, node, "host", G_phy): node.host = ank.neigh_attr(G_ip, node, "host", G_phy).next() # first attribute #TODO: Need to allocate interfaces or appropriate bypass for collision domain nodes # set collision domain IPs #TODO: trim next line collision_domain_id = itertools.count(0) # TODO: remove this, as isn't needed as set id to be based on neighbors for node in G_ip.nodes("collision_domain"): graphics_node = G_graphics.node(node) graphics_node.device_type = "collision_domain" cd_id = collision_domain_id.next() node.cd_id = cd_id #TODO: Use this label if not node.is_switch: label = "_".join(sorted(ank.neigh_attr(G_ip, 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 if G_in.data.allocate_ipv4 == False: import netaddr G_in_directed = anm['input_directed'] for l3_device in G_ip.nodes("is_l3device"): directed_node = G_in_directed.node(l3_device) l3_device.loopback = directed_node.ipv4loopback for edge in l3_device.edges(): # find edge in G_in_directed directed_edge = G_in_directed.edge(edge) edge.ip_address = netaddr.IPAddress(directed_edge.ipv4) # set subnet onto collision domain (can come from either direction) collision_domain = edge.dst if not collision_domain.subnet: #TODO: see if direct method in netaddr to deduce network prefixlen = directed_edge.netPrefixLenV4 cidr_string = "%s/%s" % (edge.ip_address, prefixlen) intermediate_subnet = netaddr.IPNetwork(cidr_string) cidr_string = "%s/%s" % (intermediate_subnet.network, prefixlen) subnet = netaddr.IPNetwork(cidr_string) collision_domain.subnet = subnet # also need to form aggregated IP blocks (used for e.g. routing prefix advertisement) loopback_blocks = {} infra_blocks = {} for asn, devices in G_ip.groupby("asn").items(): routers = [d for d in devices if d.is_router] loopbacks = [r.loopback for r in routers] loopback_blocks[asn] = netaddr.cidr_merge(loopbacks) collision_domains = [d for d in devices if d.collision_domain] subnets = [cd.subnet for cd in collision_domains] infra_blocks[asn] = netaddr.cidr_merge(subnets) G_ip.data.loopback_blocks = loopback_blocks G_ip.data.infra_blocks = infra_blocks else: ip.allocate_ips(G_ip) ank.save(G_ip)
def build_bgp(anm): """Build iBGP end eBGP overlays""" # eBGP g_in = anm['input'] g_phy = anm['phy'] if not anm['phy'].data.enable_routing: log.info("Routing disabled, not configuring BGP") return 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.routers()) ebgp_edges = [edge for edge in g_in.edges() if edge.src.asn != edge.dst.asn] g_bgp.add_edges_from(ebgp_edges, bidirectional=True, type='ebgp') ebgp_switches = [n for n in g_in.switches() 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) ebgp_switches = list(g_bgp.switches()) # 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) same_asn_edges = [] for edge in exploded_edges: if edge.src.asn == edge.dst.asn: same_asn_edges.append(edge) else: edge.multipoint = True """TODO: remove up to here once compiler updated""" ank_utils.copy_attr_from(g_in, g_bgp, "custom_config_bgp", dst_attr="custom_config") g_bgp.remove_edges_from(same_asn_edges) build_ibgp(anm) 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_layer2_broadcast(anm): g_l2 = anm['layer2'] g_phy = anm['phy'] g_graphics = anm['graphics'] g_l2_bc = anm.add_overlay('layer2_bc') g_l2_bc.add_nodes_from(g_l2) g_l2_bc.add_edges_from(g_l2.edges()) edges_to_split = [edge for edge in g_l2_bc.edges() if edge.src.is_l3device() and edge.dst.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_l2_bc, edges_to_split, retain=['split'], id_prepend='cd_')) for node in split_created_nodes: node['graphics'].x = ank_utils.neigh_average(g_l2_bc, node, 'x', g_graphics) + 0.1 # temporary fix for gh-90 node['graphics'].y = ank_utils.neigh_average(g_l2_bc, node, 'y', g_graphics) + 0.1 # temporary fix for gh-90 asn = ank_utils.neigh_most_frequent(g_l2_bc, 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_l2_bc.switches() # regenerate due to aggregated g_l2_bc.update(switch_nodes, broadcast_domain=True) # switches are part of collision domain g_l2_bc.update(split_created_nodes, broadcast_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_l2_bc, node, 'host', g_phy): node.host = ank_utils.neigh_attr(g_l2_bc, node, 'host', g_phy).next() # first attribute # set collision domain IPs #TODO; work out why this throws a json exception #autonetkit.ank.set_node_default(g_l2_bc, broadcast_domain=False) for node in g_l2_bc.nodes('broadcast_domain'): graphics_node = g_graphics.node(node) #graphics_node.device_type = 'broadcast_domain' if node.is_switch(): node['phy'].broadcast_domain = True if not node.is_switch(): # use node sorting, as accomodates for numeric/string names graphics_node.device_type = 'broadcast_domain' 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 graphics_node.label = cd_label node.device_type = "broadcast_domain"
def build_layer2_broadcast(anm): g_l2 = anm['layer2'] g_phy = anm['phy'] g_graphics = anm['graphics'] g_l2_bc = anm.add_overlay('layer2_bc') g_l2_bc.add_nodes_from(g_l2.l3devices()) g_l2_bc.add_nodes_from(g_l2.switches()) g_l2_bc.add_edges_from(g_l2.edges()) # remove external connectors edges_to_split = [ edge for edge in g_l2_bc.edges() if edge.src.is_l3device() and edge.dst.is_l3device() ] #TODO: debug the edges to split #print "edges to split", edges_to_split 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_l2_bc, edges_to_split, retain=['split'], id_prepend='cd_')) #TODO: if parallel nodes, offset #TODO: remove graphics, assign directly for node in split_created_nodes: node['graphics'].x = ank_utils.neigh_average(g_l2_bc, node, 'x', g_graphics) + 0.1 # temporary fix for gh-90 node['graphics'].y = ank_utils.neigh_average(g_l2_bc, node, 'y', g_graphics) + 0.1 # temporary fix for gh-90 asn = ank_utils.neigh_most_frequent(g_l2_bc, node, 'asn', g_phy) # arbitrary choice node['graphics'].asn = asn node.asn = asn # need to use asn in IP overlay for aggregating subnets from collections import defaultdict coincident_nodes = defaultdict(list) for node in split_created_nodes: coincident_nodes[(node['graphics'].x, node['graphics'].y)].append(node) coincident_nodes = { k: v for k, v in coincident_nodes.items() if len(v) > 1 } # trim out single node co-ordinates import math for key, val in coincident_nodes.items(): for index, item in enumerate(val): index = index + 1 x_offset = 25 * math.floor(index / 2) * math.pow(-1, index) y_offset = -1 * 25 * math.floor(index / 2) * math.pow(-1, index) item['graphics'].x = item['graphics'].x + x_offset item['graphics'].y = item['graphics'].y + y_offset switch_nodes = g_l2_bc.switches() # regenerate due to aggregated g_l2_bc.update(switch_nodes, broadcast_domain=True) # switches are part of collision domain g_l2_bc.update(split_created_nodes, broadcast_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_l2_bc, node, 'host', g_phy): node.host = ank_utils.neigh_attr(g_l2_bc, node, 'host', g_phy).next() # first attribute # set collision domain IPs #TODO; work out why this throws a json exception #autonetkit.ank.set_node_default(g_l2_bc, broadcast_domain=False) for node in g_l2_bc.nodes('broadcast_domain'): graphics_node = g_graphics.node(node) #graphics_node.device_type = 'broadcast_domain' if node.is_switch(): node['phy'].broadcast_domain = True if not node.is_switch(): # use node sorting, as accomodates for numeric/string names graphics_node.device_type = 'broadcast_domain' 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 graphics_node.label = cd_label node.device_type = "broadcast_domain" node.label = node.id graphics_node.label = node.id
def build_bgp(anm): """Build iBGP end eBGP overlays""" # eBGP g_in = anm['input'] g_phy = anm['phy'] if not anm['phy'].data.enable_routing: log.info("Routing disabled, not configuring BGP") return 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.routers()) 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') ebgp_switches = [n for n in g_in.switches() 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) ebgp_switches = list(g_bgp.switches()) # 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) same_asn_edges = [] for edge in exploded_edges: if edge.src.asn == edge.dst.asn: same_asn_edges.append(edge) else: edge.multipoint = True """TODO: remove up to here once compiler updated""" g_bgp.remove_edges_from(same_asn_edges) build_ibgp(anm) 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_bgp(anm): """Build iBGP end eBGP overlays""" # eBGP g_in = anm['input'] g_phy = anm['phy'] if not anm['phy'].data.enable_routing: log.info("Routing disabled, not configuring BGP") return 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") same_asn_edges = [] for edge in exploded_edges: if edge.src.asn == edge.dst.asn: same_asn_edges.append(edge) else: edge.multipoint = True """TODO: remove up to here once compiler updated""" g_bgp.remove_edges_from(same_asn_edges) # 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: #TODO: check when this is reached - as RR is not HRR.... due to naming/levels mapping 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_layer2_broadcast(anm): g_l2 = anm['layer2'] g_phy = anm['phy'] g_graphics = anm['graphics'] g_l2_bc = anm.add_overlay('layer2_bc') g_l2_bc.add_nodes_from(g_l2.l3devices()) g_l2_bc.add_nodes_from(g_l2.switches()) g_l2_bc.add_edges_from(g_l2.edges(), retain=['link_type']) # remove external connectors edges_to_split = [edge for edge in g_l2_bc.edges() if edge.src.is_l3device() and edge.dst.is_l3device()] # TODO: debug the edges to split 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_l2_bc, edges_to_split, retain=['split'], id_prepend='cd_')) # TODO: if parallel nodes, offset # TODO: remove graphics, assign directly if len(g_graphics): co_ords_overlay = g_graphics # source from graphics overlay else: co_ords_overlay = g_phy # source from phy overlay for node in split_created_nodes: node['graphics'].x = ank_utils.neigh_average(g_l2_bc, node, 'x', co_ords_overlay) + 0.1 # temporary fix for gh-90 node['graphics'].y = ank_utils.neigh_average(g_l2_bc, node, 'y', co_ords_overlay) + 0.1 # temporary fix for gh-90 asn = ank_utils.neigh_most_frequent( g_l2_bc, node, 'asn', g_phy) # arbitrary choice node['graphics'].asn = asn node.asn = asn # need to use asn in IP overlay for aggregating subnets # also allocate an ASN for virtual switches vswitches = [n for n in g_l2_bc.nodes() if n['layer2'].device_type == "switch" and n['layer2'].device_subtype == "virtual"] for node in vswitches: # TODO: refactor neigh_most_frequent to allow fallthrough attributes # asn = ank_utils.neigh_most_frequent(g_l2_bc, node, 'asn', g_l2) # # arbitrary choice asns = [n['layer2'].asn for n in node.neighbors()] asns = [x for x in asns if x is not None] asn = ank_utils.most_frequent(asns) node.asn = asn # need to use asn in IP overlay for aggregating subnets # also mark as broadcast domain from collections import defaultdict coincident_nodes = defaultdict(list) for node in split_created_nodes: coincident_nodes[(node['graphics'].x, node['graphics'].y)].append(node) coincident_nodes = {k: v for k, v in coincident_nodes.items() if len(v) > 1} # trim out single node co-ordinates import math for _, val in coincident_nodes.items(): for index, item in enumerate(val): index = index + 1 x_offset = 25 * math.floor(index / 2) * math.pow(-1, index) y_offset = -1 * 25 * math.floor(index / 2) * math.pow(-1, index) item['graphics'].x = item['graphics'].x + x_offset item['graphics'].y = item['graphics'].y + y_offset switch_nodes = g_l2_bc.switches() # regenerate due to aggregated g_l2_bc.update(switch_nodes, broadcast_domain=True) # switches are part of collision domain g_l2_bc.update(split_created_nodes, broadcast_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_l2_bc, node, 'host', g_phy): node.host = ank_utils.neigh_attr(g_l2_bc, node, 'host', g_phy).next() # first attribute # set collision domain IPs # TODO; work out why this throws a json exception #autonetkit.ank.set_node_default(g_l2_bc, broadcast_domain=False) for node in g_l2_bc.nodes('broadcast_domain'): graphics_node = g_graphics.node(node) #graphics_node.device_type = 'broadcast_domain' if node.is_switch(): # TODO: check not virtual node['phy'].broadcast_domain = True if not node.is_switch(): # use node sorting, as accomodates for numeric/string names graphics_node.device_type = 'broadcast_domain' 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 graphics_node.label = cd_label node.device_type = "broadcast_domain" node.label = node.id graphics_node.label = node.id for node in vswitches: node.broadcast_domain = True
def build_bgp(anm): """Build iBGP end eBGP overlays""" # eBGP g_in = anm["input"] g_phy = anm["phy"] 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 # 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", 3: "RR", 1: "RRC", 2: "HRR"} # Explicitly set role to "None" -> Not in iBGP 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())