github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/ipam/structures.go (about)

     1  package ipam
     2  
     3  import (
     4  	"fmt"
     5  	"net/netip"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/bitmap"
    10  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/ipamapi"
    11  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/types"
    12  )
    13  
    14  // PoolID is the pointer to the configured pools in each address space
    15  type PoolID struct {
    16  	AddressSpace string
    17  	SubnetKey
    18  }
    19  
    20  // PoolData contains the configured pool data
    21  type PoolData struct {
    22  	addrs    *bitmap.Bitmap
    23  	children map[netip.Prefix]struct{}
    24  
    25  	// Whether to implicitly release the pool once it no longer has any children.
    26  	autoRelease bool
    27  }
    28  
    29  // SubnetKey is the composite key to an address pool within an address space.
    30  type SubnetKey struct {
    31  	Subnet, ChildSubnet netip.Prefix
    32  }
    33  
    34  // addrSpace contains the pool configurations for the address space
    35  type addrSpace struct {
    36  	// Master subnet pools, indexed by the value's stringified PoolData.Pool field.
    37  	subnets map[netip.Prefix]*PoolData
    38  
    39  	// Predefined pool for the address space
    40  	predefined           []netip.Prefix
    41  	predefinedStartIndex int
    42  
    43  	sync.Mutex
    44  }
    45  
    46  // PoolIDFromString creates a new PoolID and populates the SubnetKey object
    47  // reading it from the given string.
    48  func PoolIDFromString(str string) (pID PoolID, err error) {
    49  	if str == "" {
    50  		return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
    51  	}
    52  
    53  	p := strings.Split(str, "/")
    54  	if len(p) != 3 && len(p) != 5 {
    55  		return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
    56  	}
    57  	pID.AddressSpace = p[0]
    58  	pID.Subnet, err = netip.ParsePrefix(p[1] + "/" + p[2])
    59  	if err != nil {
    60  		return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
    61  	}
    62  	if len(p) == 5 {
    63  		pID.ChildSubnet, err = netip.ParsePrefix(p[3] + "/" + p[4])
    64  		if err != nil {
    65  			return pID, types.InvalidParameterErrorf("invalid string form for subnetkey: %s", str)
    66  		}
    67  	}
    68  
    69  	return pID, nil
    70  }
    71  
    72  // String returns the string form of the SubnetKey object
    73  func (s *PoolID) String() string {
    74  	if s.ChildSubnet == (netip.Prefix{}) {
    75  		return s.AddressSpace + "/" + s.Subnet.String()
    76  	} else {
    77  		return s.AddressSpace + "/" + s.Subnet.String() + "/" + s.ChildSubnet.String()
    78  	}
    79  }
    80  
    81  // String returns the string form of the PoolData object
    82  func (p *PoolData) String() string {
    83  	return fmt.Sprintf("PoolData[Children: %d]", len(p.children))
    84  }
    85  
    86  // allocateSubnet adds the subnet k to the address space.
    87  func (aSpace *addrSpace) allocateSubnet(nw, sub netip.Prefix) error {
    88  	aSpace.Lock()
    89  	defer aSpace.Unlock()
    90  
    91  	// Check if already allocated
    92  	if pool, ok := aSpace.subnets[nw]; ok {
    93  		var childExists bool
    94  		if sub != (netip.Prefix{}) {
    95  			_, childExists = pool.children[sub]
    96  		}
    97  		if sub == (netip.Prefix{}) || childExists {
    98  			// This means the same pool is already allocated. allocateSubnet is called when there
    99  			// is request for a pool/subpool. It should ensure there is no overlap with existing pools
   100  			return ipamapi.ErrPoolOverlap
   101  		}
   102  	}
   103  
   104  	return aSpace.allocateSubnetL(nw, sub)
   105  }
   106  
   107  func (aSpace *addrSpace) allocateSubnetL(nw, sub netip.Prefix) error {
   108  	// If master pool, check for overlap
   109  	if sub == (netip.Prefix{}) {
   110  		if aSpace.contains(nw) {
   111  			return ipamapi.ErrPoolOverlap
   112  		}
   113  		// This is a new master pool, add it along with corresponding bitmask
   114  		aSpace.subnets[nw] = newPoolData(nw)
   115  		return nil
   116  	}
   117  
   118  	// This is a new non-master pool (subPool)
   119  	if nw.Addr().BitLen() != sub.Addr().BitLen() {
   120  		return fmt.Errorf("pool and subpool are of incompatible address families")
   121  	}
   122  
   123  	// Look for parent pool
   124  	pp, ok := aSpace.subnets[nw]
   125  	if !ok {
   126  		// Parent pool does not exist, add it along with corresponding bitmask
   127  		pp = newPoolData(nw)
   128  		pp.autoRelease = true
   129  		aSpace.subnets[nw] = pp
   130  	}
   131  	pp.children[sub] = struct{}{}
   132  	return nil
   133  }
   134  
   135  func (aSpace *addrSpace) releaseSubnet(nw, sub netip.Prefix) error {
   136  	aSpace.Lock()
   137  	defer aSpace.Unlock()
   138  
   139  	p, ok := aSpace.subnets[nw]
   140  	if !ok {
   141  		return ipamapi.ErrBadPool
   142  	}
   143  
   144  	if sub != (netip.Prefix{}) {
   145  		if _, ok := p.children[sub]; !ok {
   146  			return ipamapi.ErrBadPool
   147  		}
   148  		delete(p.children, sub)
   149  	} else {
   150  		p.autoRelease = true
   151  	}
   152  
   153  	if len(p.children) == 0 && p.autoRelease {
   154  		delete(aSpace.subnets, nw)
   155  	}
   156  
   157  	return nil
   158  }
   159  
   160  // contains checks whether nw is a superset or subset of any of the existing subnets in this address space.
   161  func (aSpace *addrSpace) contains(nw netip.Prefix) bool {
   162  	for pool := range aSpace.subnets {
   163  		if nw.Contains(pool.Addr()) || pool.Contains(nw.Addr()) {
   164  			return true
   165  		}
   166  	}
   167  	return false
   168  }