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
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_server", 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 #TODO: use interfaces throughout, rather than edges 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