def assign_asn_to_interasn_cds(g_ip, address_block = None): G_phy = g_ip.overlay("phy") for collision_domain in g_ip.nodes("collision_domain"): neigh_asn = list(ank_utils.neigh_attr(g_ip, collision_domain, "asn", G_phy)) #asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent(neigh_asn) # allocate cd to asn with most neighbors in it collision_domain.asn = asn return
def assign_asn_to_interasn_cds(g_ip, address_block=None): G_phy = g_ip.overlay('phy') for broadcast_domain in g_ip.nodes('broadcast_domain'): neigh_asn = list(ank_utils.neigh_attr(g_ip, broadcast_domain, 'asn', G_phy)) # asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent(neigh_asn) # allocate cd to asn with most neighbors in it broadcast_domain.asn = asn return
def assign_asn_to_interasn_cds(G_ip): #TODO: rename to assign_asn_to_cds as also does intra-asn cds #TODO: make this a common function to ip4 and ip6 G_phy = G_ip.overlay("phy") for collision_domain in G_ip.nodes("collision_domain"): neigh_asn = list(ank_utils.neigh_attr(G_ip, collision_domain, "asn", G_phy)) #asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent(neigh_asn) # allocate cd to asn with most neighbors in it collision_domain.asn = asn return
def assign_asn_to_interasn_cds(g_ip, address_block=None): G_phy = g_ip.overlay("phy") for collision_domain in g_ip.nodes("collision_domain"): neigh_asn = list( ank_utils.neigh_attr(g_ip, collision_domain, "asn", G_phy)) #asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent( neigh_asn) # allocate cd to asn with most neighbors in it collision_domain.asn = asn return
def assign_asn_to_interasn_cds(G_ip): #TODO: remove this if no longer needed # TODO: rename to assign_asn_to_cds as also does intra-asn cds # TODO: make this a common function to ip4 and ip6 G_phy = G_ip.overlay('phy') for broadcast_domain in G_ip.nodes('broadcast_domain'): neigh_asn = list(ank_utils.neigh_attr(G_ip, broadcast_domain, 'asn', G_phy)) # asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent(neigh_asn) # allocate bc to asn with most neighbors in it broadcast_domain.asn = asn return
def assign_asn_to_interasn_cds(G_ip): #TODO: remove this if no longer needed # TODO: rename to assign_asn_to_cds as also does intra-asn cds # TODO: make this a common function to ip4 and ip6 G_phy = G_ip.overlay('phy') for broadcast_domain in G_ip.nodes('broadcast_domain'): neigh_asn = list( ank_utils.neigh_attr(G_ip, broadcast_domain, 'asn', G_phy)) # asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent( neigh_asn) # allocate bc to asn with most neighbors in it broadcast_domain.asn = asn return
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 allocate_ips(G_ip): log.info("Allocating IP addresses") from netaddr import IPNetwork address_block = IPNetwork("10.0.0.0/8") subnet_address_blocks = address_block.subnet(16) #TODO: need to divide this up per AS G_ip.data.asn_blocks = defaultdict(list) #print G_ip._graph G_phy = G_ip.overlay.phy collision_domains = list(G_ip.nodes("collision_domain")) routers_by_asn = G_phy.groupby("asn", G_phy.nodes(device_type="router")) for collision_domain in collision_domains: neigh_asn = list(ank_utils.neigh_attr(G_ip, collision_domain, "asn", G_phy)) #asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent(neigh_asn) # allocate cd to asn with most neighbors in it collision_domain.asn = asn cds_by_asn = G_ip.groupby("asn", G_ip.nodes("collision_domain")) # if node or subnet has IP already allocated, then skip from this tree for asn in routers_by_asn: log.info("Allocating IPs for ASN %s" % asn) # Need to iterate by asn with routers, as single router AS may not have a cd asn_cds = cds_by_asn.get(asn) or [] asn_cds = sorted(asn_cds) #tree by ASN #TODO: Add in loopbacks as a subnet also asn_address_block = subnet_address_blocks.next() #print "ips for asn", asn G_ip.data.asn_blocks[asn].append(asn_address_block) #TODO: record this in G_ip graph data not node/edge data # Build list of collision domains sorted by size size_list = defaultdict(list) for cd in asn_cds: sn_size = subnet_size(cd.degree()) # Size of this collision domain size_list[sn_size].append(cd) loopback_size = subnet_size(len(routers_by_asn[asn])) # calculate from number of routers in asn ip_tree = defaultdict(list) # index by level to simplify creation of tree try: current_level = min(size_list) # start at base except ValueError: current_level = loopback_size # no cds, start at loopback asn_loopback_tree_node = None #keep track of to allocate loopbacks at end while True: cds = size_list[current_level] cds = sorted(cds, key = lambda x: x.node_id) # initialse with leaves #TODO: see if can get loopback on leftmost of tree -> then can have allocated with .1 .2 etc rather than .19 .20 etc ip_tree[current_level] += list(TreeNode(cd=cd) for cd in sorted(cds)) if current_level == loopback_size: asn_loopback_tree_node = TreeNode(cd = "loopback") ip_tree[current_level].append(asn_loopback_tree_node) # now connect up at parent level tree_nodes = sorted(ip_tree[current_level]) # both leaves and parents of lower level pairs = list(itertools.izip(tree_nodes[::2], tree_nodes[1::2])) for left, right in pairs: ip_tree[current_level+1].append(TreeNode(left, right)) if len(tree_nodes) % 2 == 1: # odd number of tree nodes, add final_tree_node = tree_nodes[-1] ip_tree[current_level+1].append(TreeNode(final_tree_node, None)) current_level += 1 if asn_loopback_tree_node and len(ip_tree[current_level]) < 2: # loopback has been allocated, and reached top of tree break #if leaf, assign back to collision domain # allocate to tree subnet_bits = 32 - max(ip_tree) tree_subnet = asn_address_block.subnet(subnet_bits) tree_root = ip_tree[max(ip_tree)].pop() # only one node at highest level (root) tree_root.subnet = tree_subnet.next() allocate_to_tree_node(tree_root) #walk_tree(tree_root) allocate_ips_to_cds(tree_root) my_tree = Tree(tree_root, asn) my_tree.save() # Get loopback from loopback tree node loopback_hosts = asn_loopback_tree_node.subnet.iter_hosts() #router.loopback = loopback_hosts.next() for router in sorted(routers_by_asn[asn], key = lambda x: x.label): router.overlay.ip.loopback = loopback_hosts.next() # now allocate to the links of each cd for cd in asn_cds: hosts = cd.subnet.iter_hosts() for edge in sorted(cd.edges()): edge.ip_address = hosts.next()
def allocate_ips(G_ip): log.info("Allocating IP addresses") from netaddr import IPNetwork address_block = IPNetwork("10.0.0.0/8") subnet_address_blocks = address_block.subnet(16) #TODO: need to divide this up per AS G_ip.data.asn_blocks = defaultdict(list) #print G_ip._graph G_phy = G_ip.overlay.phy collision_domains = list(G_ip.nodes("collision_domain")) routers_by_asn = G_phy.groupby("asn", G_phy.nodes(device_type="router")) for collision_domain in collision_domains: neigh_asn = list( ank_utils.neigh_attr(G_ip, collision_domain, "asn", G_phy)) #asn of neighbors if len(set(neigh_asn)) == 1: asn = set(neigh_asn).pop() # asn of any neigh, as all same else: asn = ank_utils.most_frequent( neigh_asn) # allocate cd to asn with most neighbors in it collision_domain.asn = asn cds_by_asn = G_ip.groupby("asn", G_ip.nodes("collision_domain")) # if node or subnet has IP already allocated, then skip from this tree for asn in routers_by_asn: log.info("Allocating IPs for ASN %s" % asn) # Need to iterate by asn with routers, as single router AS may not have a cd asn_cds = cds_by_asn.get(asn) or [] asn_cds = sorted(asn_cds) #tree by ASN #TODO: Add in loopbacks as a subnet also asn_address_block = subnet_address_blocks.next() #print "ips for asn", asn G_ip.data.asn_blocks[asn].append(asn_address_block) #TODO: record this in G_ip graph data not node/edge data # Build list of collision domains sorted by size size_list = defaultdict(list) for cd in asn_cds: sn_size = subnet_size(cd.degree()) # Size of this collision domain size_list[sn_size].append(cd) loopback_size = subnet_size(len( routers_by_asn[asn])) # calculate from number of routers in asn ip_tree = defaultdict( list) # index by level to simplify creation of tree try: current_level = min(size_list) # start at base except ValueError: current_level = loopback_size # no cds, start at loopback asn_loopback_tree_node = None #keep track of to allocate loopbacks at end while True: cds = size_list[current_level] cds = sorted(cds, key=lambda x: x.node_id) # initialse with leaves #TODO: see if can get loopback on leftmost of tree -> then can have allocated with .1 .2 etc rather than .19 .20 etc ip_tree[current_level] += list( TreeNode(cd=cd) for cd in sorted(cds)) if current_level == loopback_size: asn_loopback_tree_node = TreeNode(cd="loopback") ip_tree[current_level].append(asn_loopback_tree_node) # now connect up at parent level tree_nodes = sorted(ip_tree[current_level] ) # both leaves and parents of lower level pairs = list(itertools.izip(tree_nodes[::2], tree_nodes[1::2])) for left, right in pairs: ip_tree[current_level + 1].append(TreeNode(left, right)) if len(tree_nodes) % 2 == 1: # odd number of tree nodes, add final_tree_node = tree_nodes[-1] ip_tree[current_level + 1].append( TreeNode(final_tree_node, None)) current_level += 1 if asn_loopback_tree_node and len(ip_tree[current_level]) < 2: # loopback has been allocated, and reached top of tree break #if leaf, assign back to collision domain # allocate to tree subnet_bits = 32 - max(ip_tree) tree_subnet = asn_address_block.subnet(subnet_bits) tree_root = ip_tree[max( ip_tree)].pop() # only one node at highest level (root) tree_root.subnet = tree_subnet.next() allocate_to_tree_node(tree_root) #walk_tree(tree_root) allocate_ips_to_cds(tree_root) my_tree = Tree(tree_root, asn) my_tree.save() # Get loopback from loopback tree node loopback_hosts = asn_loopback_tree_node.subnet.iter_hosts() #router.loopback = loopback_hosts.next() for router in sorted(routers_by_asn[asn], key=lambda x: x.label): router.overlay.ip.loopback = loopback_hosts.next() # now allocate to the links of each cd for cd in asn_cds: hosts = cd.subnet.iter_hosts() for edge in sorted(cd.edges()): edge.ip_address = hosts.next()
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