Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1608 from kaccardi/topic/reserve-cnci-net
Browse files Browse the repository at this point in the history
send cnci refresh command
  • Loading branch information
kaccardi committed Jan 5, 2018
2 parents a28ffce + 23f5011 commit 3ef55e9
Show file tree
Hide file tree
Showing 27 changed files with 768 additions and 39 deletions.
21 changes: 21 additions & 0 deletions ciao-controller/client.go
Expand Up @@ -45,6 +45,7 @@ type controllerClient interface {
unMapExternalIP(t types.Tenant, m types.MappedIP) error
attachVolume(volID string, instanceID string, nodeID string) error
ssntpClient() *ssntp.Client
CNCIRefresh(cnciID string, cnciList []payloads.CNCINet) error
}

type ssntpClient struct {
Expand Down Expand Up @@ -777,3 +778,23 @@ func (client *ssntpClient) unMapExternalIP(t types.Tenant, m types.MappedIP) err
_, err = client.ssntp.SendCommand(ssntp.ReleasePublicIP, y)
return err
}

func (client *ssntpClient) CNCIRefresh(cnciID string, cnciList []payloads.CNCINet) error {
payload := payloads.CommandCNCIRefresh{
Command: payloads.CNCIRefreshCommand{
CNCIUUID: cnciID,
CNCIList: cnciList,
},
}

y, err := yaml.Marshal(payload)
if err != nil {
return err
}

glog.Infof("Refresh CNCI %s: %v\n", cnciID, cnciList)
glog.V(1).Info(string(y))

_, err = client.ssntp.SendCommand(ssntp.RefreshCNCI, y)
return err
}
5 changes: 5 additions & 0 deletions ciao-controller/client_wrapper_test.go
Expand Up @@ -22,6 +22,7 @@ import (
"time"

"github.com/ciao-project/ciao/ciao-controller/types"
"github.com/ciao-project/ciao/payloads"
"github.com/ciao-project/ciao/ssntp"
)

