Skip to content

Commit c68bd94

Browse files
committed
feat: skip in deleting ips and networks
1 parent 29f2027 commit c68bd94

File tree

13 files changed

+124
-55
lines changed

13 files changed

+124
-55
lines changed

cmd/ipam/main.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,12 @@ func main() {
7070

7171
// Server options.
7272
cmd.Flags().IntVar(&options.ServerOpts.Port, "port", consts.IpamPort, "The port on which to listen for incoming gRPC requests.")
73-
cmd.Flags().DurationVar(&options.ServerOpts.SyncFrequency, "interval", consts.SyncFrequency,
73+
cmd.Flags().DurationVar(&options.ServerOpts.SyncFrequency, "sync-interval", consts.SyncInterval,
7474
"The interval at which the IPAM will synchronize the IPAM storage.")
7575
cmd.Flags().BoolVar(&options.ServerOpts.GraphvizEnabled, "enable-graphviz", false, "Enable the graphviz output for the IPAM.")
76+
cmd.Flags().StringSliceVar(&options.ServerOpts.Pools, "pools",
77+
[]string{"10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"}, "The pools used by the IPAM.",
78+
)
7679

7780
// Leader election flags.
7881
cmd.Flags().BoolVar(&options.EnableLeaderElection, "leader-election", false, "Enable leader election for IPAM. "+
@@ -133,9 +136,7 @@ func run(cmd *cobra.Command, _ []string) error {
133136
}
134137
}
135138

136-
liqoIPAM, err := ipam.New(ctx, cl, []string{
137-
"10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12",
138-
}, &options.ServerOpts)
139+
liqoIPAM, err := ipam.New(ctx, cl, options.ServerOpts.Pools, &options.ServerOpts)
139140
if err != nil {
140141
return err
141142
}

cmd/liqo-controller-manager/modules/networking.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ func initializeReservedNetworks(ctx context.Context, cl client.Client, ipamClien
264264
Cidr: nw.Spec.CIDR.String(),
265265
})
266266
if err != nil {
267-
return err
267+
return fmt.Errorf("IPAM: %w", err)
268268
}
269269

270270
if res.Available {
@@ -275,7 +275,7 @@ func initializeReservedNetworks(ctx context.Context, cl client.Client, ipamClien
275275
PreAllocated: nw.Spec.PreAllocated,
276276
})
277277
if err != nil {
278-
return err
278+
return fmt.Errorf("IPAM: %w", err)
279279
}
280280
}
281281

@@ -286,6 +286,7 @@ func initializeReservedNetworks(ctx context.Context, cl client.Client, ipamClien
286286
if err := cl.Status().Update(ctx, nw); err != nil {
287287
return fmt.Errorf("unable to update the reserved network %s: %w", nw.Name, err)
288288
}
289+
klog.Infof("Updated reserved Network %q status (spec: %s | status: %s)", client.ObjectKeyFromObject(nw), nw.Spec.CIDR, nw.Status.CIDR)
289290
}
290291

291292
klog.Info("Reserved networks initialized")

deployments/liqo/templates/liqo-ipam-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ spec:
5151
args:
5252
- --pod-name=$(POD_NAME)
5353
- --port=6000
54-
- --interval={{ .Values.ipam.internal.syncInterval }}
54+
- --sync-interval={{ .Values.ipam.internal.syncInterval }}
5555
{{- if $ha }}
5656
- --leader-election
5757
- --leader-election-namespace=$(POD_NAMESPACE)

