123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- package ipallocator
- import (
- "encoding/binary"
- "errors"
- "github.com/dotcloud/docker/pkg/netlink"
- "net"
- "sync"
- )
- type networkSet map[iPNet]iPSet
- type iPNet struct {
- IP string
- Mask string
- }
- var (
- ErrNetworkAlreadyAllocated = errors.New("requested network overlaps with existing network")
- ErrNetworkAlreadyRegisterd = errors.New("requested network is already registered")
- ErrNoAvailableIps = errors.New("no available ips on network")
- ErrIPAlreadyAllocated = errors.New("ip already allocated")
- lock = sync.Mutex{}
- allocatedIPs = networkSet{}
- availableIPS = networkSet{}
- )
- func RegisterNetwork(network *net.IPNet) error {
- lock.Lock()
- defer lock.Unlock()
- routes, err := netlink.NetworkGetRoutes()
- if err != nil {
- return err
- }
- if err := checkRouteOverlaps(routes, network); err != nil {
- return err
- }
- if err := checkExistingNetworkOverlaps(network); err != nil {
- return err
- }
- n := newIPNet(network)
- allocatedIPs[n] = iPSet{}
- availableIPS[n] = iPSet{}
- return nil
- }
- func RequestIP(network *net.IPNet, ip *net.IP) (*net.IP, error) {
- lock.Lock()
- defer lock.Unlock()
- if ip == nil {
- next, err := getNextIp(network)
- if err != nil {
- return nil, err
- }
- return next, nil
- }
- if err := registerIP(network, ip); err != nil {
- return nil, err
- }
- return ip, nil
- }
- func ReleaseIP(network *net.IPNet, ip *net.IP) error {
- lock.Lock()
- defer lock.Unlock()
- n := newIPNet(network)
- existing := allocatedIPs[n]
- i := ipToInt(ip)
- existing.Remove(int(i))
- available := availableIPS[n]
- available.Push(int(i))
- return nil
- }
- func getNextIp(network *net.IPNet) (*net.IP, error) {
- var (
- n = newIPNet(network)
- available = availableIPS[n]
- next = available.Pop()
- allocated = allocatedIPs[n]
- ownIP = int(ipToInt(&network.IP))
- )
- if next != 0 {
- ip := intToIP(int32(next))
- allocated.Push(int(next))
- return ip, nil
- }
- size := int(networkSize(network.Mask))
- next = allocated.PullBack() + 1
- // size -1 for the broadcast address, -1 for the gateway address
- for i := 0; i < size-2; i++ {
- if next == ownIP {
- next++
- continue
- }
- ip := intToIP(int32(next))
- allocated.Push(next)
- return ip, nil
- }
- return nil, ErrNoAvailableIps
- }
- func registerIP(network *net.IPNet, ip *net.IP) error {
- existing := allocatedIPs[newIPNet(network)]
- if existing.Exists(int(ipToInt(ip))) {
- return ErrIPAlreadyAllocated
- }
- return nil
- }
- func checkRouteOverlaps(networks []netlink.Route, toCheck *net.IPNet) error {
- for _, network := range networks {
- if network.IPNet != nil && networkOverlaps(toCheck, network.IPNet) {
- return ErrNetworkAlreadyAllocated
- }
- }
- return nil
- }
- // Detects overlap between one IPNet and another
- func networkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
- if firstIP, _ := networkRange(netX); netY.Contains(firstIP) {
- return true
- }
- if firstIP, _ := networkRange(netY); netX.Contains(firstIP) {
- return true
- }
- return false
- }
- func checkExistingNetworkOverlaps(network *net.IPNet) error {
- for existing := range allocatedIPs {
- if newIPNet(network) == existing {
- return ErrNetworkAlreadyRegisterd
- }
- ex := newNetIPNet(existing)
- if networkOverlaps(network, ex) {
- return ErrNetworkAlreadyAllocated
- }
- }
- return nil
- }
- // Calculates the first and last IP addresses in an IPNet
- func networkRange(network *net.IPNet) (net.IP, net.IP) {
- var (
- netIP = network.IP.To4()
- firstIP = netIP.Mask(network.Mask)
- lastIP = net.IPv4(0, 0, 0, 0).To4()
- )
- for i := 0; i < len(lastIP); i++ {
- lastIP[i] = netIP[i] | ^network.Mask[i]
- }
- return firstIP, lastIP
- }
- func newIPNet(network *net.IPNet) iPNet {
- return iPNet{
- IP: string(network.IP),
- Mask: string(network.Mask),
- }
- }
- func newNetIPNet(network iPNet) *net.IPNet {
- return &net.IPNet{
- IP: []byte(network.IP),
- Mask: []byte(network.Mask),
- }
- }
- // Converts a 4 bytes IP into a 32 bit integer
- func ipToInt(ip *net.IP) int32 {
- return int32(binary.BigEndian.Uint32(ip.To4()))
- }
- // Converts 32 bit integer into a 4 bytes IP address
- func intToIP(n int32) *net.IP {
- b := make([]byte, 4)
- binary.BigEndian.PutUint32(b, uint32(n))
- ip := net.IP(b)
- return &ip
- }
- // Given a netmask, calculates the number of available hosts
- func networkSize(mask net.IPMask) int32 {
- m := net.IPv4Mask(0, 0, 0, 0)
- for i := 0; i < net.IPv4len; i++ {
- m[i] = ^mask[i]
- }
- return int32(binary.BigEndian.Uint32(m)) + 1
- }
|