Skip to content

Commit 3caa07e

Browse files
Merge pull request #18999 from pravisankar/expose-marking-suballocator
Automatic merge from submit-queue (batch tested with PRs 18999, 18543). Allow subnet allocator to mark assigned subnet dynamically - Moved subnet allocator from pkg/util/netutils to pkg/network/master Subnet allocator is specific to SDN master and not used anywhere. - 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
2 parents 0706074 + 9f5339f commit 3caa07e

File tree

6 files changed

+126
-69
lines changed

6 files changed

+126
-69
lines changed

pkg/network/master/master.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type OsdnMaster struct {
3333
kClient kclientset.Interface
3434
networkClient networkclient.Interface
3535
networkInfo *common.NetworkInfo
36-
subnetAllocatorList []*netutils.SubnetAllocator
36+
subnetAllocatorList []*SubnetAllocator
3737
vnids *masterVNIDMap
3838

3939
kubeInformers kinternalinformers.SharedInformerFactory

pkg/util/netutils/subnet_allocator.go renamed to pkg/network/master/subnet_allocator.go

+49-24
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
package netutils
1+
package master
22

33
import (
4+
"encoding/binary"
45
"fmt"
56
"net"
67
"sync"
8+
9+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
710
)
811

912
var ErrSubnetAllocatorFull = fmt.Errorf("No subnets available.")
@@ -23,14 +26,14 @@ type SubnetAllocator struct {
2326
func NewSubnetAllocator(network string, hostBits uint32, inUse []string) (*SubnetAllocator, error) {
2427
_, netIP, err := net.ParseCIDR(network)
2528
if err != nil {
26-
return nil, fmt.Errorf("Failed to parse network address: %q", network)
29+
return nil, fmt.Errorf("failed to parse network address: %q", network)
2730
}
2831

2932
netMaskSize, _ := netIP.Mask.Size()
3033
if hostBits == 0 {
31-
return nil, fmt.Errorf("Host capacity cannot be zero.")
34+
return nil, fmt.Errorf("host capacity cannot be zero.")
3235
} else if hostBits > (32 - uint32(netMaskSize)) {
33-
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.")
3437
}
3538
subnetBits := 32 - uint32(netMaskSize) - hostBits
3639

@@ -61,29 +64,41 @@ func NewSubnetAllocator(network string, hostBits uint32, inUse []string) (*Subne
6164
rightMask = 0
6265
}
6366

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{
67+
sa := &SubnetAllocator{
7868
network: netIP,
7969
hostBits: hostBits,
8070
leftShift: leftShift,
8171
leftMask: leftMask,
8272
rightShift: rightShift,
8373
rightMask: rightMask,
8474
next: 0,
85-
allocMap: amap,
86-
}, 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
87102
}
88103

89104
func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
@@ -120,16 +135,26 @@ func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
120135
func (sna *SubnetAllocator) ReleaseNetwork(ipnet *net.IPNet) error {
121136
sna.mutex.Lock()
122137
defer sna.mutex.Unlock()
138+
123139
if !sna.network.Contains(ipnet.IP) {
124-
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)
125141
}
126142

127143
ipnetStr := ipnet.String()
128144
if !sna.allocMap[ipnetStr] {
129-
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
130148
}
149+
return nil
150+
}
131151

132-
sna.allocMap[ipnetStr] = false
152+
func IPToUint32(ip net.IP) uint32 {
153+
return binary.BigEndian.Uint32(ip.To4())
154+
}
133155

134-
return nil
156+
func Uint32ToIP(u uint32) net.IP {
157+
ip := make([]byte, 4)
158+
binary.BigEndian.PutUint32(ip, u)
159+
return net.IPv4(ip[0], ip[1], ip[2], ip[3])
135160
}

pkg/util/netutils/subnet_allocator_test.go renamed to pkg/network/master/subnet_allocator_test.go

+70-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package netutils
1+
package master
22

33
import (
44
"fmt"
@@ -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 {
@@ -248,3 +301,19 @@ func TestAllocateReleaseSubnet(t *testing.T) {
248301
t.Fatalf("Unexpectedly succeeded in getting network (sn=%s)", sn.String())
249302
}
250303
}
304+
305+
func TestConversion(t *testing.T) {
306+
ip := net.ParseIP("10.1.2.3")
307+
if ip == nil {
308+
t.Fatal("Failed to parse IP")
309+
}
310+
311+
u := IPToUint32(ip)
312+
t.Log(u)
313+
ip2 := Uint32ToIP(u)
314+
t.Log(ip2)
315+
316+
if !ip2.Equal(ip) {
317+
t.Fatal("Conversion back and forth failed")
318+
}
319+
}

pkg/network/master/subnets.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/openshift/origin/pkg/network"
1717
networkapi "github.com/openshift/origin/pkg/network/apis/network"
1818
"github.com/openshift/origin/pkg/network/common"
19-
"github.com/openshift/origin/pkg/util/netutils"
2019
)
2120

2221
func (master *OsdnMaster) SubnetStartMaster(clusterNetworks []common.ClusterNetwork) error {
@@ -44,9 +43,9 @@ func (master *OsdnMaster) SubnetStartMaster(clusterNetworks []common.ClusterNetw
4443
}
4544
}
4645
}
47-
var subnetAllocatorList []*netutils.SubnetAllocator
46+
var subnetAllocatorList []*SubnetAllocator
4847
for _, cn := range clusterNetworks {
49-
subnetAllocator, err := netutils.NewSubnetAllocator(cn.ClusterCIDR.String(), cn.HostSubnetLength, subrange[cn])
48+
subnetAllocator, err := NewSubnetAllocator(cn.ClusterCIDR.String(), cn.HostSubnetLength, subrange[cn])
5049
if err != nil {
5150
return err
5251
}
@@ -144,7 +143,7 @@ func (master *OsdnMaster) addNode(nodeName string, nodeUID string, nodeIP string
144143
}
145144
for _, possibleSubnet := range master.subnetAllocatorList {
146145
sn, err := possibleSubnet.GetNetwork()
147-
if err == netutils.ErrSubnetAllocatorFull {
146+
if err == ErrSubnetAllocatorFull {
148147
// Current subnet exhausted, check the next one
149148
continue
150149
} else if err != nil {

pkg/util/netutils/common.go

-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package netutils
22

33
import (
4-
"encoding/binary"
54
"fmt"
65
"net"
76

@@ -13,16 +12,6 @@ import (
1312
var localHosts []string = []string{"127.0.0.1", "::1", "localhost"}
1413
var localSubnets []string = []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "fc00::/7", "fe80::/10"}
1514

16-
func IPToUint32(ip net.IP) uint32 {
17-
return binary.BigEndian.Uint32(ip.To4())
18-
}
19-
20-
func Uint32ToIP(u uint32) net.IP {
21-
ip := make([]byte, 4)
22-
binary.BigEndian.PutUint32(ip, u)
23-
return net.IPv4(ip[0], ip[1], ip[2], ip[3])
24-
}
25-
2615
// Generate the default gateway IP Address for a subnet
2716
func GenerateDefaultGateway(sna *net.IPNet) net.IP {
2817
ip := sna.IP.To4()

pkg/util/netutils/common_test.go

+3-28
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,12 @@ import (
66
"testing"
77
)
88

9-
func TestConversion(t *testing.T) {
10-
ip := net.ParseIP("10.1.2.3")
11-
if ip == nil {
12-
t.Fatal("Failed to parse IP")
13-
}
14-
15-
u := IPToUint32(ip)
16-
t.Log(u)
17-
ip2 := Uint32ToIP(u)
18-
t.Log(ip2)
19-
20-
if !ip2.Equal(ip) {
21-
t.Fatal("Conversion back and forth failed")
22-
}
23-
}
24-
259
func TestGenerateGateway(t *testing.T) {
26-
sna, err := NewSubnetAllocator("10.1.0.0/16", 8, nil)
10+
_, ipNet, err := net.ParseCIDR("10.1.0.0/24")
2711
if err != nil {
28-
t.Fatal("Failed to initialize IP allocator: ", err)
12+
t.Fatal(err)
2913
}
30-
31-
sn, err := sna.GetNetwork()
32-
if err != nil {
33-
t.Fatal("Failed to get network: ", err)
34-
}
35-
if sn.String() != "10.1.0.0/24" {
36-
t.Fatalf("Did not get expected subnet (sn=%s)", sn.String())
37-
}
38-
39-
gatewayIP := GenerateDefaultGateway(sn)
14+
gatewayIP := GenerateDefaultGateway(ipNet)
4015
if gatewayIP.String() != "10.1.0.1" {
4116
t.Fatalf("Did not get expected gateway IP Address (gatewayIP=%s)", gatewayIP.String())
4217
}

0 commit comments

Comments
 (0)