pkg/consts/ipam.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ type NetworkType string
2222
const (
2323
// IpamPort is the port used by the IPAM gRPC server.
2424
IpamPort = 6000
25-
// SyncFrequency is the frequency at which the IPAM should periodically sync its status.
26-
SyncFrequency = 2 * time.Minute
25+
// SyncInterval is the frequency at which the IPAM should periodically sync its status.
26+
SyncInterval = 2 * time.Minute
2727

2828
// NetworkNotRemappedLabelKey is the label key used to mark a Network that does not need CIDR remapping.
2929
NetworkNotRemappedLabelKey = "ipam.liqo.io/network-not-remapped"

pkg/ipam/core/doc.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@
1313
// limitations under the License.
1414

1515
// Package ipamcore provides the core functionality for the IPAM service.
16+
//
17+
// The IPAM is organized like a binary tree, where each node represents a network.
18+
// In order to optimize the network allocation we use buddy mmory allocation alghorithm
19+
// to allocate networks like they are memory blocks (https://en.wikipedia.org/wiki/Buddy_memory_allocation).
20+
// When a network is splitted in two, the left child represents the first half of the network, while the right child
21+
// represents the second half. The splitting is done until the network is splitted in blocks of the desired size.
1622
package ipamcore

pkg/ipam/core/ipam.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ type Ipam struct {
2626
}
2727

2828
// NewIpam creates a new IPAM instance.
29-
func NewIpam(roots []string) (*Ipam, error) {
30-
ipamRootsPrefixes := make([]netip.Prefix, len(roots))
31-
for i, root := range roots {
29+
func NewIpam(pools []string) (*Ipam, error) {
30+
ipamRootsPrefixes := make([]netip.Prefix, len(pools))
31+
for i, root := range pools {
3232
ipamRootsPrefixes[i] = netip.MustParsePrefix(root)
3333
}
3434

3535
if err := checkRoots(ipamRootsPrefixes); err != nil {
3636
return nil, err
3737
}
3838

39-
ipamRoots := make([]node, len(roots))
39+
ipamRoots := make([]node, len(pools))
4040
for i := range ipamRootsPrefixes {
4141
ipamRoots[i] = newNode(ipamRootsPrefixes[i])
4242
}
@@ -173,6 +173,17 @@ func (ipam *Ipam) IsAllocatedIP(prefix netip.Prefix, addr netip.Addr) (bool, err
173173
return false, nil
174174
}
175175

176+
// IsPrefixInRoots checks if the given prefix is contained in the roots.
177+
// It returns true if the prefix is contained, false otherwise.
178+
func (ipam *Ipam) IsPrefixInRoots(prefix netip.Prefix) bool {
179+
for i := range ipam.roots {
180+
if isPrefixChildOf(ipam.roots[i].prefix, prefix) {
181+
return true
182+
}
183+
}
184+
return false
185+
}
186+
176187
// ToGraphviz generates the Graphviz representation of the IPAM structure.
177188
func (ipam *Ipam) ToGraphviz() error {
178189
for i := range ipam.roots {

pkg/ipam/core/net.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,34 +45,47 @@ func checkHostBitsZero(prefix netip.Prefix) error {
4545
return nil
4646
}
4747

48+
// splitNetworkPrefix splits a network prefix into two subnets.
49+
// It increases the prefix length by one and sets the bit at
50+
// the new position to 0 or 1 to retrieve the two subnets.
4851
func splitNetworkPrefix(prefix netip.Prefix) (left, right netip.Prefix) {
52+
// We neer to check that the host bits are zero.
4953
if err := checkHostBitsZero(prefix); err != nil {
5054
panic("Host bits must be zero")
5155
}
5256

57+
// We need to convert the prefix to a byte slice to manipulate it.
5358
bin, err := prefix.MarshalBinary()
5459
if err != nil {
5560
panic(err)
5661
}
5762

63+
// We need to get the mask length to know where to split the prefix.
5864
maskLen := bin[len(bin)-1]
5965

66+
// Since the prefix host bits are zero, we just need to shift
67+
// the mask length by one to get the first splitted prefix.
6068
left = netip.MustParsePrefix(
6169
fmt.Sprintf("%s/%d", convertByteSliceToString(bin[:4]), maskLen+1),
6270
)
6371

72+
// We need to set the bit at the mask length position to 1 to get the second splitted prefix.
73+
// Since the IP is expressed like a slice of bytes, we need to get the byte index and the bit index to set the bit.
6474
byteIndex := maskLen / 8
6575
bitIndex := maskLen % 8
6676

77+
// We set the bit at the mask length position to 1.
6778
bin[byteIndex] = setBit(bin[byteIndex], bitIndex)
6879

80+
// We forge and return the second splitted prefix.
6981
right = netip.MustParsePrefix(
7082
fmt.Sprintf("%s/%d", convertByteSliceToString(bin[:4]), maskLen+1),
7183
)
7284

7385
return left, right
7486
}
7587

88+
// isPrefixChildOf checks if the child prefix is a child of the parent prefix.
7689
func isPrefixChildOf(parent, child netip.Prefix) bool {
7790
if parent.Bits() <= child.Bits() && parent.Overlaps(child) {
7891
return true

pkg/ipam/core/node.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ func allocateNetwork(size int, node *node) *netip.Prefix {
5050
return nil
5151
}
5252
if node.prefix.Bits() == size {
53-
if !node.isSplit() {
53+
if !node.isSplitted() {
5454
node.acquired = true
5555
return &node.prefix
5656
}
5757
return nil
5858
}
5959

60-
if !node.isSplit() {
60+
if !node.isSplitted() {
6161
node.split()
6262
}
6363

@@ -81,7 +81,7 @@ func allocateNetworkWithPrefix(prefix netip.Prefix, node *node) *netip.Prefix {
8181
return nil
8282
}
8383

84-
if !node.isSplit() {
84+
if !node.isSplitted() {
8585
node.split()
8686
}
8787

@@ -157,6 +157,7 @@ func (n *node) ipAcquire() *netip.Addr {
157157

158158
size := int(math.Pow(2, float64(n.prefix.Addr().BitLen()-n.prefix.Bits())))
159159

160+
// If the lastip is not initialized, set it to the first address of the prefix.
160161
if !n.lastip.IsValid() {
161162
n.lastip = n.prefix.Addr()
162163
}
@@ -168,6 +169,8 @@ func (n *node) ipAcquire() *netip.Addr {
168169
}
169170

170171
for i := 0; i < size; i++ {
172+
// we need to check if the address is contained in the prefix.
173+
// If it is not, we need to set it to the first address of the prefix to prevent overflow.
171174
if !n.prefix.Contains(addr) {
172175
addr = n.prefix.Addr()
173176
}
@@ -235,7 +238,7 @@ func search(prefix netip.Prefix, node *node) *node {
235238
}
236239

237240
func (n *node) split() {
238-
if n.isSplit() {
241+
if n.isSplitted() {
239242
return
240243
}
241244
left, right := splitNetworkPrefix(n.prefix)
@@ -265,16 +268,16 @@ func (n *node) insert(nd nodeDirection, prefix netip.Prefix) {
265268
}
266269

267270
func (n *node) bestDirection() (first, second nodeDirection) {
268-
if n.left.isSplit() {
271+
if n.left.isSplitted() {
269272
return leftDirection, rightDirection
270273
}
271-
if n.right.isSplit() {
274+
if n.right.isSplitted() {
272275
return rightDirection, leftDirection
273276
}
274277
return leftDirection, rightDirection
275278
}
276279

277-
func (n *node) isSplit() bool {
280+
func (n *node) isSplitted() bool {
278281
if n.left != nil && n.right != nil {
279282
return true
280283
}

pkg/ipam/initialize.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks,verbs=get;list;watch
2626

2727
func (lipam *LiqoIPAM) initialize(ctx context.Context) error {
28+
lipam.mutex.Lock()
29+
defer lipam.mutex.Unlock()
2830
klog.Info("Initializing IPAM")
2931

3032
if err := lipam.initializeNetworks(ctx); err != nil {

pkg/ipam/ipam.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"errors"
2020
"fmt"
2121
"net/netip"
22+
"strings"
2223
"sync"
2324
"time"
2425

@@ -90,6 +91,10 @@ func (lipam *LiqoIPAM) IPAcquire(_ context.Context, req *IPAcquireRequest) (*IPA
9091
return &IPAcquireResponse{}, fmt.Errorf("failed to parse prefix %q: %w", req.GetCidr(), err)
9192
}
9293

94+
if !lipam.isInPool(prefix) {
95+
return nil, fmt.Errorf("prefix %q is not in the pool %q", req.GetCidr(), strings.Join(lipam.opts.Pools, ","))
96+
}
97+
9398
remappedIP, err := lipam.ipAcquire(prefix)
9499
if err != nil {
95100
return &IPAcquireResponse{}, err
@@ -133,6 +138,10 @@ func (lipam *LiqoIPAM) NetworkAcquire(_ context.Context, req *NetworkAcquireRequ
133138
return &NetworkAcquireResponse{}, fmt.Errorf("failed to parse prefix %q: %w", req.GetCidr(), err)
134139
}
135140

141+
if !lipam.isInPool(prefix) {
142+
return &NetworkAcquireResponse{}, fmt.Errorf("prefix %q is not in the pool %q", req.GetCidr(), strings.Join(lipam.opts.Pools, ","))
143+
}
144+
136145
if req.GetImmutable() {
137146
remappedCidr, err = lipam.networkAcquireSpecific(prefix)
138147
if err != nil {
@@ -182,6 +191,10 @@ func (lipam *LiqoIPAM) NetworkIsAvailable(_ context.Context, req *NetworkAvailab
182191
return &NetworkAvailableResponse{}, fmt.Errorf("failed to parse prefix %q: %w", req.GetCidr(), err)
183192
}
184193

194+
if !lipam.isInPool(prefix) {
195+
return &NetworkAvailableResponse{}, fmt.Errorf("prefix %q is not in the pool %q", req.GetCidr(), strings.Join(lipam.opts.Pools, ","))
196+
}
197+
185198
available := lipam.networkIsAvailable(prefix)
186199

187200
return &NetworkAvailableResponse{Available: available}, nil

0 commit comments

Comments
 (0)