-
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.
- Loading branch information
Showing
16 changed files
with
882 additions
and
283 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"net/netip" | ||
) | ||
|
||
func main() { | ||
var addr netip.Addr | ||
|
||
fmt.Println("aaaa") | ||
fmt.Sprintln(addr) | ||
if !addr.IsValid() { | ||
fmt.Println("invalid") | ||
} | ||
fmt.Println("bbbb") | ||
} |
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,215 @@ | ||
// 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" | ||
) | ||
|
||
// 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 | ||
} | ||
|
||
// AllocateNetwork allocates a network of the given size. | ||
// It returns the allocated network or nil if no network is available. | ||
func (ipam *Ipam) AllocateNetwork(size int) *netip.Prefix { | ||
for i := range ipam.roots { | ||
if result := allocateNetwork(size, &ipam.roots[i]); result != nil { | ||
return result | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// AllocateNetworkWithPrefix allocates a network with the given prefix. | ||
// It returns the allocated network or nil if the network is not available. | ||
func (ipam *Ipam) AllocateNetworkWithPrefix(prefix netip.Prefix) *netip.Prefix { | ||
for i := range ipam.roots { | ||
if result := allocateNetworkWithPrefix(prefix, &ipam.roots[i]); result != nil { | ||
return result | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// FreeNetwork frees the network with the given prefix. | ||
// It returns the freed network or nil if the network is not found. | ||
func (ipam *Ipam) FreeNetwork(prefix netip.Prefix) *netip.Prefix { | ||
for i := range ipam.roots { | ||
if isPrefixChildOf(ipam.roots[i].prefix, prefix) { | ||
if result := freeNetwork(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 | ||
} | ||
|
||
// IsAllocatedNetwork checks if the network with the given prefix is allocated. | ||
// It returns true if the network is allocated, false otherwise. | ||
func (ipam *Ipam) IsAllocatedNetwork(prefix netip.Prefix) bool { | ||
if node := ipam.search(prefix); node != nil { | ||
return node.acquired | ||
} | ||
return false | ||
} | ||
|
||
// AllocateIP 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) AllocateIP(prefix netip.Prefix) *netip.Addr { | ||
if node := ipam.search(prefix); node != nil { | ||
return node.allocateIP() | ||
} | ||
return nil | ||
} | ||
|
||
// AllocateIPWithAddr 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) AllocateIPWithAddr(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 | ||
} | ||
|
||
// FreeIP 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) FreeIP(prefix netip.Prefix, addr netip.Addr) *netip.Addr { | ||
if node := ipam.search(prefix); node != nil { | ||
return node.freeIP(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 node.listIPs() | ||
} | ||
return nil | ||
} | ||
|
||
// 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("/app"); 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.AllocateNetworkWithPrefix(prefixes[i]); prefix == nil { | ||
return fmt.Errorf("prefix %s is not allocated", prefixes[i]) | ||
} | ||
} | ||
} | ||
} | ||
return nil | ||
} |
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,81 @@ | ||
// 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" | ||
"strings" | ||
) | ||
|
||
// convertByteSliceToString converts a slice of bytes to a comma-separated string. | ||
func convertByteSliceToString(byteSlice []byte) string { | ||
strSlice := make([]string, len(byteSlice)) | ||
for i, b := range byteSlice { | ||
strSlice[i] = fmt.Sprintf("%d", b) | ||
} | ||
return strings.Join(strSlice, ".") | ||
} | ||
|
||
// setBit sets the bit at the given position to 1. | ||
func setBit(b, position byte) byte { | ||
if position > 7 { | ||
fmt.Println("Bit position out of range") | ||
return b | ||
} | ||
return b | (1 << (7 - position)) | ||
} | ||
|
||
func checkHostBitsZero(prefix netip.Prefix) error { | ||
if prefix.Masked().Addr().Compare(prefix.Addr()) != 0 { | ||
return fmt.Errorf("%s :host bits must be zero", prefix) | ||
} | ||
return nil | ||
} | ||
|
||
func splitNetworkPrefix(prefix netip.Prefix) (left, right netip.Prefix) { | ||
if err := checkHostBitsZero(prefix); err != nil { | ||
panic("Host bits must be zero") | ||
} | ||
|
||
bin, err := prefix.MarshalBinary() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
maskLen := bin[len(bin)-1] | ||
|
||
left = netip.MustParsePrefix( | ||
fmt.Sprintf("%s/%d", convertByteSliceToString(bin[:4]), maskLen+1), | ||
) | ||
|
||
byteIndex := maskLen / 8 | ||
bitIndex := maskLen % 8 | ||
|
||
bin[byteIndex] = setBit(bin[byteIndex], bitIndex) | ||
|
||
right = netip.MustParsePrefix( | ||
fmt.Sprintf("%s/%d", convertByteSliceToString(bin[:4]), maskLen+1), | ||
) | ||
|
||
return left, right | ||
} | ||
|
||
func isPrefixChildOf(parent, child netip.Prefix) bool { | ||
if parent.Bits() <= child.Bits() && parent.Overlaps(child) { | ||
return true | ||
} | ||
return false | ||
} |
Oops, something went wrong.