Skip to content

Commit 7dd0bd6

Browse files
author
Rajat Chopra
committed
One can now allocate hostsubnets for hosts that are not part of the cluster. This is useful when a host wants to be part of the SDN, but not part of the cluster (e.g. F5)
1 parent 8ce6de4 commit 7dd0bd6

File tree

4 files changed

+55
-3
lines changed

4 files changed

+55
-3
lines changed

pkg/sdn/api/validation/validation.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
oapi "github.com/openshift/origin/pkg/api"
1010
sdnapi "github.com/openshift/origin/pkg/sdn/api"
11+
sdnplugin "github.com/openshift/origin/pkg/sdn/plugin"
1112
)
1213

1314
// ValidateClusterNetwork tests if required fields in the ClusterNetwork are set.
@@ -85,9 +86,16 @@ func ValidateClusterNetworkUpdate(obj *sdnapi.ClusterNetwork, old *sdnapi.Cluste
8586
func ValidateHostSubnet(hs *sdnapi.HostSubnet) field.ErrorList {
8687
allErrs := validation.ValidateObjectMeta(&hs.ObjectMeta, false, oapi.MinimalNameRequirements, field.NewPath("metadata"))
8788

88-
_, _, err := net.ParseCIDR(hs.Subnet)
89-
if err != nil {
90-
allErrs = append(allErrs, field.Invalid(field.NewPath("subnet"), hs.Subnet, err.Error()))
89+
if hs.Subnet == "" {
90+
// check if annotation exists, then let the Subnet field be empty
91+
if _, ok := hs.Annotations[sdnplugin.AssignHostSubnetAnnotation]; !ok {
92+
allErrs = append(allErrs, field.Invalid(field.NewPath("subnet"), hs.Subnet, "Field cannot be empty"))
93+
}
94+
} else {
95+
_, _, err := net.ParseCIDR(hs.Subnet)
96+
if err != nil {
97+
allErrs = append(allErrs, field.Invalid(field.NewPath("subnet"), hs.Subnet, err.Error()))
98+
}
9199
}
92100
if net.ParseIP(hs.HostIP) == nil {
93101
allErrs = append(allErrs, field.Invalid(field.NewPath("hostIP"), hs.HostIP, "invalid IP address"))

pkg/sdn/plugin/plugin.go

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const (
2525
IngressBandwidthAnnotation string = "kubernetes.io/ingress-bandwidth"
2626
EgressBandwidthAnnotation string = "kubernetes.io/egress-bandwidth"
2727
AssignMacVlanAnnotation string = "pod.network.openshift.io/assign-macvlan"
28+
AssignHostSubnetAnnotation string = "pod.network.openshift.io/assign-subnet"
2829
)
2930

3031
func IsOpenShiftNetworkPlugin(pluginName string) bool {

pkg/sdn/plugin/subnets.go

+36
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func (master *OsdnMaster) SubnetStartMaster(clusterNetwork *net.IPNet, hostSubne
4242
}
4343

4444
go utilwait.Forever(master.watchNodes, 0)
45+
go utilwait.Forever(master.watchSubnets, 0)
4546
return nil
4647
}
4748

@@ -242,6 +243,41 @@ func (node *OsdnNode) initSelfSubnet() error {
242243
return nil
243244
}
244245

246+
// Only run on the master
247+
// Watch for all hostsubnet events and if one is found with the right annotation, use the SubnetAllocator to dole a real subnet
248+
func (master *OsdnMaster) watchSubnets() {
249+
master.registry.RunEventQueue(HostSubnets, func(delta cache.Delta) error {
250+
hs := delta.Object.(*osapi.HostSubnet)
251+
name := hs.ObjectMeta.Name
252+
hostIP := hs.HostIP
253+
254+
log.V(5).Infof("Watch %s event for HostSubnet %q", delta.Type, hs.ObjectMeta.Name)
255+
switch delta.Type {
256+
case cache.Sync, cache.Added, cache.Updated:
257+
if _, ok := hs.Annotations[AssignHostSubnetAnnotation]; ok {
258+
// Delete the annotated hostsubnet and create a new one with an assigned subnet
259+
// We do not update (instead of delete+create) because the watchSubnets on the nodes
260+
// will skip the event if it finds that the hostsubnet has the same host
261+
// And we cannot fix the watchSubnets code for node because it will break migration if
262+
// nodes are upgraded after the master
263+
err := master.registry.DeleteSubnet(name)
264+
if err != nil {
265+
log.Errorf("Error in deleting annotated subnet from master, name: %s, ip %s: %v", name, hostIP, err)
266+
return nil
267+
}
268+
err = master.addNode(name, hostIP)
269+
if err != nil {
270+
log.Errorf("Error creating subnet for node %s, ip %s: %v", name, hostIP, err)
271+
return nil
272+
}
273+
}
274+
case cache.Deleted:
275+
// ignore all deleted hostsubnets
276+
}
277+
return nil
278+
})
279+
}
280+
245281
// Only run on the nodes
246282
func (node *OsdnNode) watchSubnets() {
247283
subnets := make(map[string]*osapi.HostSubnet)

pkg/util/netutils/subnet_allocator.go

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package netutils
33
import (
44
"fmt"
55
"net"
6+
"sync"
67
)
78

89
type SubnetAllocator struct {
@@ -14,6 +15,7 @@ type SubnetAllocator struct {
1415
rightMask uint32
1516
next uint32
1617
allocMap map[string]bool
18+
mutex sync.Mutex
1719
}
1820

1921
func NewSubnetAllocator(network string, hostBits uint32, inUse []string) (*SubnetAllocator, error) {
@@ -85,6 +87,9 @@ func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
8587
numSubnets uint32
8688
numSubnetBits uint32
8789
)
90+
sna.mutex.Lock()
91+
defer sna.mutex.Unlock()
92+
8893
baseipu := IPToUint32(sna.network.IP)
8994
netMaskSize, _ := sna.network.Mask.Size()
9095
numSubnetBits = 32 - uint32(netMaskSize) - sna.hostBits
@@ -109,6 +114,8 @@ func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
109114
}
110115

111116
func (sna *SubnetAllocator) ReleaseNetwork(ipnet *net.IPNet) error {
117+
sna.mutex.Lock()
118+
defer sna.mutex.Unlock()
112119
if !sna.network.Contains(ipnet.IP) {
113120
return fmt.Errorf("Provided subnet %v doesn't belong to the network %v.", ipnet, sna.network)
114121
}

0 commit comments

Comments
 (0)