github.com/cilium/cilium@v1.16.2/pkg/ipam/allocator/clusterpool/cidralloc/cidralloc.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package cidralloc
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"net/netip"
    10  
    11  	"github.com/cilium/cilium/pkg/ip"
    12  	"github.com/cilium/cilium/pkg/ipam/cidrset"
    13  )
    14  
    15  type CIDRAllocator interface {
    16  	fmt.Stringer
    17  
    18  	Occupy(cidr *net.IPNet) error
    19  	AllocateNext() (*net.IPNet, error)
    20  	Release(cidr *net.IPNet) error
    21  	IsAllocated(cidr *net.IPNet) (bool, error)
    22  	IsFull() bool
    23  	InRange(cidr *net.IPNet) bool
    24  	IsClusterCIDR(prefix netip.Prefix) bool
    25  	Prefix() netip.Prefix
    26  }
    27  
    28  type ErrCIDRCollision struct {
    29  	cidr      string
    30  	allocator CIDRAllocator
    31  }
    32  
    33  func (e ErrCIDRCollision) Error() string {
    34  	return fmt.Sprintf("requested CIDR %s collides with %s", e.cidr, e.allocator)
    35  }
    36  
    37  func (e *ErrCIDRCollision) Is(target error) bool {
    38  	t, ok := target.(*ErrCIDRCollision)
    39  	if !ok {
    40  		return false
    41  	}
    42  	return t.cidr == e.cidr
    43  }
    44  
    45  func NewCIDRSets(isV6 bool, strCIDRs []string, maskSize int) ([]CIDRAllocator, error) {
    46  	cidrAllocators := make([]CIDRAllocator, 0, len(strCIDRs))
    47  	for _, strCIDR := range strCIDRs {
    48  		addr, cidr, err := net.ParseCIDR(strCIDR)
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  		// Check if CIDRs collide with each other.
    53  		for _, cidrAllocator := range cidrAllocators {
    54  			if cidrAllocator.InRange(cidr) {
    55  				return nil, &ErrCIDRCollision{
    56  					cidr:      strCIDR,
    57  					allocator: cidrAllocator,
    58  				}
    59  			}
    60  		}
    61  
    62  		switch {
    63  		case isV6 && ip.IsIPv4(addr):
    64  			return nil, fmt.Errorf("CIDR is not v6 family: %s", cidr)
    65  		case !isV6 && !ip.IsIPv4(addr):
    66  			return nil, fmt.Errorf("CIDR is not v4 family: %s", cidr)
    67  		}
    68  		cidrSet, err := cidrset.NewCIDRSet(cidr, maskSize)
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  		cidrAllocators = append(cidrAllocators, cidrSet)
    73  	}
    74  	return cidrAllocators, nil
    75  }