Skip to content

Commit 37e2a24

Browse files
author
Ravi Sankar Penta
committed
Allow subnet allocator to mark assigned subnet dynamically
- Currently, we need to pass all allocated subnets during subnet allocator creation time (inUse arg to NewSubnetAllocator()). This means we need to know all existing subnets beforehand. - This change exposes additional method so that we can mark a specific subnet as already allocated dynamically (after the subnet allocated is created). Precursor for #18911
1 parent 9d81d1b commit 37e2a24

File tree

2 files changed

+91
-24
lines changed

2 files changed

+91
-24
lines changed

pkg/util/netutils/subnet_allocator.go

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"fmt"
55
"net"
66
"sync"
7+
8+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
79
)
810

911
var ErrSubnetAllocatorFull = fmt.Errorf("No subnets available.")
@@ -23,14 +25,14 @@ type SubnetAllocator struct {
2325
func NewSubnetAllocator(network string, hostBits uint32, inUse []string) (*SubnetAllocator, error) {
2426
_, netIP, err := net.ParseCIDR(network)
2527
if err != nil {
26-
return nil, fmt.Errorf("Failed to parse network address: %q", network)
28+
return nil, fmt.Errorf("failed to parse network address: %q", network)
2729
}
2830

2931
netMaskSize, _ := netIP.Mask.Size()
3032
if hostBits == 0 {
31-
return nil, fmt.Errorf("Host capacity cannot be zero.")
33+
return nil, fmt.Errorf("host capacity cannot be zero.")
3234
} else if hostBits > (32 - uint32(netMaskSize)) {
33-
return nil, fmt.Errorf("Subnet capacity cannot be larger than number of networks available.")
35+
return nil, fmt.Errorf("subnet capacity cannot be larger than number of networks available.")
3436
}
3537
subnetBits := 32 - uint32(netMaskSize) - hostBits
3638

@@ -61,29 +63,41 @@ func NewSubnetAllocator(network string, hostBits uint32, inUse []string) (*Subne
6163
rightMask = 0
6264
}
6365

64-
amap := make(map[string]bool)
65-
for _, netStr := range inUse {
66-
_, nIp, err := net.ParseCIDR(netStr)
67-
if err != nil {
68-
fmt.Println("Failed to parse network address: ", netStr)
69-
continue
70-
}
71-
if !netIP.Contains(nIp.IP) {
72-
fmt.Println("Provided subnet doesn't belong to network: ", nIp)
73-
continue
74-
}
75-
amap[nIp.String()] = true
76-
}
77-
return &SubnetAllocator{
66+
sa := &SubnetAllocator{
7867
network: netIP,
7968
hostBits: hostBits,
8069
leftShift: leftShift,
8170
leftMask: leftMask,
8271
rightShift: rightShift,
8372
rightMask: rightMask,
8473
next: 0,
85-
allocMap: amap,
86-
}, nil
74+
allocMap: make(map[string]bool),
75+
}
76+
for _, netStr := range inUse {
77+
_, ipNet, err := net.ParseCIDR(netStr)
78+
if err != nil {
79+
utilruntime.HandleError(fmt.Errorf("failed to parse network address: %s", netStr))
80+
continue
81+
}
82+
if err = sa.AllocateNetwork(ipNet); err != nil {
83+
utilruntime.HandleError(err)
84+
continue
85+
}
86+
}
87+
return sa, nil
88+
}
89+
90+
func (sna *SubnetAllocator) AllocateNetwork(ipNet *net.IPNet) error {
91+
sna.mutex.Lock()
92+
defer sna.mutex.Unlock()
93+
94+
if !sna.network.Contains(ipNet.IP) {
95+
return fmt.Errorf("provided subnet doesn't belong to network: %v", ipNet)
96+
}
97+
if !sna.allocMap[ipNet.String()] {
98+
sna.allocMap[ipNet.String()] = true
99+
}
100+
return nil
87101
}
88102

89103
func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
@@ -120,16 +134,16 @@ func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
120134
func (sna *SubnetAllocator) ReleaseNetwork(ipnet *net.IPNet) error {
121135
sna.mutex.Lock()
122136
defer sna.mutex.Unlock()
137+
123138
if !sna.network.Contains(ipnet.IP) {
124-
return fmt.Errorf("Provided subnet %v doesn't belong to the network %v.", ipnet, sna.network)
139+
return fmt.Errorf("provided subnet %v doesn't belong to the network %v.", ipnet, sna.network)
125140
}
126141

127142
ipnetStr := ipnet.String()
128143
if !sna.allocMap[ipnetStr] {
129-
return fmt.Errorf("Provided subnet %v is already available.", ipnet)
144+
return fmt.Errorf("provided subnet %v is already available.", ipnet)
145+
} else {
146+
sna.allocMap[ipnetStr] = false
130147
}
131-
132-
sna.allocMap[ipnetStr] = false
133-
134148
return nil
135149
}

pkg/util/netutils/subnet_allocator_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,59 @@ func TestAllocateSubnetInUse(t *testing.T) {
205205
}
206206
}
207207

