Skip to content

Commit 2e12311

Browse files
authored
Merge pull request kubernetes#91606 from danwinship/service-ipallocator-cleanups
Service IPAllocator cleanups
2 parents 696e60d + f6dcc1c commit 2e12311

File tree

3 files changed

+47
-112
lines changed

3 files changed

+47
-112
lines changed

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

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,28 @@ type Range struct {
8282

8383
// NewAllocatorCIDRRange creates a Range over a net.IPNet, calling allocatorFactory to construct the backing store.
8484
func NewAllocatorCIDRRange(cidr *net.IPNet, allocatorFactory allocator.AllocatorFactory) (*Range, error) {
85-
max := RangeSize(cidr)
86-
base := bigForIP(cidr.IP)
85+
max := utilnet.RangeSize(cidr)
86+
base := utilnet.BigForIP(cidr.IP)
8787
rangeSpec := cidr.String()
8888

89+
if utilnet.IsIPv6CIDR(cidr) {
90+
// Limit the max size, since the allocator keeps a bitmap of that size.
91+
if max > 65536 {
92+
max = 65536
93+
}
94+
} else {
95+
// Don't use the IPv4 network's broadcast address.
96+
max--
97+
}
98+
99+
// Don't use the network's ".0" address.
100+
base.Add(base, big.NewInt(1))
101+
max--
102+
89103
r := Range{
90104
net: cidr,
91-
base: base.Add(base, big.NewInt(1)), // don't use the network base
92-
max: maximum(0, int(max-2)), // don't use the network broadcast,
105+
base: base,
106+
max: maximum(0, int(max)),
93107
}
94108
var err error
95109
r.alloc, err = allocatorFactory(r.max, rangeSpec)
@@ -171,7 +185,7 @@ func (r *Range) AllocateNext() (net.IP, error) {
171185
if !ok {
172186
return nil, ErrFull
173187
}
174-
return addIPOffset(r.base, offset), nil
188+
return utilnet.AddIPOffset(r.base, offset), nil
175189
}
176190

177191
// Release releases the IP back to the pool. Releasing an
@@ -247,40 +261,8 @@ func (r *Range) contains(ip net.IP) (bool, int) {
247261
return true, offset
248262
}
249263

250-
// bigForIP creates a big.Int based on the provided net.IP
251-
func bigForIP(ip net.IP) *big.Int {
252-
b := ip.To4()
253-
if b == nil {
254-
b = ip.To16()
255-
}
256-
return big.NewInt(0).SetBytes(b)
257-
}
258-
259-
// addIPOffset adds the provided integer offset to a base big.Int representing a
260-
// net.IP
261-
func addIPOffset(base *big.Int, offset int) net.IP {
262-
return net.IP(big.NewInt(0).Add(base, big.NewInt(int64(offset))).Bytes())
263-
}
264-
265264
// calculateIPOffset calculates the integer offset of ip from base such that
266265
// base + offset = ip. It requires ip >= base.
267266
func calculateIPOffset(base *big.Int, ip net.IP) int {
268-
return int(big.NewInt(0).Sub(bigForIP(ip), base).Int64())
269-
}
270-
271-
// RangeSize returns the size of a range in valid addresses.
272-
func RangeSize(subnet *net.IPNet) int64 {
273-
ones, bits := subnet.Mask.Size()
274-
if bits == 32 && (bits-ones) >= 31 || bits == 128 && (bits-ones) >= 127 {
275-
return 0
276-
}
277-
// For IPv6, the max size will be limited to 65536
278-
// This is due to the allocator keeping track of all the
279-
// allocated IP's in a bitmap. This will keep the size of
280-
// the bitmap to 64k.
281-
if bits == 128 && (bits-ones) >= 16 {
282-
return int64(1) << uint(16)
283-
} else {
284-
return int64(1) << uint(bits-ones)
285-
}
267+
return int(big.NewInt(0).Sub(utilnet.BigForIP(ip), base).Int64())
286268
}

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

Lines changed: 26 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -30,29 +30,33 @@ func TestAllocate(t *testing.T) {
3030
cidr string
3131
free int
3232
released string
33-
outOfRange1 string
34-
outOfRange2 string
35-
outOfRange3 string
33+
outOfRange []string
3634
alreadyAllocated string
3735
}{
3836
{
39-
name: "IPv4",
40-
cidr: "192.168.1.0/24",
41-
free: 254,
42-
released: "192.168.1.5",
43-
outOfRange1: "192.168.0.1",
44-
outOfRange2: "192.168.1.0",
45-
outOfRange3: "192.168.1.255",
37+
name: "IPv4",
38+
cidr: "192.168.1.0/24",
39+
free: 254,
40+
released: "192.168.1.5",
41+
outOfRange: []string{
42+
"192.168.0.1", // not in 192.168.1.0/24
43+
"192.168.1.0", // reserved (base address)
44+
"192.168.1.255", // reserved (broadcast address)
45+
"192.168.2.2", // not in 192.168.1.0/24
46+
},
4647
alreadyAllocated: "192.168.1.1",
4748
},
4849
{
49-
name: "IPv6",
50-
cidr: "2001:db8:1::/48",
51-
free: 65534,
52-
released: "2001:db8:1::5",
53-
outOfRange1: "2001:db8::1",
54-
outOfRange2: "2001:db8:1::",
55-
outOfRange3: "2001:db8:1::ffff",
50+
name: "IPv6",
51+
cidr: "2001:db8:1::/48",
52+
free: 65535,
53+
released: "2001:db8:1::5",
54+
outOfRange: []string{
55+
"2001:db8::1", // not in 2001:db8:1::/48
56+
"2001:db8:1::", // reserved (base address)
57+
"2001:db8:1::1:0", // not in the low 16 bits of 2001:db8:1::/48
58+
"2001:db8:2::2", // not in 2001:db8:1::/48
59+
},
5660
alreadyAllocated: "2001:db8:1::1",
5761
},
5862
}
@@ -119,21 +123,15 @@ func TestAllocate(t *testing.T) {
119123
if err := r.Release(released); err != nil {
120124
t.Fatal(err)
121125
}
122-
err = r.Allocate(net.ParseIP(tc.outOfRange1))
123-
if _, ok := err.(*ErrNotInRange); !ok {
124-
t.Fatal(err)
126+
for _, outOfRange := range tc.outOfRange {
127+
err = r.Allocate(net.ParseIP(outOfRange))
128+
if _, ok := err.(*ErrNotInRange); !ok {
129+
t.Fatal(err)
130+
}
125131
}
126132
if err := r.Allocate(net.ParseIP(tc.alreadyAllocated)); err != ErrAllocated {
127133
t.Fatal(err)
128134
}
129-
err = r.Allocate(net.ParseIP(tc.outOfRange2))
130-
if _, ok := err.(*ErrNotInRange); !ok {
131-
t.Fatal(err)
132-
}
133-
err = r.Allocate(net.ParseIP(tc.outOfRange3))
134-
if _, ok := err.(*ErrNotInRange); !ok {
135-
t.Fatal(err)
136-
}
137135
if f := r.Free(); f != 1 {
138136
t.Errorf("Test %s unexpected free %d", tc.name, f)
139137
}
@@ -213,51 +211,6 @@ func TestAllocateSmall(t *testing.T) {
213211
t.Logf("allocated: %v", found)
214212
}
215213

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-
261214
func TestForEach(t *testing.T) {
262215
_, cidr, err := net.ParseCIDR("192.168.1.0/24")
263216
if err != nil {

pkg/registry/core/service/ipallocator/controller/repair_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ func TestRepairWithExistingDualStack(t *testing.T) {
529529
if !secondaryAfter.Has(net.ParseIP("2000::1")) || !secondaryAfter.Has(net.ParseIP("2000::2")) {
530530
t.Errorf("unexpected ipallocator state: %#v", secondaryAfter)
531531
}
532-
if free := secondaryAfter.Free(); free != 65532 {
532+
if free := secondaryAfter.Free(); free != 65533 {
533533
t.Errorf("unexpected ipallocator state: %d free (number of free ips is not 65532)", free)
534534
}
535535

0 commit comments

Comments
 (0)