-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ipam core
- Loading branch information
Showing
19 changed files
with
1,075 additions
and
228 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,5 +48,5 @@ docs/_build | |
|
||
# development files | ||
/tmp | ||
|
||
/graphviz | ||
/k3s-ansible |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright 2019-2024 The Liqo Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package ipamcore provides the core functionality for the IPAM service. | ||
package ipamcore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
// Copyright 2019-2024 The Liqo Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package ipamcore | ||
|
||
import ( | ||
"fmt" | ||
"net/netip" | ||
"slices" | ||
) | ||
|
||
// Ipam represents the IPAM core structure. | ||
type Ipam struct { | ||
roots []node | ||
} | ||
|
||
// NewIpam creates a new IPAM instance. | ||
func NewIpam(roots, preallocated []string) (*Ipam, error) { | ||
ipamRootsPrefixes := make([]netip.Prefix, len(roots)) | ||
for i, root := range roots { | ||
ipamRootsPrefixes[i] = netip.MustParsePrefix(root) | ||
} | ||
|
||
ipamPreallocated := make([]netip.Prefix, len(preallocated)) | ||
for i, prefix := range preallocated { | ||
ipamPreallocated[i] = netip.MustParsePrefix(prefix) | ||
} | ||
|
||
if err := checkRoots(ipamRootsPrefixes); err != nil { | ||
return nil, err | ||
} | ||
|
||
if err := checkPreallocated(ipamRootsPrefixes, ipamPreallocated); err != nil { | ||
return nil, err | ||
} | ||
|
||
ipamRoots := make([]node, len(roots)) | ||
for i := range ipamRootsPrefixes { | ||
ipamRoots[i] = newNode(ipamRootsPrefixes[i]) | ||
} | ||
|
||
ipam := &Ipam{ | ||
roots: ipamRoots, | ||
} | ||
|
||
if err := ipam.preallocateNetwork(ipamRootsPrefixes, ipamPreallocated); err != nil { | ||
return nil, err | ||
} | ||
|
||
return ipam, nil | ||
} | ||
|
||
// NetworkAcquire allocates a network of the given size. | ||
// It returns the allocated network or nil if no network is available. | ||
func (ipam *Ipam) NetworkAcquire(size int) *netip.Prefix { | ||
for i := range ipam.roots { | ||
if result := allocateNetwork(size, &ipam.roots[i]); result != nil { | ||
return result | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// NetworkAcquireWithPrefix allocates a network with the given prefix. | ||
// It returns the allocated network or nil if the network is not available. | ||
func (ipam *Ipam) NetworkAcquireWithPrefix(prefix netip.Prefix) *netip.Prefix { | ||
for i := range ipam.roots { | ||
if result := allocateNetworkWithPrefix(prefix, &ipam.roots[i]); result != nil { | ||
return result | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// NetworkRelease frees the network with the given prefix. | ||
// It returns the freed network or nil if the network is not found. | ||
func (ipam *Ipam) NetworkRelease(prefix netip.Prefix) *netip.Prefix { | ||
for i := range ipam.roots { | ||
if isPrefixChildOf(ipam.roots[i].prefix, prefix) { | ||
if result := networkRelease(prefix, &ipam.roots[i]); result != nil { | ||
return result | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// ListNetworks returns the list of allocated networks. | ||
func (ipam *Ipam) ListNetworks() []netip.Prefix { | ||
var networks []netip.Prefix | ||
for i := range ipam.roots { | ||
networks = append(networks, listNetworks(&ipam.roots[i])...) | ||
} | ||
return networks | ||
} | ||
|
||
// NetworkIsAvailable checks if the network with the given prefix is allocated. | ||
// It returns true if the network is allocated, false otherwise. | ||
func (ipam *Ipam) NetworkIsAvailable(prefix netip.Prefix) bool { | ||
if node := ipam.search(prefix); node != nil { | ||
return node.acquired | ||
} | ||
return false | ||
} | ||
|
||
// IPAcquire allocates an IP address from the given prefix. | ||
// It returns the allocated IP address or nil if the IP address is not available. | ||
func (ipam *Ipam) IPAcquire(prefix netip.Prefix) *netip.Addr { | ||
if node := ipam.search(prefix); node != nil { | ||
return node.ipAcquire() | ||
} | ||
return nil | ||
} | ||
|
||
// IPAcquireWithAddr allocates the IP address from the given prefix. | ||
// It returns the allocated IP address or nil if the IP address is not available. | ||
func (ipam *Ipam) IPAcquireWithAddr(prefix netip.Prefix, addr netip.Addr) *netip.Addr { | ||
if !prefix.Contains(addr) { | ||
return nil | ||
} | ||
if node := ipam.search(prefix); node != nil { | ||
return node.allocateIPWithAddr(addr) | ||
} | ||
return nil | ||
} | ||
|
||
// IPRelease frees the IP address from the given prefix. | ||
// It returns the freed IP address or nil if the IP address is not found. | ||
func (ipam *Ipam) IPRelease(prefix netip.Prefix, addr netip.Addr) *netip.Addr { | ||
if node := ipam.search(prefix); node != nil { | ||
return node.ipRelease(addr) | ||
} | ||
return nil | ||
} | ||
|
||
// ListIPs returns the list of allocated IP addresses from the given prefix. | ||
func (ipam *Ipam) ListIPs(prefix netip.Prefix) []netip.Addr { | ||
if node := ipam.search(prefix); node != nil { | ||
return slices.Clone(node.listIPs()) | ||
} | ||
return nil | ||
} | ||
|
||
// IsAllocatedIP checks if the IP address is allocated from the given prefix. | ||
// It returns true if the IP address is allocated, false otherwise. | ||
func (ipam *Ipam) IsAllocatedIP(prefix netip.Prefix, addr netip.Addr) bool { | ||
if node := ipam.search(prefix); node != nil { | ||
return node.isAllocatedIP(addr) | ||
} | ||
return false | ||
} | ||
|
||
// ToGraphviz generates the Graphviz representation of the IPAM structure. | ||
func (ipam *Ipam) ToGraphviz() error { | ||
for i := range ipam.roots { | ||
_ = i | ||
if err := ipam.roots[i].toGraphviz(); err != nil { | ||
return fmt.Errorf("failed to generate Graphviz representation: %w", err) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (ipam *Ipam) search(prefix netip.Prefix) *node { | ||
for i := range ipam.roots { | ||
if node := search(prefix, &ipam.roots[i]); node != nil { | ||
return node | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func checkRoots(roots []netip.Prefix) error { | ||
for i := range roots { | ||
if err := checkHostBitsZero(roots[i]); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func checkPreallocated(roots, preallocated []netip.Prefix) error { | ||
var err error | ||
for i := range preallocated { | ||
if err = checkHostBitsZero(preallocated[i]); err != nil { | ||
return err | ||
} | ||
isChild := false | ||
for j := range roots { | ||
if isPrefixChildOf(roots[j], preallocated[i]) { | ||
isChild = true | ||
break | ||
} | ||
isChild = false | ||
} | ||
if !isChild { | ||
return fmt.Errorf("prefix %s is not a child of any root cidr", preallocated[i]) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (ipam *Ipam) preallocateNetwork(roots, prefixes []netip.Prefix) error { | ||
for i := range prefixes { | ||
for j := range roots { | ||
if isPrefixChildOf(roots[j], prefixes[i]) { | ||
if prefix := ipam.NetworkAcquireWithPrefix(prefixes[i]); prefix == nil { | ||
return fmt.Errorf("prefix %s is not allocated", prefixes[i]) | ||
} | ||
} | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.