Skip to content

Commit

Permalink
feature: reserve n IPs on Networks
Browse files Browse the repository at this point in the history
  • Loading branch information
fra98 committed Nov 27, 2024
1 parent 3a039b2 commit c6c6174
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 72 deletions.
5 changes: 5 additions & 0 deletions apis/ipam/v1alpha1/network_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ type NetworkSpec struct {
// CIDR is the desired CIDR for the remote cluster.
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="CIDR field is immutable"
CIDR networkingv1beta1.CIDR `json:"cidr"`
// 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"`
}

// NetworkStatus defines the observed state of Network.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ spec:
x-kubernetes-validations:
- message: CIDR field is immutable
rule: self == oldSelf
preAllocated:
description: PreAllocated is the number of IPs to pre-allocate (reserve)
in the CIDR, starting from the first IP.
minimum: 0
type: integer
x-kubernetes-validations:
- message: Reserved field is immutable
rule: self == oldSelf
required:
- cidr
type: object
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 @@ -31,6 +31,7 @@ metadata:
ipam.liqo.io/network-type: external-cidr
spec:
cidr: {{ .Values.ipam.externalCIDR }}
preAllocated: 1 # the first IP of the external CIDR is reserved for the unknown source traffic
---
apiVersion: ipam.liqo.io/v1alpha1
kind: Network
Expand Down
6 changes: 3 additions & 3 deletions 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(), req.GetImmutable())
remappedCidr, err := lipam.acquireNetwork(req.GetCidr(), uint(req.GetPreAllocated()), req.GetImmutable())
if err != nil {
return &NetworkAcquireResponse{}, err
}
Expand All @@ -100,14 +100,14 @@ func (lipam *LiqoIPAM) NetworkAcquire(_ context.Context, req *NetworkAcquireRequ

// NetworkRelease releases a network.
func (lipam *LiqoIPAM) NetworkRelease(_ context.Context, req *NetworkReleaseRequest) (*NetworkReleaseResponse, error) {
lipam.freeNetwork(req.GetCidr())
lipam.freeNetwork(network{cidr: req.GetCidr()})

return &NetworkReleaseResponse{}, nil
}

// NetworkIsAvailable checks if a network is available.
func (lipam *LiqoIPAM) NetworkIsAvailable(_ context.Context, req *NetworkAvailableRequest) (*NetworkAvailableResponse, error) {
available := lipam.isNetworkAvailable(req.GetCidr())
available := lipam.isNetworkAvailable(network{cidr: req.GetCidr()})

return &NetworkAvailableResponse{Available: available}, nil
}
104 changes: 57 additions & 47 deletions pkg/ipam/ipam.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/ipam/ipam.proto
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ message IPReleaseResponse {
message NetworkAcquireRequest {
string cidr = 1;
bool immutable = 2; // If true, the network cannot be remapped. It will be allocated if available, or an error will be returned.
uint32 preAllocated = 3; // The number of IPs to pre-allocate (reserve) in the CIDR, starting from the first IP of the CIDR.
}

message NetworkAcquireResponse {
Expand Down
55 changes: 37 additions & 18 deletions pkg/ipam/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,39 @@ import (
)

type networkInfo struct {
cidr string
network
creationTimestamp time.Time
}

type network struct {
cidr string
preAllocated uint
}

func (n network) String() string {
return n.cidr
}

// reserveNetwork reserves a network, saving it in the cache.
func (lipam *LiqoIPAM) reserveNetwork(cidr string) error {
func (lipam *LiqoIPAM) reserveNetwork(nw network) error {
lipam.mutex.Lock()
defer lipam.mutex.Unlock()

// TODO: implement real network reserve logic
if lipam.cacheNetworks == nil {
lipam.cacheNetworks = make(map[string]networkInfo)
}
lipam.cacheNetworks[cidr] = networkInfo{
cidr: cidr,
lipam.cacheNetworks[nw.String()] = networkInfo{
network: nw,
creationTimestamp: time.Now(),
}

klog.Infof("Reserved network %q", cidr)
klog.Infof("Reserved network %q", nw)
return nil
}

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

Expand All @@ -56,39 +66,45 @@ func (lipam *LiqoIPAM) acquireNetwork(cidr string, immutable bool) (string, erro
if lipam.cacheNetworks == nil {
lipam.cacheNetworks = make(map[string]networkInfo)
}
lipam.cacheNetworks[cidr] = networkInfo{
cidr: cidr,
nw := network{
cidr: cidr,
preAllocated: preAllocated,
}
lipam.cacheNetworks[nw.String()] = networkInfo{
network: nw,
creationTimestamp: time.Now(),
}

klog.Infof("Acquired network %q", cidr)
return cidr, nil
klog.Infof("Acquired network %q", nw.cidr)
return nw.cidr, nil
}

// freeNetwork frees a network, removing it from the cache.
func (lipam *LiqoIPAM) freeNetwork(cidr string) {
func (lipam *LiqoIPAM) freeNetwork(nw network) {
lipam.mutex.Lock()
defer lipam.mutex.Unlock()

delete(lipam.cacheNetworks, cidr)
klog.Infof("Freed network %q", cidr)
// TODO: implement real network free logic
delete(lipam.cacheNetworks, nw.String())
klog.Infof("Freed network %q", nw.cidr)
}

// isNetworkAvailable checks if a network is available.
func (lipam *LiqoIPAM) isNetworkAvailable(cidr string) bool {
func (lipam *LiqoIPAM) isNetworkAvailable(nw network) bool {
lipam.mutex.Lock()
defer lipam.mutex.Unlock()

// TODO: implement real network availability check logic
if lipam.cacheNetworks == nil {
return true
}
_, ok := lipam.cacheNetworks[cidr]
_, ok := lipam.cacheNetworks[nw.String()]

return ok
}

func listNetworksOnCluster(ctx context.Context, cl client.Client) ([]string, error) {
var nets []string
func listNetworksOnCluster(ctx context.Context, cl client.Client) ([]network, error) {
var nets []network
var networks ipamv1alpha1.NetworkList
if err := cl.List(ctx, &networks); err != nil {
return nil, err
Expand All @@ -103,7 +119,10 @@ func listNetworksOnCluster(ctx context.Context, cl client.Client) ([]string, err
continue
}

nets = append(nets, cidr)
nets = append(nets, network{
cidr: cidr,
preAllocated: net.Spec.PreAllocated,
})
}

return nets, nil
Expand Down
6 changes: 3 additions & 3 deletions pkg/ipam/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,18 @@ func (lipam *LiqoIPAM) syncNetworks(ctx context.Context, expiredThreshold time.T

// Add networks that are present in the cluster but not in the cache.
for _, net := range clusterNetworks {
if _, inCache := lipam.cacheNetworks[net]; !inCache {
if _, inCache := lipam.cacheNetworks[net.String()]; !inCache {
if err := lipam.reserveNetwork(net); err != nil {
return err
}
}
setClusterNetworks[net] = struct{}{} // add network to the set
setClusterNetworks[net.String()] = struct{}{} // add network to the set
}

// Remove networks that are present in the cache but not in the cluster, and were added before the threshold.
for key := range lipam.cacheNetworks {
if _, inCluster := setClusterNetworks[key]; !inCluster && lipam.cacheNetworks[key].creationTimestamp.Before(expiredThreshold) {
lipam.freeNetwork(lipam.cacheNetworks[key].cidr)
lipam.freeNetwork(lipam.cacheNetworks[key].network)
}
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/ipam/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ var _ = Describe("Sync routine tests", func() {

addNetowrkToCache = func(ipamServer *LiqoIPAM, cidr string, creationTimestamp time.Time) {
ipamServer.cacheNetworks[cidr] = networkInfo{
cidr: cidr,
network: network{
cidr: cidr,
},
creationTimestamp: creationTimestamp,
}
}
Expand Down

0 comments on commit c6c6174

Please sign in to comment.