208+
func TestAllocateNetwork(t *testing.T) {
209+
sna, err := NewSubnetAllocator("10.1.0.0/16", 14, nil)
210+
if err != nil {
211+
t.Fatal("Failed to initialize IP allocator: ", err)
212+
}
213+
214+
allocSubnets := make([]*net.IPNet, 4)
215+
for i := 0; i < 4; i++ {
216+
if allocSubnets[i], err = sna.GetNetwork(); err != nil {
217+
t.Fatal("Failed to get network: ", err)
218+
}
219+
}
220+
221+
if sn, err := sna.GetNetwork(); err == nil {
222+
t.Fatalf("Unexpectedly succeeded in getting network (sn=%s)", sn.String())
223+
}
224+
if err := sna.ReleaseNetwork(allocSubnets[2]); err != nil {
225+
t.Fatalf("Failed to release the subnet (allocSubnets[2]=%s): %v", allocSubnets[2].String(), err)
226+
}
227+
for i := 0; i < 2; i++ {
228+
if err := sna.AllocateNetwork(allocSubnets[2]); err != nil {
229+
t.Fatalf("Failed to allocate the subnet (allocSubnets[2]=%s): %v", allocSubnets[2].String(), err)
230+
}
231+
}
232+
if sn, err := sna.GetNetwork(); err == nil {
233+
t.Fatalf("Unexpectedly succeeded in getting network (sn=%s)", sn.String())
234+
}
235+
236+
// Test subnet does not belong to network
237+
var sn *net.IPNet
238+
_, sn, err = net.ParseCIDR("10.2.3.4/24")
239+
if err != nil {
240+
t.Fatal("Failed to parse given network: ", err)
241+
}
242+
if err := sna.AllocateNetwork(sn); err == nil {
243+
t.Fatalf("Unexpectedly succeeded in allocating subnet that doesn't belong to network (sn=%s)", sn.String())
244+
}
245+
246+
// Test AllocateNetwork usage in NewSubnetAllocator
247+
var subnetStrs []string
248+
for _, sn := range allocSubnets {
249+
subnetStrs = append(subnetStrs, sn.String())
250+
}
251+
var sa *SubnetAllocator
252+
sa, err = NewSubnetAllocator("10.1.0.0/16", 14, subnetStrs)
253+
if err != nil {
254+
t.Fatal("Failed to initialize IP allocator: ", err)
255+
}
256+
if sn, err = sa.GetNetwork(); err == nil {
257+
t.Fatalf("Unexpectedly succeeded in getting network (sn=%s)", sn.String())
258+
}
259+
}
260+
208261
func TestAllocateReleaseSubnet(t *testing.T) {
209262
sna, err := NewSubnetAllocator("10.1.0.0/16", 14, nil)
210263
if err != nil {

0 commit comments

Comments
 (0)