Expand Down Expand Up @@ -272,3 +273,7 @@ func (client *ssntpClientWrapper) sendAndDelEventChan(cmd ssntp.Event) {
func (client *ssntpClientWrapper) RemoveInstance(ID string) {
client.realClient.RemoveInstance(ID)
}

func (client *ssntpClientWrapper) CNCIRefresh(cnciID string, cnciList []payloads.CNCINet) error {
return client.realClient.CNCIRefresh(cnciID, cnciList)
}
82 changes: 80 additions & 2 deletions ciao-controller/cnci.go
Expand Up @@ -16,8 +16,11 @@ package main

import (
"crypto/rand"
"encoding/binary"
"encoding/hex"
"fmt"
"hash/crc32"
"net"
"sync"
"time"

Expand Down Expand Up @@ -122,6 +125,36 @@ func (c *CNCI) transitionState(to CNCIState) {
}
}

func getTunnelIP(subnet string) net.IP {
startTunnelIP := net.ParseIP(cnciNet.String())
IP, ipNet, err := net.ParseCIDR(subnet)
if err != nil {
return nil
}

ones, bits := ipNet.Mask.Size()
hostBits := bits - ones

addr := binary.BigEndian.Uint32(IP.To4())
mask := binary.BigEndian.Uint32(ipNet.Mask)
start := binary.BigEndian.Uint32(startTunnelIP.To4())
subnetNum := addr & mask

// to calculate the tunnelIP, use the significant subnet
// bits only. Since the top 12 bits are always the same,
// get rid of them.
tunnelNum := (subnetNum & 0x00cfffff) >> uint(hostBits)

// add one to this value so that we don't allocate host 0
tunnelNum++

tunnelIP := make(net.IP, net.IPv4len)
addr = start + uint32(tunnelNum)
binary.BigEndian.PutUint32(tunnelIP, addr)

return tunnelIP
}

// Active will return true if the CNCI has been launched successfully
func (c *CNCIManager) Active(ID string) bool {
c.cnciLock.RLock()
Expand Down Expand Up @@ -223,7 +256,12 @@ func (c *CNCIManager) WaitForActive(subnet string) error {

// we release the lock before waiting because
// we need to be able to read the event channel.
return waitForEventTimeout(ch, added, cnciEventTimeout)
err = waitForEventTimeout(ch, added, cnciEventTimeout)
if err != nil {
return err
}

return c.refresh()
}

// ScheduleRemoveSubnet will kick off a timer to remove a subnet after 5 min.
Expand Down Expand Up @@ -294,7 +332,12 @@ func (c *CNCIManager) RemoveSubnet(subnet string) error {

c.cnciLock.Unlock()

return waitForEventTimeout(ch, removed, cnciEventTimeout)
err = waitForEventTimeout(ch, removed, cnciEventTimeout)
if err != nil {
return err
}

return c.refresh()
}

// CNCIRemoved will move the CNCI back to the initial state
Expand Down Expand Up @@ -401,6 +444,41 @@ func (c *CNCIManager) waitForActive(subnet string) error {
return errors.New("CNCI not active")
}

func (c *CNCIManager) refresh() error {
c.cnciLock.RLock()
defer c.cnciLock.RUnlock()

var cnciList []payloads.CNCINet

// create a ConcentratorInstanceRefresh struct for each cnci
for _, cnci := range c.cncis {
tunnelID := crc32.ChecksumIEEE([]byte(c.tenant))
tunnelIP := getTunnelIP(cnci.instance.Subnet)
if tunnelIP == nil {
return errors.New("Unable to derive CNCI tunnel IP")
}

r := payloads.CNCINet{
PhysicalIP: cnci.instance.IPAddress,
Subnet: cnci.instance.Subnet,
TunnelIP: tunnelIP.String(),
TunnelID: tunnelID,
}
cnciList = append(cnciList, r)
}

// send the event to each cnci
for _, cnci := range c.cncis {
err := c.ctrl.client.CNCIRefresh(cnci.instance.ID, cnciList)
if err != nil {
// keep going, but log error.
glog.Warningf("Unable to send cnci refresh to %s: (%v)", cnci.instance.ID, err)
}
}

return nil
}

// GetInstanceCNCI will return the CNCI Instance for a specific tenant Instance
func (c *CNCIManager) GetInstanceCNCI(ID string) (*types.Instance, error) {
// figure out what subnet we are looking for.
Expand Down
30 changes: 30 additions & 0 deletions ciao-controller/main.go
Expand Up @@ -22,6 +22,7 @@ import (
"crypto/x509"
"flag"
"fmt"
"net"
"net/http"
"os"
"os/signal"
Expand Down Expand Up @@ -56,6 +57,23 @@ type controller struct {
httpServers []*http.Server
}

type cnciNetFlag string

func (c *cnciNetFlag) String() string {
return string(*c)
}

func (c *cnciNetFlag) Set(val string) error {
IP := net.ParseIP(val)
if IP == nil {
return fmt.Errorf("Unable to parse CNCI network address")
}

*c = cnciNetFlag(IP.String())

return nil
}

var cert = flag.String("cert", "", "Client certificate")
var caCert = flag.String("cacert", "", "CA certificate")
var serverURL = flag.String("url", "", "Server URL")
Expand All @@ -73,6 +91,10 @@ var cephID = flag.String("ceph_id", "", "ceph client id")

var adminSSHKey = ""

// this default allows us to have up to 32K hosts within the upper part
// of the 192.168.0.0/16 private address space.
var cnciNet cnciNetFlag = "192.168.128.0"

func init() {
flag.Parse()

Expand Down Expand Up @@ -195,6 +217,14 @@ func main() {
clientCertCAPath = clusterConfig.Configure.Controller.ClientAuthCACertPath
}

if clusterConfig.Configure.Controller.CNCINet != "" {
err = cnciNet.Set(clusterConfig.Configure.Controller.CNCINet)
if err != nil {
glog.Fatalf("Invalid CNCI Net cluster configuration: %v", err)
return
}
}

ctl.ds.GenerateCNCIWorkload(cnciVCPUs, cnciMem, cnciDisk, adminSSHKey)

database.Logger = gloginterface.CiaoGlogLogger{}
Expand Down
1 change: 1 addition & 0 deletions ciao-deploy/cmd/setup.go
Expand Up @@ -140,6 +140,7 @@ func init() {
setupCmd.Flags().StringVar(&clusterConf.AdminSSHKeyPath, "admin-ssh-key", "", "Path to SSH public key for accessing CNCI")
setupCmd.Flags().StringVar(&clusterConf.ComputeNet, "compute-net", hostNetwork, "Network range for compute network")
setupCmd.Flags().StringVar(&clusterConf.MgmtNet, "mgmt-net", hostNetwork, "Network range for management network")
setupCmd.Flags().StringVar(&clusterConf.CNCINet, "cnci-net", "192.168.128.0", "Host start address for CNCI mgmt network - must be at least /18")
setupCmd.Flags().StringVar(&clusterConf.ServerIP, "server-ip", hostIP, "IP address nodes can reach this host on")
setupCmd.Flags().StringVar(&clusterConf.ServerHostname, "server-hostname", deploy.HostnameWithFallback(), "Name or FQDN that this host can be reached on")
setupCmd.Flags().StringVar(&imageCacheDirectory, "image-cache-directory", deploy.DefaultImageCacheDir(), "Directory to use for caching of downloaded images")
Expand Down
2 changes: 2 additions & 0 deletions ciao-deploy/deploy/setup.go
Expand Up @@ -44,6 +44,7 @@ type ClusterConfiguration struct {
AdminSSHKeyPath string
ComputeNet string
MgmtNet string
CNCINet string
ServerIP string
AuthCACertPath string
AuthAdminCertPath string
Expand Down Expand Up @@ -96,6 +97,7 @@ func createConfigurationFile(ctx context.Context, clusterConf *ClusterConfigurat
config.Configure.Controller.HTTPSCACert = clusterConf.HTTPSCaCertPath
config.Configure.Controller.HTTPSKey = clusterConf.HTTPSCertPath
config.Configure.Controller.ClientAuthCACertPath = clusterConf.AuthCACertPath
config.Configure.Controller.CNCINet = clusterConf.CNCINet

config.Configure.Controller.AdminSSHKey = adminSSHKeyData

Expand Down
10 changes: 10 additions & 0 deletions ciao-scheduler/scheduler.go
Expand Up @@ -546,6 +546,10 @@ func (sched *ssntpSchedulerServer) getCommandConcentratorUUID(command ssntp.Comm
var cmd payloads.CommandReleasePublicIP
err := yaml.Unmarshal(payload, &cmd)
return cmd.ReleaseIP.ConcentratorUUID, err
case ssntp.RefreshCNCI:
var cmd payloads.CommandCNCIRefresh
err := yaml.Unmarshal(payload, &cmd)
return cmd.Command.CNCIUUID, err
}
}

Expand Down Expand Up @@ -811,6 +815,8 @@ func (sched *ssntpSchedulerServer) CommandForward(controllerUUID string, command
fallthrough
case ssntp.Restore:
dest, instanceUUID = sched.fwdCmdToComputeNode(command, payload)
case ssntp.RefreshCNCI:
fallthrough
case ssntp.AssignPublicIP:
fallthrough
case ssntp.ReleasePublicIP:
Expand Down Expand Up @@ -1125,6 +1131,10 @@ func setSSNTPForwardRules(sched *ssntpSchedulerServer) {
Operand: ssntp.ReleasePublicIP,
CommandForward: sched,
},
{ // all RefreshCNCI commands are processed by the Command forwarder
Operand: ssntp.RefreshCNCI,
CommandForward: sched,
},
}
}

Expand Down
2 changes: 2 additions & 0 deletions configuration/configuration_test.go
Expand Up @@ -65,6 +65,7 @@ const fullValidConf = `configure:
cnci_disk: 128
admin_ssh_key: ""
client_auth_ca_cert_path: /etc/pki/ciao/auth-CA.pem
cnci_net: 10.10.0.0
launcher:
compute_net:
- 192.168.1.0/24
Expand Down Expand Up @@ -119,6 +120,7 @@ func fillPayload(conf *payloads.Configure) {
conf.Configure.Controller.CNCIMem = 128
conf.Configure.Controller.CNCIDisk = 128
conf.Configure.Controller.ClientAuthCACertPath = clientAuthCACert
conf.Configure.Controller.CNCINet = "10.10.0.0"
conf.Configure.Launcher.ComputeNetwork = []string{computeNet}
conf.Configure.Launcher.ManagementNetwork = []string{mgmtNet}
conf.Configure.Launcher.ChildUser = "ciao"
Expand Down
31 changes: 31 additions & 0 deletions networking/ciao-cnci-agent/client.go
Expand Up @@ -169,6 +169,17 @@ func createMandatoryDirs() error {
return nil
}

func processRefreshCNCI(cmd *payloads.CommandCNCIRefresh) {
c := &cmd.Command
glog.Infof("Processing: CiaoCommandCNCIRefresh %v", c)

// add call to function to refresh cnci.
err := refreshCNCI(c)
if err != nil {
glog.Errorf("Unable to refresh CNCI list: %v", err)
}
}

func processCommand(client *ssntpConn, cmd *cmdWrapper) {

switch netCmd := cmd.cmd.(type) {
Expand Down Expand Up @@ -232,6 +243,10 @@ func processCommand(client *ssntpConn, cmd *cmdWrapper) {
}
}(cmd)

case *payloads.CommandCNCIRefresh:

go processRefreshCNCI(netCmd)

case *statusConnected:
//Block and send this as it does not make sense to send other events
//or process commands when we have not yet registered
Expand Down Expand Up @@ -291,6 +306,22 @@ func (client *agentClient) CommandNotify(cmd ssntp.Command, frame *ssntp.Frame)
client.cmdCh <- &cmdWrapper{&releaseIP}
}(payload)

case ssntp.RefreshCNCI:
glog.Infof("CMD: ssntp.RefreshCNCI %v", len(payload))

go func(payload []byte) {
var refreshCNCI payloads.CommandCNCIRefresh

err := yaml.Unmarshal(payload, &refreshCNCI)
if err != nil {
glog.Warning("Error unmarshalling CNCI refresh")
return
}
glog.Infof("CMD: ssntp.RefreshCNCI %v", refreshCNCI)

client.cmdCh <- &cmdWrapper{&refreshCNCI}
}(payload)

default:
glog.Infof("CMD: %s", cmd)
}
Expand Down
17 changes: 17 additions & 0 deletions networking/ciao-cnci-agent/network.go
Expand Up @@ -409,3 +409,20 @@ func releasePubIP(cmd *payloads.PublicIPCommand) error {
err = gFw.PublicIPAccess(libsnnet.FwDisable, prIP, puIP, gCnci.ComputeLink[0].Attrs().Name)
return errors.Wrapf(err, "release ip")
}

func refreshCNCI(cmd *payloads.CNCIRefreshCommand) error {
var neighbors []libsnnet.Neighbor

cncis := cmd.CNCIList
for _, c := range cncis {
n := libsnnet.Neighbor{
PhysicalIP: c.PhysicalIP,
Subnet: c.Subnet,
TunnelIP: c.TunnelIP,
TunnelID: c.TunnelID,
}
neighbors = append(neighbors, n)
}

return gCnci.UpdateNeighbors(neighbors)
}

0 comments on commit 3ef55e9

Please sign in to comment.