-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
pool.go
128 lines (107 loc) · 2.61 KB
/
pool.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium
package multipool
import (
"errors"
"fmt"
"net/netip"
"go4.org/netipx"
"github.com/cilium/cilium/pkg/ipam"
"github.com/cilium/cilium/pkg/ipam/allocator/clusterpool/cidralloc"
)
var (
errPoolEmpty = errors.New("pool empty")
)
func allocFirstFreeCIDR(allocators []cidralloc.CIDRAllocator) (netip.Prefix, error) {
for _, alloc := range allocators {
if alloc.IsFull() {
continue
}
ipnet, err := alloc.AllocateNext()
if err != nil {
return netip.Prefix{}, err
}
prefix, ok := netipx.FromStdIPNet(ipnet)
if !ok {
return netip.Prefix{}, fmt.Errorf("invalid cidr %s allocated", ipnet)
}
return prefix, nil
}
return netip.Prefix{}, errPoolEmpty
}
func occupyCIDR(allocators []cidralloc.CIDRAllocator, cidr netip.Prefix) error {
ipnet := netipx.PrefixIPNet(cidr)
for _, alloc := range allocators {
if !alloc.InRange(ipnet) {
continue
}
if alloc.IsFull() {
return errPoolEmpty
}
allocated, err := alloc.IsAllocated(ipnet)
if err != nil {
return err
}
if allocated {
return fmt.Errorf("cidr %s has already been allocated", cidr)
}
return alloc.Occupy(ipnet)
}
return fmt.Errorf("cidr %s is not part of the requested pool", cidr)
}
func releaseCIDR(allocators []cidralloc.CIDRAllocator, cidr netip.Prefix) error {
ipnet := netipx.PrefixIPNet(cidr)
for _, alloc := range allocators {
if !alloc.InRange(ipnet) {
continue
}
allocated, err := alloc.IsAllocated(ipnet)
if err != nil {
return err
}
if !allocated {
return nil // not an error to release a cidr twice
}
return alloc.Release(ipnet)
}
return fmt.Errorf("released cidr %s was not part the pool", cidr)
}
func hasCIDR(allocators []cidralloc.CIDRAllocator, cidr netip.Prefix) bool {
for _, alloc := range allocators {
if alloc.IsClusterCIDR(cidr) {
return true
}
}
return false
}
func (c *cidrPool) allocCIDR(family ipam.Family) (netip.Prefix, error) {
switch family {
case ipam.IPv4:
return allocFirstFreeCIDR(c.v4)
case ipam.IPv6:
return allocFirstFreeCIDR(c.v6)
default:
return netip.Prefix{}, fmt.Errorf("invalid cidr family: %s", family)
}
}
func (c *cidrPool) occupyCIDR(cidr netip.Prefix) error {
if cidr.Addr().Is4() {
return occupyCIDR(c.v4, cidr)
} else {
return occupyCIDR(c.v6, cidr)
}
}
func (c *cidrPool) releaseCIDR(cidr netip.Prefix) error {
if cidr.Addr().Is4() {
return releaseCIDR(c.v4, cidr)
} else {
return releaseCIDR(c.v6, cidr)
}
}
func (c *cidrPool) hasCIDR(cidr netip.Prefix) bool {
if cidr.Addr().Is4() {
return hasCIDR(c.v4, cidr)
} else {
return hasCIDR(c.v6, cidr)
}
}