github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/ipam/structures.go (about)

     1  package ipam
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net"
     7  	"strings"
     8  	"sync"
     9  
    10  	"github.com/docker/docker/libnetwork/datastore"
    11  	"github.com/docker/docker/libnetwork/ipamapi"
    12  	"github.com/docker/docker/libnetwork/types"
    13  )
    14  
    15  // SubnetKey is the pointer to the configured pools in each address space
    16  type SubnetKey struct {
    17  	AddressSpace string
    18  	Subnet       string
    19  	ChildSubnet  string
    20  }
    21  
    22  // PoolData contains the configured pool data
    23  type PoolData struct {
    24  	ParentKey SubnetKey
    25  	Pool      *net.IPNet
    26  	Range     *AddressRange `json:",omitempty"`
    27  	RefCount  int
    28  }
    29  
    30  // addrSpace contains the pool configurations for the address space
    31  type addrSpace struct {
    32  	subnets  map[SubnetKey]*PoolData
    33  	dbIndex  uint64
    34  	dbExists bool
    35  	id       string
    36  	scope    string
    37  	ds       datastore.DataStore
    38  	alloc    *Allocator
    39  	sync.Mutex
    40  }
    41  
    42  // AddressRange specifies first and last ip ordinal which
    43  // identifies a range in a pool of addresses
    44  type AddressRange struct {
    45  	Sub        *net.IPNet
    46  	Start, End uint64
    47  }
    48  
    49  // String returns the string form of the AddressRange object
    50  func (r *AddressRange) String() string {
    51  	return fmt.Sprintf("Sub: %s, range [%d, %d]", r.Sub, r.Start, r.End)
    52  }
    53  
    54  // MarshalJSON returns the JSON encoding of the Range object
    55  func (r *AddressRange) MarshalJSON() ([]byte, error) {
    56  	m := map[string]interface{}{
    57  		"Sub":   r.Sub.String(),
    58  		"Start": r.Start,
    59  		"End":   r.End,
    60  	}
    61  	return json.Marshal(m)
    62  }
    63  
    64  // UnmarshalJSON decodes data into the Range object
    65  func (r *AddressRange) UnmarshalJSON(data []byte) error {
    66  	m := map[string]interface{}{}
    67  	err := json.Unmarshal(data, &m)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	if r.Sub, err = types.ParseCIDR(m["Sub"].(string)); err != nil {
    72  		return err
    73  	}
    74  	r.Start = uint64(m["Start"].(float64))
    75  	r.End = uint64(m["End"].(float64))
    76  	return nil
    77  }
    78  
    79  // String returns the string form of the SubnetKey object
    80  func (s *SubnetKey) String() string {
    81  	k := fmt.Sprintf("%s/%s", s.AddressSpace, s.Subnet)
    82  	if s.ChildSubnet != "" {
    83  		k = fmt.Sprintf("%s/%s", k, s.ChildSubnet)
    84  	}
    85  	return k
    86  }
    87  
    88  // FromString populates the SubnetKey object reading it from string
    89  func (s *SubnetKey) FromString(str string) error {
    90  	if str == "" || !strings.Contains(str, "/") {
    91  		return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)
    92  	}
    93  
    94  	p := strings.Split(str, "/")
    95  	if len(p) != 3 && len(p) != 5 {
    96  		return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)
    97  	}
    98  	s.AddressSpace = p[0]
    99  	s.Subnet = fmt.Sprintf("%s/%s", p[1], p[2])
   100  	if len(p) == 5 {
   101  		s.ChildSubnet = fmt.Sprintf("%s/%s", p[3], p[4])
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  // String returns the string form of the PoolData object
   108  func (p *PoolData) String() string {
   109  	return fmt.Sprintf("ParentKey: %s, Pool: %s, Range: %s, RefCount: %d",
   110  		p.ParentKey.String(), p.Pool.String(), p.Range, p.RefCount)
   111  }
   112  
   113  // MarshalJSON returns the JSON encoding of the PoolData object
   114  func (p *PoolData) MarshalJSON() ([]byte, error) {
   115  	m := map[string]interface{}{
   116  		"ParentKey": p.ParentKey,
   117  		"RefCount":  p.RefCount,
   118  	}
   119  	if p.Pool != nil {
   120  		m["Pool"] = p.Pool.String()
   121  	}
   122  	if p.Range != nil {
   123  		m["Range"] = p.Range
   124  	}
   125  	return json.Marshal(m)
   126  }
   127  
   128  // UnmarshalJSON decodes data into the PoolData object
   129  func (p *PoolData) UnmarshalJSON(data []byte) error {
   130  	var (
   131  		err error
   132  		t   struct {
   133  			ParentKey SubnetKey
   134  			Pool      string
   135  			Range     *AddressRange `json:",omitempty"`
   136  			RefCount  int
   137  		}
   138  	)
   139  
   140  	if err = json.Unmarshal(data, &t); err != nil {
   141  		return err
   142  	}
   143  
   144  	p.ParentKey = t.ParentKey
   145  	p.Range = t.Range
   146  	p.RefCount = t.RefCount
   147  	if t.Pool != "" {
   148  		if p.Pool, err = types.ParseCIDR(t.Pool); err != nil {
   149  			return err
   150  		}
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // MarshalJSON returns the JSON encoding of the addrSpace object
   157  func (aSpace *addrSpace) MarshalJSON() ([]byte, error) {
   158  	aSpace.Lock()
   159  	defer aSpace.Unlock()
   160  
   161  	m := map[string]interface{}{
   162  		"Scope": aSpace.scope,
   163  	}
   164  
   165  	if aSpace.subnets != nil {
   166  		s := map[string]*PoolData{}
   167  		for k, v := range aSpace.subnets {
   168  			s[k.String()] = v
   169  		}
   170  		m["Subnets"] = s
   171  	}
   172  
   173  	return json.Marshal(m)
   174  }
   175  
   176  // UnmarshalJSON decodes data into the addrSpace object
   177  func (aSpace *addrSpace) UnmarshalJSON(data []byte) error {
   178  	aSpace.Lock()
   179  	defer aSpace.Unlock()
   180  
   181  	m := map[string]interface{}{}
   182  	err := json.Unmarshal(data, &m)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	aSpace.scope = datastore.LocalScope
   188  	s := m["Scope"].(string)
   189  	if s == datastore.GlobalScope {
   190  		aSpace.scope = datastore.GlobalScope
   191  	}
   192  
   193  	if v, ok := m["Subnets"]; ok {
   194  		sb, _ := json.Marshal(v)
   195  		var s map[string]*PoolData
   196  		err := json.Unmarshal(sb, &s)
   197  		if err != nil {
   198  			return err
   199  		}
   200  		for ks, v := range s {
   201  			k := SubnetKey{}
   202  			k.FromString(ks)
   203  			aSpace.subnets[k] = v
   204  		}
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  // CopyTo deep copies the pool data to the destination pooldata
   211  func (p *PoolData) CopyTo(dstP *PoolData) error {
   212  	dstP.ParentKey = p.ParentKey
   213  	dstP.Pool = types.GetIPNetCopy(p.Pool)
   214  
   215  	if p.Range != nil {
   216  		dstP.Range = &AddressRange{}
   217  		dstP.Range.Sub = types.GetIPNetCopy(p.Range.Sub)
   218  		dstP.Range.Start = p.Range.Start
   219  		dstP.Range.End = p.Range.End
   220  	}
   221  
   222  	dstP.RefCount = p.RefCount
   223  	return nil
   224  }
   225  
   226  func (aSpace *addrSpace) CopyTo(o datastore.KVObject) error {
   227  	aSpace.Lock()
   228  	defer aSpace.Unlock()
   229  
   230  	dstAspace := o.(*addrSpace)
   231  
   232  	dstAspace.id = aSpace.id
   233  	dstAspace.ds = aSpace.ds
   234  	dstAspace.alloc = aSpace.alloc
   235  	dstAspace.scope = aSpace.scope
   236  	dstAspace.dbIndex = aSpace.dbIndex
   237  	dstAspace.dbExists = aSpace.dbExists
   238  
   239  	dstAspace.subnets = make(map[SubnetKey]*PoolData)
   240  	for k, v := range aSpace.subnets {
   241  		dstAspace.subnets[k] = &PoolData{}
   242  		v.CopyTo(dstAspace.subnets[k])
   243  	}
   244  
   245  	return nil
   246  }
   247  
   248  func (aSpace *addrSpace) New() datastore.KVObject {
   249  	aSpace.Lock()
   250  	defer aSpace.Unlock()
   251  
   252  	return &addrSpace{
   253  		id:    aSpace.id,
   254  		ds:    aSpace.ds,
   255  		alloc: aSpace.alloc,
   256  		scope: aSpace.scope,
   257  	}
   258  }
   259  
   260  // updatePoolDBOnAdd returns a closure which will add the subnet k to the address space when executed.
   261  func (aSpace *addrSpace) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange, pdf bool) (func() error, error) {
   262  	aSpace.Lock()
   263  	defer aSpace.Unlock()
   264  
   265  	// Check if already allocated
   266  	if _, ok := aSpace.subnets[k]; ok {
   267  		if pdf {
   268  			return nil, types.InternalMaskableErrorf("predefined pool %s is already reserved", nw)
   269  		}
   270  		// This means the same pool is already allocated. updatePoolDBOnAdd is called when there
   271  		// is request for a pool/subpool. It should ensure there is no overlap with existing pools
   272  		return nil, ipamapi.ErrPoolOverlap
   273  	}
   274  
   275  	// If master pool, check for overlap
   276  	if ipr == nil {
   277  		if aSpace.contains(k.AddressSpace, nw) {
   278  			return nil, ipamapi.ErrPoolOverlap
   279  		}
   280  		// This is a new master pool, add it along with corresponding bitmask
   281  		aSpace.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
   282  		return func() error { return aSpace.alloc.insertBitMask(k, nw) }, nil
   283  	}
   284  
   285  	// This is a new non-master pool (subPool)
   286  	p := &PoolData{
   287  		ParentKey: SubnetKey{AddressSpace: k.AddressSpace, Subnet: k.Subnet},
   288  		Pool:      nw,
   289  		Range:     ipr,
   290  		RefCount:  1,
   291  	}
   292  	aSpace.subnets[k] = p
   293  
   294  	// Look for parent pool
   295  	pp, ok := aSpace.subnets[p.ParentKey]
   296  	if ok {
   297  		aSpace.incRefCount(pp, 1)
   298  		return func() error { return nil }, nil
   299  	}
   300  
   301  	// Parent pool does not exist, add it along with corresponding bitmask
   302  	aSpace.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
   303  	return func() error { return aSpace.alloc.insertBitMask(p.ParentKey, nw) }, nil
   304  }
   305  
   306  func (aSpace *addrSpace) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
   307  	aSpace.Lock()
   308  	defer aSpace.Unlock()
   309  
   310  	p, ok := aSpace.subnets[k]
   311  	if !ok {
   312  		return nil, ipamapi.ErrBadPool
   313  	}
   314  
   315  	aSpace.incRefCount(p, -1)
   316  
   317  	c := p
   318  	for ok {
   319  		if c.RefCount == 0 {
   320  			delete(aSpace.subnets, k)
   321  			if c.Range == nil {
   322  				return func() error {
   323  					bm, err := aSpace.alloc.retrieveBitmask(k, c.Pool)
   324  					if err != nil {
   325  						return types.InternalErrorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
   326  					}
   327  					return bm.Destroy()
   328  				}, nil
   329  			}
   330  		}
   331  		k = c.ParentKey
   332  		c, ok = aSpace.subnets[k]
   333  	}
   334  
   335  	return func() error { return nil }, nil
   336  }
   337  
   338  func (aSpace *addrSpace) incRefCount(p *PoolData, delta int) {
   339  	c := p
   340  	ok := true
   341  	for ok {
   342  		c.RefCount += delta
   343  		c, ok = aSpace.subnets[c.ParentKey]
   344  	}
   345  }
   346  
   347  // Checks whether the passed subnet is a superset or subset of any of the subset in this config db
   348  func (aSpace *addrSpace) contains(space string, nw *net.IPNet) bool {
   349  	for k, v := range aSpace.subnets {
   350  		if space == k.AddressSpace && k.ChildSubnet == "" {
   351  			if nw.Contains(v.Pool.IP) || v.Pool.Contains(nw.IP) {
   352  				return true
   353  			}
   354  		}
   355  	}
   356  	return false
   357  }
   358  
   359  func (aSpace *addrSpace) store() datastore.DataStore {
   360  	aSpace.Lock()
   361  	defer aSpace.Unlock()
   362  
   363  	return aSpace.ds
   364  }