コード例 #1
0
ファイル: ip.py プロジェクト: iainwp/ank_le
def allocate_subnets(network, address_block=IPNetwork("10.0.0.0/8")):

    """Allocates subnets and IP addresses to links in the network.

    Args:
        address_block (IPNetwork):  The address block to use.

    Returns:
        ip_as_allocs

    Example usage:

    >>> network = ank.example_multi_as()
    >>> allocate_subnets(network)
    >>> print ank.debug_nodes(network.graph, "lo_ip")
    {'1a.AS1': IPNetwork('10.0.0.32/32'),
     '1b.AS1': IPNetwork('10.0.0.33/32'),
     '1c.AS1': IPNetwork('10.0.0.34/32'),
     '2a.AS2': IPNetwork('10.1.0.64/32'),
     '2b.AS2': IPNetwork('10.1.0.65/32'),
     '2c.AS2': IPNetwork('10.1.0.66/32'),
     '2d.AS2': IPNetwork('10.1.0.67/32'),
     '3a.AS3': IPNetwork('10.2.0.0/32')}
    
    >>> print ank.debug_edges(network.graph, "ip")
    {('1a.AS1', '1b.AS1'): IPAddress('10.0.0.10'),
     ('1a.AS1', '1c.AS1'): IPAddress('10.0.0.22'),
     ('1b.AS1', '1a.AS1'): IPAddress('10.0.0.9'),
     ('1b.AS1', '1c.AS1'): IPAddress('10.0.0.26'),
     ('1b.AS1', '3a.AS3'): IPAddress('10.0.0.17'),
     ('1c.AS1', '1a.AS1'): IPAddress('10.0.0.21'),
     ('1c.AS1', '1b.AS1'): IPAddress('10.0.0.25'),
     ('1c.AS1', '2a.AS2'): IPAddress('10.0.0.29'),
     ('2a.AS2', '1c.AS1'): IPAddress('10.0.0.30'),
     ('2a.AS2', '2b.AS2'): IPAddress('10.1.0.10'),
     ('2a.AS2', '2d.AS2'): IPAddress('10.1.0.26'),
     ('2b.AS2', '2a.AS2'): IPAddress('10.1.0.9'),
     ('2b.AS2', '2c.AS2'): IPAddress('10.1.0.18'),
     ('2c.AS2', '2b.AS2'): IPAddress('10.1.0.17'),
     ('2c.AS2', '2d.AS2'): IPAddress('10.1.0.30'),
     ('2d.AS2', '2a.AS2'): IPAddress('10.1.0.25'),
     ('2d.AS2', '2c.AS2'): IPAddress('10.1.0.29'),
     ('2d.AS2', '3a.AS3'): IPAddress('10.1.0.33'),
     ('3a.AS3', '1b.AS1'): IPAddress('10.0.0.18'),
     ('3a.AS3', '2d.AS2'): IPAddress('10.1.0.34')}

    
    >>> print ank.debug_edges(network.graph, "sn")
    {('1a.AS1', '1b.AS1'): IPNetwork('10.0.0.8/30'),
     ('1a.AS1', '1c.AS1'): IPNetwork('10.0.0.20/30'),
     ('1b.AS1', '1a.AS1'): IPNetwork('10.0.0.8/30'),
     ('1b.AS1', '1c.AS1'): IPNetwork('10.0.0.24/30'),
     ('1b.AS1', '3a.AS3'): IPNetwork('10.0.0.16/30'),
     ('1c.AS1', '1a.AS1'): IPNetwork('10.0.0.20/30'),
     ('1c.AS1', '1b.AS1'): IPNetwork('10.0.0.24/30'),
     ('1c.AS1', '2a.AS2'): IPNetwork('10.0.0.28/30'),
     ('2a.AS2', '1c.AS1'): IPNetwork('10.0.0.28/30'),
     ('2a.AS2', '2b.AS2'): IPNetwork('10.1.0.8/30'),
     ('2a.AS2', '2d.AS2'): IPNetwork('10.1.0.24/30'),
     ('2b.AS2', '2a.AS2'): IPNetwork('10.1.0.8/30'),
     ('2b.AS2', '2c.AS2'): IPNetwork('10.1.0.16/30'),
     ('2c.AS2', '2b.AS2'): IPNetwork('10.1.0.16/30'),
     ('2c.AS2', '2d.AS2'): IPNetwork('10.1.0.28/30'),
     ('2d.AS2', '2a.AS2'): IPNetwork('10.1.0.24/30'),
     ('2d.AS2', '2c.AS2'): IPNetwork('10.1.0.28/30'),
     ('2d.AS2', '3a.AS3'): IPNetwork('10.1.0.32/30'),
     ('3a.AS3', '1b.AS1'): IPNetwork('10.0.0.16/30'),
     ('3a.AS3', '2d.AS2'): IPNetwork('10.1.0.32/30')}
    
    """
    LOG.debug("Allocating subnets")
    # Initialise IP list to be graph edge format
    ip_as_allocs = {}

    # allocates subnets to the edges and loopback in network graph
    # Put into dictionary, indexed by ASN (the name attribute of each as graph)
    # for easy appending of eBGP links
    asgraphs = dict((my_as.asn, my_as) for my_as in ank.get_as_graphs(network))

    # Simple method: break address_block into a /16 for each network
    #TODO: check this is feasible - ie against required host count
    subnet_list = address_block.subnet(16)

    ebgp_edges = ank.ebgp_edges(network)
    visited_ebgp_edges = set()
    for src, dst in sorted(ebgp_edges):
      # Add the dst (external peer) to AS of src node so they are allocated
        # a subnet. (The AS choice is arbitrary)
        if (dst, src) in visited_ebgp_edges:
            continue
        src_as = asgraphs[src.asn]
        src_as.add_edge(src, dst)
