Skip to content

Commit

Permalink
One can now allocate hostsubnets for hosts that are not part of the c…
Browse files Browse the repository at this point in the history
…luster. This is useful when a host wants to be part of the SDN, but not part of the cluster (e.g. F5)
  • Loading branch information
Rajat Chopra committed Sep 30, 2016
1 parent 8ce6de4 commit 6926d71
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 3 deletions.
14 changes: 11 additions & 3 deletions pkg/sdn/api/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

oapi "github.com/openshift/origin/pkg/api"
sdnapi "github.com/openshift/origin/pkg/sdn/api"
sdnplugin "github.com/openshift/origin/pkg/sdn/plugin"
)

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

_, _, err := net.ParseCIDR(hs.Subnet)
if err != nil {
allErrs = append(allErrs, field.Invalid(field.NewPath("subnet"), hs.Subnet, err.Error()))
if hs.Subnet == "" {
// check if annotation exists, then let the Subnet field be empty
if _, ok := hs.Annotations[sdnplugin.AssignHostSubnetAnnotation]; !ok {
allErrs = append(allErrs, field.Invalid(field.NewPath("subnet"), hs.Subnet, "Field cannot be empty"))
}
} else {
_, _, err := net.ParseCIDR(hs.Subnet)
if err != nil {
allErrs = append(allErrs, field.Invalid(field.NewPath("subnet"), hs.Subnet, err.Error()))
}
}
if net.ParseIP(hs.HostIP) == nil {
allErrs = append(allErrs, field.Invalid(field.NewPath("hostIP"), hs.HostIP, "invalid IP address"))
Expand Down
1 change: 1 addition & 0 deletions pkg/sdn/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
IngressBandwidthAnnotation string = "kubernetes.io/ingress-bandwidth"
EgressBandwidthAnnotation string = "kubernetes.io/egress-bandwidth"
AssignMacVlanAnnotation string = "pod.network.openshift.io/assign-macvlan"
AssignHostSubnetAnnotation string = "pod.network.openshift.io/assign-subnet"
)

func IsOpenShiftNetworkPlugin(pluginName string) bool {
Expand Down
36 changes: 36 additions & 0 deletions pkg/sdn/plugin/subnets.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func (master *OsdnMaster) SubnetStartMaster(clusterNetwork *net.IPNet, hostSubne
}

go utilwait.Forever(master.watchNodes, 0)
go utilwait.Forever(master.watchSubnets, 0)
return nil
}

Expand Down Expand Up @@ -242,6 +243,41 @@ func (node *OsdnNode) initSelfSubnet() error {
return nil
}

// Only run on the master
// Watch for all hostsubnet events and if one is found with the right annotation, use the SubnetAllocator to dole a real subnet
func (master *OsdnMaster) watchSubnets() {
RunEventQueue(master.osClient, HostSubnets, func(delta cache.Delta) error {
hs := delta.Object.(*osapi.HostSubnet)
name := hs.ObjectMeta.Name
hostIP := hs.HostIP

log.V(5).Infof("Watch %s event for HostSubnet %q", delta.Type, hs.ObjectMeta.Name)
switch delta.Type {
case cache.Sync, cache.Added, cache.Updated:
if _, ok := hs.Annotations[AssignHostSubnetAnnotation]; ok {
// Delete the annotated hostsubnet and create a new one with an assigned subnet
// We do not update (instead of delete+create) because the watchSubnets on the nodes
// will skip the event if it finds that the hostsubnet has the same host
// And we cannot fix the watchSubnets code for node because it will break migration if
// nodes are upgraded after the master
err := master.osClient.HostSubnets().Delete(name)
if err != nil {
log.Errorf("Error in deleting annotated subnet from master, name: %s, ip %s: %v", name, hostIP, err)
return nil
}
err = master.addNode(name, hostIP)
if err != nil {
log.Errorf("Error creating subnet for node %s, ip %s: %v", name, hostIP, err)
return nil
}
}
case cache.Deleted:
// ignore all deleted hostsubnets
}
return nil
})
}

// Only run on the nodes
func (node *OsdnNode) watchSubnets() {
subnets := make(map[string]*osapi.HostSubnet)
Expand Down
7 changes: 7 additions & 0 deletions pkg/util/netutils/subnet_allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package netutils
import (
"fmt"
"net"
"sync"
)

type SubnetAllocator struct {
Expand All @@ -14,6 +15,7 @@ type SubnetAllocator struct {
rightMask uint32
next uint32
allocMap map[string]bool
mutex sync.Mutex
}

func NewSubnetAllocator(network string, hostBits uint32, inUse []string) (*SubnetAllocator, error) {
Expand Down Expand Up @@ -85,6 +87,9 @@ func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
numSubnets uint32
numSubnetBits uint32
)
sna.mutex.Lock()
defer sna.mutex.Unlock()

baseipu := IPToUint32(sna.network.IP)
netMaskSize, _ := sna.network.Mask.Size()
numSubnetBits = 32 - uint32(netMaskSize) - sna.hostBits
Expand All @@ -109,6 +114,8 @@ func (sna *SubnetAllocator) GetNetwork() (*net.IPNet, error) {
}

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

0 comments on commit 6926d71

Please sign in to comment.