Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IPAM] support reserved networks #2829

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apis/ipam/v1alpha1/network_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ type NetworkSpec struct {
// PreAllocated is the number of IPs to pre-allocate (reserve) in the CIDR, starting from the first IP.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=0
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Reserved field is immutable"
PreAllocated uint `json:"preAllocated"`
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="PreAllocated field is immutable"
PreAllocated uint32 `json:"preAllocated"`
}

// NetworkStatus defines the observed state of Network.
Expand Down
2 changes: 1 addition & 1 deletion cmd/liqo-controller-manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ func main() {
ipamClient = ipam.NewIPAMClient(conn)
}

if err := modules.SetupNetworkingModule(mgr, &modules.NetworkingOption{
if err := modules.SetupNetworkingModule(ctx, mgr, uncachedClient, &modules.NetworkingOption{
DynClient: dynClient,
Factory: factory,

Expand Down
3 changes: 2 additions & 1 deletion cmd/liqo-controller-manager/modules/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func SetupAuthenticationModule(ctx context.Context, mgr manager.Manager, uncache
}

if err := enforceAuthenticationKeys(ctx, uncachedClient, opts.LiqoNamespace); err != nil {
klog.Errorf("Unable to enforce authentication keys: %v", err)
return err
}

Expand Down Expand Up @@ -135,7 +136,7 @@ func SetupAuthenticationModule(ctx context.Context, mgr manager.Manager, uncache

func enforceAuthenticationKeys(ctx context.Context, cl client.Client, liqoNamespace string) error {
if err := authentication.InitClusterKeys(ctx, cl, liqoNamespace); err != nil {
klog.Errorf("Unable to initialize cluster authentication keys: %v", err)
return err
}

klog.Info("Enforced cluster authentication keys")
Expand Down
84 changes: 83 additions & 1 deletion cmd/liqo-controller-manager/modules/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@
package modules

import (
"context"
"fmt"

"k8s.io/client-go/dynamic"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
"github.com/liqotech/liqo/pkg/ipam"
clientoperator "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/external-network/client-operator"
configuration "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/external-network/configuration"
Expand All @@ -36,6 +41,7 @@ import (
ipctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/ip-controller"
networkctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/network-controller"
dynamicutils "github.com/liqotech/liqo/pkg/utils/dynamic"
ipamutils "github.com/liqotech/liqo/pkg/utils/ipam"
)

// NetworkingOption defines the options to setup the Networking module.
Expand All @@ -59,7 +65,13 @@ type NetworkingOption struct {
}

// SetupNetworkingModule setup the networking module and initializes its controllers .
func SetupNetworkingModule(mgr manager.Manager, opts *NetworkingOption) error {
func SetupNetworkingModule(ctx context.Context, mgr manager.Manager, uncachedClient client.Client, opts *NetworkingOption) error {
// Initialize reserved networks
if err := initializeReservedNetworks(ctx, uncachedClient, opts.IpamClient); err != nil {
klog.Errorf("Unable to initialize reserved networks: %v", err)
return err
}

networkReconciler := networkctrl.NewNetworkReconciler(mgr.GetClient(), mgr.GetScheme(), opts.IpamClient)
if err := networkReconciler.SetupWithManager(mgr, opts.NetworkWorkers); err != nil {
klog.Errorf("Unable to start the networkReconciler: %v", err)
Expand Down Expand Up @@ -209,3 +221,73 @@ func SetupNetworkingModule(mgr manager.Manager, opts *NetworkingOption) error {

return nil
}

func initializeReservedNetworks(ctx context.Context, cl client.Client, ipamClient ipam.IPAMClient) error {
var networksToReserve []ipamv1alpha1.Network

// PodCIDR is a special case of reserved network
podCidr, err := ipamutils.GetPodCIDRNetwork(ctx, cl)
if err != nil {
return err
}
networksToReserve = append(networksToReserve, *podCidr)

// ServiceCIDR is a special case of reserved network
serviceCidr, err := ipamutils.GetServiceCIDRNetwork(ctx, cl)
if err != nil {
return err
}
networksToReserve = append(networksToReserve, *serviceCidr)

// Get the reserved networks
reservedNetworks, err := ipamutils.GetReservedSubnetNetworks(ctx, cl)
if err != nil {
return err
}
networksToReserve = append(networksToReserve, reservedNetworks...)

// Reserve the networks and fill their status CIDR.
for i := range networksToReserve {
nw := &networksToReserve[i]

// If the status CIDR is already set, we do not need to reserve the network
// as it will be reserved when the ipam server is initialized.
if nw.Status.CIDR != "" {
continue
}

if ipamClient == nil {
nw.Status.CIDR = nw.Spec.CIDR
} else {
// First check if the network is already reserved
res, err := ipamClient.NetworkIsAvailable(ctx, &ipam.NetworkAvailableRequest{
Cidr: nw.Spec.CIDR.String(),
})
if err != nil {
return err
}

if res.Available {
// Network is not reserved, reserve it
_, err := ipamClient.NetworkAcquire(ctx, &ipam.NetworkAcquireRequest{
Cidr: nw.Spec.CIDR.String(),
Immutable: true,
PreAllocated: nw.Spec.PreAllocated,
})
if err != nil {
return err
}
}

// Since reserved network must not be remapped (immutable), we can set the status CIDR to the spec CIDR
nw.Status.CIDR = nw.Spec.CIDR
}

if err := cl.Status().Update(ctx, nw); err != nil {
return fmt.Errorf("unable to update the reserved network %s: %w", nw.Name, err)
}
}

klog.Info("Reserved networks initialized")
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ spec:
preAllocated:
description: PreAllocated is the number of IPs to pre-allocate (reserve)
in the CIDR, starting from the first IP.
format: int32
minimum: 0
type: integer
x-kubernetes-validations:
- message: Reserved field is immutable
- message: PreAllocated field is immutable
rule: self == oldSelf
required:
- cidr
Expand Down
1 change: 1 addition & 0 deletions deployments/liqo/templates/liqo-ipam-networks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ metadata:
ipam.liqo.io/network-not-remapped: "true"
spec:
cidr: {{ $value }}
---
{{- end }}
2 changes: 1 addition & 1 deletion pkg/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (lipam *LiqoIPAM) IPRelease(_ context.Context, req *IPReleaseRequest) (*IPR

// NetworkAcquire acquires a network. If it is already reserved, it allocates and reserves a new free one with the same prefix length.
func (lipam *LiqoIPAM) NetworkAcquire(_ context.Context, req *NetworkAcquireRequest) (*NetworkAcquireResponse, error) {
remappedCidr, err := lipam.acquireNetwork(req.GetCidr(), uint(req.GetPreAllocated()), req.GetImmutable())
remappedCidr, err := lipam.acquireNetwork(req.GetCidr(), req.GetPreAllocated(), req.GetImmutable())
if err != nil {
return &NetworkAcquireResponse{}, err
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/ipam/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type networkInfo struct {

type network struct {
cidr string
preAllocated uint
preAllocated uint32
}

func (n network) String() string {
Expand All @@ -57,7 +57,7 @@ func (lipam *LiqoIPAM) reserveNetwork(nw network) error {
}

// acquireNetwork acquires a network, eventually remapped if conflicts are found.
func (lipam *LiqoIPAM) acquireNetwork(cidr string, preAllocated uint, immutable bool) (string, error) {
func (lipam *LiqoIPAM) acquireNetwork(cidr string, preAllocated uint32, immutable bool) (string, error) {
lipam.mutex.Lock()
defer lipam.mutex.Unlock()

Expand Down Expand Up @@ -98,9 +98,9 @@ func (lipam *LiqoIPAM) isNetworkAvailable(nw network) bool {
if lipam.cacheNetworks == nil {
return true
}
_, ok := lipam.cacheNetworks[nw.String()]
_, exists := lipam.cacheNetworks[nw.String()]

return ok
return !exists
}

func listNetworksOnCluster(ctx context.Context, cl client.Client) ([]network, error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ func (r *NetworkReconciler) handleNetworkStatus(ctx context.Context, nw *ipamv1a
desiredCIDR := nw.Spec.CIDR
// if the Network must not be remapped, we acquire the network specifying to the IPAM that the cidr is immutable.
immutable := ipamutils.NetworkNotRemapped(nw)
remappedCIDR, err := getRemappedCIDR(ctx, r.ipamClient, desiredCIDR, immutable)
preallocated := nw.Spec.PreAllocated
remappedCIDR, err := getRemappedCIDR(ctx, r.ipamClient, desiredCIDR, immutable, preallocated)
if err != nil {
return err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ import (

// getRemappedCIDR returns the remapped CIDR for the given CIDR.
func getRemappedCIDR(ctx context.Context, ipamClient ipam.IPAMClient,
desiredCIDR networkingv1beta1.CIDR, immutable bool) (networkingv1beta1.CIDR, error) {
desiredCIDR networkingv1beta1.CIDR, immutable bool, preallocated uint32) (networkingv1beta1.CIDR, error) {
switch ipamClient.(type) {
case nil:
// IPAM is not enabled, use original CIDR from spec
return desiredCIDR, nil
default:
// interact with the IPAM to retrieve the correct mapping.
response, err := ipamClient.NetworkAcquire(ctx, &ipam.NetworkAcquireRequest{
Cidr: desiredCIDR.String(),
Immutable: immutable,
Cidr: desiredCIDR.String(),
Immutable: immutable,
PreAllocated: preallocated,
})
if err != nil {
klog.Errorf("IPAM: error while mapping network CIDR %s: %v", desiredCIDR, err)
Expand Down