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 }