# record for DNS purposes
        ank.dns_advertise_link(src, dst)
        visited_ebgp_edges.add( (src, dst))

    for my_as in sorted(asgraphs.values(), key = lambda x: x.asn):
        asn = my_as.asn
        as_subnet =  subnet_list.next()

        as_internal_nodes = [n for n in sorted(my_as.nodes()) if network.asn(n) == asn]

        host_count = my_as.number_of_nodes()

        # record this subnet
        ip_as_allocs[my_as.asn] = as_subnet

        # split into subnets for loopback and ptp
        ptp_count = my_as.number_of_edges()

        # Now subnet network into subnets of the larger of these two
        # TODO tidy up this comment
        # Note ptp subnets required a /30 ie 4 ips
        req_sn_count = max(host_count, 4*ptp_count)

        if req_sn_count == 0:
            # Nothing to allocate for this AS
            continue

        req_pref_len = int(32 - math.ceil(math.log(req_sn_count, 2)) )
        # Subnet as subnet into subnets of this size
        sn_iter = as_subnet.subnet(req_pref_len)
        # And allocate a subnet for each ptp and loopback

        if ptp_count > 0:
            # Don't allocate a ptp subnet if there are no ptp links
            ptp_subnet = sn_iter.next()
        loopback_subnet = sn_iter.next()

        if ptp_count > 0:
            link_subnet = ptp_subnet.subnet(30)

            # Now iterate over edges in this as and apply
            for src, dst in sorted(my_as.edges()):
                # Note we apply this back to the main graph
                # not to the as graph!

                subnet = link_subnet.next()

                #TODO: fix the technique for accessing edges
                # as it breaks with multigraphs, as it creates a new edge
                if network.asn(dst) != asn:
# eBGP link where dst has IP allocated from subnet of this AS
                    network.graph[dst][src]['remote_as_sn_block'] = True

                network.graph[src][dst]['sn'] = subnet
                network.graph[dst][src]['sn'] = subnet
                # allocate an ip to each end
                network.graph[src][dst]['ip'] = subnet[1]
                network.graph[dst][src]['ip'] = subnet[2]

        # Allocate an loopback interface to each router
        #TODO: check if next step is necessary
        loopback_ips = loopback_subnet.subnet(32)
    
        for rtr in sorted(as_internal_nodes):
            lo_ip = loopback_ips.next()
            network.graph.node[rtr]['lo_ip'] = lo_ip

    network.ip_as_allocs = ip_as_allocs