@@ -30,13 +30,26 @@ import (
30
30
// be allocated from.
31
31
type CidrSet struct {
32
32
sync.Mutex
33
- clusterCIDR * net.IPNet
34
- clusterIP net.IP
33
+ // clusterCIDR is the CIDR assigned to the cluster
34
+ clusterCIDR * net.IPNet
35
+ // clusterMaskSize is the mask size, in bits, assigned to the cluster
36
+ // caches the mask size to avoid the penalty of calling clusterCIDR.Mask.Size()
35
37
clusterMaskSize int
36
- maxCIDRs int
37
- nextCandidate int
38
- used big.Int
39
- subNetMaskSize int
38
+ // nodeMask is the network mask assigned to the nodes
39
+ nodeMask net.IPMask
40
+ // nodeMaskSize is the mask size, in bits,assigned to the nodes
41
+ // caches the mask size to avoid the penalty of calling nodeMask.Size()
42
+ nodeMaskSize int
43
+ // maxCIDRs is the maximum number of CIDRs that can be allocated
44
+ maxCIDRs int
45
+ // allocatedCIDRs counts the number of CIDRs allocated
46
+ allocatedCIDRs int
47
+ // nextCandidate points to the next CIDR that should be free
48
+ nextCandidate int
49
+ // used is a bitmap used to track the CIDRs allocated
50
+ used big.Int
51
+ // label is used to identify the metrics
52
+ label string
40
53
}
41
54
42
55
const (
@@ -64,72 +77,71 @@ var (
64
77
// NewCIDRSet creates a new CidrSet.
65
78
func NewCIDRSet (clusterCIDR * net.IPNet , subNetMaskSize int ) (* CidrSet , error ) {
66
79
clusterMask := clusterCIDR .Mask
67
- clusterMaskSize , _ := clusterMask .Size ()
80
+ clusterMaskSize , bits := clusterMask .Size ()
68
81
69
82
var maxCIDRs int
70
83
if (clusterCIDR .IP .To4 () == nil ) && (subNetMaskSize - clusterMaskSize > clusterSubnetMaxDiff ) {
71
84
return nil , ErrCIDRSetSubNetTooBig
72
85
}
86
+
87
+ // register CidrSet metrics
88
+ registerCidrsetMetrics ()
89
+
73
90
maxCIDRs = 1 << uint32 (subNetMaskSize - clusterMaskSize )
74
91
return & CidrSet {
75
92
clusterCIDR : clusterCIDR ,
76
- clusterIP : clusterCIDR . IP ,
93
+ nodeMask : net . CIDRMask ( subNetMaskSize , bits ) ,
77
94
clusterMaskSize : clusterMaskSize ,
78
95
maxCIDRs : maxCIDRs ,
79
- subNetMaskSize : subNetMaskSize ,
96
+ nodeMaskSize : subNetMaskSize ,
97
+ label : clusterCIDR .String (),
80
98
}, nil
81
99
}
82
100
83
101
func (s * CidrSet ) indexToCIDRBlock (index int ) * net.IPNet {
84
102
var ip []byte
85
- var mask int
86
103
switch /*v4 or v6*/ {
87
- case s .clusterIP .To4 () != nil :
104
+ case s .clusterCIDR . IP .To4 () != nil :
88
105
{
89
- j := uint32 (index ) << uint32 (32 - s .subNetMaskSize )
90
- ipInt := (binary .BigEndian .Uint32 (s .clusterIP )) | j
91
- ip = make ([]byte , 4 )
106
+ j := uint32 (index ) << uint32 (32 - s .nodeMaskSize )
107
+ ipInt := (binary .BigEndian .Uint32 (s .clusterCIDR . IP )) | j
108
+ ip = make ([]byte , net . IPv4len )
92
109
binary .BigEndian .PutUint32 (ip , ipInt )
93
- mask = 32
94
-
95
110
}
96
- case s .clusterIP .To16 () != nil :
111
+ case s .clusterCIDR . IP .To16 () != nil :
97
112
{
98
113
// leftClusterIP | rightClusterIP
99
114
// 2001:0DB8:1234:0000:0000:0000:0000:0000
100
115
const v6NBits = 128
101
116
const halfV6NBits = v6NBits / 2
102
- leftClusterIP := binary .BigEndian .Uint64 (s .clusterIP [:halfIPv6Len ])
103
- rightClusterIP := binary .BigEndian .Uint64 (s .clusterIP [halfIPv6Len :])
117
+ leftClusterIP := binary .BigEndian .Uint64 (s .clusterCIDR . IP [:halfIPv6Len ])
118
+ rightClusterIP := binary .BigEndian .Uint64 (s .clusterCIDR . IP [halfIPv6Len :])
104
119
105
- leftIP , rightIP : = make ([]byte , halfIPv6Len ), make ([] byte , halfIPv6Len )
120
+ ip = make ([]byte , net . IPv6len )
106
121
107
- if s .subNetMaskSize <= halfV6NBits {
122
+ if s .nodeMaskSize <= halfV6NBits {
108
123
// We only care about left side IP
109
- leftClusterIP |= uint64 (index ) << uint (halfV6NBits - s .subNetMaskSize )
124
+ leftClusterIP |= uint64 (index ) << uint (halfV6NBits - s .nodeMaskSize )
110
125
} else {
111
126
if s .clusterMaskSize < halfV6NBits {
112
127
// see how many bits are needed to reach the left side
113
- btl := uint (s .subNetMaskSize - halfV6NBits )
128
+ btl := uint (s .nodeMaskSize - halfV6NBits )
114
129
indexMaxBit := uint (64 - bits .LeadingZeros64 (uint64 (index )))
115
130
if indexMaxBit > btl {
116
131
leftClusterIP |= uint64 (index ) >> btl
117
132
}
118
133
}
119
134
// the right side will be calculated the same way either the
120
135
// subNetMaskSize affects both left and right sides
121
- rightClusterIP |= uint64 (index ) << uint (v6NBits - s .subNetMaskSize )
136
+ rightClusterIP |= uint64 (index ) << uint (v6NBits - s .nodeMaskSize )
122
137
}
123
- binary .BigEndian .PutUint64 (leftIP , leftClusterIP )
124
- binary .BigEndian .PutUint64 (rightIP , rightClusterIP )
125
-
126
- ip = append (leftIP , rightIP ... )
127
- mask = 128
138
+ binary .BigEndian .PutUint64 (ip [:halfIPv6Len ], leftClusterIP )
139
+ binary .BigEndian .PutUint64 (ip [halfIPv6Len :], rightClusterIP )
128
140
}
129
141
}
130
142
return & net.IPNet {
131
143
IP : ip ,
132
- Mask : net . CIDRMask ( s . subNetMaskSize , mask ) ,
144
+ Mask : s . nodeMask ,
133
145
}
134
146
}
135
147
@@ -139,22 +151,27 @@ func (s *CidrSet) AllocateNext() (*net.IPNet, error) {
139
151
s .Lock ()
140
152
defer s .Unlock ()
141
153
142
- nextUnused := - 1
143
- for i := 0 ; i < s .maxCIDRs ; i ++ {
144
- candidate := (i + s .nextCandidate ) % s .maxCIDRs
154
+ if s .allocatedCIDRs == s .maxCIDRs {
155
+ return nil , ErrCIDRRangeNoCIDRsRemaining
156
+ }
157
+ candidate := s .nextCandidate
158
+ var i int
159
+ for i = 0 ; i < s .maxCIDRs ; i ++ {
145
160
if s .used .Bit (candidate ) == 0 {
146
- nextUnused = candidate
147
161
break
148
162
}
163
+ candidate = (candidate + 1 ) % s .maxCIDRs
149
164
}
150
- if nextUnused == - 1 {
151
- return nil , ErrCIDRRangeNoCIDRsRemaining
152
- }
153
- s .nextCandidate = (nextUnused + 1 ) % s .maxCIDRs
154
165
155
- s .used .SetBit (& s .used , nextUnused , 1 )
166
+ s .nextCandidate = (candidate + 1 ) % s .maxCIDRs
167
+ s .used .SetBit (& s .used , candidate , 1 )
168
+ s .allocatedCIDRs ++
169
+ // Update metrics
170
+ cidrSetAllocations .WithLabelValues (s .label ).Inc ()
171
+ cidrSetAllocationTriesPerRequest .WithLabelValues (s .label ).Observe (float64 (i ))
172
+ cidrSetUsage .WithLabelValues (s .label ).Set (float64 (s .allocatedCIDRs ) / float64 (s .maxCIDRs ))
156
173
157
- return s .indexToCIDRBlock (nextUnused ), nil
174
+ return s .indexToCIDRBlock (candidate ), nil
158
175
}
159
176
160
177
func (s * CidrSet ) getBeginingAndEndIndices (cidr * net.IPNet ) (begin , end int , err error ) {
@@ -176,10 +193,9 @@ func (s *CidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err
176
193
if cidr .IP .To4 () == nil {
177
194
ipSize = net .IPv6len
178
195
}
179
- subNetMask := net .CIDRMask (s .subNetMaskSize , ipSize * 8 )
180
196
begin , err = s .getIndexForCIDR (& net.IPNet {
181
- IP : cidr .IP .Mask (subNetMask ),
182
- Mask : subNetMask ,
197
+ IP : cidr .IP .Mask (s . nodeMask ),
198
+ Mask : s . nodeMask ,
183
199
})
184
200
if err != nil {
185
201
return - 1 , - 1 , err
@@ -197,8 +213,8 @@ func (s *CidrSet) getBeginingAndEndIndices(cidr *net.IPNet) (begin, end int, err
197
213
binary .BigEndian .PutUint64 (ip [net .IPv6len / 2 :], ipIntRight )
198
214
}
199
215
end , err = s .getIndexForCIDR (& net.IPNet {
200
- IP : net .IP (ip ).Mask (subNetMask ),
201
- Mask : subNetMask ,
216
+ IP : net .IP (ip ).Mask (s . nodeMask ),
217
+ Mask : s . nodeMask ,
202
218
})
203
219
if err != nil {
204
220
return - 1 , - 1 , err
@@ -217,7 +233,11 @@ func (s *CidrSet) Release(cidr *net.IPNet) error {
217
233
defer s .Unlock ()
218
234
for i := begin ; i <= end ; i ++ {
219
235
s .used .SetBit (& s .used , i , 0 )
236
+ s .allocatedCIDRs --
237
+ cidrSetReleases .WithLabelValues (s .label ).Inc ()
220
238
}
239
+
240
+ cidrSetUsage .WithLabelValues (s .label ).Set (float64 (s .allocatedCIDRs ) / float64 (s .maxCIDRs ))
221
241
return nil
222
242
}
223
243
@@ -228,13 +248,15 @@ func (s *CidrSet) Occupy(cidr *net.IPNet) (err error) {
228
248
if err != nil {
229
249
return err
230
250
}
231
-
232
251
s .Lock ()
233
252
defer s .Unlock ()
234
253
for i := begin ; i <= end ; i ++ {
235
254
s .used .SetBit (& s .used , i , 1 )
255
+ s .allocatedCIDRs ++
256
+ cidrSetAllocations .WithLabelValues (s .label ).Inc ()
236
257
}
237
258
259
+ cidrSetUsage .WithLabelValues (s .label ).Set (float64 (s .allocatedCIDRs ) / float64 (s .maxCIDRs ))
238
260
return nil
239
261
}
240
262
@@ -244,19 +266,19 @@ func (s *CidrSet) getIndexForCIDR(cidr *net.IPNet) (int, error) {
244
266
245
267
func (s * CidrSet ) getIndexForIP (ip net.IP ) (int , error ) {
246
268
if ip .To4 () != nil {
247
- cidrIndex := (binary .BigEndian .Uint32 (s .clusterIP ) ^ binary .BigEndian .Uint32 (ip .To4 ())) >> uint32 (32 - s .subNetMaskSize )
269
+ cidrIndex := (binary .BigEndian .Uint32 (s .clusterCIDR . IP ) ^ binary .BigEndian .Uint32 (ip .To4 ())) >> uint32 (32 - s .nodeMaskSize )
248
270
if cidrIndex >= uint32 (s .maxCIDRs ) {
249
- return 0 , fmt .Errorf ("CIDR: %v/%v is out of the range of CIDR allocator" , ip , s .subNetMaskSize )
271
+ return 0 , fmt .Errorf ("CIDR: %v/%v is out of the range of CIDR allocator" , ip , s .nodeMaskSize )
250
272
}
251
273
return int (cidrIndex ), nil
252
274
}
253
275
if ip .To16 () != nil {
254
- bigIP := big .NewInt (0 ).SetBytes (s .clusterIP )
276
+ bigIP := big .NewInt (0 ).SetBytes (s .clusterCIDR . IP )
255
277
bigIP = bigIP .Xor (bigIP , big .NewInt (0 ).SetBytes (ip ))
256
- cidrIndexBig := bigIP .Rsh (bigIP , uint (net .IPv6len * 8 - s .subNetMaskSize ))
278
+ cidrIndexBig := bigIP .Rsh (bigIP , uint (net .IPv6len * 8 - s .nodeMaskSize ))
257
279
cidrIndex := cidrIndexBig .Uint64 ()
258
280
if cidrIndex >= uint64 (s .maxCIDRs ) {
259
- return 0 , fmt .Errorf ("CIDR: %v/%v is out of the range of CIDR allocator" , ip , s .subNetMaskSize )
281
+ return 0 , fmt .Errorf ("CIDR: %v/%v is out of the range of CIDR allocator" , ip , s .nodeMaskSize )
260
282
}
261
283
return int (cidrIndex ), nil
262
284
}
0 commit comments