2015-10-03 18:51:53 -07:00
|
|
|
package ipam
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-02-09 16:43:46 -05:00
|
|
|
"net/netip"
|
2015-10-03 18:51:53 -07:00
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
2023-02-07 10:25:52 -05:00
|
|
|
"github.com/docker/docker/libnetwork/bitmap"
|
2021-04-06 00:24:47 +00:00
|
|
|
"github.com/docker/docker/libnetwork/ipamapi"
|
|
|
|
"github.com/docker/docker/libnetwork/types"
|
2015-10-03 18:51:53 -07:00
|
|
|
)
|
|
|
|
|
2023-02-07 10:25:52 -05:00
|
|
|
// PoolID is the pointer to the configured pools in each address space
|
|
|
|
type PoolID struct {
|
2015-10-03 18:51:53 -07:00
|
|
|
AddressSpace string
|
2023-02-07 10:25:52 -05:00
|
|
|
SubnetKey
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// PoolData contains the configured pool data
|
|
|
|
type PoolData struct {
|
2023-02-07 10:25:52 -05:00
|
|
|
addrs *bitmap.Bitmap
|
2023-02-09 16:43:46 -05:00
|
|
|
children map[netip.Prefix]struct{}
|
2023-02-07 10:25:52 -05:00
|
|
|
|
|
|
|
// Whether to implicitly release the pool once it no longer has any children.
|
|
|
|
autoRelease bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// SubnetKey is the composite key to an address pool within an address space.
|
|
|
|
type SubnetKey struct {
|
2023-02-09 16:43:46 -05:00
|
|
|
Subnet, ChildSubnet netip.Prefix
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2015-10-05 04:24:44 -07:00
|
|
|
// addrSpace contains the pool configurations for the address space
|
|
|
|
type addrSpace struct {
|
2023-02-07 10:25:52 -05:00
|
|
|
// Master subnet pools, indexed by the value's stringified PoolData.Pool field.
|
2023-02-09 16:43:46 -05:00
|
|
|
subnets map[netip.Prefix]*PoolData
|
2023-02-06 18:01:47 -05:00
|
|
|
|
|
|
|
// Predefined pool for the address space
|
2023-02-09 16:43:46 -05:00
|
|
|
predefined []netip.Prefix
|
2023-02-06 18:01:47 -05:00
|
|
|
predefinedStartIndex int
|
|
|
|
|
2015-10-03 18:51:53 -07:00
|
|
|
sync.Mutex
|
|
|
|
}
|
|
|
|
|
2023-07-22 16:21:48 +02:00
|
|
|
// PoolIDFromString creates a new PoolID and populates the SubnetKey object
|
|
|
|
// reading it from the given string.
|
|
|
|
func PoolIDFromString(str string) (pID PoolID, err error) {
|
|
|
|
if str == "" {
|
2023-08-08 13:35:05 +02:00
|
|
|
return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
p := strings.Split(str, "/")
|
|
|
|
if len(p) != 3 && len(p) != 5 {
|
2023-08-08 13:35:05 +02:00
|
|
|
return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
2023-07-22 16:21:48 +02:00
|
|
|
pID.AddressSpace = p[0]
|
|
|
|
pID.Subnet, err = netip.ParsePrefix(p[1] + "/" + p[2])
|
2023-02-09 16:43:46 -05:00
|
|
|
if err != nil {
|
2023-08-08 13:35:05 +02:00
|
|
|
return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
|
2023-02-09 16:43:46 -05:00
|
|
|
}
|
2015-10-03 18:51:53 -07:00
|
|
|
if len(p) == 5 {
|
2023-07-22 16:21:48 +02:00
|
|
|
pID.ChildSubnet, err = netip.ParsePrefix(p[3] + "/" + p[4])
|
2023-02-09 16:43:46 -05:00
|
|
|
if err != nil {
|
2023-08-08 13:35:05 +02:00
|
|
|
return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
|
2023-02-09 16:43:46 -05:00
|
|
|
}
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2023-07-22 16:21:48 +02:00
|
|
|
return pID, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns the string form of the SubnetKey object
|
|
|
|
func (s *PoolID) String() string {
|
|
|
|
if s.ChildSubnet == (netip.Prefix{}) {
|
|
|
|
return s.AddressSpace + "/" + s.Subnet.String()
|
|
|
|
} else {
|
|
|
|
return s.AddressSpace + "/" + s.Subnet.String() + "/" + s.ChildSubnet.String()
|
2023-02-09 16:43:46 -05:00
|
|
|
}
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// String returns the string form of the PoolData object
|
|
|
|
func (p *PoolData) String() string {
|
2023-02-09 16:43:46 -05:00
|
|
|
return fmt.Sprintf("PoolData[Children: %d]", len(p.children))
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2023-02-06 17:21:25 -05:00
|
|
|
// allocateSubnet adds the subnet k to the address space.
|
2023-02-09 16:43:46 -05:00
|
|
|
func (aSpace *addrSpace) allocateSubnet(nw, sub netip.Prefix) error {
|
2015-10-05 04:24:44 -07:00
|
|
|
aSpace.Lock()
|
|
|
|
defer aSpace.Unlock()
|
2015-10-03 18:51:53 -07:00
|
|
|
|
|
|
|
// Check if already allocated
|
2023-02-09 16:43:46 -05:00
|
|
|
if pool, ok := aSpace.subnets[nw]; ok {
|
2023-02-07 10:25:52 -05:00
|
|
|
var childExists bool
|
2023-02-09 16:43:46 -05:00
|
|
|
if sub != (netip.Prefix{}) {
|
|
|
|
_, childExists = pool.children[sub]
|
2023-02-07 10:25:52 -05:00
|
|
|
}
|
2023-02-09 16:43:46 -05:00
|
|
|
if sub == (netip.Prefix{}) || childExists {
|
2023-02-07 10:25:52 -05:00
|
|
|
// This means the same pool is already allocated. allocateSubnet is called when there
|
|
|
|
// is request for a pool/subpool. It should ensure there is no overlap with existing pools
|
2023-02-09 16:43:46 -05:00
|
|
|
return ipamapi.ErrPoolOverlap
|
2016-01-22 10:46:05 -08:00
|
|
|
}
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2023-02-07 10:25:52 -05:00
|
|
|
return aSpace.allocateSubnetL(nw, sub)
|
|
|
|
}
|
|
|
|
|
2023-02-09 16:43:46 -05:00
|
|
|
func (aSpace *addrSpace) allocateSubnetL(nw, sub netip.Prefix) error {
|
2015-10-03 18:51:53 -07:00
|
|
|
// If master pool, check for overlap
|
2023-02-09 16:43:46 -05:00
|
|
|
if sub == (netip.Prefix{}) {
|
2023-11-01 11:44:24 -04:00
|
|
|
if aSpace.overlaps(nw) {
|
2023-02-09 16:43:46 -05:00
|
|
|
return ipamapi.ErrPoolOverlap
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
// This is a new master pool, add it along with corresponding bitmask
|
2023-02-09 16:43:46 -05:00
|
|
|
aSpace.subnets[nw] = newPoolData(nw)
|
|
|
|
return nil
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2018-05-23 16:21:31 +01:00
|
|
|
// This is a new non-master pool (subPool)
|
2023-02-09 16:43:46 -05:00
|
|
|
if nw.Addr().BitLen() != sub.Addr().BitLen() {
|
|
|
|
return fmt.Errorf("pool and subpool are of incompatible address families")
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
2023-02-07 10:25:52 -05:00
|
|
|
|
2015-10-03 18:51:53 -07:00
|
|
|
// Look for parent pool
|
2023-02-09 16:43:46 -05:00
|
|
|
pp, ok := aSpace.subnets[nw]
|
2023-02-07 10:25:52 -05:00
|
|
|
if !ok {
|
|
|
|
// Parent pool does not exist, add it along with corresponding bitmask
|
|
|
|
pp = newPoolData(nw)
|
|
|
|
pp.autoRelease = true
|
2023-02-09 16:43:46 -05:00
|
|
|
aSpace.subnets[nw] = pp
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
2023-02-09 16:43:46 -05:00
|
|
|
pp.children[sub] = struct{}{}
|
|
|
|
return nil
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2023-02-09 16:43:46 -05:00
|
|
|
func (aSpace *addrSpace) releaseSubnet(nw, sub netip.Prefix) error {
|
2015-10-05 04:24:44 -07:00
|
|
|
aSpace.Lock()
|
|
|
|
defer aSpace.Unlock()
|
2015-10-03 18:51:53 -07:00
|
|
|
|
2023-02-09 16:43:46 -05:00
|
|
|
p, ok := aSpace.subnets[nw]
|
2015-10-03 18:51:53 -07:00
|
|
|
if !ok {
|
2023-01-26 13:42:46 -05:00
|
|
|
return ipamapi.ErrBadPool
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2023-02-09 16:43:46 -05:00
|
|
|
if sub != (netip.Prefix{}) {
|
|
|
|
if _, ok := p.children[sub]; !ok {
|
2023-02-07 10:25:52 -05:00
|
|
|
return ipamapi.ErrBadPool
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
2023-02-09 16:43:46 -05:00
|
|
|
delete(p.children, sub)
|
2023-02-07 10:25:52 -05:00
|
|
|
} else {
|
|
|
|
p.autoRelease = true
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2023-02-07 10:25:52 -05:00
|
|
|
if len(p.children) == 0 && p.autoRelease {
|
2023-02-09 16:43:46 -05:00
|
|
|
delete(aSpace.subnets, nw)
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
2023-02-07 10:25:52 -05:00
|
|
|
|
|
|
|
return nil
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
|
2023-11-01 11:44:24 -04:00
|
|
|
// overlaps reports whether nw contains any IP addresses in common with any of
|
|
|
|
// the existing subnets in this address space.
|
|
|
|
func (aSpace *addrSpace) overlaps(nw netip.Prefix) bool {
|
2023-02-09 16:43:46 -05:00
|
|
|
for pool := range aSpace.subnets {
|
2023-11-01 11:44:24 -04:00
|
|
|
if pool.Overlaps(nw) {
|
2023-02-07 10:25:52 -05:00
|
|
|
return true
|
2015-10-03 18:51:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|