ipallocator/cidrallocator: use new ServiceCIDR API

Change-Id: I5b300373e21cc65f6ef171790ef81ee391f1c752

cidrallocator

Change-Id: I13050a9d60360e555b75a13beaa9a923268ec4e8
This commit is contained in:
Antonio Ojea 2023-10-29 18:19:01 +00:00
parent 7e87806fab
commit 881cf4d54f
2 changed files with 33 additions and 24 deletions

View File

@ -69,8 +69,8 @@ type MetaAllocator struct {
var _ Interface = &MetaAllocator{} var _ Interface = &MetaAllocator{}
// NewMetaAllocator returns an IP allocator associated to a network range // NewMetaAllocator returns an IP allocator that use the IPAddress
// that use the IPAddress and ServiceCIDR objects to track the assigned IP addresses, // and ServiceCIDR objects to track the assigned IP addresses,
// using an informer cache as storage. // using an informer cache as storage.
func NewMetaAllocator( func NewMetaAllocator(
client networkingv1alpha1client.NetworkingV1alpha1Interface, client networkingv1alpha1client.NetworkingV1alpha1Interface,
@ -79,6 +79,7 @@ func NewMetaAllocator(
isIPv6 bool, isIPv6 bool,
) (*MetaAllocator, error) { ) (*MetaAllocator, error) {
// TODO: make the NewMetaAllocator agnostic of the IP family
family := api.IPv4Protocol family := api.IPv4Protocol
if isIPv6 { if isIPv6 {
family = api.IPv6Protocol family = api.IPv6Protocol
@ -186,20 +187,18 @@ func (c *MetaAllocator) syncTree() error {
} }
cidrsSet := sets.New[string]() cidrsSet := sets.New[string]()
cidrState := map[string]bool{} cidrReady := map[string]bool{}
for _, cidr := range serviceCIDRs { for _, serviceCIDR := range serviceCIDRs {
ready := true ready := true
if !isReady(cidr) || !cidr.DeletionTimestamp.IsZero() { if !isReady(serviceCIDR) || !serviceCIDR.DeletionTimestamp.IsZero() {
ready = false ready = false
} }
if c.ipFamily == api.IPv4Protocol && cidr.Spec.IPv4 != "" { for _, cidr := range serviceCIDR.Spec.CIDRs {
cidrsSet.Insert(cidr.Spec.IPv4) if c.ipFamily == api.IPFamily(convertToV1IPFamily(netutils.IPFamilyOfCIDRString(cidr))) {
cidrState[cidr.Spec.IPv4] = ready cidrsSet.Insert(cidr)
cidrReady[cidr] = ready
} }
if c.ipFamily == api.IPv6Protocol && cidr.Spec.IPv6 != "" {
cidrsSet.Insert(cidr.Spec.IPv6)
cidrState[cidr.Spec.IPv6] = ready
} }
} }
@ -207,7 +206,7 @@ func (c *MetaAllocator) syncTree() error {
treeSet := sets.New[string]() treeSet := sets.New[string]()
c.muTree.Lock() c.muTree.Lock()
c.tree.DepthFirstWalk(c.ipFamily == api.IPv6Protocol, func(k netip.Prefix, v *Allocator) bool { c.tree.DepthFirstWalk(c.ipFamily == api.IPv6Protocol, func(k netip.Prefix, v *Allocator) bool {
v.ready.Store(cidrState[k.String()]) v.ready.Store(cidrReady[k.String()])
treeSet.Insert(k.String()) treeSet.Insert(k.String())
return false return false
}) })
@ -228,7 +227,7 @@ func (c *MetaAllocator) syncTree() error {
errs = append(errs, err) errs = append(errs, err)
continue continue
} }
allocator.ready.Store(cidrState[cidr]) allocator.ready.Store(cidrReady[cidr])
prefix, err := netip.ParsePrefix(cidr) prefix, err := netip.ParsePrefix(cidr)
if err != nil { if err != nil {
return err return err
@ -252,12 +251,8 @@ func (c *MetaAllocator) getAllocator(ip net.IP) (*Allocator, error) {
c.muTree.Lock() c.muTree.Lock()
defer c.muTree.Unlock() defer c.muTree.Unlock()
var prefix netip.Prefix address := ipToAddr(ip)
if c.ipFamily == api.IPv4Protocol { prefix := netip.PrefixFrom(address, address.BitLen())
prefix = netip.PrefixFrom(ipToAddr(ip), 32)
} else {
prefix = netip.PrefixFrom(ipToAddr(ip), 128)
}
// Use the largest subnet to allocate addresses because // Use the largest subnet to allocate addresses because
// all the other subnets will be contained. // all the other subnets will be contained.
_, allocator, ok := c.tree.ShortestPrefixMatch(prefix) _, allocator, ok := c.tree.ShortestPrefixMatch(prefix)
@ -432,8 +427,7 @@ func isReady(serviceCIDR *networkingv1alpha1.ServiceCIDR) bool {
return condition.Status == metav1.ConditionStatus(metav1.ConditionTrue) return condition.Status == metav1.ConditionStatus(metav1.ConditionTrue)
} }
} }
// if condition is not found assume it is ready to handle scenarios // assume the ServiceCIDR is Ready, in order to handle scenarios where kcm is not running
// where the kube-controller-manager is not running
return true return true
} }
@ -452,3 +446,17 @@ func ipToAddr(ip net.IP) netip.Addr {
address, _ := netip.AddrFromSlice(bytes) address, _ := netip.AddrFromSlice(bytes)
return address return address
} }
// Convert netutils.IPFamily to v1.IPFamily
// TODO: consolidate helpers
// copied from pkg/proxy/util/utils.go
func convertToV1IPFamily(ipFamily netutils.IPFamily) v1.IPFamily {
switch ipFamily {
case netutils.IPv4:
return v1.IPv4Protocol
case netutils.IPv6:
return v1.IPv6Protocol
}
return v1.IPFamilyUnknown
}

View File

@ -468,13 +468,14 @@ func TestCIDRAllocateShrink(t *testing.T) {
} }
func newServiceCIDR(name, cidrV4 string) *networkingv1alpha1.ServiceCIDR { // TODO: add IPv6 and dual stack test cases
func newServiceCIDR(name, cidr string) *networkingv1alpha1.ServiceCIDR {
return &networkingv1alpha1.ServiceCIDR{ return &networkingv1alpha1.ServiceCIDR{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
}, },
Spec: networkingv1alpha1.ServiceCIDRSpec{ Spec: networkingv1alpha1.ServiceCIDRSpec{
IPv4: cidrV4, CIDRs: []string{cidr},
}, },
Status: networkingv1alpha1.ServiceCIDRStatus{ Status: networkingv1alpha1.ServiceCIDRStatus{
Conditions: []metav1.Condition{ Conditions: []metav1.Condition{