Skip to content

Commit 5e31799

Browse files
authored
Merge pull request kubernetes#86534 from liggitt/ipallocator-range
Restore IPAllocator ipv4 range handling
2 parents 06fb3eb + 6a13542 commit 5e31799

File tree

3 files changed

+93
-14
lines changed

3 files changed

+93
-14
lines changed

pkg/registry/core/service/ipallocator/BUILD

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ go_library(
1313
deps = [
1414
"//pkg/apis/core:go_default_library",
1515
"//pkg/registry/core/service/allocator:go_default_library",
16-
"//vendor/k8s.io/utils/integer:go_default_library",
17-
"//vendor/k8s.io/utils/net:go_default_library",
1816
],
1917
)
2018

pkg/registry/core/service/ipallocator/allocator.go

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,10 @@ package ipallocator
1919
import (
2020
"errors"
2121
"fmt"
22-
23-
"math/big"
24-
"net"
25-
2622
api "k8s.io/kubernetes/pkg/apis/core"
2723
"k8s.io/kubernetes/pkg/registry/core/service/allocator"
28-
"k8s.io/utils/integer"
29-
utilnet "k8s.io/utils/net"
24+
"math/big"
25+
"net"
3026
)
3127

3228
// Interface manages the allocation of IP addresses out of a range. Interface
@@ -84,8 +80,8 @@ type Range struct {
8480

8581
// NewAllocatorCIDRRange creates a Range over a net.IPNet, calling allocatorFactory to construct the backing store.
8682
func NewAllocatorCIDRRange(cidr *net.IPNet, allocatorFactory allocator.AllocatorFactory) (*Range, error) {
87-
max := integer.Int64Min(utilnet.RangeSize(cidr), 1<<16)
88-
base := utilnet.BigForIP(cidr.IP)
83+
max := RangeSize(cidr)
84+
base := bigForIP(cidr.IP)
8985
rangeSpec := cidr.String()
9086

9187
r := Range{
@@ -173,7 +169,7 @@ func (r *Range) AllocateNext() (net.IP, error) {
173169
if !ok {
174170
return nil, ErrFull
175171
}
176-
return utilnet.AddIPOffset(r.base, offset), nil
172+
return addIPOffset(r.base, offset), nil
177173
}
178174

179175
// Release releases the IP back to the pool. Releasing an
@@ -191,7 +187,7 @@ func (r *Range) Release(ip net.IP) error {
191187
// ForEach calls the provided function for each allocated IP.
192188
func (r *Range) ForEach(fn func(net.IP)) {
193189
r.alloc.ForEach(func(offset int) {
194-
ip, _ := utilnet.GetIndexedIP(r.net, offset+1) // +1 because Range doesn't store IP 0
190+
ip, _ := GetIndexedIP(r.net, offset+1) // +1 because Range doesn't store IP 0
195191
fn(ip)
196192
})
197193
}
@@ -249,8 +245,49 @@ func (r *Range) contains(ip net.IP) (bool, int) {
249245
return true, offset
250246
}
251247

248+
// bigForIP creates a big.Int based on the provided net.IP
249+
func bigForIP(ip net.IP) *big.Int {
250+
b := ip.To4()
251+
if b == nil {
252+
b = ip.To16()
253+
}
254+
return big.NewInt(0).SetBytes(b)
255+
}
256+
257+
// addIPOffset adds the provided integer offset to a base big.Int representing a
258+
// net.IP
259+
func addIPOffset(base *big.Int, offset int) net.IP {
260+
return net.IP(big.NewInt(0).Add(base, big.NewInt(int64(offset))).Bytes())
261+
}
262+
252263
// calculateIPOffset calculates the integer offset of ip from base such that
253264
// base + offset = ip. It requires ip >= base.
254265
func calculateIPOffset(base *big.Int, ip net.IP) int {
255-
return int(big.NewInt(0).Sub(utilnet.BigForIP(ip), base).Int64())
266+
return int(big.NewInt(0).Sub(bigForIP(ip), base).Int64())
267+
}
268+
269+
// RangeSize returns the size of a range in valid addresses.
270+
func RangeSize(subnet *net.IPNet) int64 {
271+
ones, bits := subnet.Mask.Size()
272+
if bits == 32 && (bits-ones) >= 31 || bits == 128 && (bits-ones) >= 127 {
273+
return 0
274+
}
275+
// For IPv6, the max size will be limited to 65536
276+
// This is due to the allocator keeping track of all the
277+
// allocated IP's in a bitmap. This will keep the size of
278+
// the bitmap to 64k.
279+
if bits == 128 && (bits-ones) >= 16 {
280+
return int64(1) << uint(16)
281+
} else {
282+
return int64(1) << uint(bits-ones)
283+
}
284+
}
285+
286+
// GetIndexedIP returns a net.IP that is subnet.IP + index in the contiguous IP space.
287+
func GetIndexedIP(subnet *net.IPNet, index int) (net.IP, error) {
288+
ip := addIPOffset(bigForIP(subnet.IP), index)
289+
if !subnet.Contains(ip) {
290+
return nil, fmt.Errorf("can't generate IP with index %d from subnet. subnet too small. subnet: %q", index, subnet)
291+
}
292+
return ip, nil
256293
}

pkg/registry/core/service/ipallocator/allocator_test.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ func TestAllocate(t *testing.T) {
6666
t.Fatal(err)
6767
}
6868
t.Logf("base: %v", r.base.Bytes())
69-
t.Logf("max: %v", r.max)
7069
if f := r.Free(); f != tc.free {
7170
t.Errorf("Test %s unexpected free %d", tc.name, f)
7271
}
@@ -214,6 +213,51 @@ func TestAllocateSmall(t *testing.T) {
214213
t.Logf("allocated: %v", found)
215214
}
216215

216+
func TestRangeSize(t *testing.T) {
217+
testCases := []struct {
218+
name string
219+
cidr string
220+
addrs int64
221+
}{
222+
{
223+
name: "supported IPv4 cidr",
224+
cidr: "192.168.1.0/24",
225+
addrs: 256,
226+
},
227+
{
228+
name: "supported large IPv4 cidr",
229+
cidr: "10.96.0.0/12",
230+
addrs: 1048576,
231+
},
232+
{
233+
name: "unsupported IPv4 cidr",
234+
cidr: "192.168.1.0/1",
235+
addrs: 0,
236+
},
237+
{
238+
name: "supported IPv6 cidr",
239+
cidr: "2001:db8::/48",
240+
addrs: 65536,
241+
},
242+
{
243+
name: "unsupported IPv6 mask",
244+
cidr: "2001:db8::/1",
245+
addrs: 0,
246+
},
247+
}
248+
249+
for _, tc := range testCases {
250+
_, cidr, err := net.ParseCIDR(tc.cidr)
251+
if err != nil {
252+
t.Errorf("failed to parse cidr for test %s, unexpected error: '%s'", tc.name, err)
253+
}
254+
if size := RangeSize(cidr); size != tc.addrs {
255+
t.Errorf("test %s failed. %s should have a range size of %d, got %d",
256+
tc.name, tc.cidr, tc.addrs, size)
257+
}
258+
}
259+
}
260+
217261
func TestForEach(t *testing.T) {
218262
_, cidr, err := net.ParseCIDR("192.168.1.0/24")
219263
if err != nil {

0 commit comments

Comments
 (0)