Skip to content

Commit 9f5339f

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 allocator is created). Precursor for #18911
1 parent d8501d2 commit 9f5339f

File tree

2 files changed

+91
-24
lines changed

2 files changed

+91
-24
lines changed

pkg/network/master/subnet_allocator.go

+38-24
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"net"
77
"sync"
8+
9+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
810
)
911

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

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

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

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

90104
func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
@@ -121,17 +135,17 @@ func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
121135
func (sna *SubnetAllocator) ReleaseNetwork(ipnet *net.IPNet) error {
122136
sna.mutex.Lock()
123137
defer sna.mutex.Unlock()
138+
124139
if !sna.network.Contains(ipnet.IP) {
125-
return fmt.Errorf("Provided subnet %v doesn't belong to the network %v.", ipnet, sna.network)
140+
return fmt.Errorf("provided subnet %v doesn't belong to the network %v.", ipnet, sna.network)
126141
}
127142

128143
ipnetStr := ipnet.String()
129144
if !sna.allocMap[ipnetStr] {
130-
return fmt.Errorf("Provided subnet %v is already available.", ipnet)
145+
return fmt.Errorf("provided subnet %v is already available.", ipnet)
146+
} else {
147+
sna.allocMap[ipnetStr] = false
131148
}
132-
133-
sna.allocMap[ipnetStr] = false
134-
135149
return nil
136150
}
137151

pkg/network/master/subnet_allocator_test.go

+53
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)