github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  // ipIndex calculates the index of the IP in the subnet.
    51  // e.g. 10.0.0.1 in 10.0.0.0/8 has index 1.
    52  func ipIndex(ip net.IP, subnetMask uint32) int {
    53  	return int(ipUint32(ip) & ^subnetMask)
    54  }
    55  
    56  func ipUint32(ip net.IP) uint32 {
    57  	ip = ip.To4()
    58  	return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
    59  }
    60  
    61  func uint32IP(n uint32) net.IP {
    62  	return net.IPv4(byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
    63  }