2015-06-12 19:43:18 +00:00
|
|
|
package ipam
|
|
|
|
|
|
|
|
import (
|
2015-09-22 20:20:55 +00:00
|
|
|
"encoding/json"
|
2015-06-12 19:43:18 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
2015-06-16 00:13:49 +00:00
|
|
|
"strings"
|
2015-06-12 22:36:28 +00:00
|
|
|
"sync"
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-06-16 01:28:00 +00:00
|
|
|
log "github.com/Sirupsen/logrus"
|
2015-09-22 20:20:55 +00:00
|
|
|
|
2015-06-16 21:46:51 +00:00
|
|
|
"github.com/docker/libkv/store"
|
2015-06-12 19:43:18 +00:00
|
|
|
"github.com/docker/libnetwork/bitseq"
|
2015-06-15 18:43:02 +00:00
|
|
|
"github.com/docker/libnetwork/datastore"
|
2015-09-22 20:20:55 +00:00
|
|
|
"github.com/docker/libnetwork/ipamapi"
|
|
|
|
"github.com/docker/libnetwork/netutils"
|
2015-06-16 01:28:00 +00:00
|
|
|
"github.com/docker/libnetwork/types"
|
2015-06-12 19:43:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2015-09-22 20:20:55 +00:00
|
|
|
localAddressSpace = "LocalDefault"
|
|
|
|
globalAddressSpace = "GlobalDefault"
|
2015-06-12 19:43:18 +00:00
|
|
|
// The biggest configurable host subnets
|
2015-09-22 20:20:55 +00:00
|
|
|
minNetSize = 8
|
|
|
|
minNetSizeV6 = 64
|
2015-06-12 19:43:18 +00:00
|
|
|
minNetSizeV6Eff = 96
|
2015-06-25 02:11:44 +00:00
|
|
|
// datastore keyes for ipam objects
|
2015-09-22 20:20:55 +00:00
|
|
|
dsConfigKey = "ipam/" + ipamapi.DefaultIPAM + "/config"
|
|
|
|
dsDataKey = "ipam/" + ipamapi.DefaultIPAM + "/data"
|
2015-06-12 19:43:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Allocator provides per address space ipv4/ipv6 book keeping
|
|
|
|
type Allocator struct {
|
2015-09-22 20:20:55 +00:00
|
|
|
// Predefined pools for default address spaces
|
|
|
|
predefined map[string][]*net.IPNet
|
2015-06-12 19:43:18 +00:00
|
|
|
// Static subnet information
|
2015-09-22 20:20:55 +00:00
|
|
|
subnets map[SubnetKey]*PoolData
|
|
|
|
// Allocated addresses in each address space's subnet
|
|
|
|
addresses map[SubnetKey]*bitseq.Handle
|
2015-06-15 18:43:02 +00:00
|
|
|
// Datastore
|
2015-06-18 22:13:38 +00:00
|
|
|
store datastore.DataStore
|
|
|
|
dbIndex uint64
|
|
|
|
dbExists bool
|
2015-06-12 22:36:28 +00:00
|
|
|
sync.Mutex
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewAllocator returns an instance of libnetwork ipam
|
2015-09-22 20:20:55 +00:00
|
|
|
func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
|
2015-06-12 19:43:18 +00:00
|
|
|
a := &Allocator{}
|
2015-09-22 20:20:55 +00:00
|
|
|
a.subnets = make(map[SubnetKey]*PoolData)
|
|
|
|
a.addresses = make(map[SubnetKey]*bitseq.Handle)
|
|
|
|
a.predefined = make(map[string][]*net.IPNet, 2)
|
|
|
|
a.predefined[localAddressSpace] = initLocalPredefinedPools()
|
|
|
|
a.predefined[globalAddressSpace] = initGlobalPredefinedPools()
|
|
|
|
a.store = glDs
|
2015-06-16 21:46:51 +00:00
|
|
|
|
|
|
|
if a.store == nil {
|
|
|
|
return a, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register for status changes
|
|
|
|
a.watchForChanges()
|
|
|
|
|
|
|
|
// Get the initial subnet configs status from the ds if present.
|
|
|
|
kvPair, err := a.store.KVStore().Get(datastore.Key(a.Key()...))
|
|
|
|
if err != nil {
|
|
|
|
if err != store.ErrKeyNotFound {
|
|
|
|
return nil, fmt.Errorf("failed to retrieve the ipam subnet configs from datastore: %v", err)
|
|
|
|
}
|
|
|
|
return a, nil
|
|
|
|
}
|
|
|
|
a.subnetConfigFromStore(kvPair)
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// Now retrieve the bitmasks for the master pools
|
2015-06-16 21:46:51 +00:00
|
|
|
var inserterList []func() error
|
|
|
|
a.Lock()
|
|
|
|
for k, v := range a.subnets {
|
2015-09-22 20:20:55 +00:00
|
|
|
if v.Range == nil {
|
|
|
|
inserterList = append(inserterList, func() error { return a.insertBitMask(k, v.Pool) })
|
|
|
|
}
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
|
|
|
a.Unlock()
|
|
|
|
|
|
|
|
// Add the bitmasks, data could come from datastore
|
|
|
|
for _, f := range inserterList {
|
|
|
|
if err := f(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return a, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Allocator) subnetConfigFromStore(kvPair *store.KVPair) {
|
|
|
|
a.Lock()
|
|
|
|
if a.dbIndex < kvPair.LastIndex {
|
2015-09-22 20:20:55 +00:00
|
|
|
a.SetValue(kvPair.Value)
|
2015-06-16 21:46:51 +00:00
|
|
|
a.dbIndex = kvPair.LastIndex
|
2015-06-18 22:13:38 +00:00
|
|
|
a.dbExists = true
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
|
|
|
a.Unlock()
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// SubnetKey is the pointer to the configured pools in each address space
|
|
|
|
type SubnetKey struct {
|
|
|
|
AddressSpace string
|
|
|
|
Subnet string
|
|
|
|
ChildSubnet string
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// String returns the string form of the SubnetKey object
|
|
|
|
func (s *SubnetKey) String() string {
|
|
|
|
k := fmt.Sprintf("%s/%s", s.AddressSpace, s.Subnet)
|
|
|
|
if s.ChildSubnet != "" {
|
|
|
|
k = fmt.Sprintf("%s/%s", k, s.ChildSubnet)
|
2015-06-16 00:13:49 +00:00
|
|
|
}
|
|
|
|
return k
|
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// FromString populate the SubnetKey object reading it from string
|
|
|
|
func (s *SubnetKey) FromString(str string) error {
|
2015-06-16 00:13:49 +00:00
|
|
|
if str == "" || !strings.Contains(str, "/") {
|
|
|
|
return fmt.Errorf("invalid string form for subnetkey: %s", str)
|
|
|
|
}
|
|
|
|
|
|
|
|
p := strings.Split(str, "/")
|
|
|
|
if len(p) != 3 && len(p) != 5 {
|
|
|
|
return fmt.Errorf("invalid string form for subnetkey: %s", str)
|
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
s.AddressSpace = p[0]
|
|
|
|
s.Subnet = fmt.Sprintf("%s/%s", p[1], p[2])
|
2015-06-16 00:13:49 +00:00
|
|
|
if len(p) == 5 {
|
2015-09-22 20:20:55 +00:00
|
|
|
s.ChildSubnet = fmt.Sprintf("%s/%s", p[3], p[4])
|
2015-06-16 00:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// AddressRange specifies first and last ip ordinal which
|
|
|
|
// identify a range in a a pool of addresses
|
|
|
|
type AddressRange struct {
|
|
|
|
Sub *net.IPNet
|
|
|
|
Start, End uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns the string form of the AddressRange object
|
|
|
|
func (r *AddressRange) String() string {
|
|
|
|
return fmt.Sprintf("Sub: %s, range [%d, %d]", r.Sub, r.Start, r.End)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON returns the JSON encoding of the Range object
|
|
|
|
func (r *AddressRange) MarshalJSON() ([]byte, error) {
|
|
|
|
m := map[string]interface{}{
|
|
|
|
"Sub": r.Sub.String(),
|
|
|
|
"Start": r.Start,
|
|
|
|
"End": r.End,
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
return json.Marshal(m)
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON decodes data into the Range object
|
|
|
|
func (r *AddressRange) UnmarshalJSON(data []byte) error {
|
|
|
|
m := map[string]interface{}{}
|
|
|
|
err := json.Unmarshal(data, &m)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if r.Sub, err = types.ParseCIDR(m["Sub"].(string)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r.Start = uint32(m["Start"].(float64))
|
|
|
|
r.End = uint32(m["End"].(float64))
|
2015-06-16 21:46:51 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// PoolData contains the configured pool data
|
|
|
|
type PoolData struct {
|
|
|
|
ParentKey SubnetKey
|
|
|
|
Pool *net.IPNet
|
|
|
|
Range *AddressRange `json:",omitempty"`
|
|
|
|
RefCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns the string form of the PoolData object
|
|
|
|
func (p *PoolData) String() string {
|
|
|
|
return fmt.Sprintf("ParentKey: %s, Pool: %s, Range: %s, RefCount: %d",
|
|
|
|
p.ParentKey.String(), p.Pool.String(), p.Range, p.RefCount)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON returns the JSON encoding of the PoolData object
|
|
|
|
func (p *PoolData) MarshalJSON() ([]byte, error) {
|
|
|
|
m := map[string]interface{}{
|
|
|
|
"ParentKey": p.ParentKey,
|
|
|
|
"RefCount": p.RefCount,
|
|
|
|
}
|
|
|
|
if p.Pool != nil {
|
|
|
|
m["Pool"] = p.Pool.String()
|
|
|
|
}
|
|
|
|
if p.Range != nil {
|
|
|
|
m["Range"] = p.Range
|
|
|
|
}
|
|
|
|
return json.Marshal(m)
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON decodes data into the PoolData object
|
|
|
|
func (p *PoolData) UnmarshalJSON(data []byte) error {
|
|
|
|
var (
|
|
|
|
err error
|
|
|
|
t struct {
|
|
|
|
ParentKey SubnetKey
|
|
|
|
Pool string
|
|
|
|
Range *AddressRange `json:",omitempty"`
|
|
|
|
RefCount int
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
if err = json.Unmarshal(data, &t); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
p.ParentKey = t.ParentKey
|
|
|
|
p.Range = t.Range
|
|
|
|
p.RefCount = t.RefCount
|
|
|
|
if t.Pool != "" {
|
|
|
|
if p.Pool, err = types.ParseCIDR(t.Pool); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
|
2015-06-16 21:46:51 +00:00
|
|
|
return nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ipVersion int
|
|
|
|
|
|
|
|
const (
|
|
|
|
v4 = 4
|
|
|
|
v6 = 6
|
|
|
|
)
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// GetDefaultAddressSpaces returns the local and global default address spaces
|
|
|
|
func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
|
|
|
|
return localAddressSpace, globalAddressSpace, nil
|
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// RequestPool returns an address pool along with its unique id.
|
|
|
|
func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
|
|
|
k, nw, aw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6)
|
2015-06-12 19:43:18 +00:00
|
|
|
if err != nil {
|
2015-09-22 20:20:55 +00:00
|
|
|
return "", nil, nil, ipamapi.ErrInvalidPool
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-06-16 21:46:51 +00:00
|
|
|
retry:
|
2015-09-22 20:20:55 +00:00
|
|
|
insert, err := a.updatePoolDBOnAdd(*k, nw, ipr)
|
2015-06-16 21:46:51 +00:00
|
|
|
if err != nil {
|
2015-09-22 20:20:55 +00:00
|
|
|
return "", nil, nil, err
|
|
|
|
}
|
|
|
|
if err := a.writeToStore(); err != nil {
|
2015-06-16 21:46:51 +00:00
|
|
|
if _, ok := err.(types.RetryError); !ok {
|
2015-09-22 20:20:55 +00:00
|
|
|
return "", nil, nil, types.InternalErrorf("pool configuration failed because of %s", err.Error())
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
|
|
|
if erru := a.readFromStore(); erru != nil {
|
2015-09-22 20:20:55 +00:00
|
|
|
return "", nil, nil, fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
|
|
|
goto retry
|
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
return k.String(), aw, nil, insert()
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// ReleasePool releases the address pool identified by the passed id
|
|
|
|
func (a *Allocator) ReleasePool(poolID string) error {
|
|
|
|
k := SubnetKey{}
|
|
|
|
if err := k.FromString(poolID); err != nil {
|
|
|
|
return types.BadRequestErrorf("invalid pool id: %s", poolID)
|
|
|
|
}
|
2015-08-12 02:22:38 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
retry:
|
|
|
|
remove, err := a.updatePoolDBOnRemoval(k)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err = a.writeToStore(); err != nil {
|
|
|
|
if _, ok := err.(types.RetryError); !ok {
|
|
|
|
return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err)
|
2015-08-12 02:22:38 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
if erru := a.readFromStore(); erru != nil {
|
|
|
|
return fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
goto retry
|
|
|
|
}
|
2015-08-12 02:22:38 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
return remove()
|
|
|
|
}
|
2015-08-12 02:22:38 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *net.IPNet, *AddressRange, error) {
|
|
|
|
var (
|
|
|
|
nw, aw *net.IPNet
|
|
|
|
ipr *AddressRange
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
if addressSpace == "" {
|
|
|
|
return nil, nil, nil, nil, ipamapi.ErrInvalidAddressSpace
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
if pool == "" && subPool != "" {
|
|
|
|
return nil, nil, nil, nil, ipamapi.ErrInvalidSubPool
|
|
|
|
}
|
|
|
|
|
|
|
|
if pool != "" {
|
|
|
|
if _, nw, err = net.ParseCIDR(pool); err != nil {
|
|
|
|
return nil, nil, nil, nil, ipamapi.ErrInvalidPool
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
if subPool != "" {
|
|
|
|
if ipr, err = getAddressRange(subPool); err != nil {
|
|
|
|
return nil, nil, nil, nil, err
|
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-09-22 20:20:55 +00:00
|
|
|
if nw, err = a.getPredefinedPool(addressSpace, v6); err != nil {
|
|
|
|
return nil, nil, nil, nil, err
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
if aw, err = adjustAndCheckSubnetSize(nw); err != nil {
|
|
|
|
return nil, nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, aw, ipr, nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange) (func() error, error) {
|
2015-06-12 22:36:28 +00:00
|
|
|
a.Lock()
|
|
|
|
defer a.Unlock()
|
2015-09-22 20:20:55 +00:00
|
|
|
|
|
|
|
// Check if already allocated
|
|
|
|
if p, ok := a.subnets[k]; ok {
|
|
|
|
a.incRefCount(p, 1)
|
|
|
|
return func() error { return nil }, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If master pool, check for overlap
|
|
|
|
if ipr == nil {
|
|
|
|
if a.contains(k.AddressSpace, nw) {
|
|
|
|
return nil, ipamapi.ErrPoolOverlap
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
// This is a new master pool, add it along with corresponding bitmask
|
|
|
|
a.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
|
|
|
|
return func() error { return a.insertBitMask(k, nw) }, nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// This is a new non-master pool
|
|
|
|
p := &PoolData{
|
|
|
|
ParentKey: SubnetKey{AddressSpace: k.AddressSpace, Subnet: k.Subnet},
|
|
|
|
Pool: nw,
|
|
|
|
Range: ipr,
|
|
|
|
RefCount: 1,
|
|
|
|
}
|
|
|
|
a.subnets[k] = p
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// Look for parent pool
|
|
|
|
pp, ok := a.subnets[p.ParentKey]
|
|
|
|
if ok {
|
|
|
|
a.incRefCount(pp, 1)
|
|
|
|
return func() error { return nil }, nil
|
2015-06-13 20:12:24 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// Parent pool does not exist, add it along with corresponding bitmask
|
|
|
|
a.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
|
|
|
|
return func() error { return a.insertBitMask(p.ParentKey, nw) }, nil
|
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
|
|
|
|
a.Lock()
|
|
|
|
defer a.Unlock()
|
|
|
|
|
|
|
|
p, ok := a.subnets[k]
|
|
|
|
if !ok {
|
|
|
|
return nil, ipamapi.ErrBadPool
|
|
|
|
}
|
|
|
|
|
|
|
|
a.incRefCount(p, -1)
|
|
|
|
|
|
|
|
c := p
|
|
|
|
for ok {
|
|
|
|
if c.RefCount == 0 {
|
|
|
|
delete(a.subnets, k)
|
|
|
|
if c.Range == nil {
|
|
|
|
return func() error {
|
|
|
|
bm, err := a.retrieveBitmask(k, c.Pool)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
|
|
|
|
}
|
|
|
|
return bm.Destroy()
|
|
|
|
}, nil
|
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
k = c.ParentKey
|
|
|
|
c, ok = a.subnets[k]
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
|
|
|
|
return func() error { return nil }, nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) incRefCount(p *PoolData, delta int) {
|
|
|
|
c := p
|
|
|
|
ok := true
|
|
|
|
for ok {
|
|
|
|
c.RefCount += delta
|
|
|
|
c, ok = a.subnets[c.ParentKey]
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
|
|
|
|
log.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String())
|
|
|
|
ipVer := getAddressVersion(pool.IP)
|
|
|
|
ones, bits := pool.Mask.Size()
|
|
|
|
numAddresses := uint32(1 << uint(bits-ones))
|
|
|
|
|
|
|
|
if ipVer == v4 {
|
|
|
|
// Do not let broadcast address be reserved
|
|
|
|
numAddresses--
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// Generate the new address masks. AddressMask content may come from datastore
|
|
|
|
h, err := bitseq.NewHandle(dsDataKey, a.store, key.String(), numAddresses)
|
2015-06-13 20:12:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
if ipVer == v4 {
|
|
|
|
// Do not let network identifier address be reserved
|
|
|
|
h.Set(0)
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
a.Lock()
|
|
|
|
a.addresses[key] = h
|
|
|
|
a.Unlock()
|
2015-06-12 19:43:18 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
|
|
|
|
a.Lock()
|
|
|
|
bm, ok := a.addresses[k]
|
|
|
|
a.Unlock()
|
|
|
|
if !ok {
|
|
|
|
log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
|
|
|
|
if err := a.insertBitMask(k, n); err != nil {
|
|
|
|
return nil, fmt.Errorf("could not find bitmask in datastore for %s", k.String())
|
|
|
|
}
|
|
|
|
a.Lock()
|
|
|
|
bm = a.addresses[k]
|
|
|
|
a.Unlock()
|
|
|
|
}
|
|
|
|
return bm, nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) getPredefineds(as string) []*net.IPNet {
|
|
|
|
a.Lock()
|
|
|
|
defer a.Unlock()
|
|
|
|
l := make([]*net.IPNet, 0, len(a.predefined[as]))
|
|
|
|
for _, pool := range a.predefined[as] {
|
|
|
|
l = append(l, pool)
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
return l
|
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) {
|
|
|
|
var v ipVersion
|
|
|
|
v = v4
|
|
|
|
if ipV6 {
|
|
|
|
v = v6
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
if as != localAddressSpace && as != globalAddressSpace {
|
|
|
|
return nil, fmt.Errorf("no default pool availbale for non-default addresss spaces")
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
for _, nw := range a.getPredefineds(as) {
|
|
|
|
if v != getAddressVersion(nw.IP) {
|
|
|
|
continue
|
|
|
|
}
|
2015-06-12 22:36:28 +00:00
|
|
|
a.Lock()
|
2015-09-22 20:20:55 +00:00
|
|
|
_, ok := a.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
|
2015-06-12 22:36:28 +00:00
|
|
|
a.Unlock()
|
2015-09-22 20:20:55 +00:00
|
|
|
if ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !a.contains(as, nw) {
|
|
|
|
if as == localAddressSpace {
|
|
|
|
if err := netutils.CheckRouteOverlaps(nw); err == nil {
|
|
|
|
return nw, nil
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return nw, nil
|
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
return nil, types.NotFoundErrorf("could not find an available predefined network")
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// Check subnets size. In case configured subnet is v6 and host size is
|
|
|
|
// greater than 32 bits, adjust subnet to /96.
|
|
|
|
func adjustAndCheckSubnetSize(subnet *net.IPNet) (*net.IPNet, error) {
|
|
|
|
ones, bits := subnet.Mask.Size()
|
|
|
|
if v6 == getAddressVersion(subnet.IP) {
|
|
|
|
if ones < minNetSizeV6 {
|
|
|
|
return nil, ipamapi.ErrInvalidPool
|
|
|
|
}
|
|
|
|
if ones < minNetSizeV6Eff {
|
|
|
|
newMask := net.CIDRMask(minNetSizeV6Eff, bits)
|
|
|
|
return &net.IPNet{IP: subnet.IP, Mask: newMask}, nil
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ones < minNetSize {
|
|
|
|
return nil, ipamapi.ErrInvalidPool
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return subnet, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks whether the passed subnet is a superset or subset of any of the subset in the db
|
|
|
|
func (a *Allocator) contains(space string, nw *net.IPNet) bool {
|
|
|
|
for k, v := range a.subnets {
|
|
|
|
if space == k.AddressSpace && k.ChildSubnet == "" {
|
|
|
|
if nw.Contains(v.Pool.IP) || v.Pool.Contains(nw.IP) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2015-06-25 02:11:44 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// RequestAddress returns an address from the specified pool ID
|
|
|
|
func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
|
|
|
|
k := SubnetKey{}
|
|
|
|
if err := k.FromString(poolID); err != nil {
|
|
|
|
return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-06-25 02:11:44 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
a.Lock()
|
|
|
|
p, ok := a.subnets[k]
|
|
|
|
if !ok {
|
|
|
|
a.Unlock()
|
|
|
|
return nil, nil, types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-06-25 02:11:44 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
if prefAddress != nil && !p.Pool.Contains(prefAddress) {
|
|
|
|
a.Unlock()
|
|
|
|
return nil, nil, ipamapi.ErrIPOutOfRange
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
|
|
|
|
c := p
|
|
|
|
for c.Range != nil {
|
|
|
|
k = c.ParentKey
|
|
|
|
c, ok = a.subnets[k]
|
2015-06-25 02:11:44 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
a.Unlock()
|
2015-06-25 02:11:44 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
bm, err := a.retrieveBitmask(k, c.Pool)
|
2015-06-25 02:11:44 +00:00
|
|
|
if err != nil {
|
2015-09-22 20:20:55 +00:00
|
|
|
return nil, nil, fmt.Errorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
|
|
|
|
k.String(), prefAddress, poolID, err)
|
2015-06-25 02:11:44 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
ip, err := a.getAddress(p.Pool, bm, prefAddress, p.Range)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
2015-06-25 02:11:44 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
|
|
|
|
return &net.IPNet{IP: ip, Mask: p.Pool.Mask}, nil, nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// ReleaseAddress releases the address from the specified pool ID
|
|
|
|
func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
|
|
|
k := SubnetKey{}
|
|
|
|
if err := k.FromString(poolID); err != nil {
|
|
|
|
return types.BadRequestErrorf("invalid pool id: %s", poolID)
|
|
|
|
}
|
2015-06-12 19:43:18 +00:00
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
a.Lock()
|
|
|
|
p, ok := a.subnets[k]
|
|
|
|
if !ok {
|
2015-06-12 22:36:28 +00:00
|
|
|
a.Unlock()
|
2015-09-22 20:20:55 +00:00
|
|
|
return ipamapi.ErrBadPool
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
if address == nil || !p.Pool.Contains(address) {
|
2015-06-12 22:36:28 +00:00
|
|
|
a.Unlock()
|
2015-09-22 20:20:55 +00:00
|
|
|
return ipamapi.ErrInvalidRequest
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
c := p
|
|
|
|
for c.Range != nil {
|
|
|
|
k = c.ParentKey
|
|
|
|
c = a.subnets[k]
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
2015-06-12 22:36:28 +00:00
|
|
|
a.Unlock()
|
2015-09-22 20:20:55 +00:00
|
|
|
|
|
|
|
mask := p.Pool.Mask
|
|
|
|
if p.Range != nil {
|
|
|
|
mask = p.Range.Sub.Mask
|
|
|
|
}
|
|
|
|
h, err := types.GetHostPartIP(address, mask)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to release address %s: %v", address.String(), err)
|
|
|
|
}
|
|
|
|
|
|
|
|
bm, err := a.retrieveBitmask(k, c.Pool)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
|
|
|
|
k.String(), address, poolID, err)
|
|
|
|
}
|
|
|
|
return bm.Unset(ipToUint32(h))
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ipr *AddressRange) (net.IP, error) {
|
2015-06-12 19:43:18 +00:00
|
|
|
var (
|
2015-06-24 22:02:08 +00:00
|
|
|
ordinal uint32
|
|
|
|
err error
|
2015-09-22 20:20:55 +00:00
|
|
|
base *net.IPNet
|
2015-06-12 19:43:18 +00:00
|
|
|
)
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
base = types.GetIPNetCopy(nw)
|
|
|
|
|
2015-08-12 02:22:38 +00:00
|
|
|
if bitmask.Unselected() <= 0 {
|
2015-09-22 20:20:55 +00:00
|
|
|
return nil, ipamapi.ErrNoAvailableIPs
|
2015-08-12 02:22:38 +00:00
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
if ipr == nil && prefAddress == nil {
|
2015-08-12 02:22:38 +00:00
|
|
|
ordinal, err = bitmask.SetAny()
|
2015-09-22 20:20:55 +00:00
|
|
|
} else if ipr != nil {
|
|
|
|
base.IP = ipr.Sub.IP
|
|
|
|
ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End)
|
2015-08-12 02:22:38 +00:00
|
|
|
} else {
|
2015-09-22 20:20:55 +00:00
|
|
|
hostPart, e := types.GetHostPartIP(prefAddress, base.Mask)
|
2015-08-12 02:22:38 +00:00
|
|
|
if e != nil {
|
|
|
|
return nil, fmt.Errorf("failed to allocate preferred address %s: %v", prefAddress.String(), e)
|
2015-06-16 21:46:51 +00:00
|
|
|
}
|
2015-08-12 02:22:38 +00:00
|
|
|
ordinal = ipToUint32(types.GetMinimalIP(hostPart))
|
|
|
|
err = bitmask.Set(ordinal)
|
|
|
|
}
|
|
|
|
if err != nil {
|
2015-09-22 20:20:55 +00:00
|
|
|
return nil, ipamapi.ErrNoAvailableIPs
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convert IP ordinal for this subnet into IP address
|
2015-09-22 20:20:55 +00:00
|
|
|
return generateAddress(ordinal, base), nil
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DumpDatabase dumps the internal info
|
2015-09-22 20:20:55 +00:00
|
|
|
func (a *Allocator) DumpDatabase() string {
|
2015-06-12 22:36:28 +00:00
|
|
|
a.Lock()
|
|
|
|
defer a.Unlock()
|
2015-09-22 20:20:55 +00:00
|
|
|
|
|
|
|
s := fmt.Sprintf("\n\nPoolData")
|
2015-06-16 00:13:49 +00:00
|
|
|
for k, config := range a.subnets {
|
2015-09-22 20:20:55 +00:00
|
|
|
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
s = fmt.Sprintf("%s\n\nBitmasks", s)
|
|
|
|
for k, bm := range a.addresses {
|
|
|
|
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
|
|
|
|
}
|
|
|
|
return s
|
2015-08-12 02:22:38 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 19:43:18 +00:00
|
|
|
// It generates the ip address in the passed subnet specified by
|
|
|
|
// the passed host address ordinal
|
2015-06-24 17:04:34 +00:00
|
|
|
func generateAddress(ordinal uint32, network *net.IPNet) net.IP {
|
2015-06-12 19:43:18 +00:00
|
|
|
var address [16]byte
|
|
|
|
|
|
|
|
// Get network portion of IP
|
2015-06-25 02:11:44 +00:00
|
|
|
if getAddressVersion(network.IP) == v4 {
|
2015-06-12 19:43:18 +00:00
|
|
|
copy(address[:], network.IP.To4())
|
|
|
|
} else {
|
|
|
|
copy(address[:], network.IP)
|
|
|
|
}
|
|
|
|
|
|
|
|
end := len(network.Mask)
|
|
|
|
addIntToIP(address[:end], ordinal)
|
|
|
|
|
|
|
|
return net.IP(address[:end])
|
|
|
|
}
|
|
|
|
|
|
|
|
func getAddressVersion(ip net.IP) ipVersion {
|
|
|
|
if ip.To4() == nil {
|
|
|
|
return v6
|
|
|
|
}
|
|
|
|
return v4
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adds the ordinal IP to the current array
|
|
|
|
// 192.168.0.0 + 53 => 192.168.53
|
2015-06-24 17:04:34 +00:00
|
|
|
func addIntToIP(array []byte, ordinal uint32) {
|
2015-06-12 19:43:18 +00:00
|
|
|
for i := len(array) - 1; i >= 0; i-- {
|
|
|
|
array[i] |= (byte)(ordinal & 0xff)
|
|
|
|
ordinal >>= 8
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert an ordinal to the respective IP address
|
2015-06-24 17:04:34 +00:00
|
|
|
func ipToUint32(ip []byte) uint32 {
|
|
|
|
value := uint32(0)
|
2015-06-12 19:43:18 +00:00
|
|
|
for i := 0; i < len(ip); i++ {
|
|
|
|
j := len(ip) - 1 - i
|
2015-06-24 17:04:34 +00:00
|
|
|
value += uint32(ip[i]) << uint(j*8)
|
2015-06-12 19:43:18 +00:00
|
|
|
}
|
|
|
|
return value
|
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
|
|
|
|
func initLocalPredefinedPools() []*net.IPNet {
|
|
|
|
pl := make([]*net.IPNet, 0, 274)
|
|
|
|
mask := []byte{255, 255, 0, 0}
|
|
|
|
for i := 17; i < 32; i++ {
|
|
|
|
pl = append(pl, &net.IPNet{IP: []byte{172, byte(i), 0, 0}, Mask: mask})
|
|
|
|
}
|
|
|
|
for i := 0; i < 256; i++ {
|
|
|
|
pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), 0, 0}, Mask: mask})
|
|
|
|
}
|
|
|
|
mask24 := []byte{255, 255, 255, 0}
|
|
|
|
for i := 42; i < 45; i++ {
|
|
|
|
pl = append(pl, &net.IPNet{IP: []byte{192, 168, byte(i), 0}, Mask: mask24})
|
|
|
|
}
|
|
|
|
return pl
|
|
|
|
}
|
|
|
|
|
|
|
|
func initGlobalPredefinedPools() []*net.IPNet {
|
|
|
|
pl := make([]*net.IPNet, 0, 256*256)
|
|
|
|
mask := []byte{255, 255, 255, 0}
|
|
|
|
for i := 0; i < 256; i++ {
|
|
|
|
for j := 0; j < 256; j++ {
|
|
|
|
pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), byte(j), 0}, Mask: mask})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pl
|
|
|
|
}
|
|
|
|
|
|
|
|
func getAddressRange(pool string) (*AddressRange, error) {
|
|
|
|
ip, nw, err := net.ParseCIDR(pool)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ipamapi.ErrInvalidSubPool
|
|
|
|
}
|
|
|
|
lIP, e := types.GetHostPartIP(nw.IP, nw.Mask)
|
|
|
|
if e != nil {
|
|
|
|
return nil, fmt.Errorf("failed to compute range's lowest ip address: %v", e)
|
|
|
|
}
|
|
|
|
bIP, e := types.GetBroadcastIP(nw.IP, nw.Mask)
|
|
|
|
if e != nil {
|
|
|
|
return nil, fmt.Errorf("failed to compute range's broadcast ip address: %v", e)
|
|
|
|
}
|
|
|
|
hIP, e := types.GetHostPartIP(bIP, nw.Mask)
|
|
|
|
if e != nil {
|
|
|
|
return nil, fmt.Errorf("failed to compute range's highest ip address: %v", e)
|
|
|
|
}
|
|
|
|
nw.IP = ip
|
|
|
|
return &AddressRange{nw, ipToUint32(types.GetMinimalIP(lIP)), ipToUint32(types.GetMinimalIP(hIP))}, nil
|
|
|
|
}
|