github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/azure/internal/iputils/iputils.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package iputils
     5  
     6  import (
     7  	"math/big"
     8  	"net"
     9  
    10  	"github.com/juju/errors"
    11  )
    12  
    13  // Azure reserves the first four addresses in each subnet
    14  // (or so it seems -- it's not clearly documented).
    15  const reservedAddressRangeEnd = 3
    16  
    17  // NextSubnetIP returns the next available IP address in a given subnet.
    18  func NextSubnetIP(subnet *net.IPNet, ipsInUse []net.IP) (net.IP, error) {
    19  	ones, bits := subnet.Mask.Size()
    20  	subnetMaskUint32 := ipUint32(net.IP(subnet.Mask))
    21  
    22  	inUse := big.NewInt(0)
    23  	for _, ip := range ipsInUse {
    24  		if !subnet.Contains(ip) {
    25  			continue
    26  		}
    27  		index := ipIndex(ip, subnetMaskUint32)
    28  		inUse = inUse.SetBit(inUse, index, 1)
    29  	}
    30  
    31  	// Now iterate through all addresses in the subnet and return the
    32  	// first address that is not in use. We start at the first non-
    33  	// reserved address, and stop short of the last address in the
    34  	// subnet (i.e. all non-mask bits set), which is the broadcast
    35  	// address for the subnet.
    36  	n := ipUint32(subnet.IP)
    37  	for i := reservedAddressRangeEnd + 1; i < (1<<uint64(bits-ones) - 1); i++ {
    38  		ip := uint32IP(n + uint32(i))
    39  		if !ip.IsGlobalUnicast() {
    40  			continue
    41  		}
    42  		index := ipIndex(ip, subnetMaskUint32)
    43  		if inUse.Bit(index) == 0 {
    44  			return ip, nil
    45  		}
    46  	}
    47  	return nil, errors.Errorf("no addresses available in %s", subnet)
    48  }
    49  
    50  // NthSubnetIP returns the n'th IP address in a given subnet, where n is a
    51  // zero-based index, zero being the first available IP address in the subnet.
    52  //
    53  // If n is out of range, NthSubnetIP will return nil.
    54  func NthSubnetIP(subnet *net.IPNet, n int) net.IP {
    55  	ones, bits := subnet.Mask.Size()
    56  	base := ipUint32(subnet.IP)
    57  	var valid int
    58  	for i := reservedAddressRangeEnd + 1; i < (1<<uint64(bits-ones) - 1); i++ {
    59  		ip := uint32IP(base + uint32(i))
    60  		if !ip.IsGlobalUnicast() {
    61  			continue
    62  		}
    63  		if n == valid {
    64  			return ip
    65  		}
    66  		valid++
    67  	}
    68  	return nil
    69  }
    70  
    71  // ipIndex calculates the index of the IP in the subnet.
    72  // e.g. 10.0.0.1 in 10.0.0.0/8 has index 1.
    73  func ipIndex(ip net.IP, subnetMask uint32) int {
    74  	return int(ipUint32(ip) & ^subnetMask)
    75  }
    76  
    77  func ipUint32(ip net.IP) uint32 {
    78  	ip = ip.To4()
    79  	return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
    80  }
    81  
    82  func uint32IP(n uint32) net.IP {
    83  	return net.IPv4(byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
    84  }